Sync with trunk (48237)
[reactos.git] / base / applications / notepad / main.c
1 /*
2 * Notepad
3 *
4 * Copyright 2000 Mike McCormack <Mike_McCormack@looksmart.com.au>
5 * Copyright 1997,98 Marcel Baur <mbaur@g26.ethz.ch>
6 * Copyright 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
7 * Copyright 2002 Andriy Palamarchuk
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 */
24
25 #include <notepad.h>
26
27 NOTEPAD_GLOBALS Globals;
28 static ATOM aFINDMSGSTRING;
29
30 VOID NOTEPAD_EnableSearchMenu()
31 {
32 EnableMenuItem(GetMenu(Globals.hMainWnd), CMD_SEARCH,
33 MF_BYCOMMAND | ((GetWindowTextLength(Globals.hEdit) == 0) ? MF_DISABLED | MF_GRAYED : MF_ENABLED));
34 EnableMenuItem(GetMenu(Globals.hMainWnd), CMD_SEARCH_NEXT,
35 MF_BYCOMMAND | ((GetWindowTextLength(Globals.hEdit) == 0) ? MF_DISABLED | MF_GRAYED : MF_ENABLED));
36 }
37
38 /***********************************************************************
39 *
40 * SetFileName
41 *
42 * Sets Global File Name.
43 */
44 VOID SetFileName(LPCTSTR szFileName)
45 {
46 _tcscpy(Globals.szFileName, szFileName);
47 Globals.szFileTitle[0] = 0;
48 GetFileTitle(szFileName, Globals.szFileTitle, SIZEOF(Globals.szFileTitle));
49 }
50
51 /***********************************************************************
52 *
53 * NOTEPAD_MenuCommand
54 *
55 * All handling of main menu events
56 */
57 static int NOTEPAD_MenuCommand(WPARAM wParam)
58 {
59 switch (wParam)
60 {
61 case CMD_NEW: DIALOG_FileNew(); break;
62 case CMD_OPEN: DIALOG_FileOpen(); break;
63 case CMD_SAVE: DIALOG_FileSave(); break;
64 case CMD_SAVE_AS: DIALOG_FileSaveAs(); break;
65 case CMD_PRINT: DIALOG_FilePrint(); break;
66 case CMD_PAGE_SETUP: DIALOG_FilePageSetup(); break;
67 case CMD_PRINTER_SETUP: DIALOG_FilePrinterSetup();break;
68 case CMD_EXIT: DIALOG_FileExit(); break;
69
70 case CMD_UNDO: DIALOG_EditUndo(); break;
71 case CMD_CUT: DIALOG_EditCut(); break;
72 case CMD_COPY: DIALOG_EditCopy(); break;
73 case CMD_PASTE: DIALOG_EditPaste(); break;
74 case CMD_DELETE: DIALOG_EditDelete(); break;
75 case CMD_SELECT_ALL: DIALOG_EditSelectAll(); break;
76 case CMD_TIME_DATE: DIALOG_EditTimeDate();break;
77
78 case CMD_SEARCH: DIALOG_Search(); break;
79 case CMD_SEARCH_NEXT: DIALOG_SearchNext(); break;
80 case CMD_REPLACE: DIALOG_Replace(); break;
81 case CMD_GOTO: DIALOG_GoTo(); break;
82
83 case CMD_WRAP: DIALOG_EditWrap(); break;
84 case CMD_FONT: DIALOG_SelectFont(); break;
85
86 case CMD_STATUSBAR: DIALOG_ViewStatusBar(); break;
87
88 case CMD_HELP_CONTENTS: DIALOG_HelpContents(); break;
89 case CMD_HELP_SEARCH: DIALOG_HelpSearch(); break;
90 case CMD_HELP_ON_HELP: DIALOG_HelpHelp(); break;
91 case CMD_ABOUT: DialogBox(GetModuleHandle(NULL),
92 MAKEINTRESOURCE(IDD_ABOUTBOX),
93 Globals.hMainWnd,
94 AboutDialogProc);
95 break;
96 case CMD_ABOUT_WINE: DIALOG_HelpAboutWine(); break;
97
98 default:
99 break;
100 }
101 return 0;
102 }
103
104 /***********************************************************************
105 *
106 * NOTEPAD_FindTextAt
107 */
108
109 static BOOL NOTEPAD_FindTextAt(FINDREPLACE *pFindReplace, LPCTSTR pszText, int iTextLength, DWORD dwPosition)
110 {
111 BOOL bMatches;
112 size_t iTargetLength;
113
114 iTargetLength = _tcslen(pFindReplace->lpstrFindWhat);
115
116 /* Make proper comparison */
117 if (pFindReplace->Flags & FR_MATCHCASE)
118 bMatches = !_tcsncmp(&pszText[dwPosition], pFindReplace->lpstrFindWhat, iTargetLength);
119 else
120 bMatches = !_tcsnicmp(&pszText[dwPosition], pFindReplace->lpstrFindWhat, iTargetLength);
121
122 if (bMatches && pFindReplace->Flags & FR_WHOLEWORD)
123 {
124 if ((dwPosition > 0) && !_istspace(pszText[dwPosition-1]))
125 bMatches = FALSE;
126 if ((dwPosition < (DWORD) iTextLength - 1) && !_istspace(pszText[dwPosition+1]))
127 bMatches = FALSE;
128 }
129
130 return bMatches;
131 }
132
133 /***********************************************************************
134 *
135 * NOTEPAD_FindNext
136 */
137
138 BOOL NOTEPAD_FindNext(FINDREPLACE *pFindReplace, BOOL bReplace, BOOL bShowAlert)
139 {
140 int iTextLength, iTargetLength;
141 size_t iAdjustment = 0;
142 LPTSTR pszText = NULL;
143 DWORD dwPosition, dwBegin, dwEnd;
144 BOOL bMatches = FALSE;
145 TCHAR szResource[128], szText[128];
146 BOOL bSuccess;
147
148 iTargetLength = (int) _tcslen(pFindReplace->lpstrFindWhat);
149
150 /* Retrieve the window text */
151 iTextLength = GetWindowTextLength(Globals.hEdit);
152 if (iTextLength > 0)
153 {
154 pszText = (LPTSTR) HeapAlloc(GetProcessHeap(), 0, (iTextLength + 1) * sizeof(TCHAR));
155 if (!pszText)
156 return FALSE;
157
158 GetWindowText(Globals.hEdit, pszText, iTextLength + 1);
159 }
160
161 SendMessage(Globals.hEdit, EM_GETSEL, (WPARAM) &dwBegin, (LPARAM) &dwEnd);
162 if (bReplace && ((dwEnd - dwBegin) == (DWORD) iTargetLength))
163 {
164 if (NOTEPAD_FindTextAt(pFindReplace, pszText, iTextLength, dwBegin))
165 {
166 SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM) pFindReplace->lpstrReplaceWith);
167 iAdjustment = _tcslen(pFindReplace->lpstrReplaceWith) - (dwEnd - dwBegin);
168 }
169 }
170
171 if (pFindReplace->Flags & FR_DOWN)
172 {
173 /* Find Down */
174 dwPosition = dwEnd;
175 while(dwPosition < (DWORD) iTextLength)
176 {
177 bMatches = NOTEPAD_FindTextAt(pFindReplace, pszText, iTextLength, dwPosition);
178 if (bMatches)
179 break;
180 dwPosition++;
181 }
182 }
183 else
184 {
185 /* Find Up */
186 dwPosition = dwBegin;
187 while(dwPosition > 0)
188 {
189 dwPosition--;
190 bMatches = NOTEPAD_FindTextAt(pFindReplace, pszText, iTextLength, dwPosition);
191 if (bMatches)
192 break;
193 }
194 }
195
196 if (bMatches)
197 {
198 /* Found target */
199 if (dwPosition > dwBegin)
200 dwPosition += (DWORD) iAdjustment;
201 SendMessage(Globals.hEdit, EM_SETSEL, dwPosition, dwPosition + iTargetLength);
202 SendMessage(Globals.hEdit, EM_SCROLLCARET, 0, 0);
203 bSuccess = TRUE;
204 }
205 else
206 {
207 /* Can't find target */
208 if (bShowAlert)
209 {
210 LoadString(Globals.hInstance, STRING_CANNOTFIND, szResource, SIZEOF(szResource));
211 _sntprintf(szText, SIZEOF(szText), szResource, pFindReplace->lpstrFindWhat);
212 LoadString(Globals.hInstance, STRING_NOTEPAD, szResource, SIZEOF(szResource));
213 MessageBox(Globals.hFindReplaceDlg, szText, szResource, MB_OK);
214 }
215 bSuccess = FALSE;
216 }
217
218 if (pszText)
219 HeapFree(GetProcessHeap(), 0, pszText);
220 return bSuccess;
221 }
222
223 /***********************************************************************
224 *
225 * NOTEPAD_ReplaceAll
226 */
227
228 static VOID NOTEPAD_ReplaceAll(FINDREPLACE *pFindReplace)
229 {
230 BOOL bShowAlert = TRUE;
231
232 SendMessage(Globals.hEdit, EM_SETSEL, 0, 0);
233
234 while (NOTEPAD_FindNext(pFindReplace, TRUE, bShowAlert))
235 {
236 bShowAlert = FALSE;
237 }
238 }
239
240 /***********************************************************************
241 *
242 * NOTEPAD_FindTerm
243 */
244
245 static VOID NOTEPAD_FindTerm(VOID)
246 {
247 Globals.hFindReplaceDlg = NULL;
248 }
249
250 /***********************************************************************
251 * Data Initialization
252 */
253 static VOID NOTEPAD_InitData(VOID)
254 {
255 LPTSTR p = Globals.szFilter;
256 static const TCHAR txt_files[] = _T("*.txt");
257 static const TCHAR all_files[] = _T("*.*");
258
259 p += LoadString(Globals.hInstance, STRING_TEXT_FILES_TXT, p, MAX_STRING_LEN)+1;
260 _tcscpy(p, txt_files);
261 p += SIZEOF(txt_files);
262
263 p += LoadString(Globals.hInstance, STRING_ALL_FILES, p, MAX_STRING_LEN)+1;
264 _tcscpy(p, all_files);
265 p += SIZEOF(all_files);
266 *p = '\0';
267 Globals.find.lpstrFindWhat = NULL;
268 }
269
270 /***********************************************************************
271 * Enable/disable items on the menu based on control state
272 */
273 static VOID NOTEPAD_InitMenuPopup(HMENU menu, LPARAM index)
274 {
275 int enable;
276
277 UNREFERENCED_PARAMETER(index);
278
279 CheckMenuItem(GetMenu(Globals.hMainWnd), CMD_WRAP,
280 MF_BYCOMMAND | (Globals.bWrapLongLines ? MF_CHECKED : MF_UNCHECKED));
281 if ( !Globals.bWrapLongLines )
282 {
283 CheckMenuItem(GetMenu(Globals.hMainWnd), CMD_STATUSBAR,
284 MF_BYCOMMAND | (Globals.bShowStatusBar ? MF_CHECKED : MF_UNCHECKED));
285 }
286 EnableMenuItem(menu, CMD_UNDO,
287 SendMessage(Globals.hEdit, EM_CANUNDO, 0, 0) ? MF_ENABLED : MF_GRAYED);
288 EnableMenuItem(menu, CMD_PASTE,
289 IsClipboardFormatAvailable(CF_TEXT) ? MF_ENABLED : MF_GRAYED);
290 enable = (int) SendMessage(Globals.hEdit, EM_GETSEL, 0, 0);
291 enable = (HIWORD(enable) == LOWORD(enable)) ? MF_GRAYED : MF_ENABLED;
292 EnableMenuItem(menu, CMD_CUT, enable);
293 EnableMenuItem(menu, CMD_COPY, enable);
294 EnableMenuItem(menu, CMD_DELETE, enable);
295
296 EnableMenuItem(menu, CMD_SELECT_ALL,
297 GetWindowTextLength(Globals.hEdit) ? MF_ENABLED : MF_GRAYED);
298 DrawMenuBar(Globals.hMainWnd);
299 }
300
301 LRESULT CALLBACK EDIT_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
302 {
303 switch (msg)
304 {
305 case WM_KEYDOWN:
306 case WM_KEYUP:
307 {
308 switch (wParam)
309 {
310 case VK_UP:
311 case VK_DOWN:
312 case VK_LEFT:
313 case VK_RIGHT:
314 DIALOG_StatusBarUpdateCaretPos();
315 break;
316 }
317 }
318 case WM_LBUTTONUP:
319 {
320 DIALOG_StatusBarUpdateCaretPos();
321 break;
322 }
323 }
324 return CallWindowProc( (WNDPROC)Globals.EditProc, hWnd, msg, wParam, lParam);
325 }
326
327 /***********************************************************************
328 *
329 * NOTEPAD_WndProc
330 */
331 static LRESULT WINAPI NOTEPAD_WndProc(HWND hWnd, UINT msg, WPARAM wParam,
332 LPARAM lParam)
333 {
334 switch (msg) {
335
336 case WM_CREATE:
337 {
338 static const TCHAR edit[] = _T("edit");
339 RECT rc;
340 GetClientRect(hWnd, &rc);
341 Globals.hEdit = CreateWindowEx(EDIT_EXSTYLE, edit, NULL, Globals.bWrapLongLines ? EDIT_STYLE_WRAP : EDIT_STYLE,
342 0, 0, rc.right, rc.bottom, hWnd,
343 NULL, Globals.hInstance, NULL);
344 if (!Globals.hEdit)
345 return -1;
346 SendMessage(Globals.hEdit, EM_LIMITTEXT, 0, 0);
347 if (Globals.hFont)
348 SendMessage(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, (LPARAM)TRUE);
349
350 Globals.EditProc = (WNDPROC) SetWindowLongPtr(Globals.hEdit, GWLP_WNDPROC, (LONG_PTR)EDIT_WndProc);
351
352 break;
353 }
354
355 case WM_COMMAND:
356 if (HIWORD(wParam) == EN_CHANGE || HIWORD(wParam) == EN_HSCROLL || HIWORD(wParam) == EN_VSCROLL)
357 DIALOG_StatusBarUpdateCaretPos();
358 if ((HIWORD(wParam) == EN_CHANGE))
359 NOTEPAD_EnableSearchMenu();
360 NOTEPAD_MenuCommand(LOWORD(wParam));
361 break;
362
363 case WM_DESTROYCLIPBOARD:
364 /*MessageBox(Globals.hMainWnd, "Empty clipboard", "Debug", MB_ICONEXCLAMATION);*/
365 break;
366
367 case WM_CLOSE:
368 if (DoCloseFile()) {
369 if (Globals.hFont)
370 DeleteObject(Globals.hFont);
371 DestroyWindow(hWnd);
372 }
373 break;
374
375 case WM_QUERYENDSESSION:
376 if (DoCloseFile()) {
377 return 1;
378 }
379 break;
380
381 case WM_DESTROY:
382 SetWindowLongPtr(Globals.hEdit, GWLP_WNDPROC, (LONG_PTR)Globals.EditProc);
383 SaveSettings();
384 PostQuitMessage(0);
385 break;
386
387 case WM_SIZE:
388 {
389 if (Globals.bShowStatusBar)
390 {
391 RECT rcStatusBar;
392 HDWP hdwp;
393
394 if (!GetWindowRect(Globals.hStatusBar, &rcStatusBar))
395 break;
396
397 hdwp = BeginDeferWindowPos(2);
398 if (hdwp == NULL)
399 break;
400
401 hdwp = DeferWindowPos(hdwp, Globals.hEdit, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam) - (rcStatusBar.bottom - rcStatusBar.top), SWP_NOZORDER | SWP_NOMOVE);
402 if (hdwp == NULL)
403 break;
404
405 hdwp = DeferWindowPos(hdwp, Globals.hStatusBar, NULL, 0, 0, LOWORD(lParam), LOWORD(wParam), SWP_NOZORDER);
406
407 if (hdwp != NULL)
408 EndDeferWindowPos(hdwp);
409 }
410 else
411 SetWindowPos(Globals.hEdit, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOZORDER | SWP_NOMOVE);
412
413 break;
414 }
415
416 case WM_SETFOCUS:
417 SetFocus(Globals.hEdit);
418 break;
419
420 case WM_DROPFILES:
421 {
422 TCHAR szFileName[MAX_PATH];
423 HDROP hDrop = (HDROP) wParam;
424
425 DragQueryFile(hDrop, 0, szFileName, SIZEOF(szFileName));
426 DragFinish(hDrop);
427 DoOpenFile(szFileName);
428 break;
429 }
430 case WM_CHAR:
431 case WM_INITMENUPOPUP:
432 NOTEPAD_InitMenuPopup((HMENU)wParam, lParam);
433 break;
434 default:
435 if (msg == aFINDMSGSTRING)
436 {
437 FINDREPLACE *pFindReplace = (FINDREPLACE *) lParam;
438 Globals.find = *(FINDREPLACE *) lParam;
439
440 if (pFindReplace->Flags & FR_FINDNEXT)
441 NOTEPAD_FindNext(pFindReplace, FALSE, TRUE);
442 else if (pFindReplace->Flags & FR_REPLACE)
443 NOTEPAD_FindNext(pFindReplace, TRUE, TRUE);
444 else if (pFindReplace->Flags & FR_REPLACEALL)
445 NOTEPAD_ReplaceAll(pFindReplace);
446 else if (pFindReplace->Flags & FR_DIALOGTERM)
447 NOTEPAD_FindTerm();
448 break;
449 }
450
451 return DefWindowProc(hWnd, msg, wParam, lParam);
452 }
453 return 0;
454 }
455
456 static int AlertFileDoesNotExist(LPCTSTR szFileName)
457 {
458 int nResult;
459 TCHAR szMessage[MAX_STRING_LEN];
460 TCHAR szResource[MAX_STRING_LEN];
461
462 LoadString(Globals.hInstance, STRING_DOESNOTEXIST, szResource, SIZEOF(szResource));
463 wsprintf(szMessage, szResource, szFileName);
464
465 LoadString(Globals.hInstance, STRING_NOTEPAD, szResource, SIZEOF(szResource));
466
467 nResult = MessageBox(Globals.hMainWnd, szMessage, szResource,
468 MB_ICONEXCLAMATION | MB_YESNO);
469
470 return(nResult);
471 }
472
473 static void HandleCommandLine(LPTSTR cmdline)
474 {
475 int opt_print=0;
476
477 while (*cmdline == _T(' ') || *cmdline == _T('-') || *cmdline == _T('/'))
478 {
479 TCHAR option;
480
481 if (*cmdline++ == _T(' ')) continue;
482
483 option = *cmdline;
484 if (option) cmdline++;
485 while (*cmdline == _T(' ')) cmdline++;
486
487 switch(option)
488 {
489 case 'p':
490 case 'P':
491 opt_print=1;
492 break;
493 }
494 }
495
496 if (*cmdline)
497 {
498 /* file name is passed in the command line */
499 LPCTSTR file_name = NULL;
500 BOOL file_exists = FALSE;
501 TCHAR buf[MAX_PATH];
502
503 if (cmdline[0] == _T('"'))
504 {
505 cmdline++;
506 cmdline[lstrlen(cmdline) - 1] = 0;
507 }
508
509 file_name = cmdline;
510 if (FileExists(file_name))
511 {
512 file_exists = TRUE;
513 }
514 else if (!HasFileExtension(cmdline))
515 {
516 static const TCHAR txt[] = _T(".txt");
517
518 /* try to find file with ".txt" extension */
519 if (!_tcscmp(txt, cmdline + _tcslen(cmdline) - _tcslen(txt)))
520 {
521 file_exists = FALSE;
522 }
523 else
524 {
525 _tcsncpy(buf, cmdline, MAX_PATH - _tcslen(txt) - 1);
526 _tcscat(buf, txt);
527 file_name = buf;
528 file_exists = FileExists(file_name);
529 }
530 }
531
532 if (file_exists)
533 {
534 DoOpenFile(file_name);
535 InvalidateRect(Globals.hMainWnd, NULL, FALSE);
536 if (opt_print)
537 DIALOG_FilePrint();
538 }
539 else
540 {
541 switch (AlertFileDoesNotExist(file_name)) {
542 case IDYES:
543 DoOpenFile(file_name);
544 break;
545
546 case IDNO:
547 break;
548 }
549 }
550 }
551 }
552
553 /***********************************************************************
554 *
555 * WinMain
556 */
557 int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE prev, LPTSTR cmdline, int show)
558 {
559 MSG msg;
560 HACCEL hAccel;
561 WNDCLASSEX wndclass;
562 HMONITOR monitor;
563 MONITORINFO info;
564 INT x, y;
565
566 static const TCHAR className[] = _T("NPClass");
567 static const TCHAR winName[] = _T("Notepad");
568
569 UNREFERENCED_PARAMETER(prev);
570
571 aFINDMSGSTRING = (ATOM) RegisterWindowMessage(FINDMSGSTRING);
572
573 ZeroMemory(&Globals, sizeof(Globals));
574 Globals.hInstance = hInstance;
575 LoadSettings();
576
577 ZeroMemory(&wndclass, sizeof(wndclass));
578 wndclass.cbSize = sizeof(wndclass);
579 wndclass.lpfnWndProc = NOTEPAD_WndProc;
580 wndclass.hInstance = Globals.hInstance;
581 wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_NPICON));
582 wndclass.hCursor = LoadCursor(0, IDC_ARROW);
583 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
584 wndclass.lpszMenuName = MAKEINTRESOURCE(MAIN_MENU);
585 wndclass.lpszClassName = className;
586 wndclass.hIconSm = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_NPICON),
587 IMAGE_ICON, 16, 16, 0);
588
589 if (!RegisterClassEx(&wndclass)) return FALSE;
590
591 /* Setup windows */
592
593 monitor = MonitorFromRect( &Globals.main_rect, MONITOR_DEFAULTTOPRIMARY );
594 info.cbSize = sizeof(info);
595 GetMonitorInfoW( monitor, &info );
596
597 x = Globals.main_rect.left;
598 y = Globals.main_rect.top;
599 if (Globals.main_rect.left >= info.rcWork.right ||
600 Globals.main_rect.top >= info.rcWork.bottom ||
601 Globals.main_rect.right < info.rcWork.left ||
602 Globals.main_rect.bottom < info.rcWork.top)
603 x = y = CW_USEDEFAULT;
604
605 Globals.hMainWnd =
606 CreateWindow(className, winName, WS_OVERLAPPEDWINDOW,
607 x, y, Globals.main_rect.right - Globals.main_rect.left,
608 Globals.main_rect.bottom - Globals.main_rect.top,
609 NULL, NULL, Globals.hInstance, NULL);
610 if (!Globals.hMainWnd)
611 {
612 ShowLastError();
613 ExitProcess(1);
614 }
615
616 NOTEPAD_InitData();
617 DIALOG_FileNew();
618
619 ShowWindow(Globals.hMainWnd, show);
620 UpdateWindow(Globals.hMainWnd);
621 DragAcceptFiles(Globals.hMainWnd, TRUE);
622
623 DIALOG_ViewStatusBar();
624
625 HandleCommandLine(cmdline);
626
627 hAccel = LoadAccelerators( hInstance, MAKEINTRESOURCE(ID_ACCEL) );
628
629 while (GetMessage(&msg, 0, 0, 0))
630 {
631 if (!IsDialogMessage(Globals.hFindReplaceDlg, &msg) &&
632 !TranslateAccelerator(Globals.hMainWnd, hAccel, &msg))
633 {
634 TranslateMessage(&msg);
635 DispatchMessage(&msg);
636 }
637 }
638 return (int) msg.wParam;
639 }