[CMAKE]
[reactos.git] / dll / win32 / shell32 / startmenu.c
1 /*
2 * Start menu object
3 *
4 * Copyright 2007 Hervé Poussineau
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 <precomp.h>
22
23 WINE_DEFAULT_DEBUG_CHANNEL(shell32start);
24
25 typedef struct _tagStartMenu {
26 const IMenuPopupVtbl *vtbl;
27 const IObjectWithSiteVtbl *objectSiteVtbl;
28 const IInitializeObjectVtbl *initObjectVtbl;
29 const IMenuBandVtbl *menuBandVtbl;
30 IUnknown *pUnkSite;
31 LONG refCount;
32 IBandSite * pBandSite;
33 } StartMenu, *LPStartMenu;
34
35 typedef struct _tagMenuBandSite {
36 const IBandSiteVtbl * lpVtbl;
37 LONG refCount;
38
39 IUnknown ** Objects;
40 LONG ObjectsCount;
41
42 } MenuBandSite, *LPMenuBandSite;
43
44 static const IMenuPopupVtbl StartMenuVtbl;
45 static const IObjectWithSiteVtbl StartMenu_ObjectWithSiteVtbl;
46 static const IInitializeObjectVtbl StartMenu_InitializeObjectVtbl;
47 static const IBandSiteVtbl StartMenu_BandSiteVtbl;
48 static const IMenuBandVtbl StartMenu_MenuBandVtbl;
49
50 static LPStartMenu __inline impl_from_IMenuPopup(IMenuPopup *iface)
51 {
52 return (LPStartMenu)((char *)iface - FIELD_OFFSET(StartMenu, vtbl));
53 }
54
55 static LPStartMenu __inline impl_from_IObjectWithSite(IObjectWithSite *iface)
56 {
57 return (LPStartMenu)((char *)iface - FIELD_OFFSET(StartMenu, objectSiteVtbl));
58 }
59
60 static LPStartMenu __inline impl_from_IInitializeObject(IInitializeObject *iface)
61 {
62 return (LPStartMenu)((char *)iface - FIELD_OFFSET(StartMenu, initObjectVtbl));
63 }
64
65 HRESULT WINAPI StartMenu_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv)
66 {
67 StartMenu *This;
68
69 TRACE("StartMenu_Constructor(%p, %s, %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
70
71 if (pUnkOuter)
72 return E_POINTER;
73
74 This = CoTaskMemAlloc(sizeof(StartMenu));
75 if (!This)
76 return E_OUTOFMEMORY;
77 ZeroMemory(This, sizeof(*This));
78 This->vtbl = &StartMenuVtbl;
79 This->objectSiteVtbl = &StartMenu_ObjectWithSiteVtbl;
80 This->initObjectVtbl = &StartMenu_InitializeObjectVtbl;
81 This->menuBandVtbl = &StartMenu_MenuBandVtbl;
82 This->refCount = 1;
83
84 TRACE("StartMenu_Constructor returning %p\n", This);
85 *ppv = (IUnknown *)This;
86 return S_OK;
87 }
88
89 static void WINAPI StartMenu_Destructor(StartMenu *This)
90 {
91 TRACE("destroying %p\n", This);
92 if (This->pUnkSite) IUnknown_Release(This->pUnkSite);
93 CoTaskMemFree(This);
94 }
95
96 static HRESULT WINAPI StartMenu_QueryInterface(IMenuPopup *iface, REFIID iid, LPVOID *ppvOut)
97 {
98 StartMenu *This = impl_from_IMenuPopup(iface);
99 *ppvOut = NULL;
100
101 TRACE("StartMenu_QueryInterface (%p, %s, %p)\n", iface, debugstr_guid(iid), ppvOut);
102
103 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IOleWindow)
104 || IsEqualIID(iid, &IID_IDeskBar) || IsEqualIID(iid, &IID_IMenuPopup))
105 {
106 *ppvOut = (void *)&This->vtbl;
107 }
108 else if (IsEqualIID(iid, &IID_IObjectWithSite))
109 {
110 *ppvOut = (void *)&This->objectSiteVtbl;
111 }
112 else if (IsEqualIID(iid, &IID_IInitializeObject))
113 {
114 *ppvOut = (void *)&This->initObjectVtbl;
115 }
116
117 if (*ppvOut)
118 {
119 IUnknown_AddRef(iface);
120 return S_OK;
121 }
122
123 WARN("unsupported interface: %s\n", debugstr_guid(iid));
124 return E_NOINTERFACE;
125 }
126
127 static ULONG WINAPI StartMenu_AddRef(IMenuPopup *iface)
128 {
129 StartMenu *This = impl_from_IMenuPopup(iface);
130 TRACE("StartMenu_AddRef(%p)\n", iface);
131 return InterlockedIncrement(&This->refCount);
132 }
133
134 static ULONG WINAPI StartMenu_Release(IMenuPopup *iface)
135 {
136 StartMenu *This = impl_from_IMenuPopup(iface);
137 ULONG ret;
138
139 TRACE("StartMenu_Release(%p)\n", iface);
140
141 ret = InterlockedDecrement(&This->refCount);
142 if (ret == 0)
143 StartMenu_Destructor(This);
144 return ret;
145 }
146
147 static HRESULT WINAPI StartMenu_GetWindow(IMenuPopup *iface, HWND *phwnd)
148 {
149 FIXME("(%p, %p)\n", iface, phwnd);
150 return E_NOTIMPL;
151 }
152
153 static HRESULT WINAPI StartMenu_ContextSensitiveHelp(IMenuPopup *iface, BOOL fEnterMode)
154 {
155 FIXME("(%p, %d)\n", iface, fEnterMode);
156 return E_NOTIMPL;
157 }
158
159 static HRESULT WINAPI StartMenu_SetClient(IMenuPopup *iface, IUnknown *punkClient)
160 {
161 FIXME("(%p, %p)\n", iface, punkClient);
162 return E_NOTIMPL;
163 }
164
165 static HRESULT WINAPI StartMenu_GetClient(IMenuPopup *iface, IUnknown **ppunkClient)
166 {
167 StartMenu * This = (StartMenu*)iface;
168
169 TRACE("StartMenu_GetClient (%p, %p)\n", iface, ppunkClient);
170
171 *ppunkClient = (IUnknown*)This->pBandSite;
172 IUnknown_AddRef(*ppunkClient);
173 return S_OK;
174 }
175
176 static HRESULT WINAPI StartMenu_OnPosRectChangeDB(IMenuPopup *iface, LPRECT prc)
177 {
178 FIXME("(%p, %p)\n", iface, prc);
179 return E_NOTIMPL;
180 }
181
182 static HRESULT WINAPI StartMenu_Popup(IMenuPopup *iface, POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
183 {
184 FIXME("(%p, %p, %p, %x)\n", iface, ppt, prcExclude, dwFlags);
185 return E_NOTIMPL;
186 }
187
188 static HRESULT WINAPI StartMenu_OnSelect(IMenuPopup *iface, DWORD dwSelectType)
189 {
190 FIXME("(%p, %u)\n", iface, dwSelectType);
191 return E_NOTIMPL;
192 }
193
194 static HRESULT WINAPI StartMenu_SetSubMenu(IMenuPopup *iface, IMenuPopup *pmp, BOOL fSet)
195 {
196 FIXME("(%p, %p, %d)\n", iface, pmp, fSet);
197 return E_NOTIMPL;
198 }
199
200 static const IMenuPopupVtbl StartMenuVtbl =
201 {
202 /* IUnknown */
203 StartMenu_QueryInterface,
204 StartMenu_AddRef,
205 StartMenu_Release,
206
207 /* IOleWindow */
208 StartMenu_GetWindow,
209 StartMenu_ContextSensitiveHelp,
210
211 /* IDeskBar */
212 StartMenu_SetClient,
213 StartMenu_GetClient,
214 StartMenu_OnPosRectChangeDB,
215
216 /* IMenuPopup */
217 StartMenu_Popup,
218 StartMenu_OnSelect,
219 StartMenu_SetSubMenu,
220 };
221
222 static HRESULT WINAPI StartMenu_IObjectWithSite_QueryInterface(IObjectWithSite *iface, REFIID iid, LPVOID *ppvOut)
223 {
224 StartMenu *This = impl_from_IObjectWithSite(iface);
225 TRACE("(%p, %s, %p)\n", iface, debugstr_guid(iid), ppvOut);
226 return StartMenu_QueryInterface((IMenuPopup *)This, iid, ppvOut);
227 }
228
229 static ULONG WINAPI StartMenu_IObjectWithSite_AddRef(IObjectWithSite *iface)
230 {
231 StartMenu *This = impl_from_IObjectWithSite(iface);
232 TRACE("(%p)\n", iface);
233 return StartMenu_AddRef((IMenuPopup *)This);
234 }
235
236 static ULONG WINAPI StartMenu_IObjectWithSite_Release(IObjectWithSite *iface)
237 {
238 StartMenu *This = impl_from_IObjectWithSite(iface);
239 TRACE("StartMenu_IObjectWithSite_Release (%p)\n", iface);
240 return StartMenu_Release((IMenuPopup *)This);
241 }
242
243 static HRESULT WINAPI StartMenu_IObjectWithSite_SetSite(IObjectWithSite *iface, IUnknown *pUnkSite)
244 {
245 StartMenu *This = impl_from_IObjectWithSite(iface);
246
247 TRACE("StartMenu_IObjectWithSite_SetSite(%p, %p)\n", iface, pUnkSite);
248
249 if (This->pUnkSite)
250 IUnknown_Release(This->pUnkSite);
251 This->pUnkSite = pUnkSite;
252 if (This->pUnkSite)
253 IUnknown_AddRef(This->pUnkSite);
254 return S_OK;
255 }
256
257 static HRESULT WINAPI StartMenu_IObjectWithSite_GetSite(IObjectWithSite *iface, REFIID riid, void **ppvSite)
258 {
259 StartMenu *This = impl_from_IObjectWithSite(iface);
260
261 TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), ppvSite);
262
263 if (!This->pUnkSite)
264 return E_FAIL;
265
266 return IUnknown_QueryInterface(This->pUnkSite, riid, ppvSite);
267 }
268
269 static const IObjectWithSiteVtbl StartMenu_ObjectWithSiteVtbl =
270 {
271 StartMenu_IObjectWithSite_QueryInterface,
272 StartMenu_IObjectWithSite_AddRef,
273 StartMenu_IObjectWithSite_Release,
274
275 StartMenu_IObjectWithSite_SetSite,
276 StartMenu_IObjectWithSite_GetSite,
277 };
278
279 static HRESULT WINAPI StartMenu_IInitializeObject_QueryInterface(IInitializeObject *iface, REFIID iid, LPVOID *ppvOut)
280 {
281 StartMenu *This = impl_from_IInitializeObject(iface);
282 TRACE("(%p, %s, %p)\n", iface, debugstr_guid(iid), ppvOut);
283 return StartMenu_QueryInterface((IMenuPopup *)This, iid, ppvOut);
284 }
285
286 static ULONG WINAPI StartMenu_IInitializeObject_AddRef(IInitializeObject *iface)
287 {
288 StartMenu *This = impl_from_IInitializeObject(iface);
289 TRACE("StartMenu_IInitializeObject_AddRef(%p)\n", iface);
290 return StartMenu_AddRef((IMenuPopup *)This);
291 }
292
293 static ULONG WINAPI StartMenu_IInitializeObject_Release(IInitializeObject *iface)
294 {
295 StartMenu *This = impl_from_IInitializeObject(iface);
296 TRACE("StartMenu_IInitializeObject_Release (%p)\n", iface);
297 return StartMenu_Release((IMenuPopup *)This);
298 }
299
300 static HRESULT WINAPI StartMenu_IInitializeObject_Initialize(IInitializeObject *iface)
301 {
302 HRESULT hr;
303 StartMenu *This = impl_from_IInitializeObject(iface);
304 TRACE("StartMenu_IInitializeObject_Initialize (%p)\n", iface);
305
306 hr = MenuBandSite_Constructor(NULL, &IID_IBandSite, (LPVOID*)&This->pBandSite);
307 if (FAILED(hr))
308 return hr;
309
310 return IBandSite_AddBand(This->pBandSite, (IUnknown*)&This->menuBandVtbl);
311 }
312
313 static const IInitializeObjectVtbl StartMenu_InitializeObjectVtbl =
314 {
315 StartMenu_IInitializeObject_QueryInterface,
316 StartMenu_IInitializeObject_AddRef,
317 StartMenu_IInitializeObject_Release,
318
319 StartMenu_IInitializeObject_Initialize,
320 };
321
322 //--------------------------------------------------------------
323 // IMenuBand interface
324
325
326 static HRESULT STDMETHODCALLTYPE StartMenu_IMenuBand_QueryInterface(IMenuBand *iface, REFIID iid, LPVOID *ppvOut)
327 {
328 StartMenu *This = (StartMenu*)CONTAINING_RECORD(iface, StartMenu, menuBandVtbl);
329
330 if (IsEqualIID(iid, &IID_IUnknown) ||
331 IsEqualIID(iid, &IID_IMenuBand))
332 {
333 *ppvOut = &This->menuBandVtbl;
334 IUnknown_AddRef((IUnknown*)*ppvOut);
335 return S_OK;
336 }
337
338 WARN("unsupported interface:(%p, %s, %p)\n", iface, debugstr_guid(iid), ppvOut);
339 return E_NOINTERFACE;
340 }
341
342 static ULONG STDMETHODCALLTYPE StartMenu_IMenuBand_AddRef(IMenuBand *iface)
343 {
344 StartMenu *This = (StartMenu*)CONTAINING_RECORD(iface, StartMenu, menuBandVtbl);
345 TRACE("StartMenu_IInitializeObject_AddRef(%p)\n", This);
346 return StartMenu_AddRef((IMenuPopup *)This);
347 }
348
349 static ULONG STDMETHODCALLTYPE StartMenu_IMenuBand_Release(IMenuBand *iface)
350 {
351 StartMenu *This = (StartMenu*)CONTAINING_RECORD(iface, StartMenu, menuBandVtbl);
352 TRACE("StartMenu_IInitializeObject_Release (%p)\n", This);
353 return StartMenu_Release((IMenuPopup *)This);
354 }
355
356 HRESULT STDMETHODCALLTYPE StartMenu_IMenuBand_IsMenuMessage(IMenuBand *iface, MSG *pmsg)
357 {
358 StartMenu *This = (StartMenu*)CONTAINING_RECORD(iface, StartMenu, menuBandVtbl);
359 TRACE("StartMenu_IMenuBand_IsMenuMessage Stub(%p)\n", This);
360 return E_NOTIMPL;
361 }
362
363 HRESULT STDMETHODCALLTYPE StartMenu_IMenuBand_TranslateMenuMessage(IMenuBand *iface, MSG *pmsg, LRESULT *plRet)
364 {
365 StartMenu *This = (StartMenu*)CONTAINING_RECORD(iface, StartMenu, menuBandVtbl);
366 TRACE("StartMenu_IMenuBand_TranslateMenuMessage Stub(%p)\n", This);
367 return E_NOTIMPL;
368 }
369
370
371 static const IMenuBandVtbl StartMenu_MenuBandVtbl =
372 {
373 /* IUnknown methods */
374 StartMenu_IMenuBand_QueryInterface,
375 StartMenu_IMenuBand_AddRef,
376 StartMenu_IMenuBand_Release,
377 /* IMenuBand methods */
378 StartMenu_IMenuBand_IsMenuMessage,
379 StartMenu_IMenuBand_TranslateMenuMessage,
380 };
381
382
383 //---------------------------------------------------------------------------------------------------------
384 // IBandSite interface
385
386
387 HRESULT WINAPI MenuBandSite_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv)
388 {
389 MenuBandSite *This;
390 HRESULT hr;
391
392 TRACE("StartMenu_Constructor(%p, %s, %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
393
394 if (pUnkOuter)
395 return E_POINTER;
396
397 This = CoTaskMemAlloc(sizeof(MenuBandSite));
398 if (!This)
399 return E_OUTOFMEMORY;
400
401 ZeroMemory(This, sizeof(MenuBandSite));
402 This->lpVtbl = &StartMenu_BandSiteVtbl;
403
404 hr = IUnknown_QueryInterface((IUnknown*)&This->lpVtbl, riid, ppv);
405
406 if (FAILED(hr))
407 {
408 CoTaskMemFree(This);
409 return hr;
410 }
411
412 TRACE("StartMenu_Constructor returning %p\n", This);
413 *ppv = (IUnknown *)This;
414 return S_OK;
415 }
416
417 static HRESULT WINAPI BandSite_QueryInterface(IBandSite *iface, REFIID iid, LPVOID *ppvOut)
418 {
419 MenuBandSite *This = (MenuBandSite*)CONTAINING_RECORD(iface, MenuBandSite, lpVtbl);
420
421 if (IsEqualIID(iid, &IID_IUnknown) ||
422 IsEqualIID(iid, &IID_IBandSite))
423 {
424 *ppvOut = &This->lpVtbl;
425 IUnknown_AddRef((IUnknown*)*ppvOut);
426 return S_OK;
427 }
428
429 return E_NOINTERFACE;
430 }
431
432 static ULONG WINAPI BandSite_AddRef(IBandSite *iface)
433 {
434 MenuBandSite *This = (MenuBandSite*)CONTAINING_RECORD(iface, MenuBandSite, lpVtbl);
435 TRACE("BandSite_AddRef(%p)\n", iface);
436 return InterlockedIncrement(&This->refCount);
437 }
438
439 static ULONG WINAPI BandSite_Release(IBandSite *iface)
440 {
441 LONG ret;
442 MenuBandSite *This = (MenuBandSite*)CONTAINING_RECORD(iface, MenuBandSite, lpVtbl);
443
444 ret = InterlockedDecrement(&This->refCount);
445 TRACE("BandSite_Release refCount %u\n", ret);
446
447 if (ret == 0)
448 {
449 CoTaskMemFree(This->Objects);
450 CoTaskMemFree(This);
451 }
452
453 return ret;
454 }
455
456
457 static HRESULT STDMETHODCALLTYPE BandSite_AddBand(IBandSite *iface, IUnknown *punk)
458 {
459 IUnknown ** Objects;
460 MenuBandSite *This = (MenuBandSite*)CONTAINING_RECORD(iface, MenuBandSite, lpVtbl);
461
462 TRACE("StartMenu_IBandSite_AddBand Stub punk %p\n", punk);
463
464 if (!punk)
465 return E_FAIL;
466
467 Objects = (IUnknown**) CoTaskMemAlloc(sizeof(IUnknown*) * (This->ObjectsCount + 1));
468 if (!Objects)
469 return E_FAIL;
470
471 RtlMoveMemory(Objects, This->Objects, sizeof(IUnknown*) * This->ObjectsCount);
472
473 CoTaskMemFree(This->Objects);
474
475 This->Objects = Objects;
476 Objects[This->ObjectsCount] = punk;
477
478 IUnknown_AddRef(punk);
479
480 This->ObjectsCount++;
481
482
483 return S_OK;
484 }
485
486 static HRESULT STDMETHODCALLTYPE BandSite_EnumBands(IBandSite *iface, UINT uBand, DWORD *pdwBandID)
487 {
488 ULONG Index, ObjectCount;
489 MenuBandSite *This = (MenuBandSite*)CONTAINING_RECORD(iface, MenuBandSite, lpVtbl);
490
491 TRACE("StartMenu_IBandSite_EnumBands Stub uBand %uu pdwBandID %p\n", uBand, pdwBandID);
492
493 if (uBand == (UINT)-1)
494 return This->ObjectsCount;
495
496 ObjectCount = 0;
497
498 for(Index = 0; Index < This->ObjectsCount; Index++)
499 {
500 if (This->Objects[Index] != NULL)
501 {
502 if (uBand == ObjectCount)
503 {
504 *pdwBandID = Index;
505 return S_OK;
506 }
507 ObjectCount++;
508 }
509 }
510 return E_FAIL;
511 }
512
513 static HRESULT STDMETHODCALLTYPE BandSite_QueryBand(IBandSite *iface, DWORD dwBandID, IDeskBand **ppstb, DWORD *pdwState, LPWSTR pszName, int cchName)
514 {
515 FIXME("StartMenu_IBandSite_QueryBand Stub dwBandID %u IDeskBand %p pdwState %p Name %p cchName %u\n", dwBandID, ppstb, pdwState, pszName, cchName);
516 return E_FAIL;
517 }
518
519 static HRESULT STDMETHODCALLTYPE BandSite_SetBandState(IBandSite *iface, DWORD dwBandID, DWORD dwMask, DWORD dwState)
520 {
521 FIXME("StartMenu_IBandSite_SetBandState Stub dwBandID %u dwMask %x dwState %u\n", dwBandID, dwMask, dwState);
522 return E_FAIL;
523 }
524 static HRESULT STDMETHODCALLTYPE BandSite_RemoveBand(IBandSite *iface, DWORD dwBandID)
525 {
526 MenuBandSite *This = (MenuBandSite*)CONTAINING_RECORD(iface, MenuBandSite, lpVtbl);
527 TRACE("StartMenu_IBandSite_RemoveBand Stub dwBandID %u\n", dwBandID);
528
529 if (This->ObjectsCount <= dwBandID)
530 return E_FAIL;
531
532 if (This->Objects[dwBandID])
533 {
534 This->Objects[dwBandID]->lpVtbl->Release(This->Objects[dwBandID]);
535 This->Objects[dwBandID] = NULL;
536 }
537
538 return S_OK;
539 }
540
541 static HRESULT STDMETHODCALLTYPE BandSite_GetBandObject(IBandSite *iface, DWORD dwBandID, REFIID riid, void **ppv)
542 {
543 MenuBandSite *This = (MenuBandSite*)CONTAINING_RECORD(iface, MenuBandSite, lpVtbl);
544
545 TRACE("StartMenu_IBandSite_GetBandObject Stub dwBandID %u riid %p ppv %p\n", dwBandID, riid, ppv);
546
547 if (This->ObjectsCount <= dwBandID)
548 return E_FAIL;
549
550 if (This->Objects[dwBandID])
551 {
552 return IUnknown_QueryInterface(This->Objects[dwBandID], riid, ppv);
553 }
554
555 return E_FAIL;
556 }
557 static HRESULT STDMETHODCALLTYPE BandSite_SetBandSiteInfo(IBandSite *iface, const BANDSITEINFO *pbsinfo)
558 {
559 FIXME("StartMenu_IBandSite_SetBandSiteInfo Stub pbsinfo %p\n", pbsinfo);
560 return E_FAIL;
561
562 }
563 static HRESULT STDMETHODCALLTYPE BandSite_GetBandSiteInfo(IBandSite *iface, BANDSITEINFO *pbsinfo)
564 {
565 FIXME("StartMenu_IBandSite_GetBandSiteInfo Stub pbsinfo %p\n", pbsinfo);
566 return E_FAIL;
567 }
568
569 static const IBandSiteVtbl StartMenu_BandSiteVtbl =
570 {
571 BandSite_QueryInterface,
572 BandSite_AddRef,
573 BandSite_Release,
574 BandSite_AddBand,
575 BandSite_EnumBands,
576 BandSite_QueryBand,
577 BandSite_SetBandState,
578 BandSite_RemoveBand,
579 BandSite_GetBandObject,
580 BandSite_SetBandSiteInfo,
581 BandSite_GetBandSiteInfo
582 };
583