1 /*
2 * PROJECT: ReactOS Clipboard Viewer
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Provides a view of the contents of the ReactOS clipboard.
5 * COPYRIGHT: Copyright 2015-2018 Ricardo Hanke
6 * Copyright 2015-2018 Hermes Belusca-Maito
7 */
8
9 #include "precomp.h"
10
11 static const WCHAR szClassName[] = L"ClipBookWClass";
12
13 CLIPBOARD_GLOBALS Globals;
14 SCROLLSTATE Scrollstate;
15
SaveClipboardToFile(void)16 static void SaveClipboardToFile(void)
17 {
18 OPENFILENAMEW sfn;
19 LPWSTR c;
20 WCHAR szFileName[MAX_PATH];
21 WCHAR szFilterMask[MAX_STRING_LEN + 10];
22
23 ZeroMemory(&szFilterMask, sizeof(szFilterMask));
24 c = szFilterMask + LoadStringW(Globals.hInstance, STRING_FORMAT_NT, szFilterMask, MAX_STRING_LEN) + 1;
25 wcscpy(c, L"*.clp");
26
27 ZeroMemory(&szFileName, sizeof(szFileName));
28 ZeroMemory(&sfn, sizeof(sfn));
29 sfn.lStructSize = sizeof(sfn);
30 sfn.hwndOwner = Globals.hMainWnd;
31 sfn.hInstance = Globals.hInstance;
32 sfn.lpstrFilter = szFilterMask;
33 sfn.lpstrFile = szFileName;
34 sfn.nMaxFile = ARRAYSIZE(szFileName);
35 sfn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
36 sfn.lpstrDefExt = L"clp";
37
38 if (!GetSaveFileNameW(&sfn))
39 return;
40
41 if (!OpenClipboard(Globals.hMainWnd))
42 {
43 ShowLastWin32Error(Globals.hMainWnd);
44 return;
45 }
46
47 WriteClipboardFile(szFileName, CLIP_FMT_NT /* CLIP_FMT_31 */);
48
49 CloseClipboard();
50 }
51
LoadClipboardDataFromFile(LPWSTR lpszFileName)52 static void LoadClipboardDataFromFile(LPWSTR lpszFileName)
53 {
54 if (MessageBoxRes(Globals.hMainWnd, Globals.hInstance,
55 STRING_DELETE_MSG, STRING_DELETE_TITLE,
56 MB_ICONWARNING | MB_YESNO) != IDYES)
57 {
58 return;
59 }
60
61 if (!OpenClipboard(Globals.hMainWnd))
62 {
63 ShowLastWin32Error(Globals.hMainWnd);
64 return;
65 }
66
67 EmptyClipboard();
68 ReadClipboardFile(lpszFileName);
69
70 CloseClipboard();
71 }
72
LoadClipboardFromFile(void)73 static void LoadClipboardFromFile(void)
74 {
75 OPENFILENAMEW ofn;
76 LPWSTR c;
77 WCHAR szFileName[MAX_PATH];
78 WCHAR szFilterMask[MAX_STRING_LEN + 10];
79
80 ZeroMemory(&szFilterMask, sizeof(szFilterMask));
81 c = szFilterMask + LoadStringW(Globals.hInstance, STRING_FORMAT_GEN, szFilterMask, MAX_STRING_LEN) + 1;
82 wcscpy(c, L"*.clp");
83
84 ZeroMemory(&szFileName, sizeof(szFileName));
85 ZeroMemory(&ofn, sizeof(ofn));
86 ofn.lStructSize = sizeof(ofn);
87 ofn.hwndOwner = Globals.hMainWnd;
88 ofn.hInstance = Globals.hInstance;
89 ofn.lpstrFilter = szFilterMask;
90 ofn.lpstrFile = szFileName;
91 ofn.nMaxFile = ARRAYSIZE(szFileName);
92 ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
93
94 if (!GetOpenFileNameW(&ofn))
95 return;
96
97 LoadClipboardDataFromFile(szFileName);
98 }
99
LoadClipboardFromDrop(HDROP hDrop)100 static void LoadClipboardFromDrop(HDROP hDrop)
101 {
102 WCHAR szFileName[MAX_PATH];
103
104 DragQueryFileW(hDrop, 0, szFileName, ARRAYSIZE(szFileName));
105 DragFinish(hDrop);
106
107 LoadClipboardDataFromFile(szFileName);
108 }
109
SetDisplayFormat(UINT uFormat)110 static void SetDisplayFormat(UINT uFormat)
111 {
112 RECT rc;
113
114 CheckMenuItem(Globals.hMenu, Globals.uCheckedItem, MF_BYCOMMAND | MF_UNCHECKED);
115 Globals.uCheckedItem = uFormat + CMD_AUTOMATIC;
116 CheckMenuItem(Globals.hMenu, Globals.uCheckedItem, MF_BYCOMMAND | MF_CHECKED);
117
118 if (uFormat == 0)
119 {
120 Globals.uDisplayFormat = GetAutomaticClipboardFormat();
121 }
122 else
123 {
124 Globals.uDisplayFormat = uFormat;
125 }
126
127 GetClipboardDataDimensions(Globals.uDisplayFormat, &rc);
128 Scrollstate.CurrentX = Scrollstate.CurrentY = 0;
129 Scrollstate.iWheelCarryoverX = Scrollstate.iWheelCarryoverY = 0;
130 UpdateWindowScrollState(Globals.hMainWnd, rc.right, rc.bottom, &Scrollstate);
131
132 InvalidateRect(Globals.hMainWnd, NULL, TRUE);
133 }
134
InitMenuPopup(HMENU hMenu,LPARAM index)135 static void InitMenuPopup(HMENU hMenu, LPARAM index)
136 {
137 if ((GetMenuItemID(hMenu, 0) == CMD_DELETE) || (GetMenuItemID(hMenu, 1) == CMD_SAVE_AS))
138 {
139 if (CountClipboardFormats() == 0)
140 {
141 EnableMenuItem(hMenu, CMD_DELETE, MF_GRAYED);
142 EnableMenuItem(hMenu, CMD_SAVE_AS, MF_GRAYED);
143 }
144 else
145 {
146 EnableMenuItem(hMenu, CMD_DELETE, MF_ENABLED);
147 EnableMenuItem(hMenu, CMD_SAVE_AS, MF_ENABLED);
148 }
149 }
150
151 DrawMenuBar(Globals.hMainWnd);
152 }
153
UpdateDisplayMenu(void)154 static void UpdateDisplayMenu(void)
155 {
156 UINT uFormat;
157 HMENU hMenu;
158 WCHAR szFormatName[MAX_FMT_NAME_LEN + 1];
159
160 hMenu = GetSubMenu(Globals.hMenu, DISPLAY_MENU_POS);
161
162 while (GetMenuItemCount(hMenu) > 1)
163 {
164 DeleteMenu(hMenu, 1, MF_BYPOSITION);
165 }
166
167 if (CountClipboardFormats() == 0)
168 return;
169
170 if (!OpenClipboard(Globals.hMainWnd))
171 return;
172
173 AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
174
175 /* Display the supported clipboard formats first */
176 for (uFormat = EnumClipboardFormats(0); uFormat;
177 uFormat = EnumClipboardFormats(uFormat))
178 {
179 if (IsClipboardFormatSupported(uFormat))
180 {
181 RetrieveClipboardFormatName(Globals.hInstance, uFormat, TRUE,
182 szFormatName, ARRAYSIZE(szFormatName));
183 AppendMenuW(hMenu, MF_STRING, CMD_AUTOMATIC + uFormat, szFormatName);
184 }
185 }
186
187 /* Now display the unsupported clipboard formats */
188 for (uFormat = EnumClipboardFormats(0); uFormat;
189 uFormat = EnumClipboardFormats(uFormat))
190 {
191 if (!IsClipboardFormatSupported(uFormat))
192 {
193 RetrieveClipboardFormatName(Globals.hInstance, uFormat, TRUE,
194 szFormatName, ARRAYSIZE(szFormatName));
195 AppendMenuW(hMenu, MF_STRING | MF_GRAYED, 0, szFormatName);
196 }
197 }
198
199 CloseClipboard();
200 }
201
OnCommand(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)202 static int OnCommand(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
203 {
204 switch (LOWORD(wParam))
205 {
206 case CMD_OPEN:
207 {
208 LoadClipboardFromFile();
209 break;
210 }
211
212 case CMD_SAVE_AS:
213 {
214 SaveClipboardToFile();
215 break;
216 }
217
218 case CMD_EXIT:
219 {
220 PostMessageW(Globals.hMainWnd, WM_CLOSE, 0, 0);
221 break;
222 }
223
224 case CMD_DELETE:
225 {
226 if (MessageBoxRes(Globals.hMainWnd, Globals.hInstance,
227 STRING_DELETE_MSG, STRING_DELETE_TITLE,
228 MB_ICONWARNING | MB_YESNO) != IDYES)
229 {
230 break;
231 }
232
233 DeleteClipboardContent();
234 break;
235 }
236
237 case CMD_AUTOMATIC:
238 {
239 SetDisplayFormat(0);
240 break;
241 }
242
243 case CMD_HELP:
244 {
245 HtmlHelpW(Globals.hMainWnd, L"clipbrd.chm", 0, 0);
246 break;
247 }
248
249 case CMD_ABOUT:
250 {
251 WCHAR szTitle[MAX_STRING_LEN];
252
253 LoadStringW(Globals.hInstance, STRING_CLIPBOARD, szTitle, ARRAYSIZE(szTitle));
254 ShellAboutW(Globals.hMainWnd, szTitle, NULL,
255 LoadIconW(Globals.hInstance, MAKEINTRESOURCEW(CLIPBRD_ICON)));
256 break;
257 }
258
259 default:
260 {
261 break;
262 }
263 }
264 return 0;
265 }
266
OnPaint(HWND hWnd,WPARAM wParam,LPARAM lParam)267 static void OnPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
268 {
269 HDC hdc;
270 PAINTSTRUCT ps;
271 COLORREF crOldBkColor, crOldTextColor;
272 RECT rc;
273
274 if (!OpenClipboard(Globals.hMainWnd))
275 return;
276
277 hdc = BeginPaint(hWnd, &ps);
278
279 /* Erase the background if needed */
280 if (ps.fErase)
281 FillRect(ps.hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
282
283 /* Set the correct background and text colors */
284 crOldBkColor = SetBkColor(ps.hdc, GetSysColor(COLOR_WINDOW));
285 crOldTextColor = SetTextColor(ps.hdc, GetSysColor(COLOR_WINDOWTEXT));
286
287 /* Realize the clipboard palette if there is one */
288 RealizeClipboardPalette(ps.hdc);
289
290 switch (Globals.uDisplayFormat)
291 {
292 case CF_NONE:
293 {
294 /* The clipboard is empty */
295 break;
296 }
297
298 case CF_DSPTEXT:
299 case CF_TEXT:
300 case CF_OEMTEXT:
301 case CF_UNICODETEXT:
302 {
303 DrawTextFromClipboard(Globals.uDisplayFormat, ps, Scrollstate);
304 break;
305 }
306
307 case CF_DSPBITMAP:
308 case CF_BITMAP:
309 {
310 BitBltFromClipboard(ps, Scrollstate, SRCCOPY);
311 break;
312 }
313
314 case CF_DIB:
315 case CF_DIBV5:
316 {
317 SetDIBitsToDeviceFromClipboard(Globals.uDisplayFormat, ps, Scrollstate, DIB_RGB_COLORS);
318 break;
319 }
320
321 case CF_DSPMETAFILEPICT:
322 case CF_METAFILEPICT:
323 {
324 GetClientRect(hWnd, &rc);
325 PlayMetaFileFromClipboard(hdc, &rc);
326 break;
327 }
328
329 case CF_DSPENHMETAFILE:
330 case CF_ENHMETAFILE:
331 {
332 GetClientRect(hWnd, &rc);
333 PlayEnhMetaFileFromClipboard(hdc, &rc);
334 break;
335 }
336
337 // case CF_PALETTE:
338 // TODO: Draw a palette with squares filled with colors.
339 // break;
340
341 case CF_OWNERDISPLAY:
342 {
343 HGLOBAL hglb;
344 PPAINTSTRUCT pps;
345
346 hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(ps));
347 if (hglb)
348 {
349 pps = GlobalLock(hglb);
350 CopyMemory(pps, &ps, sizeof(ps));
351 GlobalUnlock(hglb);
352
353 SendClipboardOwnerMessage(TRUE, WM_PAINTCLIPBOARD,
354 (WPARAM)hWnd, (LPARAM)hglb);
355
356 GlobalFree(hglb);
357 }
358 break;
359 }
360
361 case CF_HDROP:
362 {
363 GetClientRect(hWnd, &rc);
364 HDropFromClipboard(hdc, &rc);
365 break;
366 }
367
368 default:
369 {
370 GetClientRect(hWnd, &rc);
371 DrawTextFromResource(Globals.hInstance, ERROR_UNSUPPORTED_FORMAT,
372 hdc, &rc, DT_CENTER | DT_WORDBREAK | DT_NOPREFIX);
373 break;
374 }
375 }
376
377 /* Restore the original colors */
378 SetTextColor(ps.hdc, crOldTextColor);
379 SetBkColor(ps.hdc, crOldBkColor);
380
381 EndPaint(hWnd, &ps);
382
383 CloseClipboard();
384 }
385
MainWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)386 static LRESULT WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
387 {
388 switch(uMsg)
389 {
390 case WM_CREATE:
391 {
392 TEXTMETRICW tm;
393 HDC hDC = GetDC(hWnd);
394
395 /*
396 * Note that the method with GetObjectW just returns
397 * the original parameters with which the font was created.
398 */
399 if (GetTextMetricsW(hDC, &tm))
400 {
401 Globals.CharWidth = tm.tmMaxCharWidth; // tm.tmAveCharWidth;
402 Globals.CharHeight = tm.tmHeight + tm.tmExternalLeading;
403 }
404 ReleaseDC(hWnd, hDC);
405
406
407 Globals.hMenu = GetMenu(hWnd);
408 Globals.hWndNext = SetClipboardViewer(hWnd);
409
410 // For now, the Help dialog item is disabled because of lacking of HTML support
411 EnableMenuItem(Globals.hMenu, CMD_HELP, MF_BYCOMMAND | MF_GRAYED);
412
413 UpdateLinesToScroll(&Scrollstate);
414
415 UpdateDisplayMenu();
416 SetDisplayFormat(0);
417
418 DragAcceptFiles(hWnd, TRUE);
419 break;
420 }
421
422 case WM_CLOSE:
423 {
424 DestroyWindow(hWnd);
425 break;
426 }
427
428 case WM_DESTROY:
429 {
430 ChangeClipboardChain(hWnd, Globals.hWndNext);
431
432 if (Globals.uDisplayFormat == CF_OWNERDISPLAY)
433 {
434 HGLOBAL hglb;
435 PRECT prc;
436
437 hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(*prc));
438 if (hglb)
439 {
440 prc = GlobalLock(hglb);
441 SetRectEmpty(prc);
442 GlobalUnlock(hglb);
443
444 SendClipboardOwnerMessage(TRUE, WM_SIZECLIPBOARD,
445 (WPARAM)hWnd, (LPARAM)hglb);
446
447 GlobalFree(hglb);
448 }
449 }
450
451 PostQuitMessage(0);
452 break;
453 }
454
455 case WM_PAINT:
456 {
457 OnPaint(hWnd, wParam, lParam);
458 break;
459 }
460
461 case WM_KEYDOWN:
462 {
463 OnKeyScroll(hWnd, wParam, lParam, &Scrollstate);
464 break;
465 }
466
467 case WM_MOUSEWHEEL:
468 case WM_MOUSEHWHEEL:
469 {
470 OnMouseScroll(hWnd, uMsg, wParam, lParam, &Scrollstate);
471 break;
472 }
473
474 case WM_HSCROLL:
475 {
476 // NOTE: Windows uses an offset of 16 pixels
477 OnScroll(hWnd, SB_HORZ, wParam, 5, &Scrollstate);
478 break;
479 }
480
481 case WM_VSCROLL:
482 {
483 // NOTE: Windows uses an offset of 16 pixels
484 OnScroll(hWnd, SB_VERT, wParam, 5, &Scrollstate);
485 break;
486 }
487
488 case WM_SIZE:
489 {
490 RECT rc;
491
492 if (Globals.uDisplayFormat == CF_OWNERDISPLAY)
493 {
494 HGLOBAL hglb;
495 PRECT prc;
496
497 hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(*prc));
498 if (hglb)
499 {
500 prc = GlobalLock(hglb);
501 if (wParam == SIZE_MINIMIZED)
502 SetRectEmpty(prc);
503 else
504 GetClientRect(hWnd, prc);
505 GlobalUnlock(hglb);
506
507 SendClipboardOwnerMessage(TRUE, WM_SIZECLIPBOARD,
508 (WPARAM)hWnd, (LPARAM)hglb);
509
510 GlobalFree(hglb);
511 }
512 break;
513 }
514
515 GetClipboardDataDimensions(Globals.uDisplayFormat, &rc);
516 UpdateWindowScrollState(hWnd, rc.right, rc.bottom, &Scrollstate);
517
518 // NOTE: There still are little problems drawing
519 // the background when displaying clipboard text.
520 if (!IsClipboardFormatSupported(Globals.uDisplayFormat) ||
521 Globals.uDisplayFormat == CF_DSPTEXT ||
522 Globals.uDisplayFormat == CF_TEXT ||
523 Globals.uDisplayFormat == CF_OEMTEXT ||
524 Globals.uDisplayFormat == CF_UNICODETEXT)
525 {
526 InvalidateRect(Globals.hMainWnd, NULL, TRUE);
527 }
528 else
529 {
530 InvalidateRect(Globals.hMainWnd, NULL, FALSE);
531 }
532
533 break;
534 }
535
536 case WM_CHANGECBCHAIN:
537 {
538 /* Transmit through the clipboard viewer chain */
539 if ((HWND)wParam == Globals.hWndNext)
540 {
541 Globals.hWndNext = (HWND)lParam;
542 }
543 else if (Globals.hWndNext != NULL)
544 {
545 SendMessageW(Globals.hWndNext, uMsg, wParam, lParam);
546 }
547
548 break;
549 }
550
551 case WM_DESTROYCLIPBOARD:
552 break;
553
554 case WM_RENDERALLFORMATS:
555 {
556 /*
557 * When the user has cleared the clipboard via the DELETE command,
558 * we (clipboard viewer) become the clipboard owner. When we are
559 * subsequently closed, this message is then sent to us so that
560 * we get a chance to render everything we can. Since we don't have
561 * anything to render, just empty the clipboard.
562 */
563 DeleteClipboardContent();
564 break;
565 }
566
567 case WM_RENDERFORMAT:
568 // TODO!
569 break;
570
571 case WM_DRAWCLIPBOARD:
572 {
573 UpdateDisplayMenu();
574 SetDisplayFormat(0);
575
576 /* Pass the message to the next window in clipboard viewer chain */
577 SendMessageW(Globals.hWndNext, uMsg, wParam, lParam);
578 break;
579 }
580
581 case WM_COMMAND:
582 {
583 if ((LOWORD(wParam) > CMD_AUTOMATIC))
584 {
585 SetDisplayFormat(LOWORD(wParam) - CMD_AUTOMATIC);
586 }
587 else
588 {
589 OnCommand(hWnd, uMsg, wParam, lParam);
590 }
591 break;
592 }
593
594 case WM_INITMENUPOPUP:
595 {
596 InitMenuPopup((HMENU)wParam, lParam);
597 break;
598 }
599
600 case WM_DROPFILES:
601 {
602 LoadClipboardFromDrop((HDROP)wParam);
603 break;
604 }
605
606 case WM_PALETTECHANGED:
607 {
608 /* Ignore if this comes from ourselves */
609 if ((HWND)wParam == hWnd)
610 break;
611
612 /* Fall back to WM_QUERYNEWPALETTE */
613 }
614
615 case WM_QUERYNEWPALETTE:
616 {
617 BOOL Success;
618 HDC hDC;
619
620 if (!OpenClipboard(Globals.hMainWnd))
621 return FALSE;
622
623 hDC = GetDC(hWnd);
624 if (!hDC)
625 {
626 CloseClipboard();
627 return FALSE;
628 }
629
630 Success = RealizeClipboardPalette(hDC);
631
632 ReleaseDC(hWnd, hDC);
633 CloseClipboard();
634
635 if (Success)
636 {
637 InvalidateRect(hWnd, NULL, TRUE);
638 UpdateWindow(hWnd);
639 return TRUE;
640 }
641 return FALSE;
642 }
643
644 case WM_SYSCOLORCHANGE:
645 {
646 SetDisplayFormat(Globals.uDisplayFormat);
647 break;
648 }
649
650 case WM_SETTINGCHANGE:
651 {
652 if (wParam == SPI_SETWHEELSCROLLLINES)
653 {
654 UpdateLinesToScroll(&Scrollstate);
655 }
656 break;
657 }
658
659 default:
660 {
661 return DefWindowProc(hWnd, uMsg, wParam, lParam);
662 }
663 }
664
665 return 0;
666 }
667
wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPWSTR lpCmdLine,int nCmdShow)668 int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
669 {
670 MSG msg;
671 HACCEL hAccel;
672 HWND hPrevWindow;
673 WNDCLASSEXW wndclass;
674 WCHAR szBuffer[MAX_STRING_LEN];
675
676 hPrevWindow = FindWindowW(szClassName, NULL);
677 if (hPrevWindow)
678 {
679 BringWindowToFront(hPrevWindow);
680 return 0;
681 }
682
683 switch (GetUserDefaultUILanguage())
684 {
685 case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT):
686 SetProcessDefaultLayout(LAYOUT_RTL);
687 break;
688
689 default:
690 break;
691 }
692
693 ZeroMemory(&Globals, sizeof(Globals));
694 Globals.hInstance = hInstance;
695
696 ZeroMemory(&wndclass, sizeof(wndclass));
697 wndclass.cbSize = sizeof(wndclass);
698 wndclass.lpfnWndProc = MainWndProc;
699 wndclass.hInstance = hInstance;
700 wndclass.hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(CLIPBRD_ICON));
701 wndclass.hCursor = LoadCursorW(0, IDC_ARROW);
702 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
703 wndclass.lpszMenuName = MAKEINTRESOURCEW(MAIN_MENU);
704 wndclass.lpszClassName = szClassName;
705
706 if (!RegisterClassExW(&wndclass))
707 {
708 ShowLastWin32Error(NULL);
709 return 0;
710 }
711
712 ZeroMemory(&Scrollstate, sizeof(Scrollstate));
713
714 LoadStringW(hInstance, STRING_CLIPBOARD, szBuffer, ARRAYSIZE(szBuffer));
715 Globals.hMainWnd = CreateWindowExW(WS_EX_CLIENTEDGE | WS_EX_ACCEPTFILES,
716 szClassName,
717 szBuffer,
718 WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
719 CW_USEDEFAULT,
720 CW_USEDEFAULT,
721 CW_USEDEFAULT,
722 CW_USEDEFAULT,
723 NULL,
724 NULL,
725 Globals.hInstance,
726 NULL);
727 if (!Globals.hMainWnd)
728 {
729 ShowLastWin32Error(NULL);
730 return 0;
731 }
732
733 ShowWindow(Globals.hMainWnd, nCmdShow);
734 UpdateWindow(Globals.hMainWnd);
735
736 hAccel = LoadAcceleratorsW(Globals.hInstance, MAKEINTRESOURCEW(ID_ACCEL));
737 if (!hAccel)
738 {
739 ShowLastWin32Error(Globals.hMainWnd);
740 }
741
742 /* If the user provided a path to a clipboard data file, try to open it */
743 if (__argc >= 2)
744 LoadClipboardDataFromFile(__wargv[1]);
745
746 while (GetMessageW(&msg, 0, 0, 0))
747 {
748 if (!TranslateAcceleratorW(Globals.hMainWnd, hAccel, &msg))
749 {
750 TranslateMessage(&msg);
751 DispatchMessageW(&msg);
752 }
753 }
754
755 return (int)msg.wParam;
756 }
757