shell32: Improved equal ITEMIDLISTs handling in ILIsParent.
[wine] / dlls / shell32 / shv_item_cmenu.c
1 /*
2  *      IContextMenu for items in the shellview
3  *
4  * Copyright 1998, 2000 Juergen Schmied <juergen.schmied@debitel.net>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <string.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26
27 #include "winerror.h"
28 #include "wine/debug.h"
29
30 #include "windef.h"
31 #include "wingdi.h"
32 #include "pidl.h"
33 #include "undocshell.h"
34 #include "shlobj.h"
35 #include "winreg.h"
36 #include "prsht.h"
37
38 #include "shell32_main.h"
39 #include "shellfolder.h"
40
41 #include "shresdef.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(shell);
44
45 /**************************************************************************
46 *  IContextMenu Implementation
47 */
48 typedef struct
49 {       const IContextMenu2Vtbl *lpVtbl;
50         LONG            ref;
51         IShellFolder*   pSFParent;
52         LPITEMIDLIST    pidl;           /* root pidl */
53         LPITEMIDLIST    *apidl;         /* array of child pidls */
54         UINT            cidl;
55         BOOL            bAllValues;
56 } ItemCmImpl;
57
58
59 static const IContextMenu2Vtbl cmvt;
60
61 /**************************************************************************
62 * ISvItemCm_CanRenameItems()
63 */
64 static BOOL ISvItemCm_CanRenameItems(ItemCmImpl *This)
65 {       UINT  i;
66         DWORD dwAttributes;
67
68         TRACE("(%p)->()\n",This);
69
70         if(This->apidl)
71         {
72           for(i = 0; i < This->cidl; i++){}
73           if(i > 1) return FALSE;               /* can't rename more than one item at a time*/
74           dwAttributes = SFGAO_CANRENAME;
75           IShellFolder_GetAttributesOf(This->pSFParent, 1, (LPCITEMIDLIST*)This->apidl, &dwAttributes);
76           return dwAttributes & SFGAO_CANRENAME;
77         }
78         return FALSE;
79 }
80
81 /**************************************************************************
82 *   ISvItemCm_Constructor()
83 */
84 IContextMenu2 *ISvItemCm_Constructor(LPSHELLFOLDER pSFParent, LPCITEMIDLIST pidl, const LPCITEMIDLIST *apidl, UINT cidl)
85 {       ItemCmImpl* cm;
86         UINT  u;
87
88         cm = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ItemCmImpl));
89         cm->lpVtbl = &cmvt;
90         cm->ref = 1;
91         cm->pidl = ILClone(pidl);
92         cm->pSFParent = pSFParent;
93
94         if(pSFParent) IShellFolder_AddRef(pSFParent);
95
96         cm->apidl = _ILCopyaPidl(apidl, cidl);
97         cm->cidl = cidl;
98
99         cm->bAllValues = 1;
100         for(u = 0; u < cidl; u++)
101         {
102           cm->bAllValues &= (_ILIsValue(apidl[u]) ? 1 : 0);
103         }
104
105         TRACE("(%p)->()\n",cm);
106
107         return (IContextMenu2*)cm;
108 }
109
110 /**************************************************************************
111 *  ISvItemCm_fnQueryInterface
112 */
113 static HRESULT WINAPI ISvItemCm_fnQueryInterface(IContextMenu2 *iface, REFIID riid, LPVOID *ppvObj)
114 {
115         ItemCmImpl *This = (ItemCmImpl *)iface;
116
117         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
118
119         *ppvObj = NULL;
120
121         if(IsEqualIID(riid, &IID_IUnknown) ||
122            IsEqualIID(riid, &IID_IContextMenu) ||
123            IsEqualIID(riid, &IID_IContextMenu2))
124         {
125           *ppvObj = This;
126         }
127         else if(IsEqualIID(riid, &IID_IShellExtInit))  /*IShellExtInit*/
128         {
129           FIXME("-- LPSHELLEXTINIT pointer requested\n");
130         }
131
132         if(*ppvObj)
133         {
134           IUnknown_AddRef((IUnknown*)*ppvObj);
135           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
136           return S_OK;
137         }
138         TRACE("-- Interface: E_NOINTERFACE\n");
139         return E_NOINTERFACE;
140 }
141
142 /**************************************************************************
143 *  ISvItemCm_fnAddRef
144 */
145 static ULONG WINAPI ISvItemCm_fnAddRef(IContextMenu2 *iface)
146 {
147         ItemCmImpl *This = (ItemCmImpl *)iface;
148         ULONG refCount = InterlockedIncrement(&This->ref);
149
150         TRACE("(%p)->(count=%u)\n", This, refCount - 1);
151
152         return refCount;
153 }
154
155 /**************************************************************************
156 *  ISvItemCm_fnRelease
157 */
158 static ULONG WINAPI ISvItemCm_fnRelease(IContextMenu2 *iface)
159 {
160         ItemCmImpl *This = (ItemCmImpl *)iface;
161         ULONG refCount = InterlockedDecrement(&This->ref);
162
163         TRACE("(%p)->(count=%i)\n", This, refCount + 1);
164
165         if (!refCount)
166         {
167           TRACE(" destroying IContextMenu(%p)\n",This);
168
169           if(This->pSFParent)
170             IShellFolder_Release(This->pSFParent);
171
172           SHFree(This->pidl);
173
174           /*make sure the pidl is freed*/
175           _ILFreeaPidl(This->apidl, This->cidl);
176
177           HeapFree(GetProcessHeap(),0,This);
178         }
179         return refCount;
180 }
181
182 static void _InsertMenuItemW (
183         HMENU hmenu,
184         UINT indexMenu,
185         BOOL fByPosition,
186         UINT wID,
187         UINT fType,
188         LPWSTR dwTypeData,
189         UINT fState)
190 {
191         MENUITEMINFOW   mii;
192
193         mii.cbSize = sizeof(mii);
194         if (fType == MFT_SEPARATOR)
195         {
196           mii.fMask = MIIM_ID | MIIM_TYPE;
197         }
198         else
199         {
200           mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
201           mii.dwTypeData = dwTypeData;
202           mii.fState = fState;
203         }
204         mii.wID = wID;
205         mii.fType = fType;
206         InsertMenuItemW( hmenu, indexMenu, fByPosition, &mii);
207 }
208
209 /**************************************************************************
210 * ISvItemCm_fnQueryContextMenu()
211 */
212 static HRESULT WINAPI ISvItemCm_fnQueryContextMenu(
213         IContextMenu2 *iface,
214         HMENU hmenu,
215         UINT indexMenu,
216         UINT idCmdFirst,
217         UINT idCmdLast,
218         UINT uFlags)
219 {
220         ItemCmImpl *This = (ItemCmImpl *)iface;
221         INT uIDMax;
222
223         TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",This, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
224
225         if (idCmdFirst != 0)
226           FIXME("We should use idCmdFirst=%d and idCmdLast=%d for command ids\n", idCmdFirst, idCmdLast);
227
228         if(!(CMF_DEFAULTONLY & uFlags) && This->cidl>0)
229         {
230           HMENU hmenures = LoadMenuW(shell32_hInstance, MAKEINTRESOURCEW(MENU_SHV_FILE));
231
232           if(uFlags & CMF_EXPLORE)
233             RemoveMenu(hmenures, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
234
235           uIDMax = Shell_MergeMenus(hmenu, GetSubMenu(hmenures, 0), indexMenu, idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS);
236
237           DestroyMenu(hmenures);
238
239           if(This->bAllValues)
240           {
241             MENUITEMINFOW mi;
242             WCHAR str[255];
243             mi.cbSize = sizeof(mi);
244             mi.fMask = MIIM_ID | MIIM_STRING | MIIM_FTYPE;
245             mi.dwTypeData = str;
246             mi.cch = 255;
247             GetMenuItemInfoW(hmenu, FCIDM_SHVIEW_EXPLORE, MF_BYCOMMAND, &mi);
248             RemoveMenu(hmenu, FCIDM_SHVIEW_EXPLORE, MF_BYCOMMAND);
249             _InsertMenuItemW(hmenu, (uFlags & CMF_EXPLORE) ? 1 : 2, MF_BYPOSITION, FCIDM_SHVIEW_EXPLORE, MFT_STRING, str, MFS_ENABLED);
250           }
251
252           SetMenuDefaultItem(hmenu, 0, MF_BYPOSITION);
253
254           if(uFlags & ~CMF_CANRENAME)
255             RemoveMenu(hmenu, FCIDM_SHVIEW_RENAME, MF_BYCOMMAND);
256           else
257             EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, MF_BYCOMMAND | ISvItemCm_CanRenameItems(This) ? MFS_ENABLED : MFS_DISABLED);
258
259           return MAKE_HRESULT(SEVERITY_SUCCESS, 0, uIDMax);
260         }
261         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
262 }
263
264 /**************************************************************************
265 * DoOpenExplore
266 *
267 *  for folders only
268 */
269
270 static void DoOpenExplore(
271         IContextMenu2 *iface,
272         HWND hwnd,
273         LPCSTR verb)
274 {
275         ItemCmImpl *This = (ItemCmImpl *)iface;
276
277         UINT i, bFolderFound = FALSE;
278         LPITEMIDLIST    pidlFQ;
279         SHELLEXECUTEINFOA       sei;
280
281         /* Find the first item in the list that is not a value. These commands
282             should never be invoked if there isn't at least one folder item in the list.*/
283
284         for(i = 0; i<This->cidl; i++)
285         {
286           if(!_ILIsValue(This->apidl[i]))
287           {
288             bFolderFound = TRUE;
289             break;
290           }
291         }
292
293         if (!bFolderFound) return;
294
295         pidlFQ = ILCombine(This->pidl, This->apidl[i]);
296
297         ZeroMemory(&sei, sizeof(sei));
298         sei.cbSize = sizeof(sei);
299         sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME;
300         sei.lpIDList = pidlFQ;
301         sei.lpClass = "Folder";
302         sei.hwnd = hwnd;
303         sei.nShow = SW_SHOWNORMAL;
304         sei.lpVerb = verb;
305         ShellExecuteExA(&sei);
306         SHFree(pidlFQ);
307 }
308
309 /**************************************************************************
310 * DoRename
311 */
312 static void DoRename(
313         IContextMenu2 *iface,
314         HWND hwnd)
315 {
316         ItemCmImpl *This = (ItemCmImpl *)iface;
317
318         LPSHELLBROWSER  lpSB;
319         LPSHELLVIEW     lpSV;
320
321         TRACE("(%p)->(wnd=%p)\n",This, hwnd);
322
323         /* get the active IShellView */
324         if ((lpSB = (LPSHELLBROWSER)SendMessageA(hwnd, CWM_GETISHELLBROWSER,0,0)))
325         {
326           if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV)))
327           {
328             TRACE("(sv=%p)\n",lpSV);
329             IShellView_SelectItem(lpSV, This->apidl[0],
330               SVSI_DESELECTOTHERS|SVSI_EDIT|SVSI_ENSUREVISIBLE|SVSI_FOCUSED|SVSI_SELECT);
331             IShellView_Release(lpSV);
332           }
333         }
334 }
335
336 /**************************************************************************
337  * DoDelete
338  *
339  * deletes the currently selected items
340  */
341 static void DoDelete(IContextMenu2 *iface)
342 {
343         ItemCmImpl *This = (ItemCmImpl *)iface;
344         ISFHelper * psfhlp;
345
346         IShellFolder_QueryInterface(This->pSFParent, &IID_ISFHelper, (LPVOID*)&psfhlp);
347         if (psfhlp)
348         {
349           ISFHelper_DeleteItems(psfhlp, This->cidl, (LPCITEMIDLIST *)This->apidl);
350           ISFHelper_Release(psfhlp);
351         }
352 }
353
354 /**************************************************************************
355  * DoCopyOrCut
356  *
357  * copies the currently selected items into the clipboard
358  */
359 static BOOL DoCopyOrCut(
360         IContextMenu2 *iface,
361         HWND hwnd,
362         BOOL bCut)
363 {
364         ItemCmImpl *This = (ItemCmImpl *)iface;
365
366         LPSHELLBROWSER  lpSB;
367         LPSHELLVIEW     lpSV;
368         LPDATAOBJECT    lpDo;
369
370         TRACE("(%p)->(wnd=%p,bCut=0x%08x)\n",This, hwnd, bCut);
371
372         /* get the active IShellView */
373         if ((lpSB = (LPSHELLBROWSER)SendMessageA(hwnd, CWM_GETISHELLBROWSER,0,0)))
374         {
375           if (SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV)))
376           {
377             if (SUCCEEDED(IShellView_GetItemObject(lpSV, SVGIO_SELECTION, &IID_IDataObject, (LPVOID*)&lpDo)))
378             {
379               OleSetClipboard(lpDo);
380               IDataObject_Release(lpDo);
381             }
382             IShellView_Release(lpSV);
383           }
384         }
385         return TRUE;
386 }
387
388 /**************************************************************************
389  * Properties_AddPropSheetCallback
390  *
391  * Used by DoOpenProperties through SHCreatePropSheetExtArrayEx to add
392  * propertysheet pages from shell extensions.
393  */
394 static BOOL Properties_AddPropSheetCallback(HPROPSHEETPAGE hpage, LPARAM lparam)
395 {
396         LPPROPSHEETHEADERW psh = (LPPROPSHEETHEADERW) lparam;
397         psh->u3.phpage[psh->nPages++] = hpage;
398
399         return TRUE;
400 }
401
402 /**************************************************************************
403  * DoOpenProperties
404  */
405 static void DoOpenProperties(IContextMenu2 *iface, HWND hwnd)
406 {
407         ItemCmImpl *This = (ItemCmImpl *)iface;
408         static const UINT MAX_PROP_PAGES = 99;
409         static const WCHAR wszFolder[] = {'F','o','l','d','e','r', 0};
410         static const WCHAR wszFiletypeAll[] = {'*',0};
411         LPSHELLFOLDER lpDesktopSF;
412         LPSHELLFOLDER lpSF;
413         LPDATAOBJECT lpDo;
414         WCHAR wszFiletype[MAX_PATH];
415         WCHAR wszFilename[MAX_PATH];
416         PROPSHEETHEADERW psh;
417         HPROPSHEETPAGE hpages[MAX_PROP_PAGES];
418         HPSXA hpsxa;
419         UINT ret;
420
421         TRACE("(%p)->(wnd=%p)\n", This, hwnd);
422
423         ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
424         psh.dwSize = sizeof (PROPSHEETHEADERW);
425         psh.hwndParent = hwnd;
426         psh.dwFlags = PSH_PROPTITLE;
427         psh.nPages = 0;
428         psh.u3.phpage = hpages;
429         psh.u2.nStartPage = 0;
430
431         _ILSimpleGetTextW(This->apidl[0], (LPVOID)&wszFilename, MAX_PATH);
432         psh.pszCaption = (LPCWSTR)&wszFilename;
433
434         /* Find out where to look for the shell extensions */
435         if (_ILIsValue(This->apidl[0]))
436         {
437             char sTemp[64];
438             sTemp[0] = 0;
439             if (_ILGetExtension(This->apidl[0], sTemp, 64))
440             {
441                 HCR_MapTypeToValueA(sTemp, sTemp, 64, TRUE);
442                 MultiByteToWideChar(CP_ACP, 0, sTemp, -1, wszFiletype, MAX_PATH);
443             }
444             else
445             {
446                 wszFiletype[0] = 0;
447             }
448         }
449         else if (_ILIsFolder(This->apidl[0]))
450         {
451             lstrcpynW(wszFiletype, wszFolder, 64);
452         }
453         else if (_ILIsSpecialFolder(This->apidl[0]))
454         {
455             LPGUID folderGUID;
456             static const WCHAR wszclsid[] = {'C','L','S','I','D','\\', 0};
457             folderGUID = _ILGetGUIDPointer(This->apidl[0]);
458             lstrcpyW(wszFiletype, wszclsid);
459             StringFromGUID2(folderGUID, &wszFiletype[6], MAX_PATH - 6);
460         }
461         else
462         {
463             FIXME("Requested properties for unknown type.\n");
464             return;
465         }
466
467         /* Get a suitable DataObject for accessing the files */
468         SHGetDesktopFolder(&lpDesktopSF);
469         if (_ILIsPidlSimple(This->pidl))
470         {
471             ret = IShellFolder_GetUIObjectOf(lpDesktopSF, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl,
472                                              &IID_IDataObject, NULL, (LPVOID *)&lpDo);
473             IShellFolder_Release(lpDesktopSF);
474         }
475         else
476         {
477             IShellFolder_BindToObject(lpDesktopSF, This->pidl, NULL, &IID_IShellFolder, (LPVOID*) &lpSF);
478             ret = IShellFolder_GetUIObjectOf(lpSF, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl,
479                                              &IID_IDataObject, NULL, (LPVOID *)&lpDo);
480             IShellFolder_Release(lpSF);
481             IShellFolder_Release(lpDesktopSF);
482         }
483
484         if (SUCCEEDED(ret))
485         {
486             hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, wszFiletype, MAX_PROP_PAGES - psh.nPages, lpDo);
487             if (hpsxa != NULL)
488             {
489                 SHAddFromPropSheetExtArray((HPSXA)hpsxa,
490                                            (LPFNADDPROPSHEETPAGE)&Properties_AddPropSheetCallback,
491                                            (LPARAM)&psh);
492                 SHDestroyPropSheetExtArray(hpsxa);
493             }
494             hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, wszFiletypeAll, MAX_PROP_PAGES - psh.nPages, lpDo);
495             if (hpsxa != NULL)
496             {
497                 SHAddFromPropSheetExtArray((HPSXA)hpsxa,
498                                            (LPFNADDPROPSHEETPAGE)&Properties_AddPropSheetCallback,
499                                            (LPARAM)&psh);
500                 SHDestroyPropSheetExtArray(hpsxa);
501             }
502             IDataObject_Release(lpDo);
503         }
504
505         if (psh.nPages)
506             PropertySheetW(&psh);
507         else
508             FIXME("No property pages found.\n");
509 }
510
511 /**************************************************************************
512 * ISvItemCm_fnInvokeCommand()
513 */
514 static HRESULT WINAPI ISvItemCm_fnInvokeCommand(
515         IContextMenu2 *iface,
516         LPCMINVOKECOMMANDINFO lpcmi)
517 {
518     ItemCmImpl *This = (ItemCmImpl *)iface;
519
520     if (lpcmi->cbSize != sizeof(CMINVOKECOMMANDINFO))
521         FIXME("Is an EX structure\n");
522
523     TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);
524
525     if( HIWORD(lpcmi->lpVerb)==0 && LOWORD(lpcmi->lpVerb) > FCIDM_SHVIEWLAST)
526     {
527         TRACE("Invalid Verb %x\n",LOWORD(lpcmi->lpVerb));
528         return E_INVALIDARG;
529     }
530
531     if (HIWORD(lpcmi->lpVerb) == 0)
532     {
533         switch(LOWORD(lpcmi->lpVerb))
534         {
535         case FCIDM_SHVIEW_EXPLORE:
536             TRACE("Verb FCIDM_SHVIEW_EXPLORE\n");
537             DoOpenExplore(iface, lpcmi->hwnd, "explore");
538             break;
539         case FCIDM_SHVIEW_OPEN:
540             TRACE("Verb FCIDM_SHVIEW_OPEN\n");
541             DoOpenExplore(iface, lpcmi->hwnd, "open");
542             break;
543         case FCIDM_SHVIEW_RENAME:
544             TRACE("Verb FCIDM_SHVIEW_RENAME\n");
545             DoRename(iface, lpcmi->hwnd);
546             break;
547         case FCIDM_SHVIEW_DELETE:
548             TRACE("Verb FCIDM_SHVIEW_DELETE\n");
549             DoDelete(iface);
550             break;
551         case FCIDM_SHVIEW_COPY:
552             TRACE("Verb FCIDM_SHVIEW_COPY\n");
553             DoCopyOrCut(iface, lpcmi->hwnd, FALSE);
554             break;
555         case FCIDM_SHVIEW_CUT:
556             TRACE("Verb FCIDM_SHVIEW_CUT\n");
557             DoCopyOrCut(iface, lpcmi->hwnd, TRUE);
558             break;
559         case FCIDM_SHVIEW_PROPERTIES:
560             TRACE("Verb FCIDM_SHVIEW_PROPERTIES\n");
561             DoOpenProperties(iface, lpcmi->hwnd);
562             break;
563         default:
564             FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb));
565             return E_INVALIDARG;
566         }
567     }
568     else
569     {
570         TRACE("Verb is %s\n",debugstr_a(lpcmi->lpVerb));
571         if (strcmp(lpcmi->lpVerb,"delete")==0)
572             DoDelete(iface);
573         else if (strcmp(lpcmi->lpVerb,"properties")==0)
574             DoOpenProperties(iface, lpcmi->hwnd);
575         else {
576             FIXME("Unhandled string verb %s\n",debugstr_a(lpcmi->lpVerb));
577             return E_FAIL;
578         }
579     }
580     return NOERROR;
581 }
582
583 /**************************************************************************
584 *  ISvItemCm_fnGetCommandString()
585 */
586 static HRESULT WINAPI ISvItemCm_fnGetCommandString(
587         IContextMenu2 *iface,
588         UINT_PTR idCommand,
589         UINT uFlags,
590         UINT* lpReserved,
591         LPSTR lpszName,
592         UINT uMaxNameLen)
593 {
594         ItemCmImpl *This = (ItemCmImpl *)iface;
595
596         HRESULT  hr = E_INVALIDARG;
597
598         TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n",This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
599
600         switch(uFlags)
601         {
602           case GCS_HELPTEXTA:
603           case GCS_HELPTEXTW:
604             hr = E_NOTIMPL;
605             break;
606
607           case GCS_VERBA:
608             switch(idCommand)
609             {
610               case FCIDM_SHVIEW_RENAME:
611                 strcpy(lpszName, "rename");
612                 hr = NOERROR;
613                 break;
614             }
615             break;
616
617              /* NT 4.0 with IE 3.0x or no IE will always call This with GCS_VERBW. In This
618              case, you need to do the lstrcpyW to the pointer passed.*/
619           case GCS_VERBW:
620             switch(idCommand)
621             { case FCIDM_SHVIEW_RENAME:
622                 MultiByteToWideChar( CP_ACP, 0, "rename", -1, (LPWSTR)lpszName, uMaxNameLen );
623                 hr = NOERROR;
624                 break;
625             }
626             break;
627
628           case GCS_VALIDATEA:
629           case GCS_VALIDATEW:
630             hr = NOERROR;
631             break;
632         }
633         TRACE("-- (%p)->(name=%s)\n",This, lpszName);
634         return hr;
635 }
636
637 /**************************************************************************
638 * ISvItemCm_fnHandleMenuMsg()
639 * NOTES
640 *  should be only in IContextMenu2 and IContextMenu3
641 *  is nevertheless called from word95
642 */
643 static HRESULT WINAPI ISvItemCm_fnHandleMenuMsg(
644         IContextMenu2 *iface,
645         UINT uMsg,
646         WPARAM wParam,
647         LPARAM lParam)
648 {
649         ItemCmImpl *This = (ItemCmImpl *)iface;
650
651         TRACE("(%p)->(msg=%x wp=%lx lp=%lx)\n",This, uMsg, wParam, lParam);
652
653         return E_NOTIMPL;
654 }
655
656 static const IContextMenu2Vtbl cmvt =
657 {
658         ISvItemCm_fnQueryInterface,
659         ISvItemCm_fnAddRef,
660         ISvItemCm_fnRelease,
661         ISvItemCm_fnQueryContextMenu,
662         ISvItemCm_fnInvokeCommand,
663         ISvItemCm_fnGetCommandString,
664         ISvItemCm_fnHandleMenuMsg
665 };