Make acpi compile with Visual C++
[reactos.git] / dll / win32 / shell32 / shv_def_cmenu.c
1 /*
2 * PROJECT: shell32
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/shell32/shv_item_new.c
5 * PURPOSE: provides default context menu implementation
6 * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org)
7 */
8
9 #include <precomp.h>
10
11 WINE_DEFAULT_DEBUG_CHANNEL(dmenu);
12
13 typedef struct _DynamicShellEntry_
14 {
15 UINT iIdCmdFirst;
16 UINT NumIds;
17 CLSID ClassID;
18 IContextMenu * CMenu;
19 struct _DynamicShellEntry_ * Next;
20 }DynamicShellEntry, *PDynamicShellEntry;
21
22 typedef struct _StaticShellEntry_
23 {
24 LPWSTR szVerb;
25 LPWSTR szClass;
26 struct _StaticShellEntry_ * Next;
27 }StaticShellEntry, *PStaticShellEntry;
28
29
30 typedef struct
31 {
32 const IContextMenu2Vtbl *lpVtbl;
33 LONG ref;
34 DEFCONTEXTMENU dcm;
35 IDataObject * pDataObj;
36 DWORD bGroupPolicyActive;
37 PDynamicShellEntry dhead; /* first dynamic shell extension entry */
38 UINT iIdSHEFirst; /* first used id */
39 UINT iIdSHELast; /* last used id */
40 PStaticShellEntry shead; /* first static shell extension entry */
41 UINT iIdSCMFirst; /* first static used id */
42 UINT iIdSCMLast; /* last static used id */
43 }IDefaultContextMenuImpl, *LPIDefaultContextMenuImpl;
44
45 static LPIDefaultContextMenuImpl __inline impl_from_IContextMenu( IContextMenu2 *iface )
46 {
47 return (LPIDefaultContextMenuImpl)((char*)iface - FIELD_OFFSET(IDefaultContextMenuImpl, lpVtbl));
48 }
49
50 VOID INewItem_SetCurrentShellFolder(IShellFolder * psfParent); // HACK
51
52
53 static
54 HRESULT
55 WINAPI
56 IDefaultContextMenu_fnQueryInterface(
57 IContextMenu2 *iface,
58 REFIID riid,
59 LPVOID *ppvObj)
60 {
61 IDefaultContextMenuImpl *This = (IDefaultContextMenuImpl *)iface;
62
63 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
64
65 *ppvObj = NULL;
66
67 if(IsEqualIID(riid, &IID_IUnknown) ||
68 IsEqualIID(riid, &IID_IContextMenu) ||
69 IsEqualIID(riid, &IID_IContextMenu2))
70 {
71 *ppvObj = This;
72 }
73
74 if(*ppvObj)
75 {
76 IUnknown_AddRef((IUnknown*)*ppvObj);
77 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
78 return S_OK;
79 }
80 TRACE("-- Interface: E_NOINTERFACE\n");
81 return E_NOINTERFACE;
82 }
83
84
85 static
86 ULONG
87 WINAPI
88 IDefaultContextMenu_fnAddRef(
89 IContextMenu2 *iface)
90 {
91 IDefaultContextMenuImpl *This = (IDefaultContextMenuImpl *)iface;
92 ULONG refCount = InterlockedIncrement(&This->ref);
93
94 TRACE("(%p)->(count=%u)\n", This, refCount - 1);
95
96 return refCount;
97 }
98
99 static
100 ULONG
101 WINAPI
102 IDefaultContextMenu_fnRelease(
103 IContextMenu2 *iface)
104 {
105 PDynamicShellEntry dEntry, dNext;
106 PStaticShellEntry sEntry, sNext;
107 IDefaultContextMenuImpl *This = (IDefaultContextMenuImpl *)iface;
108 ULONG refCount = InterlockedDecrement(&This->ref);
109
110 TRACE("(%p)->(count=%u)\n", This, refCount + 1);
111 if (!refCount)
112 {
113 /* free dynamic shell extension entries */
114 dEntry = This->dhead;
115 while(dEntry)
116 {
117 dNext = dEntry->Next;
118 IContextMenu_Release(dEntry->CMenu);
119 HeapFree(GetProcessHeap(), 0, dEntry);
120 dEntry = dNext;
121 }
122 /* free static shell extension entries */
123 sEntry = This->shead;
124 while(sEntry)
125 {
126 sNext = sEntry->Next;
127 HeapFree(GetProcessHeap(), 0, sEntry->szClass);
128 HeapFree(GetProcessHeap(), 0, sEntry->szVerb);
129 HeapFree(GetProcessHeap(), 0, sEntry);
130 sEntry = sNext;
131 }
132 HeapFree(GetProcessHeap(),0,This);
133 }
134
135 return refCount;
136 }
137
138 static
139 void
140 SH_AddStaticEntry(IDefaultContextMenuImpl * This, WCHAR *szVerb, WCHAR * szClass)
141 {
142 PStaticShellEntry curEntry;
143 PStaticShellEntry lastEntry = NULL;
144
145 curEntry = This->shead;
146 while(curEntry)
147 {
148 if (!wcsicmp(curEntry->szVerb, szVerb))
149 {
150 /* entry already exists */
151 return;
152 }
153 lastEntry = curEntry;
154 curEntry = curEntry->Next;
155 }
156
157 TRACE("adding verb %s szClass %s\n", debugstr_w(szVerb), debugstr_w(szClass));
158
159 curEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry));
160 if (curEntry)
161 {
162 curEntry->Next = NULL;
163 curEntry->szVerb = HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb)+1) * sizeof(WCHAR));
164 if (curEntry->szVerb)
165 wcscpy(curEntry->szVerb, szVerb);
166 curEntry->szClass = HeapAlloc(GetProcessHeap(), 0, (wcslen(szClass)+1) * sizeof(WCHAR));
167 if (curEntry->szClass)
168 wcscpy(curEntry->szClass, szClass);
169 }
170
171 if (lastEntry)
172 {
173 lastEntry->Next = curEntry;
174 }
175 else
176 {
177 This->shead = curEntry;
178 }
179 }
180
181 static
182 void
183 SH_AddStaticEntryForKey(IDefaultContextMenuImpl * This, HKEY hKey, WCHAR * szClass)
184 {
185 LONG result;
186 DWORD dwIndex;
187 WCHAR szName[40];
188 DWORD dwName;
189
190 dwIndex = 0;
191 do
192 {
193 szName[0] = 0;
194 dwName = sizeof(szName) / sizeof(WCHAR);
195 result = RegEnumKeyExW(hKey, dwIndex, szName, &dwName, NULL, NULL, NULL, NULL);
196 szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0;
197 if (result == ERROR_SUCCESS)
198 {
199 SH_AddStaticEntry(This, szName, szClass);
200 }
201 dwIndex++;
202 }while(result == ERROR_SUCCESS);
203 }
204
205 static
206 void
207 SH_AddStaticEntryForFileClass(IDefaultContextMenuImpl * This, WCHAR * szExt)
208 {
209 WCHAR szBuffer[100];
210 HKEY hKey;
211 LONG result;
212 DWORD dwBuffer;
213 UINT Length;
214 static WCHAR szShell[] = L"\\shell";
215 static WCHAR szShellAssoc[] = L"SystemFileAssociations\\";
216
217 TRACE("SH_AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt));
218
219 Length = wcslen(szExt);
220 if (Length + (sizeof(szShell)/sizeof(WCHAR)) + 1 < sizeof(szBuffer)/sizeof(WCHAR))
221 {
222 wcscpy(szBuffer, szExt);
223 wcscpy(&szBuffer[Length], szShell);
224 result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
225 if (result == ERROR_SUCCESS)
226 {
227 szBuffer[Length] = 0;
228 SH_AddStaticEntryForKey(This, hKey, szExt);
229 RegCloseKey(hKey);
230 }
231 }
232
233 dwBuffer = sizeof(szBuffer);
234 result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, NULL, RRF_RT_REG_SZ, NULL, (LPBYTE)szBuffer, &dwBuffer);
235 if (result == ERROR_SUCCESS)
236 {
237 Length = wcslen(szBuffer);
238 if (Length + (sizeof(szShell)/sizeof(WCHAR)) + 1 < sizeof(szBuffer)/sizeof(WCHAR))
239 {
240 wcscpy(&szBuffer[Length], szShell);
241 TRACE("szBuffer %s\n", debugstr_w(szBuffer));
242
243 result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
244 if (result == ERROR_SUCCESS)
245 {
246 szBuffer[Length] = 0;
247 SH_AddStaticEntryForKey(This, hKey, szBuffer);
248 RegCloseKey(hKey);
249 }
250 }
251 }
252
253 wcscpy(szBuffer, szShellAssoc);
254 dwBuffer = sizeof(szBuffer) - sizeof(szShellAssoc) - sizeof(WCHAR);
255 result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, L"PerceivedType", RRF_RT_REG_SZ, NULL, (LPBYTE)&szBuffer[(sizeof(szShellAssoc)/sizeof(WCHAR))], &dwBuffer);
256 if (result == ERROR_SUCCESS)
257 {
258 Length = wcslen(&szBuffer[(sizeof(szShellAssoc)/sizeof(WCHAR))]) + (sizeof(szShellAssoc)/sizeof(WCHAR));
259 wcscat(&szBuffer[(sizeof(szShellAssoc)/sizeof(WCHAR))], szShell);
260 TRACE("szBuffer %s\n", debugstr_w(szBuffer));
261
262 result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
263 if (result == ERROR_SUCCESS)
264 {
265 szBuffer[Length] = 0;
266 SH_AddStaticEntryForKey(This, hKey, szBuffer);
267 RegCloseKey(hKey);
268 }
269 }
270 RegCloseKey(hKey);
271 }
272
273 static
274 BOOL
275 HasClipboardData()
276 {
277 BOOL ret = FALSE;
278 IDataObject * pda;
279
280 if(SUCCEEDED(OleGetClipboard(&pda)))
281 {
282 STGMEDIUM medium;
283 FORMATETC formatetc;
284
285 TRACE("pda=%p\n", pda);
286
287 /* Set the FORMATETC structure*/
288 InitFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
289 if(SUCCEEDED(IDataObject_GetData(pda,&formatetc,&medium)))
290 {
291 ret = TRUE;
292 }
293
294 IDataObject_Release(pda);
295 ReleaseStgMedium(&medium);
296 }
297
298 return ret;
299 }
300
301 VOID
302 DisablePasteOptions(HMENU hMenu)
303 {
304 MENUITEMINFOW mii;
305
306 mii.cbSize = sizeof(mii);
307 mii.fMask = MIIM_STATE;
308 mii.fState = MFS_DISABLED;
309
310 TRACE("result %d\n", SetMenuItemInfoW(hMenu, FCIDM_SHVIEW_INSERT, FALSE, &mii));
311 TRACE("result %d\n", SetMenuItemInfoW(hMenu, FCIDM_SHVIEW_INSERTLINK, FALSE, &mii));
312 }
313
314 BOOL
315 IsShellExtensionAlreadyLoaded(IDefaultContextMenuImpl * This, const CLSID * szClass)
316 {
317 PDynamicShellEntry curEntry = This->dhead;
318
319 while(curEntry)
320 {
321 if (!memcmp(&curEntry->ClassID, szClass, sizeof(CLSID)))
322 return TRUE;
323 curEntry = curEntry->Next;
324 }
325 return FALSE;
326 }
327
328
329 static
330 HRESULT
331 SH_LoadDynamicContextMenuHandler(IDefaultContextMenuImpl * This, HKEY hKey, const CLSID * szClass, BOOL bExternalInit)
332 {
333 HRESULT hr;
334 IContextMenu * cmobj;
335 IShellExtInit *shext;
336 PDynamicShellEntry curEntry;
337 //WCHAR szTemp[100];
338 LPOLESTR pstr;
339
340 StringFromCLSID(szClass, &pstr);
341
342 TRACE("SH_LoadDynamicContextMenuHandler entered with This %p hKey %p szClass %s bExternalInit %u\n",This, hKey, wine_dbgstr_guid(szClass), bExternalInit);
343 //swprintf(szTemp, L"This %p hKey %p szClass %s bExternalInit %u", This, hKey, pstr, bExternalInit);
344 //MessageBoxW(NULL, szTemp, NULL, MB_OK);
345
346 if (IsShellExtensionAlreadyLoaded(This, szClass))
347 return S_OK;
348
349 hr = SHCoCreateInstance(NULL, szClass, NULL, &IID_IContextMenu, (void**)&cmobj);
350 if (hr != S_OK)
351 {
352 TRACE("SHCoCreateInstance failed %x\n", GetLastError());
353 return hr;
354 }
355
356 if (bExternalInit)
357 {
358 hr = IContextMenu_QueryInterface(cmobj, &IID_IShellExtInit, (void**)&shext);
359 if (hr != S_OK)
360 {
361 TRACE("Failed to query for interface IID_IShellExtInit\n");
362 IContextMenu_Release(cmobj);
363 return FALSE;
364 }
365 hr = IShellExtInit_Initialize(shext, NULL, This->pDataObj, hKey);
366 IShellExtInit_Release(shext);
367 if (hr != S_OK)
368 {
369 TRACE("Failed to initialize shell extension error %x\n", hr);
370 IContextMenu_Release(cmobj);
371 return hr;
372 }
373 }
374
375 curEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry));
376 if(!curEntry)
377 {
378 IContextMenu_Release(cmobj);
379 return E_OUTOFMEMORY;
380 }
381
382 curEntry->iIdCmdFirst = 0;
383 curEntry->Next = NULL;
384 curEntry->NumIds = 0;
385 curEntry->CMenu = cmobj;
386 memcpy(&curEntry->ClassID, szClass, sizeof(CLSID));
387
388 if (This->dhead)
389 {
390 PDynamicShellEntry pEntry = This->dhead;
391
392 while(pEntry->Next)
393 {
394 pEntry = pEntry->Next;
395 }
396
397 pEntry->Next = curEntry;
398 }
399 else
400 {
401 This->dhead = curEntry;
402 }
403
404
405 if (!memcmp(szClass, &CLSID_NewMenu, sizeof(CLSID)))
406 {
407 /* A REAL UGLY HACK */
408 INewItem_SetCurrentShellFolder(This->dcm.psf);
409 }
410
411
412 return hr;
413 }
414
415 static
416 UINT
417 EnumerateDynamicContextHandlerForKey(IDefaultContextMenuImpl *This, HKEY hRootKey)
418 {
419 WCHAR szKey[MAX_PATH] = {0};
420 WCHAR szName[MAX_PATH] = {0};
421 DWORD dwIndex, dwName;
422 LONG res;
423 HRESULT hResult;
424 UINT index;
425 CLSID clsid;
426 HKEY hKey;
427
428 static const WCHAR szShellEx[] = { 's','h','e','l','l','e','x','\\','C','o','n','t','e','x','t','M','e','n','u','H','a','n','d','l','e','r','s',0 };
429
430 if (RegOpenKeyExW(hRootKey, szShellEx, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
431 {
432 TRACE("RegOpenKeyExW failed for key %s\n", debugstr_w(szKey));
433 return 0;
434 }
435
436 dwIndex = 0;
437 index = 0;
438 do
439 {
440 dwName = MAX_PATH;
441 res = RegEnumKeyExW(hKey, dwIndex, szName, &dwName, NULL, NULL, NULL, NULL);
442 if (res == ERROR_SUCCESS)
443 {
444 hResult = CLSIDFromString(szName, &clsid);
445 if (hResult != S_OK)
446 {
447 dwName = MAX_PATH;
448 if (RegGetValueW(hKey, szName, NULL, RRF_RT_REG_SZ, NULL, szKey, &dwName) == ERROR_SUCCESS)
449 {
450 hResult = CLSIDFromString(szKey, &clsid);
451 }
452 }
453 if (SUCCEEDED(hResult))
454 {
455 if (This->bGroupPolicyActive)
456 {
457 if (RegGetValueW(HKEY_LOCAL_MACHINE,
458 L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
459 szKey,
460 RRF_RT_REG_SZ,
461 NULL,
462 NULL,
463 &dwName) == ERROR_SUCCESS)
464 {
465 SH_LoadDynamicContextMenuHandler(This, hKey, &clsid, TRUE);
466 }
467 }
468 else
469 {
470 SH_LoadDynamicContextMenuHandler(This, hKey, &clsid, TRUE);
471 }
472 }
473 }
474 dwIndex++;
475 }while(res == ERROR_SUCCESS);
476
477 RegCloseKey(hKey);
478 return index;
479 }
480
481
482 static
483 UINT
484 InsertMenuItemsOfDynamicContextMenuExtension(IDefaultContextMenuImpl * This, HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast)
485 {
486 PDynamicShellEntry curEntry;
487 HRESULT hResult;
488
489 if (!This->dhead)
490 {
491 This->iIdSHEFirst = 0;
492 This->iIdSHELast = 0;
493 return indexMenu;
494 }
495
496 curEntry = This->dhead;
497 idCmdFirst = 0x5000;
498 idCmdLast = 0x6000;
499 This->iIdSHEFirst = idCmdFirst;
500 do
501 {
502 hResult = IContextMenu_QueryContextMenu(curEntry->CMenu, hMenu, indexMenu++, idCmdFirst, idCmdLast, CMF_NORMAL);
503 if (SUCCEEDED(hResult))
504 {
505 curEntry->iIdCmdFirst = idCmdFirst;
506 curEntry->NumIds = LOWORD(hResult);
507 indexMenu += curEntry->NumIds;
508 idCmdFirst += curEntry->NumIds + 0x10;
509 }
510 TRACE("curEntry %p hresult %x contextmenu %p cmdfirst %x num ids %x\n", curEntry, hResult, curEntry->CMenu, curEntry->iIdCmdFirst, curEntry->NumIds);
511 curEntry = curEntry->Next;
512 }while(curEntry);
513
514 This->iIdSHELast = idCmdFirst;
515 TRACE("SH_LoadContextMenuHandlers first %x last %x\n", This->iIdSHEFirst, This->iIdSHELast);
516 return indexMenu;
517 }
518
519 UINT
520 BuildBackgroundContextMenu(
521 IDefaultContextMenuImpl * This,
522 HMENU hMenu,
523 UINT iIdCmdFirst,
524 UINT iIdCmdLast,
525 UINT uFlags)
526 {
527 MENUITEMINFOW mii;
528 WCHAR szBuffer[MAX_PATH];
529 UINT indexMenu = 0;
530 HMENU hSubMenu;
531 HKEY hKey;
532
533 ZeroMemory(&mii, sizeof(mii));
534
535 TRACE("BuildBackgroundContextMenu entered\n");
536
537 if (!_ILIsDesktop(This->dcm.pidlFolder))
538 {
539 /* view option is only available in browsing mode */
540 hSubMenu = LoadMenuA(shell32_hInstance, "MENU_001");
541 if (hSubMenu)
542 {
543 szBuffer[0] = 0;
544 LoadStringW(shell32_hInstance, FCIDM_SHVIEW_VIEW, szBuffer, MAX_PATH);
545 szBuffer[MAX_PATH-1] = 0;
546
547 TRACE("szBuffer %s\n", debugstr_w(szBuffer));
548
549 mii.cbSize = sizeof(mii);
550 mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU | MIIM_ID;
551 mii.fType = MFT_STRING;
552 mii.wID = iIdCmdFirst++;
553 mii.dwTypeData = szBuffer;
554 mii.cch = wcslen( mii.dwTypeData );
555 mii.fState = MFS_ENABLED;
556 mii.hSubMenu = hSubMenu;
557 InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii);
558 DestroyMenu(hSubMenu);
559 }
560 }
561 hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_002");
562 if (hSubMenu)
563 {
564 /* merge general background context menu in */
565 iIdCmdFirst = Shell_MergeMenus(hMenu, GetSubMenu(hSubMenu, 0), indexMenu, 0, 0xFFFF, MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS) + 1;
566 DestroyMenu(hSubMenu);
567 }
568
569 if (!HasClipboardData())
570 {
571 TRACE("disabling paste options\n");
572 DisablePasteOptions(hMenu);
573 }
574 /* load extensions from HKCR\* key */
575 if (RegOpenKeyExW(HKEY_CLASSES_ROOT,
576 L"*",
577 0,
578 KEY_READ,
579 &hKey) == ERROR_SUCCESS)
580 {
581 EnumerateDynamicContextHandlerForKey(This, hKey);
582 RegCloseKey(hKey);
583 }
584
585 /* load create new shell extension */
586 if (RegOpenKeyExW(HKEY_CLASSES_ROOT,
587 L"CLSID\\{D969A300-E7FF-11d0-A93B-00A0C90F2719}",
588 0,
589 KEY_READ,
590 &hKey) == ERROR_SUCCESS)
591 {
592 SH_LoadDynamicContextMenuHandler(This, hKey, &CLSID_NewMenu, TRUE);
593 RegCloseKey(hKey);
594 }
595
596 if (InsertMenuItemsOfDynamicContextMenuExtension(This, hMenu, GetMenuItemCount(hMenu)-1, iIdCmdFirst, iIdCmdLast))
597 {
598 /* seperate dynamic context menu items */
599 _InsertMenuItemW(hMenu, GetMenuItemCount(hMenu)-1, TRUE, -1, MFT_SEPARATOR, NULL, MFS_ENABLED);
600 }
601
602 return iIdCmdLast;
603 }
604
605 static
606 UINT
607 AddStaticContextMenusToMenu(
608 HMENU hMenu,
609 UINT indexMenu,
610 IDefaultContextMenuImpl * This)
611 {
612 MENUITEMINFOW mii;
613 UINT idResource;
614 PStaticShellEntry curEntry;
615 WCHAR szVerb[40];
616 WCHAR szTemp[50];
617 DWORD dwSize;
618 UINT fState;
619 UINT Length;
620
621 mii.cbSize = sizeof(mii);
622 mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
623 mii.fType = MFT_STRING;
624 mii.fState = MFS_ENABLED | MFS_DEFAULT;
625 mii.wID = 0x4000;
626 This->iIdSCMFirst = mii.wID;
627
628 curEntry = This->shead;
629
630 while(curEntry)
631 {
632 fState = MFS_ENABLED;
633 if (!wcsicmp(curEntry->szVerb, L"open"))
634 {
635 fState |= MFS_DEFAULT;
636 idResource = IDS_OPEN_VERB;
637 }
638 else if (!wcsicmp(curEntry->szVerb, L"runas"))
639 idResource = IDS_RUNAS_VERB;
640 else if (!wcsicmp(curEntry->szVerb, L"edit"))
641 idResource = IDS_EDIT_VERB;
642 else if (!wcsicmp(curEntry->szVerb, L"find"))
643 idResource = IDS_FIND_VERB;
644 else if (!wcsicmp(curEntry->szVerb, L"print"))
645 idResource = IDS_PRINT_VERB;
646 else if (!wcsicmp(curEntry->szVerb, L"play"))
647 idResource = IDS_PLAY_VERB;
648 else if (!wcsicmp(curEntry->szVerb, L"preview"))
649 idResource = IDS_PREVIEW_VERB;
650 else
651 idResource = 0;
652
653 if (idResource > 0)
654 {
655 if (LoadStringW(shell32_hInstance, idResource, szVerb, sizeof(szVerb)/sizeof(WCHAR)))
656 {
657 /* use translated verb */
658 szVerb[(sizeof(szVerb)/sizeof(WCHAR))-1] = L'\0';
659 mii.dwTypeData = szVerb;
660 }
661 }
662 else
663 {
664 Length = wcslen(curEntry->szClass) + wcslen(curEntry->szVerb) + 8;
665 if (Length < sizeof(szTemp)/sizeof(WCHAR))
666 {
667 wcscpy(szTemp, curEntry->szClass);
668 wcscat(szTemp, L"\\shell\\");
669 wcscat(szTemp, curEntry->szVerb);
670 dwSize = sizeof(szVerb);
671
672 if (RegGetValueW(HKEY_CLASSES_ROOT, szTemp, NULL, RRF_RT_REG_SZ, NULL, szVerb, &dwSize) == ERROR_SUCCESS)
673 {
674 /* use description for the menu entry */
675 mii.dwTypeData = szVerb;
676 }
677 else
678 {
679 /* use verb for the menu entry */
680 mii.dwTypeData = curEntry->szVerb;
681 }
682 }
683
684 }
685
686 mii.cch = wcslen(mii.dwTypeData);
687 InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii);
688 mii.fState = fState;
689 mii.wID++;
690 curEntry = curEntry->Next;
691 }
692 This->iIdSCMLast = mii.wID - 1;
693 return indexMenu;
694 }
695
696 void WINAPI _InsertMenuItemW (
697 HMENU hmenu,
698 UINT indexMenu,
699 BOOL fByPosition,
700 UINT wID,
701 UINT fType,
702 LPCWSTR dwTypeData,
703 UINT fState)
704 {
705 MENUITEMINFOW mii;
706 WCHAR szText[100];
707
708 ZeroMemory(&mii, sizeof(mii));
709 mii.cbSize = sizeof(mii);
710 if (fType == MFT_SEPARATOR)
711 {
712 mii.fMask = MIIM_ID | MIIM_TYPE;
713 }
714 else if (fType == MFT_STRING)
715 {
716 mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
717 if ((ULONG_PTR)HIWORD((ULONG_PTR)dwTypeData) == 0)
718 {
719 if (LoadStringW(shell32_hInstance, LOWORD((ULONG_PTR)dwTypeData), szText, sizeof(szText)/sizeof(WCHAR)))
720 {
721 szText[(sizeof(szText)/sizeof(WCHAR))-1] = 0;
722 mii.dwTypeData = szText;
723 }
724 else
725 {
726 TRACE("failed to load string %p\n", dwTypeData);
727 return;
728 }
729 }
730 else
731 {
732 mii.dwTypeData = (LPWSTR) dwTypeData;
733 }
734 mii.fState = fState;
735 }
736
737 mii.wID = wID;
738 mii.fType = fType;
739 InsertMenuItemW( hmenu, indexMenu, fByPosition, &mii);
740 }
741
742 UINT
743 BuildShellItemContextMenu(
744 IDefaultContextMenuImpl * This,
745 HMENU hMenu,
746 UINT iIdCmdFirst,
747 UINT iIdCmdLast,
748 UINT uFlags)
749 {
750 WCHAR szPath[MAX_PATH];
751 WCHAR szTemp[40];
752 HKEY hKey;
753 UINT indexMenu;
754 SFGAOF rfg;
755 HRESULT hr;
756 BOOL bAddSep;
757 GUID * guid;
758 BOOL bClipboardData;
759 STRRET strFile;
760 LPWSTR pOffset;
761 DWORD dwSize;
762
763 TRACE("BuildShellItemContextMenu entered\n");
764
765 if (IShellFolder2_GetDisplayNameOf(This->dcm.psf, This->dcm.apidl[0], SHGDN_FORPARSING, &strFile) == S_OK)
766 {
767 if (StrRetToBufW(&strFile, This->dcm.apidl[0], szPath, MAX_PATH) == S_OK)
768 {
769 pOffset = wcsrchr(szPath, L'.');
770 if (pOffset)
771 {
772 /* enumerate dynamic/static for a given file class */
773 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pOffset, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
774 {
775 /* add static verbs */
776 SH_AddStaticEntryForFileClass(This, pOffset);
777 /* load dynamic extensions from file extension key */
778 EnumerateDynamicContextHandlerForKey(This, hKey);
779 RegCloseKey(hKey);
780 }
781 dwSize = sizeof(szTemp);
782 if (RegGetValueW(HKEY_CLASSES_ROOT, pOffset, NULL, RRF_RT_REG_SZ, NULL, szTemp, &dwSize) == ERROR_SUCCESS)
783 {
784 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szTemp, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
785 {
786 /* add static verbs from progid key */
787 SH_AddStaticEntryForFileClass(This, szTemp);
788 /* load dynamic extensions from progid key */
789 EnumerateDynamicContextHandlerForKey(This, hKey);
790 RegCloseKey(hKey);
791 }
792 }
793 }
794 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"*", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
795 {
796 /* load default extensions */
797 EnumerateDynamicContextHandlerForKey(This, hKey);
798 RegCloseKey(hKey);
799 }
800 }
801 }
802
803 guid = _ILGetGUIDPointer(This->dcm.apidl[0]);
804 if (guid)
805 {
806 LPOLESTR pwszCLSID;
807 WCHAR buffer[60];
808
809 wcscpy(buffer, L"CLSID\\");
810 hr = StringFromCLSID(guid, &pwszCLSID);
811 if (hr == S_OK)
812 {
813 wcscpy(&buffer[6], pwszCLSID);
814 TRACE("buffer %s\n", debugstr_w(buffer));
815 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
816 {
817 EnumerateDynamicContextHandlerForKey(This, hKey);
818 SH_AddStaticEntryForFileClass(This, buffer);
819 RegCloseKey(hKey);
820 }
821 CoTaskMemFree(pwszCLSID);
822 }
823 }
824
825
826 if (_ILIsDrive(This->dcm.apidl[0]))
827 {
828 SH_AddStaticEntryForFileClass(This, L"Drive");
829 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Drive", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
830 {
831 EnumerateDynamicContextHandlerForKey(This, hKey);
832 RegCloseKey(hKey);
833 }
834
835 }
836
837 /* add static actions */
838 rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
839 hr = IShellFolder_GetAttributesOf(This->dcm.psf, This->dcm.cidl, This->dcm.apidl, &rfg);
840 if (!SUCCEEDED(hr))
841 rfg = 0;
842
843 if (rfg & SFGAO_FOLDER)
844 {
845 /* add the default verbs open / explore */
846 SH_AddStaticEntryForFileClass(This, L"Folder");
847 SH_AddStaticEntryForFileClass(This, L"Directory");
848 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Folder", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
849 {
850 EnumerateDynamicContextHandlerForKey(This, hKey);
851 RegCloseKey(hKey);
852 }
853 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
854 {
855 EnumerateDynamicContextHandlerForKey(This, hKey);
856 RegCloseKey(hKey);
857 }
858 }
859
860
861 if (rfg & SFGAO_FILESYSTEM)
862 {
863 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"AllFilesystemObjects", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
864 {
865 /* sendto service is registered here */
866 EnumerateDynamicContextHandlerForKey(This, hKey);
867 RegCloseKey(hKey);
868 }
869 }
870
871 /* add static context menu handlers */
872 indexMenu = AddStaticContextMenusToMenu(hMenu, 0, This);
873 /* now process dynamic context menu handlers */
874 indexMenu = InsertMenuItemsOfDynamicContextMenuExtension(This, hMenu, indexMenu, iIdCmdFirst, iIdCmdLast);
875 TRACE("indexMenu %d\n", indexMenu);
876
877 if (_ILIsDrive(This->dcm.apidl[0]))
878 {
879 /* The 'Format' option must be always available,
880 * thus it is not registered as a static shell extension
881 */
882 _InsertMenuItemW(hMenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
883 _InsertMenuItemW(hMenu, indexMenu++, TRUE, 0x7ABC, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED);
884 bAddSep = TRUE;
885 }
886
887 bClipboardData = (HasClipboardData() && (rfg & SFGAO_FILESYSTEM));
888 if (rfg & (SFGAO_CANCOPY | SFGAO_CANMOVE) || bClipboardData)
889 {
890 _InsertMenuItemW(hMenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
891 if (rfg & SFGAO_CANMOVE)
892 _InsertMenuItemW(hMenu, indexMenu++, TRUE, FCIDM_SHVIEW_CUT, MFT_STRING, MAKEINTRESOURCEW(IDS_CUT), MFS_ENABLED);
893 if (rfg & SFGAO_CANCOPY)
894 _InsertMenuItemW(hMenu, indexMenu++, TRUE, FCIDM_SHVIEW_COPY, MFT_STRING, MAKEINTRESOURCEW(IDS_COPY), MFS_ENABLED);
895 if (bClipboardData)
896 _InsertMenuItemW(hMenu, indexMenu++, TRUE, FCIDM_SHVIEW_INSERT, MFT_STRING, MAKEINTRESOURCEW(IDS_INSERT), MFS_ENABLED);
897
898 bAddSep = TRUE;
899 }
900
901
902 if (rfg & SFGAO_CANLINK)
903 {
904 bAddSep = FALSE;
905 _InsertMenuItemW(hMenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
906 _InsertMenuItemW(hMenu, indexMenu++, TRUE, FCIDM_SHVIEW_CREATELINK, MFT_STRING, MAKEINTRESOURCEW(IDS_CREATELINK), MFS_ENABLED);
907 }
908
909
910 if (rfg & SFGAO_CANDELETE)
911 {
912 if (bAddSep)
913 {
914 bAddSep = FALSE;
915 _InsertMenuItemW(hMenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
916 }
917 _InsertMenuItemW(hMenu, indexMenu++, TRUE, FCIDM_SHVIEW_DELETE, MFT_STRING, MAKEINTRESOURCEW(IDS_DELETE), MFS_ENABLED);
918 }
919
920 if (rfg & SFGAO_CANRENAME)
921 {
922 if (bAddSep)
923 {
924 _InsertMenuItemW(hMenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
925 }
926 _InsertMenuItemW(hMenu, indexMenu++, TRUE, FCIDM_SHVIEW_RENAME, MFT_STRING, MAKEINTRESOURCEW(IDS_RENAME), MFS_ENABLED);
927 bAddSep = TRUE;
928 }
929
930 if (rfg & SFGAO_HASPROPSHEET)
931 {
932 _InsertMenuItemW(hMenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
933 _InsertMenuItemW(hMenu, indexMenu++, TRUE, FCIDM_SHVIEW_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
934 }
935
936 return iIdCmdLast;
937 }
938
939 static
940 HRESULT
941 WINAPI
942 IDefaultContextMenu_fnQueryContextMenu(
943 IContextMenu2 *iface,
944 HMENU hmenu,
945 UINT indexMenu,
946 UINT idCmdFirst,
947 UINT idCmdLast,
948 UINT uFlags)
949 {
950 IDefaultContextMenuImpl * This = impl_from_IContextMenu(iface);
951 if (This->dcm.cidl)
952 {
953 idCmdFirst = BuildShellItemContextMenu(This, hmenu, idCmdFirst, idCmdLast, uFlags);
954 }
955 else
956 {
957 idCmdFirst = BuildBackgroundContextMenu(This, hmenu, idCmdFirst, idCmdLast, uFlags);
958 }
959
960 return S_OK;
961 }
962
963 static
964 HRESULT
965 NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi, BOOL bRefresh)
966 {
967 LPSHELLBROWSER lpSB;
968 LPSHELLVIEW lpSV = NULL;
969 HWND hwndSV = NULL;
970
971 if((lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER,0,0)))
972 {
973 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV)))
974 {
975 IShellView_GetWindow(lpSV, &hwndSV);
976 }
977 }
978
979 if (LOWORD(lpcmi->lpVerb) == FCIDM_SHVIEW_REFRESH || bRefresh)
980 {
981 if (lpSV)
982 IShellView_Refresh(lpSV);
983
984 return S_OK;
985 }
986
987 SendMessageW(hwndSV, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0), 0);
988
989 return S_OK;
990 }
991
992 static
993 HRESULT
994 DoPaste(
995 IDefaultContextMenuImpl *This,
996 LPCMINVOKECOMMANDINFO lpcmi)
997 {
998 IDataObject * pda;
999 STGMEDIUM medium;
1000 FORMATETC formatetc;
1001 LPITEMIDLIST * apidl;
1002 LPITEMIDLIST pidl;
1003 IShellFolder *psfFrom = NULL, *psfDesktop, *psfTarget = NULL;
1004 LPIDA lpcida;
1005 ISFHelper *psfhlpdst, *psfhlpsrc;
1006 HRESULT hr;
1007
1008 if (OleGetClipboard(&pda) != S_OK)
1009 return E_FAIL;
1010
1011 InitFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
1012 hr = IDataObject_GetData(pda,&formatetc,&medium);
1013
1014 if (FAILED(hr))
1015 {
1016 IDataObject_Release(pda);
1017 return E_FAIL;
1018 }
1019
1020 /* lock the handle */
1021 lpcida = GlobalLock(medium.u.hGlobal);
1022 if (!lpcida)
1023 {
1024 ReleaseStgMedium(&medium);
1025 IDataObject_Release(pda);
1026 return E_FAIL;
1027 }
1028
1029 /* convert the data into pidl */
1030 apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
1031
1032 if (!apidl)
1033 return E_FAIL;
1034
1035 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
1036 {
1037 SHFree(pidl);
1038 _ILFreeaPidl(apidl, lpcida->cidl);
1039 ReleaseStgMedium(&medium);
1040 IDataObject_Release(pda);
1041 return E_FAIL;
1042 }
1043
1044 if (FAILED(IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (LPVOID*)&psfFrom)))
1045 {
1046 ERR("no IShellFolder\n");
1047
1048 IShellFolder_Release(psfDesktop);
1049 SHFree(pidl);
1050 _ILFreeaPidl(apidl, lpcida->cidl);
1051 ReleaseStgMedium(&medium);
1052 IDataObject_Release(pda);
1053
1054 return E_FAIL;
1055 }
1056
1057 IShellFolder_Release(psfDesktop);
1058
1059 if (FAILED(IShellFolder_BindToObject(This->dcm.psf, This->dcm.apidl[0], NULL, &IID_IShellFolder, (LPVOID*)&psfTarget)))
1060 {
1061 ERR("no IShellFolder\n");
1062
1063 IShellFolder_Release(psfFrom);
1064 SHFree(pidl);
1065 _ILFreeaPidl(apidl, lpcida->cidl);
1066 ReleaseStgMedium(&medium);
1067 IDataObject_Release(pda);
1068
1069 return E_FAIL;
1070 }
1071
1072
1073 /* get source and destination shellfolder */
1074 if (FAILED(IShellFolder_QueryInterface(psfTarget, &IID_ISFHelper, (LPVOID*)&psfhlpdst)))
1075 {
1076 ERR("no IID_ISFHelper for destination\n");
1077
1078 IShellFolder_Release(psfFrom);
1079 IShellFolder_Release(psfTarget);
1080 SHFree(pidl);
1081 _ILFreeaPidl(apidl, lpcida->cidl);
1082 ReleaseStgMedium(&medium);
1083 IDataObject_Release(pda);
1084
1085 return E_FAIL;
1086 }
1087
1088 if (FAILED(IShellFolder_QueryInterface(psfFrom, &IID_ISFHelper, (LPVOID*)&psfhlpsrc)))
1089 {
1090 ERR("no IID_ISFHelper for source\n");
1091
1092 ISFHelper_Release(psfhlpdst);
1093 IShellFolder_Release(psfFrom);
1094 IShellFolder_Release(psfTarget);
1095 SHFree(pidl);
1096 _ILFreeaPidl(apidl, lpcida->cidl);
1097 ReleaseStgMedium(&medium);
1098 IDataObject_Release(pda);
1099 return E_FAIL;
1100 }
1101
1102 /* FIXXME
1103 * do we want to perform a copy or move ???
1104 */
1105 hr = ISFHelper_CopyItems(psfhlpdst, psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl);
1106
1107 ISFHelper_Release(psfhlpdst);
1108 ISFHelper_Release(psfhlpsrc);
1109 IShellFolder_Release(psfFrom);
1110 IShellFolder_Release(psfTarget);
1111 SHFree(pidl);
1112 _ILFreeaPidl(apidl, lpcida->cidl);
1113 ReleaseStgMedium(&medium);
1114 IDataObject_Release(pda);
1115 return S_OK;
1116 }
1117
1118 static
1119 HRESULT
1120 DoOpenOrExplore(
1121 IDefaultContextMenuImpl *iface,
1122 LPCMINVOKECOMMANDINFO lpcmi)
1123 {
1124
1125
1126 return E_FAIL;
1127 }
1128
1129 BOOL
1130 GetUniqueFileName(LPWSTR szBasePath, LPWSTR szExt, LPWSTR szTarget, BOOL bShortcut)
1131 {
1132 UINT RetryCount = 0, Length;
1133 WCHAR szLnk[40];
1134 HANDLE hFile;
1135
1136 if (!bShortcut)
1137 {
1138 Length = LoadStringW(shell32_hInstance, IDS_LNK_FILE, szLnk, sizeof(szLnk)/sizeof(WCHAR));
1139 }
1140
1141 do
1142 {
1143 if (!bShortcut)
1144 {
1145 if (RetryCount)
1146 swprintf(szTarget, L"%s%s(%u).%s", szLnk, szBasePath, RetryCount, szExt);
1147 else
1148 swprintf(szTarget, L"%s%s.%s", szLnk, szBasePath, szExt);
1149 }
1150 else
1151 {
1152 if (RetryCount)
1153 swprintf(szTarget, L"%s(%u).%s", szBasePath, RetryCount, szExt);
1154 else
1155 swprintf(szTarget, L"%s.%s", szBasePath, szExt);
1156 }
1157
1158 hFile = CreateFileW(szTarget, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
1159 if (hFile != INVALID_HANDLE_VALUE)
1160 {
1161 CloseHandle(hFile);
1162 return TRUE;
1163 }
1164
1165 }while(RetryCount++ < 100);
1166
1167 return FALSE;
1168
1169 }
1170
1171 static
1172 HRESULT
1173 DoCreateLink(
1174 IDefaultContextMenuImpl *This,
1175 LPCMINVOKECOMMANDINFO lpcmi)
1176 {
1177 WCHAR szPath[MAX_PATH];
1178 WCHAR szTarget[MAX_PATH] = {0};
1179 STRRET strFile;
1180 LPWSTR pszExt;
1181 HRESULT hr;
1182 IShellLinkW * nLink;
1183 IPersistFile * ipf;
1184 static WCHAR szLnk[] = L"lnk";
1185
1186 if (IShellFolder2_GetDisplayNameOf(This->dcm.psf, This->dcm.apidl[0], SHGDN_FORPARSING, &strFile) != S_OK)
1187 {
1188 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1189 return E_FAIL;
1190 }
1191
1192 if (StrRetToBufW(&strFile, This->dcm.apidl[0], szPath, MAX_PATH) != S_OK)
1193 return E_FAIL;
1194
1195
1196 pszExt = wcsrchr(szPath, L'.');
1197 pszExt[0] = 0;
1198
1199 if (!wcsicmp(pszExt + 1, szLnk))
1200 {
1201 if (!GetUniqueFileName(szPath, pszExt + 1, szTarget, TRUE))
1202 return E_FAIL;
1203
1204 hr = IShellLink_ConstructFromFile(NULL, &IID_IPersistFile, This->dcm.apidl[0], (LPVOID*)&ipf);
1205 if (hr != S_OK)
1206 {
1207 return hr;
1208 }
1209 hr = IPersistFile_Save(ipf, szTarget, FALSE);
1210 IPersistFile_Release(ipf);
1211 NotifyShellViewWindow(lpcmi, TRUE);
1212 return hr;
1213 }
1214 else
1215 {
1216 if (!GetUniqueFileName(szPath, szLnk, szTarget, TRUE))
1217 return E_FAIL;
1218
1219 hr = IShellLink_Constructor(NULL, &IID_IShellLinkW, (LPVOID*)&nLink);
1220 if (hr != S_OK)
1221 {
1222 return E_FAIL;
1223 }
1224 pszExt[0] = '.';
1225 if (SUCCEEDED(IShellLinkW_SetPath(nLink, szPath)))
1226 {
1227 if (SUCCEEDED(IShellLinkW_QueryInterface(nLink, &IID_IPersistFile, (LPVOID*)&ipf)))
1228 {
1229 hr = IPersistFile_Save(ipf, szTarget, TRUE);
1230 IPersistFile_Release(ipf);
1231 }
1232 }
1233 IShellLinkW_Release(nLink);
1234 NotifyShellViewWindow(lpcmi, TRUE);
1235 return hr;
1236 }
1237 }
1238
1239 static
1240 HRESULT
1241 DoDelete(
1242 IDefaultContextMenuImpl *This,
1243 LPCMINVOKECOMMANDINFO lpcmi)
1244 {
1245 HRESULT hr;
1246 STRRET strTemp;
1247 WCHAR szPath[MAX_PATH];
1248 SHFILEOPSTRUCTW op;
1249 int ret;
1250 LPSHELLBROWSER lpSB;
1251 HWND hwnd;
1252
1253
1254 hr = IShellFolder2_GetDisplayNameOf(This->dcm.psf, This->dcm.apidl[0], SHGDN_FORPARSING, &strTemp);
1255 if(hr != S_OK)
1256 {
1257 ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr);
1258 return hr;
1259 }
1260 ZeroMemory(szPath, sizeof(szPath));
1261 hr = StrRetToBufW(&strTemp, This->dcm.apidl[0], szPath, MAX_PATH);
1262 if (hr != S_OK)
1263 {
1264 ERR("StrRetToBufW failed with %x\n", hr);
1265 return hr;
1266 }
1267 /* FIXME
1268 * implement deletion with multiple files
1269 */
1270
1271 ZeroMemory(&op, sizeof(op));
1272 op.hwnd = GetActiveWindow();
1273 op.wFunc = FO_DELETE;
1274 op.pFrom = szPath;
1275 op.fFlags = FOF_ALLOWUNDO;
1276 ret = SHFileOperationW(&op);
1277
1278 if (ret)
1279 {
1280 TRACE("SHFileOperation failed with %0x%x", GetLastError());
1281 return S_OK;
1282 }
1283
1284 /* get the active IShellView */
1285 if ((lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER,0,0)))
1286 {
1287 /* is the treeview focused */
1288 if (SUCCEEDED(IShellBrowser_GetControlWindow(lpSB, FCW_TREE, &hwnd)))
1289 {
1290 HTREEITEM hItem = TreeView_GetSelection(hwnd);
1291 if (hItem)
1292 {
1293 (void)TreeView_DeleteItem(hwnd, hItem);
1294 }
1295 }
1296 }
1297 NotifyShellViewWindow(lpcmi, TRUE);
1298
1299 return S_OK;
1300
1301 }
1302
1303 static
1304 HRESULT
1305 DoCopyOrCut(
1306 IDefaultContextMenuImpl *iface,
1307 LPCMINVOKECOMMANDINFO lpcmi,
1308 BOOL bCopy)
1309 {
1310 LPSHELLBROWSER lpSB;
1311 LPSHELLVIEW lpSV;
1312 LPDATAOBJECT lpDo;
1313 HRESULT hr;
1314
1315 lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER,0,0);
1316 if (!lpSB)
1317 {
1318 TRACE("failed to get shellbrowser\n");
1319 return E_FAIL;
1320 }
1321
1322 hr = IShellBrowser_QueryActiveShellView(lpSB, &lpSV);
1323 if (FAILED(hr))
1324 {
1325 TRACE("failed to query the active shellview\n");
1326 return hr;
1327 }
1328
1329 hr = IShellView_GetItemObject(lpSV, SVGIO_SELECTION, &IID_IDataObject, (LPVOID*)&lpDo);
1330 if (FAILED(hr))
1331 {
1332 TRACE("failed to get item object\n");
1333 return hr;
1334 }
1335
1336 hr = OleSetClipboard(lpDo);
1337 if (FAILED(hr))
1338 {
1339 WARN("OleSetClipboard failed");
1340 }
1341 IDataObject_Release(lpDo);
1342 IShellView_Release(lpSV);
1343 return S_OK;
1344 }
1345
1346 static
1347 HRESULT
1348 DoRename(
1349 IDefaultContextMenuImpl *This,
1350 LPCMINVOKECOMMANDINFO lpcmi)
1351 {
1352 LPSHELLBROWSER lpSB;
1353 LPSHELLVIEW lpSV;
1354 HWND hwnd;
1355
1356 /* get the active IShellView */
1357 if ((lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER,0,0)))
1358 {
1359 /* is the treeview focused */
1360 if (SUCCEEDED(IShellBrowser_GetControlWindow(lpSB, FCW_TREE, &hwnd)))
1361 {
1362 HTREEITEM hItem = TreeView_GetSelection(hwnd);
1363 if (hItem)
1364 {
1365 (void)TreeView_EditLabel(hwnd, hItem);
1366 }
1367 }
1368
1369 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV)))
1370 {
1371 IShellView_SelectItem(lpSV, This->dcm.apidl[0],
1372 SVSI_DESELECTOTHERS|SVSI_EDIT|SVSI_ENSUREVISIBLE|SVSI_FOCUSED|SVSI_SELECT);
1373 IShellView_Release(lpSV);
1374 return S_OK;
1375 }
1376 }
1377 return E_FAIL;
1378 }
1379
1380 static
1381 HRESULT
1382 DoProperties(
1383 IDefaultContextMenuImpl *This,
1384 LPCMINVOKECOMMANDINFO lpcmi)
1385 {
1386 WCHAR szDrive[MAX_PATH];
1387 STRRET strFile;
1388
1389 if (This->dcm.cidl &&_ILIsMyComputer(This->dcm.apidl[0]))
1390 {
1391 ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL, NULL, SW_SHOWNORMAL);
1392 return S_OK;
1393 }
1394 else if (This->dcm.cidl == 0 && _ILIsDesktop(This->dcm.pidlFolder))
1395 {
1396 ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL);
1397 return S_OK;
1398 }
1399 else if (_ILIsDrive(This->dcm.apidl[0]))
1400 {
1401 ILGetDisplayName(This->dcm.apidl[0], szDrive);
1402 SH_ShowDriveProperties(szDrive, This->dcm.pidlFolder, This->dcm.apidl);
1403 return S_OK;
1404 }
1405 else if (_ILIsNetHood(This->dcm.apidl[0]))
1406 {
1407 /* FIXME
1408 * implement nethood properties
1409 */
1410 FIXME("implement network connection shell folder\n");
1411 return S_OK;
1412 }
1413 else if (_ILIsBitBucket(This->dcm.apidl[0]))
1414 {
1415 /* FIXME
1416 * detect the drive path of bitbucket if appropiate
1417 */
1418
1419 SH_ShowRecycleBinProperties(L'C');
1420 return S_OK;
1421 }
1422
1423 if (This->dcm.cidl > 1)
1424 WARN("SHMultiFileProperties is not yet implemented\n");
1425
1426 if (IShellFolder2_GetDisplayNameOf(This->dcm.psf, This->dcm.apidl[0], SHGDN_FORPARSING, &strFile) != S_OK)
1427 {
1428 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1429 return E_FAIL;
1430 }
1431
1432 if (StrRetToBufW(&strFile, This->dcm.apidl[0], szDrive, MAX_PATH) != S_OK)
1433 return E_FAIL;
1434
1435 return SH_ShowPropertiesDialog(szDrive, This->dcm.pidlFolder, This->dcm.apidl);
1436 }
1437
1438 static
1439 HRESULT
1440 DoFormat(
1441 IDefaultContextMenuImpl *This,
1442 LPCMINVOKECOMMANDINFO lpcmi)
1443 {
1444 char sDrive[5] = {0};
1445
1446 if (!_ILGetDrive(This->dcm.apidl[0], sDrive, sizeof(sDrive)))
1447 {
1448 ERR("pidl is not a drive\n");
1449 return E_FAIL;
1450 }
1451
1452 SHFormatDrive(lpcmi->hwnd, sDrive[0] - 'A', SHFMT_ID_DEFAULT, 0);
1453 return S_OK;
1454 }
1455
1456 static
1457 HRESULT
1458 DoDynamicShellExtensions(
1459 IDefaultContextMenuImpl *This,
1460 LPCMINVOKECOMMANDINFO lpcmi)
1461 {
1462 UINT verb = LOWORD(lpcmi->lpVerb);
1463 PDynamicShellEntry pCurrent = This->dhead;
1464
1465 TRACE("verb %p first %x last %x", lpcmi->lpVerb, This->iIdSHEFirst, This->iIdSHELast);
1466
1467 while(pCurrent && verb > pCurrent->iIdCmdFirst + pCurrent->NumIds)
1468 pCurrent = pCurrent->Next;
1469
1470 if (!pCurrent)
1471 return E_FAIL;
1472
1473 if (verb >= pCurrent->iIdCmdFirst && verb <= pCurrent->iIdCmdFirst + pCurrent->NumIds)
1474 {
1475 /* invoke the dynamic context menu */
1476 lpcmi->lpVerb = MAKEINTRESOURCEA(verb - pCurrent->iIdCmdFirst);
1477 return IContextMenu_InvokeCommand(pCurrent->CMenu, lpcmi);
1478 }
1479
1480 return E_FAIL;
1481 }
1482
1483
1484 static
1485 HRESULT
1486 DoStaticShellExtensions(
1487 IDefaultContextMenuImpl *This,
1488 LPCMINVOKECOMMANDINFO lpcmi)
1489 {
1490 STRRET strFile;
1491 WCHAR szPath[MAX_PATH];
1492 SHELLEXECUTEINFOW sei;
1493 PStaticShellEntry pCurrent = This->shead;
1494 int verb = LOWORD(lpcmi->lpVerb) - This->iIdSCMFirst;
1495
1496
1497 while(pCurrent && verb-- > 0)
1498 pCurrent = pCurrent->Next;
1499
1500 if (verb > 0)
1501 return E_FAIL;
1502
1503
1504 if (IShellFolder2_GetDisplayNameOf(This->dcm.psf, This->dcm.apidl[0], SHGDN_FORPARSING, &strFile) != S_OK)
1505 {
1506 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1507 return E_FAIL;
1508 }
1509
1510 if (StrRetToBufW(&strFile, This->dcm.apidl[0], szPath, MAX_PATH) != S_OK)
1511 return E_FAIL;
1512
1513
1514 ZeroMemory(&sei, sizeof(sei));
1515 sei.cbSize = sizeof(sei);
1516 sei.fMask = SEE_MASK_CLASSNAME;
1517 sei.lpClass = pCurrent->szClass;
1518 sei.hwnd = lpcmi->hwnd;
1519 sei.nShow = SW_SHOWNORMAL;
1520 sei.lpVerb = pCurrent->szVerb;
1521 sei.lpFile = szPath;
1522 ShellExecuteExW(&sei);
1523 return S_OK;
1524
1525 }
1526
1527 static
1528 HRESULT
1529 WINAPI
1530 IDefaultContextMenu_fnInvokeCommand(
1531 IContextMenu2 *iface,
1532 LPCMINVOKECOMMANDINFO lpcmi)
1533 {
1534 IDefaultContextMenuImpl * This = impl_from_IContextMenu(iface);
1535
1536 switch(LOWORD(lpcmi->lpVerb))
1537 {
1538 case FCIDM_SHVIEW_BIGICON:
1539 case FCIDM_SHVIEW_SMALLICON:
1540 case FCIDM_SHVIEW_LISTVIEW:
1541 case FCIDM_SHVIEW_REPORTVIEW:
1542 case 0x30: /* FIX IDS in resource files */
1543 case 0x31:
1544 case 0x32:
1545 case 0x33:
1546 case FCIDM_SHVIEW_AUTOARRANGE:
1547 case FCIDM_SHVIEW_SNAPTOGRID:
1548 case FCIDM_SHVIEW_REFRESH:
1549 return NotifyShellViewWindow(lpcmi, FALSE);
1550 case FCIDM_SHVIEW_INSERT:
1551 case FCIDM_SHVIEW_INSERTLINK:
1552 return DoPaste(This, lpcmi);
1553 case FCIDM_SHVIEW_OPEN:
1554 case FCIDM_SHVIEW_EXPLORE:
1555 return DoOpenOrExplore(This, lpcmi);
1556 case FCIDM_SHVIEW_COPY:
1557 case FCIDM_SHVIEW_CUT:
1558 return DoCopyOrCut(This, lpcmi, LOWORD(lpcmi->lpVerb) == FCIDM_SHVIEW_COPY);
1559 case FCIDM_SHVIEW_CREATELINK:
1560 return DoCreateLink(This, lpcmi);
1561 case FCIDM_SHVIEW_DELETE:
1562 return DoDelete(This, lpcmi);
1563 case FCIDM_SHVIEW_RENAME:
1564 return DoRename(This, lpcmi);
1565 case FCIDM_SHVIEW_PROPERTIES:
1566 return DoProperties(This, lpcmi);
1567 case 0x7ABC:
1568 return DoFormat(This, lpcmi);
1569 }
1570
1571 if (This->iIdSHEFirst && This->iIdSHELast)
1572 {
1573 if (LOWORD(lpcmi->lpVerb) >= This->iIdSHEFirst && LOWORD(lpcmi->lpVerb) <= This->iIdSHELast)
1574 {
1575 return DoDynamicShellExtensions(This, lpcmi);
1576 }
1577 }
1578
1579 if (This->iIdSCMFirst && This->iIdSCMLast)
1580 {
1581 if (LOWORD(lpcmi->lpVerb) >= This->iIdSCMFirst && LOWORD(lpcmi->lpVerb) <= This->iIdSCMLast)
1582 {
1583 return DoStaticShellExtensions(This, lpcmi);
1584 }
1585 }
1586
1587 FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb));
1588 return E_UNEXPECTED;
1589 }
1590
1591 static
1592 HRESULT
1593 WINAPI
1594 IDefaultContextMenu_fnGetCommandString(
1595 IContextMenu2 *iface,
1596 UINT_PTR idCommand,
1597 UINT uFlags,
1598 UINT* lpReserved,
1599 LPSTR lpszName,
1600 UINT uMaxNameLen)
1601 {
1602
1603 return S_OK;
1604 }
1605
1606 static
1607 HRESULT
1608 WINAPI
1609 IDefaultContextMenu_fnHandleMenuMsg(
1610 IContextMenu2 *iface,
1611 UINT uMsg,
1612 WPARAM wParam,
1613 LPARAM lParam)
1614 {
1615
1616 return S_OK;
1617 }
1618
1619 static const IContextMenu2Vtbl cmvt =
1620 {
1621 IDefaultContextMenu_fnQueryInterface,
1622 IDefaultContextMenu_fnAddRef,
1623 IDefaultContextMenu_fnRelease,
1624 IDefaultContextMenu_fnQueryContextMenu,
1625 IDefaultContextMenu_fnInvokeCommand,
1626 IDefaultContextMenu_fnGetCommandString,
1627 IDefaultContextMenu_fnHandleMenuMsg
1628 };
1629 static
1630 HRESULT
1631 IDefaultContextMenu_Constructor(
1632 const DEFCONTEXTMENU *pdcm,
1633 REFIID riid,
1634 void **ppv)
1635 {
1636 IDefaultContextMenuImpl * This;
1637 HRESULT hr = E_FAIL;
1638 IDataObject * pDataObj;
1639
1640 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDefaultContextMenuImpl));
1641 if (This)
1642 {
1643 This->lpVtbl = &cmvt;
1644 This->ref = 1;
1645 TRACE("cidl %u\n", This->dcm.cidl);
1646 if (SUCCEEDED(SHCreateDataObject(pdcm->pidlFolder, pdcm->cidl, pdcm->apidl, NULL, &IID_IDataObject, (void**)&pDataObj)))
1647 {
1648 This->pDataObj = pDataObj;
1649 }
1650 CopyMemory(&This->dcm, pdcm, sizeof(DEFCONTEXTMENU));
1651 hr = IDefaultContextMenu_fnQueryInterface((IContextMenu2*)This, riid, ppv);
1652 if (SUCCEEDED(hr))
1653 IContextMenu_Release((IContextMenu2*)This);
1654 }
1655
1656 TRACE("This(%p)(%x) cidl %u\n",This, hr, This->dcm.cidl);
1657 return hr;
1658 }
1659
1660 /*************************************************************************
1661 * SHCreateDefaultContextMenu [SHELL32.325] Vista API
1662 *
1663 */
1664
1665 HRESULT
1666 WINAPI
1667 SHCreateDefaultContextMenu(
1668 const DEFCONTEXTMENU *pdcm,
1669 REFIID riid,
1670 void **ppv)
1671 {
1672 HRESULT hr = E_FAIL;
1673
1674 *ppv = NULL;
1675 hr = IDefaultContextMenu_Constructor( pdcm, riid, ppv );
1676
1677 TRACE("pcm %p hr %x\n", pdcm, hr);
1678 return hr;
1679 }
1680
1681 /*************************************************************************
1682 * CDefFolderMenu_Create2 [SHELL32.701]
1683 *
1684 */
1685
1686 HRESULT
1687 WINAPI
1688 CDefFolderMenu_Create2(
1689 LPCITEMIDLIST pidlFolder,
1690 HWND hwnd,
1691 UINT cidl,
1692 LPCITEMIDLIST *apidl,
1693 IShellFolder *psf,
1694 LPFNDFMCALLBACK lpfn,
1695 UINT nKeys,
1696 const HKEY *ahkeyClsKeys,
1697 IContextMenu **ppcm)
1698 {
1699 DEFCONTEXTMENU pdcm;
1700 HRESULT hr;
1701
1702 pdcm.hwnd = hwnd;
1703 pdcm.pcmcb = NULL;
1704 pdcm.pidlFolder = pidlFolder;
1705 pdcm.psf = psf;
1706 pdcm.cidl = cidl;
1707 pdcm.apidl = apidl;
1708 pdcm.punkAssociationInfo = NULL;
1709 pdcm.cKeys = nKeys;
1710 pdcm.aKeys = ahkeyClsKeys;
1711
1712 hr = SHCreateDefaultContextMenu(&pdcm, &IID_IContextMenu, (void**)ppcm);
1713 return hr;
1714 }
1715