[CLIPBRD] Clipbrd program should accept the quoted file path (#638)
[reactos.git] / base / applications / clipbrd / clipbrd.c
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
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_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
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
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
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
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
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
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
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 HICON hIcon;
252 WCHAR szTitle[MAX_STRING_LEN];
253
254 hIcon = LoadIconW(Globals.hInstance, MAKEINTRESOURCE(CLIPBRD_ICON));
255 LoadStringW(Globals.hInstance, STRING_CLIPBOARD, szTitle, ARRAYSIZE(szTitle));
256 ShellAboutW(Globals.hMainWnd, szTitle, NULL, hIcon);
257 DeleteObject(hIcon);
258 break;
259 }
260
261 default:
262 {
263 break;
264 }
265 }
266 return 0;
267 }
268
269 static void OnPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
270 {
271 HDC hdc;
272 PAINTSTRUCT ps;
273 COLORREF crOldBkColor, crOldTextColor;
274 RECT rc;
275
276 if (!OpenClipboard(Globals.hMainWnd))
277 return;
278
279 hdc = BeginPaint(hWnd, &ps);
280
281 /* Erase the background if needed */
282 if (ps.fErase)
283 FillRect(ps.hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
284
285 /* Set the correct background and text colors */
286 crOldBkColor = SetBkColor(ps.hdc, GetSysColor(COLOR_WINDOW));
287 crOldTextColor = SetTextColor(ps.hdc, GetSysColor(COLOR_WINDOWTEXT));
288
289 /* Realize the clipboard palette if there is one */
290 RealizeClipboardPalette(ps.hdc);
291
292 switch (Globals.uDisplayFormat)
293 {
294 case CF_NONE:
295 {
296 /* The clipboard is empty */
297 break;
298 }
299
300 case CF_DSPTEXT:
301 case CF_TEXT:
302 case CF_OEMTEXT:
303 case CF_UNICODETEXT:
304 {
305 DrawTextFromClipboard(Globals.uDisplayFormat, ps, Scrollstate);
306 break;
307 }
308
309 case CF_DSPBITMAP:
310 case CF_BITMAP:
311 {
312 BitBltFromClipboard(ps, Scrollstate, SRCCOPY);
313 break;
314 }
315
316 case CF_DIB:
317 case CF_DIBV5:
318 {
319 SetDIBitsToDeviceFromClipboard(Globals.uDisplayFormat, ps, Scrollstate, DIB_RGB_COLORS);
320 break;
321 }
322
323 case CF_DSPMETAFILEPICT:
324 case CF_METAFILEPICT:
325 {
326 GetClientRect(hWnd, &rc);
327 PlayMetaFileFromClipboard(hdc, &rc);
328 break;
329 }
330
331 case CF_DSPENHMETAFILE:
332 case CF_ENHMETAFILE:
333 {
334 GetClientRect(hWnd, &rc);
335 PlayEnhMetaFileFromClipboard(hdc, &rc);
336 break;
337 }
338
339 // case CF_PALETTE:
340 // TODO: Draw a palette with squares filled with colors.
341 // break;
342
343 case CF_OWNERDISPLAY:
344 {
345 HGLOBAL hglb;
346 PPAINTSTRUCT pps;
347
348 hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(ps));
349 if (hglb)
350 {
351 pps = GlobalLock(hglb);
352 CopyMemory(pps, &ps, sizeof(ps));
353 GlobalUnlock(hglb);
354
355 SendClipboardOwnerMessage(TRUE, WM_PAINTCLIPBOARD,
356 (WPARAM)hWnd, (LPARAM)hglb);
357
358 GlobalFree(hglb);
359 }
360 break;
361 }
362
363 default:
364 {
365 GetClientRect(hWnd, &rc);
366 DrawTextFromResource(Globals.hInstance, ERROR_UNSUPPORTED_FORMAT,
367 hdc, &rc, DT_CENTER | DT_WORDBREAK | DT_NOPREFIX);
368 break;
369 }
370 }
371
372 /* Restore the original colors */
373 SetTextColor(ps.hdc, crOldTextColor);
374 SetBkColor(ps.hdc, crOldBkColor);
375
376 EndPaint(hWnd, &ps);
377
378 CloseClipboard();
379 }
380
381 static LRESULT WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
382 {
383 switch(uMsg)
384 {
385 case WM_CREATE:
386 {
387 TEXTMETRICW tm;
388 HDC hDC = GetDC(hWnd);
389
390 /*
391 * Note that the method with GetObjectW just returns
392 * the original parameters with which the font was created.
393 */
394 if (GetTextMetricsW(hDC, &tm))
395 {
396 Globals.CharWidth = tm.tmMaxCharWidth; // tm.tmAveCharWidth;
397 Globals.CharHeight = tm.tmHeight + tm.tmExternalLeading;
398 }
399 ReleaseDC(hWnd, hDC);
400
401
402 Globals.hMenu = GetMenu(hWnd);
403 Globals.hWndNext = SetClipboardViewer(hWnd);
404
405 // For now, the Help dialog item is disabled because of lacking of HTML support
406 EnableMenuItem(Globals.hMenu, CMD_HELP, MF_BYCOMMAND | MF_GRAYED);
407
408 UpdateLinesToScroll(&Scrollstate);
409
410 UpdateDisplayMenu();
411 SetDisplayFormat(0);
412
413 DragAcceptFiles(hWnd, TRUE);
414 break;
415 }
416
417 case WM_CLOSE:
418 {
419 DestroyWindow(hWnd);
420 break;
421 }
422
423 case WM_DESTROY:
424 {
425 ChangeClipboardChain(hWnd, Globals.hWndNext);
426
427 if (Globals.uDisplayFormat == CF_OWNERDISPLAY)
428 {
429 HGLOBAL hglb;
430 PRECT prc;
431
432 hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(*prc));
433 if (hglb)
434 {
435 prc = GlobalLock(hglb);
436 SetRectEmpty(prc);
437 GlobalUnlock(hglb);
438
439 SendClipboardOwnerMessage(TRUE, WM_SIZECLIPBOARD,
440 (WPARAM)hWnd, (LPARAM)hglb);
441
442 GlobalFree(hglb);
443 }
444 }
445
446 PostQuitMessage(0);
447 break;
448 }
449
450 case WM_PAINT:
451 {
452 OnPaint(hWnd, wParam, lParam);
453 break;
454 }
455
456 case WM_KEYDOWN:
457 {
458 OnKeyScroll(hWnd, wParam, lParam, &Scrollstate);
459 break;
460 }
461
462 case WM_MOUSEWHEEL:
463 case WM_MOUSEHWHEEL:
464 {
465 OnMouseScroll(hWnd, uMsg, wParam, lParam, &Scrollstate);
466 break;
467 }
468
469 case WM_HSCROLL:
470 {
471 // NOTE: Windows uses an offset of 16 pixels
472 OnScroll(hWnd, SB_HORZ, wParam, 5, &Scrollstate);
473 break;
474 }
475
476 case WM_VSCROLL:
477 {
478 // NOTE: Windows uses an offset of 16 pixels
479 OnScroll(hWnd, SB_VERT, wParam, 5, &Scrollstate);
480 break;
481 }
482
483 case WM_SIZE:
484 {
485 RECT rc;
486
487 if (Globals.uDisplayFormat == CF_OWNERDISPLAY)
488 {
489 HGLOBAL hglb;
490 PRECT prc;
491
492 hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(*prc));
493 if (hglb)
494 {
495 prc = GlobalLock(hglb);
496 if (wParam == SIZE_MINIMIZED)
497 SetRectEmpty(prc);
498 else
499 GetClientRect(hWnd, prc);
500 GlobalUnlock(hglb);
501
502 SendClipboardOwnerMessage(TRUE, WM_SIZECLIPBOARD,
503 (WPARAM)hWnd, (LPARAM)hglb);
504
505 GlobalFree(hglb);
506 }
507 break;
508 }
509
510 GetClipboardDataDimensions(Globals.uDisplayFormat, &rc);
511 UpdateWindowScrollState(hWnd, rc.right, rc.bottom, &Scrollstate);
512
513 // NOTE: There still are little problems drawing
514 // the background when displaying clipboard text.
515 if (!IsClipboardFormatSupported(Globals.uDisplayFormat) ||
516 Globals.uDisplayFormat == CF_DSPTEXT ||
517 Globals.uDisplayFormat == CF_TEXT ||
518 Globals.uDisplayFormat == CF_OEMTEXT ||
519 Globals.uDisplayFormat == CF_UNICODETEXT)
520 {
521 InvalidateRect(Globals.hMainWnd, NULL, TRUE);
522 }
523 else
524 {
525 InvalidateRect(Globals.hMainWnd, NULL, FALSE);
526 }
527
528 break;
529 }
530
531 case WM_CHANGECBCHAIN:
532 {
533 /* Transmit through the clipboard viewer chain */
534 if ((HWND)wParam == Globals.hWndNext)
535 {
536 Globals.hWndNext = (HWND)lParam;
537 }
538 else if (Globals.hWndNext != NULL)
539 {
540 SendMessageW(Globals.hWndNext, uMsg, wParam, lParam);
541 }
542
543 break;
544 }
545
546 case WM_DESTROYCLIPBOARD:
547 break;
548
549 case WM_RENDERALLFORMATS:
550 {
551 /*
552 * When the user has cleared the clipboard via the DELETE command,
553 * we (clipboard viewer) become the clipboard owner. When we are
554 * subsequently closed, this message is then sent to us so that
555 * we get a chance to render everything we can. Since we don't have
556 * anything to render, just empty the clipboard.
557 */
558 DeleteClipboardContent();
559 break;
560 }
561
562 case WM_RENDERFORMAT:
563 // TODO!
564 break;
565
566 case WM_DRAWCLIPBOARD:
567 {
568 UpdateDisplayMenu();
569 SetDisplayFormat(0);
570
571 /* Pass the message to the next window in clipboard viewer chain */
572 SendMessageW(Globals.hWndNext, uMsg, wParam, lParam);
573 break;
574 }
575
576 case WM_COMMAND:
577 {
578 if ((LOWORD(wParam) > CMD_AUTOMATIC))
579 {
580 SetDisplayFormat(LOWORD(wParam) - CMD_AUTOMATIC);
581 }
582 else
583 {
584 OnCommand(hWnd, uMsg, wParam, lParam);
585 }
586 break;
587 }
588
589 case WM_INITMENUPOPUP:
590 {
591 InitMenuPopup((HMENU)wParam, lParam);
592 break;
593 }
594
595 case WM_DROPFILES:
596 {
597 LoadClipboardFromDrop((HDROP)wParam);
598 break;
599 }
600
601 case WM_PALETTECHANGED:
602 {
603 /* Ignore if this comes from ourselves */
604 if ((HWND)wParam == hWnd)
605 break;
606
607 /* Fall back to WM_QUERYNEWPALETTE */
608 }
609
610 case WM_QUERYNEWPALETTE:
611 {
612 BOOL Success;
613 HDC hDC;
614
615 if (!OpenClipboard(Globals.hMainWnd))
616 return FALSE;
617
618 hDC = GetDC(hWnd);
619 if (!hDC)
620 {
621 CloseClipboard();
622 return FALSE;
623 }
624
625 Success = RealizeClipboardPalette(hDC);
626
627 ReleaseDC(hWnd, hDC);
628 CloseClipboard();
629
630 if (Success)
631 {
632 InvalidateRect(hWnd, NULL, TRUE);
633 UpdateWindow(hWnd);
634 return TRUE;
635 }
636 return FALSE;
637 }
638
639 case WM_SYSCOLORCHANGE:
640 {
641 SetDisplayFormat(Globals.uDisplayFormat);
642 break;
643 }
644
645 case WM_SETTINGCHANGE:
646 {
647 if (wParam == SPI_SETWHEELSCROLLLINES)
648 {
649 UpdateLinesToScroll(&Scrollstate);
650 }
651 break;
652 }
653
654 default:
655 {
656 return DefWindowProc(hWnd, uMsg, wParam, lParam);
657 }
658 }
659
660 return 0;
661 }
662
663 int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
664 {
665 MSG msg;
666 HACCEL hAccel;
667 HWND hPrevWindow;
668 WNDCLASSEXW wndclass;
669 WCHAR szBuffer[MAX_STRING_LEN];
670
671 hPrevWindow = FindWindowW(szClassName, NULL);
672 if (hPrevWindow)
673 {
674 BringWindowToFront(hPrevWindow);
675 return 0;
676 }
677
678 switch (GetUserDefaultUILanguage())
679 {
680 case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT):
681 SetProcessDefaultLayout(LAYOUT_RTL);
682 break;
683
684 default:
685 break;
686 }
687
688 ZeroMemory(&Globals, sizeof(Globals));
689 Globals.hInstance = hInstance;
690
691 ZeroMemory(&wndclass, sizeof(wndclass));
692 wndclass.cbSize = sizeof(wndclass);
693 wndclass.lpfnWndProc = MainWndProc;
694 wndclass.hInstance = hInstance;
695 wndclass.hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(CLIPBRD_ICON));
696 wndclass.hCursor = LoadCursorW(0, IDC_ARROW);
697 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
698 wndclass.lpszMenuName = MAKEINTRESOURCEW(MAIN_MENU);
699 wndclass.lpszClassName = szClassName;
700
701 if (!RegisterClassExW(&wndclass))
702 {
703 ShowLastWin32Error(NULL);
704 return 0;
705 }
706
707 ZeroMemory(&Scrollstate, sizeof(Scrollstate));
708
709 LoadStringW(hInstance, STRING_CLIPBOARD, szBuffer, ARRAYSIZE(szBuffer));
710 Globals.hMainWnd = CreateWindowExW(WS_EX_CLIENTEDGE | WS_EX_ACCEPTFILES,
711 szClassName,
712 szBuffer,
713 WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
714 CW_USEDEFAULT,
715 CW_USEDEFAULT,
716 CW_USEDEFAULT,
717 CW_USEDEFAULT,
718 NULL,
719 NULL,
720 Globals.hInstance,
721 NULL);
722 if (!Globals.hMainWnd)
723 {
724 ShowLastWin32Error(NULL);
725 return 0;
726 }
727
728 ShowWindow(Globals.hMainWnd, nCmdShow);
729 UpdateWindow(Globals.hMainWnd);
730
731 hAccel = LoadAcceleratorsW(Globals.hInstance, MAKEINTRESOURCEW(ID_ACCEL));
732 if (!hAccel)
733 {
734 ShowLastWin32Error(Globals.hMainWnd);
735 }
736
737 /* If the user provided a path to a clipboard data file, try to open it */
738 if (__argc >= 2)
739 LoadClipboardDataFromFile(__wargv[1]);
740
741 while (GetMessageW(&msg, 0, 0, 0))
742 {
743 if (!TranslateAcceleratorW(Globals.hMainWnd, hAccel, &msg))
744 {
745 TranslateMessage(&msg);
746 DispatchMessageW(&msg);
747 }
748 }
749
750 return (int)msg.wParam;
751 }