shell32: Fix FOLDERID_Document definition.
[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 } ItemCmImpl;
58
59 static inline ItemCmImpl *impl_from_IContextMenu2(IContextMenu2 *iface)
60 {
61     return CONTAINING_RECORD(iface, ItemCmImpl, IContextMenu2_iface);
62 }
63
64
65 static const IContextMenu2Vtbl cmvt;
66
67 /**************************************************************************
68 * ISvItemCm_CanRenameItems()
69 */
70 static BOOL ISvItemCm_CanRenameItems(ItemCmImpl *This)
71 {       UINT  i;
72         DWORD dwAttributes;
73
74         TRACE("(%p)->()\n",This);
75
76         if(This->apidl)
77         {
78           for(i = 0; i < This->cidl; i++){}
79           if(i > 1) return FALSE;               /* can't rename more than one item at a time*/
80           dwAttributes = SFGAO_CANRENAME;
81           IShellFolder_GetAttributesOf(This->pSFParent, 1, (LPCITEMIDLIST*)This->apidl, &dwAttributes);
82           return dwAttributes & SFGAO_CANRENAME;
83         }
84         return FALSE;
85 }
86
87 /**************************************************************************
88 *   ISvItemCm_Constructor()
89 */
90 IContextMenu2 *ISvItemCm_Constructor(LPSHELLFOLDER pSFParent, LPCITEMIDLIST pidl, const LPCITEMIDLIST *apidl, UINT cidl)
91 {       ItemCmImpl* cm;
92         UINT  u;
93
94         cm = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ItemCmImpl));
95         cm->IContextMenu2_iface.lpVtbl = &cmvt;
96         cm->ref = 1;
97         cm->pidl = ILClone(pidl);
98         cm->pSFParent = pSFParent;
99
100         if(pSFParent) IShellFolder_AddRef(pSFParent);
101
102         cm->apidl = _ILCopyaPidl(apidl, cidl);
103         cm->cidl = cidl;
104
105         cm->bAllValues = 1;
106         for(u = 0; u < cidl; u++)
107         {
108           cm->bAllValues &= (_ILIsValue(apidl[u]) ? 1 : 0);
109         }
110
111         TRACE("(%p)->()\n",cm);
112
113         return &cm->IContextMenu2_iface;
114 }
115
116 /**************************************************************************
117 *  ISvItemCm_fnQueryInterface
118 */
119 static HRESULT WINAPI ISvItemCm_fnQueryInterface(IContextMenu2 *iface, REFIID riid, LPVOID *ppvObj)
120 {
121         ItemCmImpl *This = impl_from_IContextMenu2(iface);
122
123         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
124
125         *ppvObj = NULL;
126
127         if(IsEqualIID(riid, &IID_IUnknown) ||
128            IsEqualIID(riid, &IID_IContextMenu) ||
129            IsEqualIID(riid, &IID_IContextMenu2))
130         {
131           *ppvObj = This;
132         }
133         else if(IsEqualIID(riid, &IID_IShellExtInit))  /*IShellExtInit*/
134         {
135           FIXME("-- LPSHELLEXTINIT pointer requested\n");
136         }
137
138         if(*ppvObj)
139         {
140           IUnknown_AddRef((IUnknown*)*ppvObj);
141           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
142           return S_OK;
143         }
144         TRACE("-- Interface: E_NOINTERFACE\n");
145         return E_NOINTERFACE;
146 }
147
148 /**************************************************************************
149 *  ISvItemCm_fnAddRef
150 */
151 static ULONG WINAPI ISvItemCm_fnAddRef(IContextMenu2 *iface)
152 {
153         ItemCmImpl *This = impl_from_IContextMenu2(iface);
154         ULONG refCount = InterlockedIncrement(&This->ref);
155
156         TRACE("(%p)->(count=%u)\n", This, refCount - 1);
157
158         return refCount;
159 }
160
161 /**************************************************************************
162 *  ISvItemCm_fnRelease
163 */
164 static ULONG WINAPI ISvItemCm_fnRelease(IContextMenu2 *iface)
165 {
166         ItemCmImpl *This = impl_from_IContextMenu2(iface);
167         ULONG refCount = InterlockedDecrement(&This->ref);
168
169         TRACE("(%p)->(count=%i)\n", This, refCount + 1);
170
171         if (!refCount)
172         {
173           TRACE(" destroying IContextMenu(%p)\n",This);
174
175           if(This->pSFParent)
176             IShellFolder_Release(This->pSFParent);
177
178           SHFree(This->pidl);
179
180           /*make sure the pidl is freed*/
181           _ILFreeaPidl(This->apidl, This->cidl);
182
183           HeapFree(GetProcessHeap(),0,This);
184         }
185         return refCount;
186 }
187
188 static void _InsertMenuItemW (
189         HMENU hmenu,
190         UINT indexMenu,
191         BOOL fByPosition,
192         UINT wID,
193         UINT fType,
194         LPWSTR dwTypeData,
195         UINT fState)
196 {
197         MENUITEMINFOW   mii;
198
199         mii.cbSize = sizeof(mii);
200         if (fType == MFT_SEPARATOR)
201         {
202           mii.fMask = MIIM_ID | MIIM_TYPE;
203         }
204         else
205         {
206           mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
207           mii.dwTypeData = dwTypeData;
208           mii.fState = fState;
209         }
210         mii.wID = wID;
211         mii.fType = fType;
212         InsertMenuItemW( hmenu, indexMenu, fByPosition, &mii);
213 }
214
215 /**************************************************************************
216 * ISvItemCm_fnQueryContextMenu()
217 */
218 static HRESULT WINAPI ISvItemCm_fnQueryContextMenu(
219         IContextMenu2 *iface,
220         HMENU hmenu,
221         UINT indexMenu,
222         UINT idCmdFirst,
223         UINT idCmdLast,
224         UINT uFlags)
225 {
226         ItemCmImpl *This = impl_from_IContextMenu2(iface);
227         INT uIDMax;
228
229         TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",This, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
230
231         if (idCmdFirst != 0)
232           FIXME("We should use idCmdFirst=%d and idCmdLast=%d for command ids\n", idCmdFirst, idCmdLast);
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);
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 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)hpsxa,
480                                            (LPFNADDPROPSHEETPAGE)&Properties_AddPropSheetCallback,
481                                            (LPARAM)&psh);
482                 SHDestroyPropSheetExtArray(hpsxa);
483             }
484             hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, wszFiletypeAll, MAX_PROP_PAGES - psh.nPages, lpDo);
485             if (hpsxa != NULL)
486             {
487                 SHAddFromPropSheetExtArray((HPSXA)hpsxa,
488                                            (LPFNADDPROPSHEETPAGE)&Properties_AddPropSheetCallback,
489                                            (LPARAM)&psh);
490                 SHDestroyPropSheetExtArray(hpsxa);
491             }
492             IDataObject_Release(lpDo);
493         }
494
495         if (psh.nPages)
496             PropertySheetW(&psh);
497         else
498             FIXME("No property pages found.\n");
499 }
500
501 /**************************************************************************
502 * ISvItemCm_fnInvokeCommand()
503 */
504 static HRESULT WINAPI ISvItemCm_fnInvokeCommand(
505         IContextMenu2 *iface,
506         LPCMINVOKECOMMANDINFO lpcmi)
507 {
508     ItemCmImpl *This = impl_from_IContextMenu2(iface);
509
510     if (lpcmi->cbSize != sizeof(CMINVOKECOMMANDINFO))
511         FIXME("Is an EX structure\n");
512
513     TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);
514
515     if( HIWORD(lpcmi->lpVerb)==0 && LOWORD(lpcmi->lpVerb) > FCIDM_SHVIEWLAST)
516     {
517         TRACE("Invalid Verb %x\n",LOWORD(lpcmi->lpVerb));
518         return E_INVALIDARG;
519     }
520
521     if (HIWORD(lpcmi->lpVerb) == 0)
522     {
523         switch(LOWORD(lpcmi->lpVerb))
524         {
525         case FCIDM_SHVIEW_EXPLORE:
526             TRACE("Verb FCIDM_SHVIEW_EXPLORE\n");
527             DoOpenExplore(This, lpcmi->hwnd, "explore");
528             break;
529         case FCIDM_SHVIEW_OPEN:
530             TRACE("Verb FCIDM_SHVIEW_OPEN\n");
531             DoOpenExplore(This, lpcmi->hwnd, "open");
532             break;
533         case FCIDM_SHVIEW_RENAME:
534             TRACE("Verb FCIDM_SHVIEW_RENAME\n");
535             DoRename(This, lpcmi->hwnd);
536             break;
537         case FCIDM_SHVIEW_DELETE:
538             TRACE("Verb FCIDM_SHVIEW_DELETE\n");
539             DoDelete(This);
540             break;
541         case FCIDM_SHVIEW_COPY:
542             TRACE("Verb FCIDM_SHVIEW_COPY\n");
543             DoCopyOrCut(This, lpcmi->hwnd, FALSE);
544             break;
545         case FCIDM_SHVIEW_CUT:
546             TRACE("Verb FCIDM_SHVIEW_CUT\n");
547             DoCopyOrCut(This, lpcmi->hwnd, TRUE);
548             break;
549         case FCIDM_SHVIEW_PROPERTIES:
550             TRACE("Verb FCIDM_SHVIEW_PROPERTIES\n");
551             DoOpenProperties(This, lpcmi->hwnd);
552             break;
553         default:
554             FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb));
555             return E_INVALIDARG;
556         }
557     }
558     else
559     {
560         TRACE("Verb is %s\n",debugstr_a(lpcmi->lpVerb));
561         if (strcmp(lpcmi->lpVerb,"delete")==0)
562             DoDelete(This);
563         else if (strcmp(lpcmi->lpVerb,"properties")==0)
564             DoOpenProperties(This, lpcmi->hwnd);
565         else {
566             FIXME("Unhandled string verb %s\n",debugstr_a(lpcmi->lpVerb));
567             return E_FAIL;
568         }
569     }
570     return NOERROR;
571 }
572
573 /**************************************************************************
574 *  ISvItemCm_fnGetCommandString()
575 */
576 static HRESULT WINAPI ISvItemCm_fnGetCommandString(
577         IContextMenu2 *iface,
578         UINT_PTR idCommand,
579         UINT uFlags,
580         UINT* lpReserved,
581         LPSTR lpszName,
582         UINT uMaxNameLen)
583 {
584         ItemCmImpl *This = impl_from_IContextMenu2(iface);
585
586         HRESULT  hr = E_INVALIDARG;
587
588         TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n",This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
589
590         switch(uFlags)
591         {
592           case GCS_HELPTEXTA:
593           case GCS_HELPTEXTW:
594             hr = E_NOTIMPL;
595             break;
596
597           case GCS_VERBA:
598             switch(idCommand)
599             {
600               case FCIDM_SHVIEW_RENAME:
601                 strcpy(lpszName, "rename");
602                 hr = NOERROR;
603                 break;
604             }
605             break;
606
607              /* NT 4.0 with IE 3.0x or no IE will always call This with GCS_VERBW. In This
608              case, you need to do the lstrcpyW to the pointer passed.*/
609           case GCS_VERBW:
610             switch(idCommand)
611             { case FCIDM_SHVIEW_RENAME:
612                 MultiByteToWideChar( CP_ACP, 0, "rename", -1, (LPWSTR)lpszName, uMaxNameLen );
613                 hr = NOERROR;
614                 break;
615             }
616             break;
617
618           case GCS_VALIDATEA:
619           case GCS_VALIDATEW:
620             hr = NOERROR;
621             break;
622         }
623         TRACE("-- (%p)->(name=%s)\n",This, lpszName);
624         return hr;
625 }
626
627 /**************************************************************************
628 * ISvItemCm_fnHandleMenuMsg()
629 * NOTES
630 *  should be only in IContextMenu2 and IContextMenu3
631 *  is nevertheless called from word95
632 */
633 static HRESULT WINAPI ISvItemCm_fnHandleMenuMsg(
634         IContextMenu2 *iface,
635         UINT uMsg,
636         WPARAM wParam,
637         LPARAM lParam)
638 {
639         ItemCmImpl *This = impl_from_IContextMenu2(iface);
640
641         TRACE("(%p)->(msg=%x wp=%lx lp=%lx)\n",This, uMsg, wParam, lParam);
642
643         return E_NOTIMPL;
644 }
645
646 static const IContextMenu2Vtbl cmvt =
647 {
648         ISvItemCm_fnQueryInterface,
649         ISvItemCm_fnAddRef,
650         ISvItemCm_fnRelease,
651         ISvItemCm_fnQueryContextMenu,
652         ISvItemCm_fnInvokeCommand,
653         ISvItemCm_fnGetCommandString,
654         ISvItemCm_fnHandleMenuMsg
655 };