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