[CLIPBRD]
[reactos.git] / reactos / 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
15 static void SaveClipboardToFile(void)
16 {
17 OPENFILENAMEW sfn;
18 WCHAR szFileName[MAX_PATH];
19 WCHAR szFilterMask[MAX_STRING_LEN + 10];
20 LPWSTR c;
21
22 ZeroMemory(&szFilterMask, sizeof(szFilterMask));
23 c = szFilterMask + LoadStringW(Globals.hInstance, STRING_FORMAT_NT, szFilterMask, MAX_STRING_LEN) + 1;
24 wcscpy(c, L"*.clp");
25
26 ZeroMemory(&szFileName, sizeof(szFileName));
27 ZeroMemory(&sfn, sizeof(sfn));
28 sfn.lStructSize = sizeof(sfn);
29 sfn.hwndOwner = Globals.hMainWnd;
30 sfn.hInstance = Globals.hInstance;
31 sfn.lpstrFilter = szFilterMask;
32 sfn.lpstrFile = szFileName;
33 sfn.nMaxFile = ARRAYSIZE(szFileName);
34 sfn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
35 sfn.lpstrDefExt = L"clp";
36
37 if (!GetSaveFileNameW(&sfn))
38 return;
39
40 if (!OpenClipboard(NULL))
41 {
42 ShowLastWin32Error(Globals.hMainWnd);
43 return;
44 }
45
46 WriteClipboardFile(szFileName);
47
48 CloseClipboard();
49 }
50
51 static void LoadClipboardFromFile(void)
52 {
53 OPENFILENAMEW ofn;
54 WCHAR szFileName[MAX_PATH];
55 WCHAR szFilterMask[MAX_STRING_LEN + 10];
56 LPWSTR c;
57
58 ZeroMemory(&szFilterMask, sizeof(szFilterMask));
59 c = szFilterMask + LoadStringW(Globals.hInstance, STRING_FORMAT_GEN, szFilterMask, MAX_STRING_LEN) + 1;
60 wcscpy(c, L"*.clp");
61
62 ZeroMemory(&szFileName, sizeof(szFileName));
63 ZeroMemory(&ofn, sizeof(ofn));
64 ofn.lStructSize = sizeof(ofn);
65 ofn.hwndOwner = Globals.hMainWnd;
66 ofn.hInstance = Globals.hInstance;
67 ofn.lpstrFilter = szFilterMask;
68 ofn.lpstrFile = szFileName;
69 ofn.nMaxFile = ARRAYSIZE(szFileName);
70 ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
71
72 if (!GetOpenFileNameW(&ofn))
73 return;
74
75 if (!OpenClipboard(NULL))
76 {
77 ShowLastWin32Error(Globals.hMainWnd);
78 return;
79 }
80
81 if (MessageBoxRes(Globals.hMainWnd, Globals.hInstance, STRING_DELETE_MSG, STRING_DELETE_TITLE, MB_ICONWARNING | MB_YESNO) == IDYES)
82 {
83 EmptyClipboard();
84 ReadClipboardFile(szFileName);
85 }
86
87 CloseClipboard();
88 }
89
90 static void LoadClipboardFromDrop(HDROP hDrop)
91 {
92 WCHAR szFileName[MAX_PATH];
93
94 DragQueryFileW(hDrop, 0, szFileName, ARRAYSIZE(szFileName));
95 DragFinish(hDrop);
96
97 if (!OpenClipboard(NULL))
98 {
99 ShowLastWin32Error(Globals.hMainWnd);
100 return;
101 }
102
103 if (MessageBoxRes(Globals.hMainWnd, Globals.hInstance, STRING_DELETE_MSG, STRING_DELETE_TITLE, MB_ICONWARNING | MB_YESNO) == IDYES)
104 {
105 EmptyClipboard();
106 ReadClipboardFile(szFileName);
107 }
108
109 CloseClipboard();
110 }
111
112 static void SetDisplayFormat(UINT uFormat)
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 InvalidateRect(Globals.hMainWnd, NULL, TRUE);
128 UpdateWindow(Globals.hMainWnd);
129 }
130
131 static void InitMenuPopup(HMENU hMenu, LPARAM index)
132 {
133 if ((GetMenuItemID(hMenu, 0) == CMD_DELETE) || (GetMenuItemID(hMenu, 1) == CMD_SAVE_AS))
134 {
135 if (CountClipboardFormats() == 0)
136 {
137 EnableMenuItem(hMenu, CMD_DELETE, MF_GRAYED);
138 EnableMenuItem(hMenu, CMD_SAVE_AS, MF_GRAYED);
139 }
140 else
141 {
142 EnableMenuItem(hMenu, CMD_DELETE, MF_ENABLED);
143 EnableMenuItem(hMenu, CMD_SAVE_AS, MF_ENABLED);
144 }
145 }
146
147 DrawMenuBar(Globals.hMainWnd);
148 }
149
150 void UpdateDisplayMenu(void)
151 {
152 UINT uFormat;
153 WCHAR szFormatName[MAX_FMT_NAME_LEN + 1];
154 HMENU hMenu;
155
156 hMenu = GetSubMenu(Globals.hMenu, DISPLAY_MENU_POS);
157
158 while (GetMenuItemCount(hMenu) > 1)
159 {
160 DeleteMenu(hMenu, 1, MF_BYPOSITION);
161 }
162
163 if (CountClipboardFormats() == 0)
164 return;
165
166 if (!OpenClipboard(NULL))
167 return;
168
169 AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
170
171 uFormat = EnumClipboardFormats(0);
172 while (uFormat)
173 {
174 RetrieveClipboardFormatName(Globals.hInstance, uFormat, szFormatName, ARRAYSIZE(szFormatName));
175
176 if (!IsClipboardFormatSupported(uFormat))
177 {
178 AppendMenuW(hMenu, MF_STRING | MF_GRAYED, 0, szFormatName);
179 }
180 else
181 {
182 AppendMenuW(hMenu, MF_STRING, CMD_AUTOMATIC + uFormat, szFormatName);
183 }
184
185 uFormat = EnumClipboardFormats(uFormat);
186 }
187
188 CloseClipboard();
189 }
190
191 static int ClipboardCommandHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
192 {
193 switch (LOWORD(wParam))
194 {
195 case CMD_OPEN:
196 {
197 LoadClipboardFromFile();
198 break;
199 }
200
201 case CMD_SAVE_AS:
202 {
203 SaveClipboardToFile();
204 break;
205 }
206
207 case CMD_EXIT:
208 {
209 PostMessageW(Globals.hMainWnd, WM_CLOSE, 0, 0);
210 break;
211 }
212
213 case CMD_DELETE:
214 {
215 if (MessageBoxRes(Globals.hMainWnd, Globals.hInstance, STRING_DELETE_MSG, STRING_DELETE_TITLE, MB_ICONWARNING | MB_YESNO) == IDYES)
216 {
217 DeleteClipboardContent();
218 }
219 break;
220 }
221
222 case CMD_AUTOMATIC:
223 {
224 SetDisplayFormat(0);
225 break;
226 }
227
228 case CMD_HELP:
229 {
230 HtmlHelpW(Globals.hMainWnd, L"clipbrd.chm", 0, 0);
231 break;
232 }
233
234 case CMD_ABOUT:
235 {
236 WCHAR szTitle[MAX_STRING_LEN];
237 LoadStringW(Globals.hInstance, STRING_CLIPBOARD, szTitle, ARRAYSIZE(szTitle));
238 ShellAboutW(Globals.hMainWnd, szTitle, 0, NULL);
239 break;
240 }
241
242 default:
243 {
244 break;
245 }
246 }
247 return 0;
248 }
249
250 static void ClipboardPaintHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
251 {
252 HDC hdc;
253 PAINTSTRUCT ps;
254 RECT rc;
255
256 hdc = BeginPaint(hWnd, &ps);
257 GetClientRect(hWnd, &rc);
258
259 switch (Globals.uDisplayFormat)
260 {
261 case CF_NONE:
262 {
263 break;
264 }
265
266 case CF_UNICODETEXT:
267 {
268 DrawTextFromClipboard(hdc, &rc, DT_LEFT);
269 break;
270 }
271
272 case CF_BITMAP:
273 {
274 BitBltFromClipboard(hdc, rc.left, rc.top, rc.right, rc.bottom, 0, 0, SRCCOPY);
275 break;
276 }
277
278 case CF_DIB:
279 {
280 SetDIBitsToDeviceFromClipboard(CF_DIB, hdc, rc.left, rc.top, 0, 0, 0, DIB_RGB_COLORS);
281 break;
282 }
283
284 case CF_DIBV5:
285 {
286 SetDIBitsToDeviceFromClipboard(CF_DIBV5, hdc, rc.left, rc.top, 0, 0, 0, DIB_RGB_COLORS);
287 break;
288 }
289
290 case CF_ENHMETAFILE:
291 {
292 PlayEnhMetaFileFromClipboard(hdc, &rc);
293 break;
294 }
295
296 case CF_METAFILEPICT:
297 {
298 PlayMetaFileFromClipboard(hdc, &rc);
299 break;
300 }
301
302 default:
303 {
304
305 DrawTextFromResource(Globals.hInstance, ERROR_UNSUPPORTED_FORMAT, hdc, &rc, DT_CENTER | DT_WORDBREAK);
306 break;
307 }
308 }
309
310 EndPaint(hWnd, &ps);
311 }
312
313 static LRESULT WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
314 {
315 switch(uMsg)
316 {
317 case WM_PAINT:
318 {
319 ClipboardPaintHandler(hWnd, uMsg, wParam, lParam);
320 break;
321 }
322
323 case WM_SIZE:
324 {
325 InvalidateRect(hWnd, NULL, TRUE);
326 UpdateWindow(hWnd);
327 break;
328 }
329
330 case WM_CREATE:
331 {
332 Globals.hMenu = GetMenu(hWnd);
333 Globals.hWndNext = SetClipboardViewer(hWnd);
334 UpdateDisplayMenu();
335 SetDisplayFormat(0);
336 break;
337 }
338
339 case WM_CLOSE:
340 {
341 DestroyWindow(hWnd);
342 break;
343 }
344
345 case WM_DESTROY:
346 {
347 ChangeClipboardChain(hWnd, Globals.hWndNext);
348 PostQuitMessage(0);
349 break;
350 }
351
352 case WM_CHANGECBCHAIN:
353 {
354 if ((HWND)wParam == Globals.hWndNext)
355 {
356 Globals.hWndNext = (HWND)lParam;
357 }
358 else if (Globals.hWndNext != NULL)
359 {
360 SendMessageW(Globals.hWndNext, uMsg, wParam, lParam);
361 }
362
363 break;
364 }
365
366 case WM_DRAWCLIPBOARD:
367 {
368 UpdateDisplayMenu();
369 SetDisplayFormat(0);
370
371 SendMessageW(Globals.hWndNext, uMsg, wParam, lParam);
372 break;
373 }
374
375 case WM_COMMAND:
376 {
377 if ((LOWORD(wParam) > CMD_AUTOMATIC))
378 {
379 SetDisplayFormat(LOWORD(wParam) - CMD_AUTOMATIC);
380 }
381 else
382 {
383 ClipboardCommandHandler(hWnd, uMsg, wParam, lParam);
384 }
385 break;
386 }
387
388 case WM_INITMENUPOPUP:
389 {
390 InitMenuPopup((HMENU)wParam, lParam);
391 break;
392 }
393
394 case WM_DROPFILES:
395 {
396 LoadClipboardFromDrop((HDROP)wParam);
397 break;
398 }
399
400 default:
401 {
402 return DefWindowProc(hWnd, uMsg, wParam, lParam);
403 }
404 }
405 return 0;
406 }
407
408 int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
409 {
410 MSG msg;
411 HACCEL hAccel;
412 HWND hPrevWindow;
413 WNDCLASSEXW wndclass;
414 WCHAR szBuffer[MAX_STRING_LEN];
415
416 hPrevWindow = FindWindowW(szClassName, NULL);
417 if (hPrevWindow)
418 {
419 BringWindowToFront(hPrevWindow);
420 return 0;
421 }
422
423 ZeroMemory(&Globals, sizeof(Globals));
424 Globals.hInstance = hInstance;
425
426 ZeroMemory(&wndclass, sizeof(wndclass));
427 wndclass.cbSize = sizeof(wndclass);
428 wndclass.lpfnWndProc = MainWndProc;
429 wndclass.hInstance = hInstance;
430 wndclass.hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(CLIP_ICON));
431 wndclass.hCursor = LoadCursorW(0, IDC_ARROW);
432 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
433 wndclass.lpszMenuName = MAKEINTRESOURCEW(MAIN_MENU);
434 wndclass.lpszClassName = szClassName;
435
436 if (!RegisterClassExW(&wndclass))
437 {
438 ShowLastWin32Error(NULL);
439 return 0;
440 }
441
442 LoadStringW(hInstance, STRING_CLIPBOARD, szBuffer, ARRAYSIZE(szBuffer));
443 Globals.hMainWnd = CreateWindowExW(WS_EX_CLIENTEDGE | WS_EX_ACCEPTFILES,
444 szClassName,
445 szBuffer,
446 WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
447 CW_USEDEFAULT,
448 CW_USEDEFAULT,
449 CW_USEDEFAULT,
450 CW_USEDEFAULT,
451 NULL,
452 NULL,
453 Globals.hInstance,
454 NULL);
455 if (!Globals.hMainWnd)
456 {
457 ShowLastWin32Error(NULL);
458 return 0;
459 }
460
461 ShowWindow(Globals.hMainWnd, nCmdShow);
462 UpdateWindow(Globals.hMainWnd);
463
464 hAccel = LoadAcceleratorsW(Globals.hInstance, MAKEINTRESOURCEW(ID_ACCEL));
465 if (!hAccel)
466 {
467 ShowLastWin32Error(Globals.hMainWnd);
468 }
469
470 while (GetMessageW(&msg, 0, 0, 0))
471 {
472 if (!TranslateAcceleratorW(Globals.hMainWnd, hAccel, &msg))
473 {
474 TranslateMessage(&msg);
475 DispatchMessageW(&msg);
476 }
477 }
478
479 return (int)msg.wParam;
480 }