1 /*
2  * oledlg tests
3  *
4  * Copyright 2015 Nikolay Sivov for CodeWeavers
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 #define COBJMACROS
22 
23 #include "wine/test.h"
24 #include <stdio.h>
25 
26 #include "initguid.h"
27 #include "oledlg.h"
28 
29 static const WCHAR *strstrW( const WCHAR *str, const WCHAR *sub )
30 {
31     while (*str)
32     {
33         const WCHAR *p1 = str, *p2 = sub;
34         while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; }
35         if (!*p2) return str;
36         str++;
37     }
38     return NULL;
39 }
40 
41 static HRESULT WINAPI enumverbs_QueryInterface(IEnumOLEVERB *iface, REFIID riid, void **ppv)
42 {
43     if (IsEqualIID(riid, &IID_IEnumOLEVERB) || IsEqualIID(riid, &IID_IUnknown)) {
44         *ppv = iface;
45         IEnumOLEVERB_AddRef(iface);
46         return S_OK;
47     }
48 
49     *ppv = NULL;
50     return E_NOINTERFACE;
51 }
52 
53 static ULONG WINAPI enumverbs_AddRef(IEnumOLEVERB *iface)
54 {
55     return 2;
56 }
57 
58 static ULONG WINAPI enumverbs_Release(IEnumOLEVERB *iface)
59 {
60     return 1;
61 }
62 
63 static int g_enumpos;
64 static const WCHAR verbW[] = {'v','e','r','b',0};
65 static HRESULT WINAPI enumverbs_Next(IEnumOLEVERB *iface, ULONG count, OLEVERB *verbs, ULONG *fetched)
66 {
67     ok(count == 1, "got %u\n", count);
68     ok(fetched == NULL, "got %p\n", fetched);
69     ok(g_enumpos == 0 || g_enumpos == 1, "got pos %d\n", g_enumpos);
70 
71     if (g_enumpos++ == 0) {
72         verbs->lVerb = 123;
73         verbs->lpszVerbName = CoTaskMemAlloc(sizeof(verbW));
74         lstrcpyW(verbs->lpszVerbName, verbW);
75         verbs->fuFlags = MF_ENABLED;
76         verbs->grfAttribs = OLEVERBATTRIB_ONCONTAINERMENU;
77         if (fetched) *fetched = 1;
78         return S_OK;
79     }
80 
81     return S_FALSE;
82 }
83 
84 static HRESULT WINAPI enumverbs_Skip(IEnumOLEVERB *iface, ULONG count)
85 {
86     ok(0, "unexpected call\n");
87     return E_NOTIMPL;
88 }
89 
90 static HRESULT WINAPI enumverbs_Reset(IEnumOLEVERB *iface)
91 {
92     ok(0, "unexpected call\n");
93     return E_NOTIMPL;
94 }
95 
96 static HRESULT WINAPI enumverbs_Clone(IEnumOLEVERB *iface, IEnumOLEVERB **ppenum)
97 {
98     ok(0, "unexpected call\n");
99     return E_NOTIMPL;
100 }
101 
102 static IEnumOLEVERBVtbl enumverbsvtbl = {
103     enumverbs_QueryInterface,
104     enumverbs_AddRef,
105     enumverbs_Release,
106     enumverbs_Next,
107     enumverbs_Skip,
108     enumverbs_Reset,
109     enumverbs_Clone
110 };
111 
112 static IEnumOLEVERB enumverbs = { &enumverbsvtbl };
113 
114 static HRESULT WINAPI oleobject_QueryInterface(IOleObject *iface, REFIID riid, void **ppv)
115 {
116     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IOleObject)) {
117         *ppv = iface;
118         IOleObject_AddRef(iface);
119         return S_OK;
120     }
121 
122     *ppv = NULL;
123     return E_NOINTERFACE;
124 }
125 
126 static ULONG WINAPI oleobject_AddRef(IOleObject *iface)
127 {
128     return 2;
129 }
130 
131 static ULONG WINAPI oleobject_Release(IOleObject *iface)
132 {
133     return 1;
134 }
135 
136 static HRESULT WINAPI oleobject_SetClientSite(IOleObject *iface, IOleClientSite *site)
137 {
138     ok(0, "unexpected call\n");
139     return E_NOTIMPL;
140 }
141 
142 static HRESULT WINAPI oleobject_GetClientSite(IOleObject *iface, IOleClientSite **site)
143 {
144     ok(0, "unexpected call\n");
145     return E_NOTIMPL;
146 }
147 
148 static HRESULT WINAPI oleobject_SetHostNames(IOleObject *iface, LPCOLESTR containerapp,
149     LPCOLESTR containerObj)
150 {
151     ok(0, "unexpected call\n");
152     return E_NOTIMPL;
153 }
154 
155 static HRESULT WINAPI oleobject_Close(IOleObject *iface, DWORD saveopt)
156 {
157     ok(0, "unexpected call\n");
158     return E_NOTIMPL;
159 }
160 
161 static HRESULT WINAPI oleobject_SetMoniker(IOleObject *iface, DWORD whichmoniker, IMoniker *mk)
162 {
163     ok(0, "unexpected call\n");
164     return E_NOTIMPL;
165 }
166 
167 static HRESULT WINAPI oleobject_GetMoniker(IOleObject *iface, DWORD assign, DWORD whichmoniker,
168     IMoniker **mk)
169 {
170     ok(0, "unexpected call\n");
171     return E_NOTIMPL;
172 }
173 
174 static HRESULT WINAPI oleobject_InitFromData(IOleObject *iface, IDataObject *dataobject,
175     BOOL creation, DWORD reserved)
176 {
177     ok(0, "unexpected call\n");
178     return E_NOTIMPL;
179 }
180 
181 static HRESULT WINAPI oleobject_GetClipboardData(IOleObject *iface, DWORD reserved, IDataObject **dataobject)
182 {
183     ok(0, "unexpected call\n");
184     return E_NOTIMPL;
185 }
186 
187 static HRESULT WINAPI oleobject_DoVerb(IOleObject *iface, LONG verb, MSG *msg, IOleClientSite *activesite,
188     LONG index, HWND hwndParent, LPCRECT rect)
189 {
190     ok(0, "unexpected call\n");
191     return E_NOTIMPL;
192 }
193 
194 static BOOL g_enumverbsfail;
195 static HRESULT WINAPI oleobject_EnumVerbs(IOleObject *iface, IEnumOLEVERB **enumverb)
196 {
197     if (g_enumverbsfail) {
198         *enumverb = NULL;
199         return E_FAIL;
200     }
201     *enumverb = &enumverbs;
202     return S_OK;
203 }
204 
205 static HRESULT WINAPI oleobject_Update(IOleObject *iface)
206 {
207     ok(0, "unexpected call\n");
208     return E_NOTIMPL;
209 }
210 
211 static HRESULT WINAPI oleobject_IsUpToDate(IOleObject *iface)
212 {
213     ok(0, "unexpected call\n");
214     return E_NOTIMPL;
215 }
216 
217 static HRESULT WINAPI oleobject_GetUserClassID(IOleObject *iface, CLSID *clsid)
218 {
219     ok(0, "unexpected call\n");
220     return E_NOTIMPL;
221 }
222 
223 static const WCHAR testW[] = {'t','e','s','t',0};
224 static HRESULT WINAPI oleobject_GetUserType(IOleObject *iface, DWORD formoftype,
225     LPOLESTR *usertype)
226 {
227     ok(formoftype == USERCLASSTYPE_SHORT, "got %d\n", formoftype);
228     *usertype = CoTaskMemAlloc(sizeof(testW));
229     lstrcpyW(*usertype, testW);
230     return S_OK;
231 }
232 
233 static HRESULT WINAPI oleobject_SetExtent(IOleObject *iface, DWORD aspect, SIZEL *size)
234 {
235     ok(0, "unexpected call\n");
236     return E_NOTIMPL;
237 }
238 
239 static HRESULT WINAPI oleobject_GetExtent(IOleObject *iface, DWORD aspect, SIZEL *size)
240 {
241     ok(0, "unexpected call\n");
242     return E_NOTIMPL;
243 }
244 
245 static HRESULT WINAPI oleobject_Advise(IOleObject *iface, IAdviseSink *sink, DWORD *connection)
246 {
247     ok(0, "unexpected call\n");
248     return E_NOTIMPL;
249 }
250 
251 static HRESULT WINAPI oleobject_Unadvise(IOleObject *iface, DWORD connection)
252 {
253     ok(0, "unexpected call\n");
254     return E_NOTIMPL;
255 }
256 
257 static HRESULT WINAPI oleobject_EnumAdvise(IOleObject *iface, IEnumSTATDATA **enumadvise)
258 {
259     ok(0, "unexpected call\n");
260     return E_NOTIMPL;
261 }
262 
263 static HRESULT WINAPI oleobject_GetMiscStatus(IOleObject *iface, DWORD aspect, DWORD *status)
264 {
265     ok(0, "unexpected call\n");
266     return E_NOTIMPL;
267 }
268 
269 static HRESULT WINAPI oleobject_SetColorScheme(IOleObject *iface, LOGPALETTE *pal)
270 {
271     ok(0, "unexpected call\n");
272     return E_NOTIMPL;
273 }
274 
275 static IOleObjectVtbl oleobjectvtbl = {
276     oleobject_QueryInterface,
277     oleobject_AddRef,
278     oleobject_Release,
279     oleobject_SetClientSite,
280     oleobject_GetClientSite,
281     oleobject_SetHostNames,
282     oleobject_Close,
283     oleobject_SetMoniker,
284     oleobject_GetMoniker,
285     oleobject_InitFromData,
286     oleobject_GetClipboardData,
287     oleobject_DoVerb,
288     oleobject_EnumVerbs,
289     oleobject_Update,
290     oleobject_IsUpToDate,
291     oleobject_GetUserClassID,
292     oleobject_GetUserType,
293     oleobject_SetExtent,
294     oleobject_GetExtent,
295     oleobject_Advise,
296     oleobject_Unadvise,
297     oleobject_EnumAdvise,
298     oleobject_GetMiscStatus,
299     oleobject_SetColorScheme
300 };
301 
302 static IOleObject oleobject = { &oleobjectvtbl };
303 
304 static void test_OleUIAddVerbMenu(void)
305 {
306     static const WCHAR cadabraW[] = {'c','a','d','a','b','r','a',0};
307     HMENU hMenu, verbmenu;
308     MENUITEMINFOW info;
309     WCHAR buffW[50];
310     int count;
311     BOOL ret;
312 
313     ret = OleUIAddVerbMenuW(NULL, NULL, NULL, 0, 0, 0, FALSE, 0, NULL);
314     ok(!ret, "got %d\n", ret);
315 
316     verbmenu = (HMENU)0xdeadbeef;
317     ret = OleUIAddVerbMenuW(NULL, NULL, NULL, 0, 0, 0, FALSE, 0, &verbmenu);
318     ok(!ret, "got %d\n", ret);
319     ok(verbmenu == NULL, "got %p\n", verbmenu);
320 
321     g_enumpos = 0;
322     ret = OleUIAddVerbMenuW(&oleobject, NULL, NULL, 0, 0, 0, FALSE, 0, NULL);
323     ok(!ret, "got %d\n", ret);
324 
325     hMenu = CreatePopupMenu();
326 
327     memset(&info, 0, sizeof(info));
328     info.cbSize = sizeof(info);
329     ret = InsertMenuItemW(hMenu, 0, TRUE, &info);
330     ok(ret, "got %d\n", ret);
331 
332     count = GetMenuItemCount(hMenu);
333     ok(count == 1, "got %d\n", count);
334 
335     g_enumpos = 0;
336     ret = OleUIAddVerbMenuW(&oleobject, NULL, hMenu, 0, 0, 0, FALSE, 0, NULL);
337     ok(!ret, "got %d\n", ret);
338 
339     count = GetMenuItemCount(hMenu);
340     ok(count == 1, "got %d\n", count);
341 
342     ret = InsertMenuItemW(hMenu, 0, TRUE, &info);
343     ok(ret, "got %d\n", ret);
344 
345     count = GetMenuItemCount(hMenu);
346     ok(count == 2, "got %d\n", count);
347 
348     verbmenu = (HMENU)0xdeadbeef;
349     g_enumpos = 0;
350     ret = OleUIAddVerbMenuW(&oleobject, NULL, hMenu, 1, 0, 0, FALSE, 0, &verbmenu);
351     ok(ret, "got %d\n", ret);
352     ok(verbmenu == NULL, "got %p\n", verbmenu);
353 
354     count = GetMenuItemCount(hMenu);
355     ok(count == 2, "got %d\n", count);
356 
357     /* object doesn't support EnumVerbs() */
358     g_enumverbsfail = TRUE;
359     g_enumpos = 0;
360     verbmenu = (HMENU)0xdeadbeef;
361     ret = OleUIAddVerbMenuW(&oleobject, NULL, hMenu, 2, 0, 0, FALSE, 0, &verbmenu);
362     ok(!ret, "got %d\n", ret);
363     ok(verbmenu == NULL, "got %p\n", verbmenu);
364     g_enumverbsfail = FALSE;
365 
366     /* added disabled item */
367     memset(&info, 0, sizeof(info));
368     info.cbSize = sizeof(info);
369     info.fMask = MIIM_STATE|MIIM_SUBMENU;
370     ret = GetMenuItemInfoW(hMenu, 2, TRUE, &info);
371     ok(ret, "got %d\n", ret);
372     ok(info.fState & MFS_DISABLED, "got state 0x%08x\n", info.fState);
373     ok(info.hSubMenu == NULL, "got submenu %p\n", info.hSubMenu);
374 
375     count = GetMenuItemCount(hMenu);
376     ok(count == 3, "got %d\n", count);
377 
378     /* now without object */
379     verbmenu = (HMENU)0xdeadbeef;
380     ret = OleUIAddVerbMenuW(NULL, testW, hMenu, 3, 42, 0, FALSE, 0, &verbmenu);
381     ok(!ret, "got %d\n", ret);
382     ok(verbmenu == NULL, "got %p\n", verbmenu);
383 
384     memset(&info, 0, sizeof(info));
385     info.cbSize = sizeof(info);
386     info.fMask = MIIM_STATE|MIIM_ID|MIIM_STRING|MIIM_SUBMENU;
387     info.dwTypeData = buffW;
388     info.cch = sizeof(buffW)/sizeof(WCHAR);
389     ret = GetMenuItemInfoW(hMenu, 3, TRUE, &info);
390     ok(ret, "got %d\n", ret);
391     ok(info.fState == MF_GRAYED, "got state 0x%08x\n", info.fState);
392     ok(info.wID == 42, "got id %d\n", info.wID);
393     ok(info.hSubMenu == NULL, "got submenu %p\n", info.hSubMenu);
394 
395     count = GetMenuItemCount(hMenu);
396     ok(count == 4, "got %d\n", count);
397 
398     verbmenu = (HMENU)0xdeadbeef;
399     g_enumpos = 0;
400     ret = OleUIAddVerbMenuW(&oleobject, NULL, hMenu, 4, 0, 0, FALSE, 0, &verbmenu);
401     ok(ret, "got %d\n", ret);
402     ok(verbmenu == NULL, "got %p\n", verbmenu);
403 
404     /* check newly added item */
405     memset(&info, 0, sizeof(info));
406     info.cbSize = sizeof(info);
407     info.fMask = MIIM_STRING|MIIM_STATE|MIIM_SUBMENU;
408     info.dwTypeData = buffW;
409     info.cch = sizeof(buffW)/sizeof(WCHAR);
410     ret = GetMenuItemInfoW(hMenu, 4, TRUE, &info);
411     ok(ret, "got %d\n", ret);
412     /* Item string contains verb, usertype and localized string for 'Object' word,
413        exact format depends on localization. */
414     ok(strstrW(buffW, verbW) != NULL, "str %s\n", wine_dbgstr_w(buffW));
415     ok(info.fState == 0, "got state 0x%08x\n", info.fState);
416     ok(info.hSubMenu == NULL, "got submenu %p\n", info.hSubMenu);
417 
418     count = GetMenuItemCount(hMenu);
419     ok(count == 5, "got %d\n", count);
420 
421     DestroyMenu(hMenu);
422 
423     /* try to add verb menu repeatedly, with same id */
424     hMenu = CreatePopupMenu();
425 
426     count = GetMenuItemCount(hMenu);
427     ok(count == 0, "got %d\n", count);
428 
429     verbmenu = NULL;
430     ret = OleUIAddVerbMenuW(NULL, NULL, hMenu, 0, 5, 10, TRUE, 3, &verbmenu);
431     ok(!ret, "got %d\n", ret);
432     ok(verbmenu == NULL, "got %p\n", verbmenu);
433 
434     count = GetMenuItemCount(hMenu);
435     ok(count == 1, "got %d\n", count);
436 
437     verbmenu = NULL;
438     ret = OleUIAddVerbMenuW(NULL, NULL, hMenu, 0, 5, 10, TRUE, 3, &verbmenu);
439     ok(!ret, "got %d\n", ret);
440     ok(verbmenu == NULL, "got %p\n", verbmenu);
441 
442     count = GetMenuItemCount(hMenu);
443     ok(count == 1, "got %d\n", count);
444 
445     /* same position, different id */
446     verbmenu = NULL;
447     ret = OleUIAddVerbMenuW(NULL, NULL, hMenu, 0, 6, 10, TRUE, 3, &verbmenu);
448     ok(!ret, "got %d\n", ret);
449     ok(verbmenu == NULL, "got %p\n", verbmenu);
450 
451     count = GetMenuItemCount(hMenu);
452     ok(count == 1, "got %d\n", count);
453 
454     /* change added item string and state */
455     memset(&info, 0, sizeof(info));
456     info.cbSize = sizeof(info);
457     info.fMask = MIIM_STRING|MIIM_STATE;
458     info.fState = MFS_ENABLED;
459     info.dwTypeData = buffW;
460     lstrcpyW(buffW, cadabraW);
461     ret = SetMenuItemInfoW(hMenu, 0, TRUE, &info);
462     ok(ret, "got %d\n", ret);
463 
464     buffW[0] = 0;
465     GetMenuStringW(hMenu, 0, buffW, sizeof(buffW)/sizeof(buffW[0]), MF_BYPOSITION);
466     ok(!lstrcmpW(buffW, cadabraW), "got %s\n", wine_dbgstr_w(buffW));
467 
468     verbmenu = NULL;
469     ret = OleUIAddVerbMenuW(NULL, NULL, hMenu, 0, 5, 10, TRUE, 3, &verbmenu);
470     ok(!ret, "got %d\n", ret);
471     ok(verbmenu == NULL, "got %p\n", verbmenu);
472 
473     memset(&info, 0, sizeof(info));
474     info.cbSize = sizeof(info);
475     info.fMask = MIIM_STRING|MIIM_STATE;
476     buffW[0] = 0;
477     info.dwTypeData = buffW;
478     info.cch = sizeof(buffW)/sizeof(WCHAR);
479     ret = GetMenuItemInfoW(hMenu, 0, TRUE, &info);
480     ok(ret, "got %d\n", ret);
481     ok(lstrcmpW(buffW, cadabraW), "got %s\n", wine_dbgstr_w(buffW));
482     ok(info.fState == MF_GRAYED, "got state 0x%08x\n", info.fState);
483 
484     count = GetMenuItemCount(hMenu);
485     ok(count == 1, "got %d\n", count);
486 
487     DestroyMenu(hMenu);
488 }
489 
490 START_TEST(main)
491 {
492     test_OleUIAddVerbMenu();
493 }
494