[CALC][CLIPBRD][SOLITAIRE][SPIDER][NOTEPAD][REGEDIT][TASKMGR] Disable help menu/button
[reactos.git] / base / applications / clipbrd / clipbrd.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Clipboard Viewer
4 * FILE: base/applications/clipbrd/clipbrd.c
5 * PURPOSE: Provides a view of the contents of the ReactOS clipboard.
6 * PROGRAMMERS: Ricardo Hanke
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 UpdateLinesToScroll(void)
17 {
18 UINT uLinesToScroll;
19
20 if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uLinesToScroll, 0))
21 {
22 Globals.uLinesToScroll = 3;
23 }
24 else
25 {
26 Globals.uLinesToScroll = uLinesToScroll;
27 }
28 }
29
30 static void SaveClipboardToFile(void)
31 {
32 OPENFILENAMEW sfn;
33 WCHAR szFileName[MAX_PATH];
34 WCHAR szFilterMask[MAX_STRING_LEN + 10];
35 LPWSTR c;
36
37 ZeroMemory(&szFilterMask, sizeof(szFilterMask));
38 c = szFilterMask + LoadStringW(Globals.hInstance, STRING_FORMAT_NT, szFilterMask, MAX_STRING_LEN) + 1;
39 wcscpy(c, L"*.clp");
40
41 ZeroMemory(&szFileName, sizeof(szFileName));
42 ZeroMemory(&sfn, sizeof(sfn));
43 sfn.lStructSize = sizeof(sfn);
44 sfn.hwndOwner = Globals.hMainWnd;
45 sfn.hInstance = Globals.hInstance;
46 sfn.lpstrFilter = szFilterMask;
47 sfn.lpstrFile = szFileName;
48 sfn.nMaxFile = ARRAYSIZE(szFileName);
49 sfn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
50 sfn.lpstrDefExt = L"clp";
51
52 if (!GetSaveFileNameW(&sfn))
53 return;
54
55 if (!OpenClipboard(Globals.hMainWnd))
56 {
57 ShowLastWin32Error(Globals.hMainWnd);
58 return;
59 }
60
61 WriteClipboardFile(szFileName, CLIP_FMT_NT /* CLIP_FMT_31 */);
62
63 CloseClipboard();
64 }
65
66 static void LoadClipboardDataFromFile(LPWSTR lpszFileName)
67 {
68 if (MessageBoxRes(Globals.hMainWnd, Globals.hInstance,
69 STRING_DELETE_MSG, STRING_DELETE_TITLE,
70 MB_ICONWARNING | MB_YESNO) != IDYES)
71 {
72 return;
73 }
74
75 if (!OpenClipboard(Globals.hMainWnd))
76 {
77 ShowLastWin32Error(Globals.hMainWnd);
78 return;
79 }
80
81 EmptyClipboard();
82 ReadClipboardFile(lpszFileName);
83
84 CloseClipboard();
85 }
86
87 static void LoadClipboardFromFile(void)
88 {
89 OPENFILENAMEW ofn;
90 WCHAR szFileName[MAX_PATH];
91 WCHAR szFilterMask[MAX_STRING_LEN + 10];
92 LPWSTR c;
93
94 ZeroMemory(&szFilterMask, sizeof(szFilterMask));
95 c = szFilterMask + LoadStringW(Globals.hInstance, STRING_FORMAT_GEN, szFilterMask, MAX_STRING_LEN) + 1;
96 wcscpy(c, L"*.clp");
97
98 ZeroMemory(&szFileName, sizeof(szFileName));
99 ZeroMemory(&ofn, sizeof(ofn));
100 ofn.lStructSize = sizeof(ofn);
101 ofn.hwndOwner = Globals.hMainWnd;
102 ofn.hInstance = Globals.hInstance;
103 ofn.lpstrFilter = szFilterMask;
104 ofn.lpstrFile = szFileName;
105 ofn.nMaxFile = ARRAYSIZE(szFileName);
106 ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
107
108 if (!GetOpenFileNameW(&ofn))
109 return;
110
111 LoadClipboardDataFromFile(szFileName);
112 }
113
114 static void LoadClipboardFromDrop(HDROP hDrop)
115 {
116 WCHAR szFileName[MAX_PATH];
117
118 DragQueryFileW(hDrop, 0, szFileName, ARRAYSIZE(szFileName));
119 DragFinish(hDrop);
120
121 LoadClipboardDataFromFile(szFileName);
122 }
123
124 static void SetDisplayFormat(UINT uFormat)
125 {
126 CheckMenuItem(Globals.hMenu, Globals.uCheckedItem, MF_BYCOMMAND | MF_UNCHECKED);
127 Globals.uCheckedItem = uFormat + CMD_AUTOMATIC;
128 CheckMenuItem(Globals.hMenu, Globals.uCheckedItem, MF_BYCOMMAND | MF_CHECKED);
129
130 if (uFormat == 0)
131 {
132 Globals.uDisplayFormat = GetAutomaticClipboardFormat();
133 }
134 else
135 {
136 Globals.uDisplayFormat = uFormat;
137 }
138
139 if (Globals.hDspBmp)
140 {
141 DeleteObject(Globals.hDspBmp);
142 }
143
144 ZeroMemory(&Scrollstate, sizeof(Scrollstate));
145 UpdateWindowScrollState(Globals.hMainWnd, Globals.hDspBmp, &Scrollstate);
146
147 InvalidateRect(Globals.hMainWnd, NULL, TRUE);
148 }
149
150 static void InitMenuPopup(HMENU hMenu, LPARAM index)
151 {
152 if ((GetMenuItemID(hMenu, 0) == CMD_DELETE) || (GetMenuItemID(hMenu, 1) == CMD_SAVE_AS))
153 {
154 if (CountClipboardFormats() == 0)
155 {
156 EnableMenuItem(hMenu, CMD_DELETE, MF_GRAYED);
157 EnableMenuItem(hMenu, CMD_SAVE_AS, MF_GRAYED);
158 }
159 else
160 {
161 EnableMenuItem(hMenu, CMD_DELETE, MF_ENABLED);
162 EnableMenuItem(hMenu, CMD_SAVE_AS, MF_ENABLED);
163 }
164 }
165
166 DrawMenuBar(Globals.hMainWnd);
167 }
168
169 static void UpdateDisplayMenu(void)
170 {
171 UINT uFormat;
172 WCHAR szFormatName[MAX_FMT_NAME_LEN + 1];
173 HMENU hMenu;
174
175 hMenu = GetSubMenu(Globals.hMenu, DISPLAY_MENU_POS);
176
177 while (GetMenuItemCount(hMenu) > 1)
178 {
179 DeleteMenu(hMenu, 1, MF_BYPOSITION);
180 }
181
182 if (CountClipboardFormats() == 0)
183 return;
184
185 if (!OpenClipboard(Globals.hMainWnd))
186 return;
187
188 AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
189
190 uFormat = EnumClipboardFormats(0);
191 while (uFormat)
192 {
193 RetrieveClipboardFormatName(Globals.hInstance, uFormat, TRUE, szFormatName, ARRAYSIZE(szFormatName));
194
195 if (!IsClipboardFormatSupported(uFormat))
196 {
197 AppendMenuW(hMenu, MF_STRING | MF_GRAYED, 0, szFormatName);
198 }
199 else
200 {
201 AppendMenuW(hMenu, MF_STRING, CMD_AUTOMATIC + uFormat, szFormatName);
202 }
203
204 uFormat = EnumClipboardFormats(uFormat);
205 }
206
207 CloseClipboard();
208 }
209
210 static int ClipboardCommandHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
211 {
212 switch (LOWORD(wParam))
213 {
214 case CMD_OPEN:
215 {
216 LoadClipboardFromFile();
217 break;
218 }
219
220 case CMD_SAVE_AS:
221 {
222 SaveClipboardToFile();
223 break;
224 }
225
226 case CMD_EXIT:
227 {
228 PostMessageW(Globals.hMainWnd, WM_CLOSE, 0, 0);
229 break;
230 }
231
232 case CMD_DELETE:
233 {
234 if (MessageBoxRes(Globals.hMainWnd, Globals.hInstance,
235 STRING_DELETE_MSG, STRING_DELETE_TITLE,
236 MB_ICONWARNING | MB_YESNO) != IDYES)
237 {
238 break;
239 }
240
241 DeleteClipboardContent();
242 break;
243 }
244
245 case CMD_AUTOMATIC:
246 {
247 SetDisplayFormat(0);
248 break;
249 }
250
251 case CMD_HELP:
252 {
253 HtmlHelpW(Globals.hMainWnd, L"clipbrd.chm", 0, 0);
254 break;
255 }
256
257 case CMD_ABOUT:
258 {
259 HICON hIcon;
260 WCHAR szTitle[MAX_STRING_LEN];
261
262 hIcon = LoadIconW(Globals.hInstance, MAKEINTRESOURCE(CLIPBRD_ICON));
263 LoadStringW(Globals.hInstance, STRING_CLIPBOARD, szTitle, ARRAYSIZE(szTitle));
264 ShellAboutW(Globals.hMainWnd, szTitle, NULL, hIcon);
265 DeleteObject(hIcon);
266 break;
267 }
268
269 default:
270 {
271 break;
272 }
273 }
274 return 0;
275 }
276
277 static void ClipboardPaintHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
278 {
279 HDC hdc;
280 PAINTSTRUCT ps;
281 RECT rc;
282
283 if (!OpenClipboard(Globals.hMainWnd))
284 return;
285
286 hdc = BeginPaint(hWnd, &ps);
287 GetClientRect(hWnd, &rc);
288
289 switch (Globals.uDisplayFormat)
290 {
291 case CF_NONE:
292 {
293 break;
294 }
295
296 case CF_UNICODETEXT:
297 {
298 DrawTextFromClipboard(hdc, &rc, DT_LEFT | DT_NOPREFIX);
299 break;
300 }
301
302 case CF_BITMAP:
303 {
304 BitBltFromClipboard(hdc, rc.left, rc.top, rc.right, rc.bottom, 0, 0, SRCCOPY);
305 break;
306 }
307
308 case CF_DIB:
309 {
310 SetDIBitsToDeviceFromClipboard(CF_DIB, hdc, rc.left, rc.top, 0, 0, 0, DIB_RGB_COLORS);
311 break;
312 }
313
314 case CF_DIBV5:
315 {
316 SetDIBitsToDeviceFromClipboard(CF_DIBV5, hdc, rc.left, rc.top, 0, 0, 0, DIB_RGB_COLORS);
317 break;
318 }
319
320 case CF_METAFILEPICT:
321 {
322 PlayMetaFileFromClipboard(hdc, &rc);
323 break;
324 }
325
326 case CF_ENHMETAFILE:
327 {
328 PlayEnhMetaFileFromClipboard(hdc, &rc);
329 break;
330 }
331
332 default:
333 {
334 DrawTextFromResource(Globals.hInstance, ERROR_UNSUPPORTED_FORMAT, hdc, &rc, DT_CENTER | DT_WORDBREAK | DT_NOPREFIX);
335 break;
336 }
337 }
338
339 EndPaint(hWnd, &ps);
340
341 CloseClipboard();
342 }
343
344 static LRESULT WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
345 {
346 switch(uMsg)
347 {
348 case WM_CREATE:
349 {
350 Globals.hMenu = GetMenu(hWnd);
351 Globals.hWndNext = SetClipboardViewer(hWnd);
352
353 // For now, the Help dialog item is disabled because of lacking of HTML support
354 EnableMenuItem(Globals.hMenu, CMD_HELP, MF_BYCOMMAND | MF_GRAYED);
355
356 UpdateDisplayMenu();
357 SetDisplayFormat(0);
358 break;
359 }
360
361 case WM_CLOSE:
362 {
363 DestroyWindow(hWnd);
364 break;
365 }
366
367 case WM_DESTROY:
368 {
369 ChangeClipboardChain(hWnd, Globals.hWndNext);
370 PostQuitMessage(0);
371 break;
372 }
373
374 case WM_PAINT:
375 {
376 ClipboardPaintHandler(hWnd, uMsg, wParam, lParam);
377 break;
378 }
379
380 case WM_KEYDOWN:
381 {
382 HandleKeyboardScrollEvents(hWnd, uMsg, wParam, lParam);
383 break;
384 }
385
386 case WM_MOUSEWHEEL:
387 {
388 HandleMouseScrollEvents(hWnd, uMsg, wParam, lParam, &Scrollstate);
389 break;
390 }
391
392 case WM_HSCROLL:
393 {
394 HandleHorizontalScrollEvents(hWnd, uMsg, wParam, lParam, &Scrollstate);
395 break;
396 }
397
398 case WM_VSCROLL:
399 {
400 HandleVerticalScrollEvents(hWnd, uMsg, wParam, lParam, &Scrollstate);
401 break;
402 }
403
404 case WM_SIZE:
405 {
406 UpdateWindowScrollState(hWnd, Globals.hDspBmp, &Scrollstate);
407
408 if ((Globals.uDisplayFormat == CF_METAFILEPICT) ||
409 (Globals.uDisplayFormat == CF_ENHMETAFILE) ||
410 (Globals.uDisplayFormat == CF_DSPENHMETAFILE) ||
411 (Globals.uDisplayFormat == CF_DSPMETAFILEPICT))
412 {
413 InvalidateRect(Globals.hMainWnd, NULL, FALSE);
414 }
415 else if (!IsClipboardFormatSupported(Globals.uDisplayFormat))
416 {
417 InvalidateRect(Globals.hMainWnd, NULL, TRUE);
418 }
419
420 break;
421 }
422
423 case WM_CHANGECBCHAIN:
424 {
425 if ((HWND)wParam == Globals.hWndNext)
426 {
427 Globals.hWndNext = (HWND)lParam;
428 }
429 else if (Globals.hWndNext != NULL)
430 {
431 SendMessageW(Globals.hWndNext, uMsg, wParam, lParam);
432 }
433
434 break;
435 }
436
437 case WM_DRAWCLIPBOARD:
438 {
439 UpdateDisplayMenu();
440 SetDisplayFormat(0);
441
442 SendMessageW(Globals.hWndNext, uMsg, wParam, lParam);
443 break;
444 }
445
446 case WM_COMMAND:
447 {
448 if ((LOWORD(wParam) > CMD_AUTOMATIC))
449 {
450 SetDisplayFormat(LOWORD(wParam) - CMD_AUTOMATIC);
451 }
452 else
453 {
454 ClipboardCommandHandler(hWnd, uMsg, wParam, lParam);
455 }
456 break;
457 }
458
459 case WM_INITMENUPOPUP:
460 {
461 InitMenuPopup((HMENU)wParam, lParam);
462 break;
463 }
464
465 case WM_DROPFILES:
466 {
467 LoadClipboardFromDrop((HDROP)wParam);
468 break;
469 }
470
471 case WM_QUERYNEWPALETTE:
472 {
473 if (RealizeClipboardPalette(hWnd) != GDI_ERROR)
474 {
475 InvalidateRect(hWnd, NULL, TRUE);
476 UpdateWindow(hWnd);
477 return TRUE;
478 }
479 return FALSE;
480 }
481
482 case WM_PALETTECHANGED:
483 {
484 if ((HWND)wParam != hWnd)
485 {
486 if (RealizeClipboardPalette(hWnd) != GDI_ERROR)
487 {
488 InvalidateRect(hWnd, NULL, TRUE);
489 UpdateWindow(hWnd);
490 }
491 }
492 break;
493 }
494
495 case WM_SYSCOLORCHANGE:
496 {
497 SetDisplayFormat(Globals.uDisplayFormat);
498 break;
499 }
500
501 case WM_SETTINGCHANGE:
502 {
503 if (wParam == SPI_SETWHEELSCROLLLINES)
504 {
505 UpdateLinesToScroll();
506 }
507 break;
508 }
509
510 default:
511 {
512 return DefWindowProc(hWnd, uMsg, wParam, lParam);
513 }
514 }
515 return 0;
516 }
517
518 int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
519 {
520 MSG msg;
521 HACCEL hAccel;
522 HWND hPrevWindow;
523 WNDCLASSEXW wndclass;
524 WCHAR szBuffer[MAX_STRING_LEN];
525
526 hPrevWindow = FindWindowW(szClassName, NULL);
527 if (hPrevWindow)
528 {
529 BringWindowToFront(hPrevWindow);
530 return 0;
531 }
532
533 ZeroMemory(&Globals, sizeof(Globals));
534 Globals.hInstance = hInstance;
535
536 ZeroMemory(&wndclass, sizeof(wndclass));
537 wndclass.cbSize = sizeof(wndclass);
538 wndclass.lpfnWndProc = MainWndProc;
539 wndclass.hInstance = hInstance;
540 wndclass.hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(CLIPBRD_ICON));
541 wndclass.hCursor = LoadCursorW(0, IDC_ARROW);
542 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
543 wndclass.lpszMenuName = MAKEINTRESOURCEW(MAIN_MENU);
544 wndclass.lpszClassName = szClassName;
545
546 switch (GetUserDefaultUILanguage())
547 {
548 case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT):
549 SetProcessDefaultLayout(LAYOUT_RTL);
550 break;
551
552 default:
553 break;
554 }
555
556 if (!RegisterClassExW(&wndclass))
557 {
558 ShowLastWin32Error(NULL);
559 return 0;
560 }
561
562 LoadStringW(hInstance, STRING_CLIPBOARD, szBuffer, ARRAYSIZE(szBuffer));
563 Globals.hMainWnd = CreateWindowExW(WS_EX_CLIENTEDGE | WS_EX_ACCEPTFILES,
564 szClassName,
565 szBuffer,
566 WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
567 CW_USEDEFAULT,
568 CW_USEDEFAULT,
569 CW_USEDEFAULT,
570 CW_USEDEFAULT,
571 NULL,
572 NULL,
573 Globals.hInstance,
574 NULL);
575 if (!Globals.hMainWnd)
576 {
577 ShowLastWin32Error(NULL);
578 return 0;
579 }
580
581 ShowWindow(Globals.hMainWnd, nCmdShow);
582 UpdateWindow(Globals.hMainWnd);
583
584 hAccel = LoadAcceleratorsW(Globals.hInstance, MAKEINTRESOURCEW(ID_ACCEL));
585 if (!hAccel)
586 {
587 ShowLastWin32Error(Globals.hMainWnd);
588 }
589
590 /* If the user provided a path to a clipboard data file, try to open it */
591 if (lpCmdLine != NULL && *lpCmdLine)
592 LoadClipboardDataFromFile(lpCmdLine);
593
594 UpdateLinesToScroll();
595
596 while (GetMessageW(&msg, 0, 0, 0))
597 {
598 if (!TranslateAcceleratorW(Globals.hMainWnd, hAccel, &msg))
599 {
600 TranslateMessage(&msg);
601 DispatchMessageW(&msg);
602 }
603 }
604
605 if (Globals.hDspBmp)
606 {
607 DeleteObject(Globals.hDspBmp);
608 }
609
610 return (int)msg.wParam;
611 }