[VFD] Fix build
[reactos.git] / modules / rosapps / lib / vfdlib / vfdshmenu.cpp
1 /*
2 vfdshmenu.cpp
3
4 Virtual Floppy Drive for Windows
5 Driver control library
6 COM shell extension class context menu functions
7
8 Copyright (c) 2003-2005 Ken Kato
9 */
10
11 #define WIN32_LEAN_AND_MEAN
12 #include <windows.h>
13 #include <shellapi.h>
14 #include <shlobj.h>
15
16 #include "vfdtypes.h"
17 #include "vfdapi.h"
18 #include "vfdlib.h"
19 #ifndef __REACTOS__
20 #include "vfdmsg.h"
21 #else
22 #include "vfdmsg_lib.h"
23 #endif
24
25 // class header
26 #include "vfdshext.h"
27
28 //
29 // Undocumented windows API to handle shell property sheets
30 //
31
32 typedef BOOL (WINAPI *SHOBJECTPROPERTIES)(
33 HWND hwnd, DWORD dwType, LPCWSTR lpObject, LPCWSTR lpPage);
34
35 #ifndef SHOP_FILEPATH
36 #define SHOP_FILEPATH 0x00000002
37 #endif
38
39 #define SHOP_EXPORT_ORDINAL 178
40
41 //
42 // Context Menu Items
43 //
44 enum {
45 VFD_CMD_OPEN = 0,
46 VFD_CMD_SAVE,
47 VFD_CMD_CLOSE,
48 VFD_CMD_PROTECT,
49 VFD_CMD_DROP,
50 VFD_CMD_PROP,
51 VFD_CMD_MAX
52 };
53
54 static struct _vfd_menu {
55 UINT textid; // menu item text id
56 UINT helpid; // menu item help id
57 #ifndef __REACTOS__
58 PCHAR verbA; // ansi verb text
59 PWCHAR verbW; // unicode verb text
60 #else
61 LPCSTR verbA; // ansi verb text
62 LPCWSTR verbW; // unicode verb text
63 #endif
64 }
65 g_VfdMenu[VFD_CMD_MAX] = {
66 { MSG_MENU_OPEN, MSG_HELP_OPEN, "vfdopen", L"vfdopen" },
67 { MSG_MENU_SAVE, MSG_HELP_SAVE, "vfdsave", L"vfdsave" },
68 { MSG_MENU_CLOSE, MSG_HELP_CLOSE, "vfdclose", L"vfdclose" },
69 { MSG_MENU_PROTECT, MSG_HELP_PROTECT, "protect", L"protect" },
70 { MSG_MENU_DROP, MSG_HELP_DROP, "vfddrop", L"vfddrop" },
71 { MSG_MENU_PROP, MSG_HELP_PROP, "vfdprop", L"vfdprop" },
72 };
73
74 //
75 // local functions
76 //
77 static void AddMenuItem(
78 HMENU hMenu,
79 UINT uPos,
80 UINT uFlags,
81 UINT uCmd,
82 UINT uText)
83 {
84 PSTR text = ModuleMessage(uText);
85
86 if (text) {
87 InsertMenu(hMenu, uPos, uFlags, uCmd, text);
88 LocalFree(text);
89 }
90 }
91
92
93 //
94 // FUNCTION: CVfdShExt::QueryContextMenu(HMENU, UINT, UINT, UINT, UINT)
95 //
96 // PURPOSE: Called by the shell just before the context menu is displayed.
97 // This is where you add your specific menu items.
98 //
99 // PARAMETERS:
100 // hMenu - Handle to the context menu
101 // indexMenu - Index of where to begin inserting menu items
102 // idCmdFirst - Lowest value for new menu ID's
103 // idCmtLast - Highest value for new menu ID's
104 // uFlags - Specifies the context of the menu event
105 //
106 STDMETHODIMP CVfdShExt::QueryContextMenu(
107 HMENU hMenu,
108 UINT indexMenu,
109 UINT idCmdFirst,
110 UINT idCmdLast,
111 UINT uFlags)
112 {
113 UNREFERENCED_PARAMETER(idCmdLast);
114 VFDTRACE(0, ("CVfdShExt::QueryContextMenu()\n"));
115
116 //
117 // Check if menu items should be added
118 //
119 if ((CMF_DEFAULTONLY & uFlags) ||
120 !m_pDataObj || m_nDevice == (ULONG)-1) {
121
122 VFDTRACE(0, ("Don't add any items.\n"));
123 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
124 }
125
126 //
127 // Drag & Drop handler?
128 //
129 if (m_bDragDrop) {
130
131 VFDTRACE(0, ("Invoked as the Drop handler.\n"));
132
133 if (GetFileAttributes(m_sTarget) & FILE_ATTRIBUTE_DIRECTORY) {
134
135 // if the dropped item is a directory, nothing to do here
136 VFDTRACE(0, ("Dropped object is a directory.\n"));
137
138 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
139 }
140
141 // Add a drop context menu item
142 AddMenuItem(
143 hMenu,
144 indexMenu,
145 MF_BYPOSITION | MF_STRING,
146 idCmdFirst + VFD_CMD_DROP,
147 g_VfdMenu[VFD_CMD_DROP].textid);
148
149 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, VFD_CMD_DROP + 1);
150 }
151
152 //
153 // Context menu handler
154 //
155 VFDTRACE(0, ("Invoked as the context menu handler.\n"));
156
157 //
158 // Get the VFD media state
159 //
160 HANDLE hDevice = VfdOpenDevice(m_nDevice);
161
162 if (hDevice == INVALID_HANDLE_VALUE) {
163 VFDTRACE(0, ("device open failed.\n"));
164 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
165 }
166
167 DWORD status = VfdGetMediaState(hDevice);
168
169 CloseHandle(hDevice);
170
171 //
172 // Add context menu items
173 //
174
175 InsertMenu(hMenu, indexMenu++,
176 MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
177
178 if (status == ERROR_SUCCESS ||
179 status == ERROR_WRITE_PROTECT) {
180
181 // An image is opened
182
183 // insert the "save" menu item
184
185 AddMenuItem(
186 hMenu,
187 indexMenu++,
188 MF_BYPOSITION | MF_STRING,
189 idCmdFirst + VFD_CMD_SAVE,
190 g_VfdMenu[VFD_CMD_SAVE].textid);
191
192 // insert the "close" menu item
193
194 AddMenuItem(
195 hMenu,
196 indexMenu++,
197 MF_BYPOSITION | MF_STRING,
198 idCmdFirst + VFD_CMD_CLOSE,
199 g_VfdMenu[VFD_CMD_CLOSE].textid);
200
201 // insert the "protect" menu item
202
203 AddMenuItem(
204 hMenu,
205 indexMenu++,
206 MF_BYPOSITION | MF_STRING,
207 idCmdFirst + VFD_CMD_PROTECT,
208 g_VfdMenu[VFD_CMD_PROTECT].textid);
209
210 // check "protect" menu item
211
212 if (status == ERROR_WRITE_PROTECT) {
213 CheckMenuItem(hMenu, indexMenu - 1,
214 MF_BYPOSITION | MF_CHECKED);
215 }
216 }
217 else {
218 // The drive is empty
219
220 // insert the "open" menu item
221
222 AddMenuItem(
223 hMenu,
224 indexMenu++,
225 MF_BYPOSITION | MF_STRING,
226 idCmdFirst + VFD_CMD_OPEN,
227 g_VfdMenu[VFD_CMD_OPEN].textid);
228 }
229
230 // Insert the "proterty" menu item
231
232 AddMenuItem(
233 hMenu,
234 indexMenu++,
235 MF_BYPOSITION | MF_STRING,
236 idCmdFirst + VFD_CMD_PROP,
237 g_VfdMenu[VFD_CMD_PROP].textid);
238
239 // Insert a separator
240
241 InsertMenu(hMenu, indexMenu,
242 MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
243
244 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, VFD_CMD_PROP + 1);
245 }
246
247 //
248 // FUNCTION: CVfdShExt::GetCommandString(LPCMINVOKECOMMANDINFO)
249 //
250 // PURPOSE: Retrieves information about a shortcut menu command,
251 // including the Help string and the language-independent,
252 // or canonical, name for the command.
253 //
254 // PARAMETERS:
255 // idCmd - Menu command identifier offset.
256 // uFlags - Flags specifying the information to return.
257 // This parameter can have one of the following values.
258 // GCS_HELPTEXTA Sets pszName to an ANSI string containing the Help text for the command.
259 // GCS_HELPTEXTW Sets pszName to a Unicode string containing the Help text for the command.
260 // GCS_VALIDATEA Returns S_OK if the menu item exists, or S_FALSE otherwise.
261 // GCS_VALIDATEW Returns S_OK if the menu item exists, or S_FALSE otherwise.
262 // GCS_VERBA Sets pszName to an ANSI string containing the language-independent command name for the menu item.
263 // GCS_VERBW Sets pszName to a Unicode string containing the language-independent command name for the menu item.
264 // pwReserved - Reserved. Applications must specify NULL when calling this method, and handlers must ignore this parameter when called.
265 // pszName - Address of the buffer to receive the null-terminated string being retrieved.
266 // cchMax - Size of the buffer to receive the null-terminated string.
267 //
268
269 STDMETHODIMP CVfdShExt::GetCommandString(
270 UINT idCmd,
271 UINT uFlags,
272 UINT *reserved,
273 LPSTR pszName,
274 UINT cchMax)
275 {
276 VFDTRACE(0,
277 ("CVfdShExt::GetCommandString(%u,...)\n", idCmd));
278
279 UNREFERENCED_PARAMETER(reserved);
280
281 if (idCmd >= sizeof(g_VfdMenu) / sizeof(g_VfdMenu[0])) {
282 return S_FALSE;
283 }
284
285 switch (uFlags) {
286 case GCS_HELPTEXTA:
287 FormatMessageA(
288 FORMAT_MESSAGE_FROM_HMODULE |
289 FORMAT_MESSAGE_IGNORE_INSERTS,
290 g_hDllModule, g_VfdMenu[idCmd].helpid,
291 0, pszName, cchMax, NULL);
292
293 VFDTRACE(0, ("HELPTEXTA: %s\n", pszName));
294 break;
295
296 case GCS_HELPTEXTW:
297 FormatMessageW(
298 FORMAT_MESSAGE_FROM_HMODULE |
299 FORMAT_MESSAGE_IGNORE_INSERTS,
300 g_hDllModule, g_VfdMenu[idCmd].helpid,
301 0, (LPWSTR)pszName, cchMax, NULL);
302
303 VFDTRACE(0, ("HELPTEXTW: %ws\n", pszName));
304 break;
305
306 case GCS_VERBA:
307 lstrcpynA(pszName, g_VfdMenu[idCmd].verbA, cchMax);
308 break;
309
310 case GCS_VERBW:
311 lstrcpynW((LPWSTR)pszName, g_VfdMenu[idCmd].verbW, cchMax);
312 break;
313 }
314
315 return NOERROR;
316 }
317
318 //
319 // FUNCTION: CVfdShExt::InvokeCommand(LPCMINVOKECOMMANDINFO)
320 //
321 // PURPOSE: Called by the shell after the user has selected on of the
322 // menu items that was added in QueryContextMenu().
323 //
324 // PARAMETERS:
325 // lpcmi - Pointer to an CMINVOKECOMMANDINFO structure
326 //
327
328 STDMETHODIMP CVfdShExt::InvokeCommand(
329 LPCMINVOKECOMMANDINFO lpcmi)
330 {
331 VFDTRACE(0, ("CVfdShExt::InvokeCommand()\n"));
332
333 BOOL unicode = FALSE;
334 UINT id;
335 DWORD ret;
336 CMINVOKECOMMANDINFOEX *excmi = (CMINVOKECOMMANDINFOEX *)lpcmi;
337
338 if (lpcmi->cbSize >= sizeof(CMINVOKECOMMANDINFOEX) &&
339 (lpcmi->fMask & CMIC_MASK_UNICODE)) {
340
341 unicode = TRUE;
342 }
343
344
345 if (!unicode && HIWORD(lpcmi->lpVerb)) {
346
347 VFDTRACE(0, ("ANSI: %s\n", lpcmi->lpVerb));
348
349 // ANSI verb
350 for (id = 0; id < sizeof(g_VfdMenu) / sizeof(g_VfdMenu[0]); id++) {
351 if (!lstrcmpi(lpcmi->lpVerb, g_VfdMenu[id].verbA)) {
352 break;
353 }
354 }
355 }
356 else if (unicode && HIWORD(excmi->lpVerbW)) {
357
358 VFDTRACE(0, ("UNICODE: %ws\n", excmi->lpVerbW));
359
360 // UNICODE verb
361 for (id = 0; id < sizeof(g_VfdMenu) / sizeof(g_VfdMenu[0]); id++) {
362 if (!lstrcmpiW(excmi->lpVerbW, g_VfdMenu[id].verbW)) {
363 break;
364 }
365 }
366 }
367 else {
368
369 VFDTRACE(0, ("Command: %u\n", LOWORD(lpcmi->lpVerb)));
370
371 // Command ID
372 id = LOWORD(lpcmi->lpVerb);
373 }
374
375 VFDTRACE(0, ("MenuItem: %u\n", id));
376
377 switch (id) {
378 case VFD_CMD_OPEN:
379 ret = DoVfdOpen(lpcmi->hwnd);
380
381 if (ret == ERROR_SUCCESS) {
382 VfdImageTip(lpcmi->hwnd, m_nDevice);
383 }
384 break;
385
386 case VFD_CMD_SAVE:
387 ret = DoVfdSave(lpcmi->hwnd);
388 break;
389
390 case VFD_CMD_CLOSE:
391 ret = DoVfdClose(lpcmi->hwnd);
392 break;
393
394 case VFD_CMD_PROTECT:
395 ret = DoVfdProtect(lpcmi->hwnd);
396
397 if (ret == ERROR_SUCCESS) {
398 VfdImageTip(lpcmi->hwnd, m_nDevice);
399 }
400 else if (ret == ERROR_WRITE_PROTECT) {
401 VfdImageTip(lpcmi->hwnd, m_nDevice);
402 ret = ERROR_SUCCESS;
403 }
404 break;
405
406 case VFD_CMD_DROP:
407 ret = DoVfdDrop(lpcmi->hwnd);
408
409 if (ret == ERROR_SUCCESS) {
410 VfdImageTip(lpcmi->hwnd, m_nDevice);
411 }
412 break;
413
414 case VFD_CMD_PROP:
415 {
416 SHOBJECTPROPERTIES pSHObjectProperties;
417 WCHAR path[4] = L" :\\";
418
419 pSHObjectProperties = (SHOBJECTPROPERTIES)GetProcAddress(
420 LoadLibrary("shell32"), "SHObjectProperties");
421
422 if (!pSHObjectProperties) {
423 pSHObjectProperties = (SHOBJECTPROPERTIES)GetProcAddress(
424 LoadLibrary("shell32"), (LPCSTR)SHOP_EXPORT_ORDINAL);
425 }
426
427 if (pSHObjectProperties) {
428 path[0] = m_sTarget[0];
429
430 pSHObjectProperties(lpcmi->hwnd,
431 SHOP_FILEPATH, path, L"VFD");
432 }
433 }
434 ret = ERROR_SUCCESS;
435 break;
436
437 default:
438 return E_INVALIDARG;
439 }
440
441 if (ret != ERROR_SUCCESS &&
442 ret != ERROR_CANCELLED) {
443
444 MessageBox(lpcmi->hwnd,
445 SystemMessage(ret), VFD_MSGBOX_TITLE, MB_ICONSTOP);
446 }
447
448 return NOERROR;
449 }
450
451 //=====================================
452 // perform VFD menu operation
453 //=====================================
454
455 DWORD CVfdShExt::DoVfdOpen(
456 HWND hParent)
457 {
458 DWORD ret = VfdGuiOpen(hParent, m_nDevice);
459
460 if (ret != ERROR_SUCCESS && ret != ERROR_CANCELLED) {
461 MessageBox(hParent, SystemMessage(ret),
462 VFD_MSGBOX_TITLE, MB_ICONSTOP);
463 }
464
465 return ret;
466 }
467
468 //
469 // Save the VFD image
470 //
471 DWORD CVfdShExt::DoVfdSave(
472 HWND hParent)
473 {
474 return VfdGuiSave(hParent, m_nDevice);
475 }
476
477 //
478 // Close current VFD image
479 //
480 DWORD CVfdShExt::DoVfdClose(
481 HWND hParent)
482 {
483 return VfdGuiClose(hParent, m_nDevice);
484 }
485
486 //
487 // Enable/disable media write protection
488 //
489 DWORD CVfdShExt::DoVfdProtect(
490 HWND hParent)
491 {
492 HANDLE hDevice;
493 DWORD ret;
494
495 UNREFERENCED_PARAMETER(hParent);
496 VFDTRACE(0, ("CVfdShExt::DoVfdProtect()\n"));
497
498 hDevice = VfdOpenDevice(m_nDevice);
499
500 if (hDevice == INVALID_HANDLE_VALUE) {
501 return GetLastError();
502 }
503
504 ret = VfdGetMediaState(hDevice);
505
506 if (ret == ERROR_SUCCESS) {
507 ret = VfdWriteProtect(hDevice, TRUE);
508 }
509 else if (ret == ERROR_WRITE_PROTECT) {
510 ret = VfdWriteProtect(hDevice, FALSE);
511 }
512
513 if (ret == ERROR_SUCCESS) {
514 ret = VfdGetMediaState(hDevice);
515 }
516
517 CloseHandle(hDevice);
518
519 return ret;
520 }
521
522 //
523 // Open dropped file with VFD
524 //
525 DWORD CVfdShExt::DoVfdDrop(
526 HWND hParent)
527 {
528 HANDLE hDevice;
529 DWORD file_attr;
530 ULONG file_size;
531 VFD_FILETYPE file_type;
532
533 VFD_DISKTYPE disk_type;
534 VFD_MEDIA media_type;
535
536 DWORD ret;
537
538 VFDTRACE(0, ("CVfdShExt::DoVfdDropOpen()\n"));
539
540 // check if dropped file is a valid image
541
542 ret = VfdCheckImageFile(
543 m_sTarget, &file_attr, &file_type, &file_size);
544
545 if (ret != ERROR_SUCCESS) {
546 return ret;
547 }
548
549 // check file size
550 media_type = VfdLookupMedia(file_size);
551
552 if (!media_type) {
553 PSTR msg = ModuleMessage(MSG_FILE_TOO_SMALL);
554
555 MessageBox(hParent, msg ? msg : "Bad size",
556 VFD_MSGBOX_TITLE, MB_ICONSTOP);
557
558 if (msg) {
559 LocalFree(msg);
560 }
561
562 return ERROR_CANCELLED;
563 }
564
565 if ((file_type == VFD_FILETYPE_ZIP) ||
566 (file_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_ENCRYPTED))) {
567
568 disk_type = VFD_DISKTYPE_RAM;
569 }
570 else {
571 disk_type = VFD_DISKTYPE_FILE;
572 }
573
574 // close current image (if opened)
575
576 ret = DoVfdClose(hParent);
577
578 if (ret != ERROR_SUCCESS &&
579 ret != ERROR_NOT_READY) {
580 return ret;
581 }
582
583 // open dropped file
584
585 hDevice = VfdOpenDevice(m_nDevice);
586
587 if (hDevice == INVALID_HANDLE_VALUE) {
588 return GetLastError();
589 }
590
591 ret = VfdOpenImage(
592 hDevice, m_sTarget, disk_type, media_type, FALSE);
593
594 CloseHandle(hDevice);
595
596 return ret;
597 }