[HEADERS] Move some helpers from undocshell.h to shellutils.h as they didn't cover...
[reactos.git] / sdk / include / reactos / shellutils.h
1 /*
2 * Copyright 1999, 2000 Juergen Schmied
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #ifndef __ROS_SHELL_UTILS_H
20 #define __ROS_SHELL_UTILS_H
21
22 #ifdef __cplusplus
23 extern "C" {
24 #endif /* defined(__cplusplus) */
25
26 static inline ULONG
27 Win32DbgPrint(const char *filename, int line, const char *lpFormat, ...)
28 {
29 char szMsg[512];
30 char *szMsgStart;
31 const char *fname;
32 va_list vl;
33 ULONG uRet;
34
35 fname = strrchr(filename, '\\');
36 if (fname == NULL)
37 {
38 fname = strrchr(filename, '/');
39 if (fname != NULL)
40 fname++;
41 }
42 else
43 fname++;
44
45 if (fname == NULL)
46 fname = filename;
47
48 szMsgStart = szMsg + sprintf(szMsg, "%s:%d: ", fname, line);
49
50 va_start(vl, lpFormat);
51 uRet = (ULONG) vsprintf(szMsgStart, lpFormat, vl);
52 va_end(vl);
53
54 OutputDebugStringA(szMsg);
55
56 return uRet;
57 }
58
59 #define DbgPrint(fmt, ...) \
60 Win32DbgPrint(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
61
62 #ifdef __cplusplus
63 # define IID_PPV_ARG(Itype, ppType) IID_##Itype, reinterpret_cast<void**>((static_cast<Itype**>(ppType)))
64 # define IID_NULL_PPV_ARG(Itype, ppType) IID_##Itype, NULL, reinterpret_cast<void**>((static_cast<Itype**>(ppType)))
65 #else
66 # define IID_PPV_ARG(Itype, ppType) IID_##Itype, (void**)(ppType)
67 # define IID_NULL_PPV_ARG(Itype, ppType) IID_##Itype, NULL, (void**)(ppType)
68 #endif
69
70 #if 1
71 #define FAILED_UNEXPECTEDLY(hr) (FAILED(hr) && (Win32DbgPrint(__FILE__, __LINE__, "Unexpected failure %08x.\n", hr), TRUE))
72 #else
73 #define FAILED_UNEXPECTEDLY(hr) FAILED(hr)
74 #endif
75
76 #ifdef __cplusplus
77 } /* extern "C" */
78 #endif /* defined(__cplusplus) */
79
80 #ifdef __cplusplus
81 template <typename T>
82 class CComCreatorCentralInstance
83 {
84 private:
85 static IUnknown *s_pInstance;
86
87 public:
88 static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, LPVOID *ppv)
89 {
90 *ppv = NULL;
91 if (pv != NULL)
92 return CLASS_E_NOAGGREGATION;
93 if (!s_pInstance)
94 {
95 PVOID pObj;
96 HRESULT hr;
97 hr = ATL::CComCreator< T >::CreateInstance(NULL, IID_IUnknown, &pObj);
98 if (FAILED(hr))
99 return hr;
100 if (InterlockedCompareExchangePointer((PVOID *)&s_pInstance, pObj, NULL))
101 static_cast<IUnknown *>(pObj)->Release();
102 }
103 return s_pInstance->QueryInterface(riid, ppv);
104 }
105 static void Term()
106 {
107 if (s_pInstance)
108 {
109 s_pInstance->Release();
110 s_pInstance = NULL;
111 }
112 }
113 };
114
115 template <typename T>
116 IUnknown *CComCreatorCentralInstance<T>::s_pInstance = NULL;
117
118 #define DECLARE_CENTRAL_INSTANCE_NOT_AGGREGATABLE(x) \
119 public: \
120 typedef CComCreatorCentralInstance< ATL::CComObject<x> > _CreatorClass;
121 #endif
122
123 #ifdef __cplusplus
124 template <class Base>
125 class CComDebugObject : public Base
126 {
127 public:
128 CComDebugObject(void * = NULL)
129 {
130 #if DEBUG_CCOMOBJECT_CREATION
131 DbgPrint("%S, this=%08p\n", __FUNCTION__, static_cast<Base*>(this));
132 #endif
133 _pAtlModule->Lock();
134 }
135
136 virtual ~CComDebugObject()
137 {
138 this->FinalRelease();
139 _pAtlModule->Unlock();
140 }
141
142 STDMETHOD_(ULONG, AddRef)()
143 {
144 int rc = this->InternalAddRef();
145 #if DEBUG_CCOMOBJECT_REFCOUNTING
146 DbgPrint("%s, RefCount is now %d(--)! \n", __FUNCTION__, rc);
147 #endif
148 return rc;
149 }
150
151 STDMETHOD_(ULONG, Release)()
152 {
153 int rc = this->InternalRelease();
154
155 #if DEBUG_CCOMOBJECT_REFCOUNTING
156 DbgPrint("%s, RefCount is now %d(--)! \n", __FUNCTION__, rc);
157 #endif
158
159 if (rc == 0)
160 {
161 #if DEBUG_CCOMOBJECT_DESTRUCTION
162 DbgPrint("%s, RefCount reached 0 Deleting!\n", __FUNCTION__);
163 #endif
164 delete this;
165 }
166 return rc;
167 }
168
169 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
170 {
171 return this->_InternalQueryInterface(iid, ppvObject);
172 }
173
174 static HRESULT WINAPI CreateInstance(CComDebugObject<Base> **pp)
175 {
176 CComDebugObject<Base> *newInstance;
177 HRESULT hResult;
178
179 ATLASSERT(pp != NULL);
180 if (pp == NULL)
181 return E_POINTER;
182
183 hResult = E_OUTOFMEMORY;
184 newInstance = NULL;
185 ATLTRY(newInstance = new CComDebugObject<Base>());
186 if (newInstance != NULL)
187 {
188 newInstance->SetVoid(NULL);
189 newInstance->InternalFinalConstructAddRef();
190 hResult = newInstance->_AtlInitialConstruct();
191 if (SUCCEEDED(hResult))
192 hResult = newInstance->FinalConstruct();
193 if (SUCCEEDED(hResult))
194 hResult = newInstance->_AtlFinalConstruct();
195 newInstance->InternalFinalConstructRelease();
196 if (hResult != S_OK)
197 {
198 delete newInstance;
199 newInstance = NULL;
200 }
201 }
202 *pp = newInstance;
203 return hResult;
204 }
205 };
206
207 #ifdef DEBUG_CCOMOBJECT
208 # define _CComObject CComDebugObject
209 #else
210 # define _CComObject CComObject
211 #endif
212
213 template<class T>
214 void ReleaseCComPtrExpectZero(CComPtr<T>& cptr, BOOL forceRelease = FALSE)
215 {
216 if (cptr.p != NULL)
217 {
218 int nrc = cptr->Release();
219 if (nrc > 0)
220 {
221 DbgPrint("WARNING: Unexpected RefCount > 0 (%d)!\n", nrc);
222 if (forceRelease)
223 {
224 while (nrc > 0)
225 {
226 nrc = cptr->Release();
227 }
228 }
229 }
230 cptr.Detach();
231 }
232 }
233
234 template<class T, class R>
235 HRESULT inline ShellDebugObjectCreator(REFIID riid, R ** ppv)
236 {
237 CComPtr<T> obj;
238 HRESULT hResult;
239
240 if (ppv == NULL)
241 return E_POINTER;
242 *ppv = NULL;
243 ATLTRY(obj = new CComDebugObject<T>);
244 if (obj.p == NULL)
245 return E_OUTOFMEMORY;
246 hResult = obj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
247 if (FAILED(hResult))
248 return hResult;
249 return S_OK;
250 }
251
252 template<class T>
253 HRESULT inline ShellObjectCreator(REFIID riid, void ** ppv)
254 {
255 _CComObject<T> *pobj;
256 HRESULT hResult;
257
258 hResult = _CComObject<T>::CreateInstance(&pobj);
259 if (FAILED(hResult))
260 return hResult;
261
262 pobj->AddRef(); /* CreateInstance returns object with 0 ref count */
263
264 hResult = pobj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
265
266 pobj->Release(); /* In case of failure the object will be released */
267
268 return hResult;
269 }
270
271 template<class T>
272 HRESULT inline ShellObjectCreatorInit(REFIID riid, void ** ppv)
273 {
274 _CComObject<T> *pobj;
275 HRESULT hResult;
276
277 hResult = _CComObject<T>::CreateInstance(&pobj);
278 if (FAILED(hResult))
279 return hResult;
280
281 pobj->AddRef(); /* CreateInstance returns object with 0 ref count */
282
283 hResult = pobj->Initialize();
284
285 if (SUCCEEDED(hResult))
286 hResult = pobj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
287
288 pobj->Release(); /* In case of failure the object will be released */
289
290 return hResult;
291 }
292
293 template<class T, class T1>
294 HRESULT inline ShellObjectCreatorInit(T1 initArg1, REFIID riid, void ** ppv)
295 {
296 _CComObject<T> *pobj;
297 HRESULT hResult;
298
299 hResult = _CComObject<T>::CreateInstance(&pobj);
300 if (FAILED(hResult))
301 return hResult;
302
303 pobj->AddRef(); /* CreateInstance returns object with 0 ref count */
304
305 hResult = pobj->Initialize(initArg1);
306
307 if (SUCCEEDED(hResult))
308 hResult = pobj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
309
310 pobj->Release(); /* In case of failure the object will be released */
311
312 return hResult;
313 }
314
315 template<class T, class T1, class T2>
316 HRESULT inline ShellObjectCreatorInit(T1 initArg1, T2 initArg2, REFIID riid, void ** ppv)
317 {
318 _CComObject<T> *pobj;
319 HRESULT hResult;
320
321 hResult = _CComObject<T>::CreateInstance(&pobj);
322 if (FAILED(hResult))
323 return hResult;
324
325 pobj->AddRef(); /* CreateInstance returns object with 0 ref count */
326
327 hResult = pobj->Initialize(initArg1, initArg2);
328
329 if (SUCCEEDED(hResult))
330 hResult = pobj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
331
332 pobj->Release(); /* In case of failure the object will be released */
333
334 return hResult;
335 }
336
337 template<class T, class T1, class T2, class T3>
338 HRESULT inline ShellObjectCreatorInit(T1 initArg1, T2 initArg2, T3 initArg3, REFIID riid, void ** ppv)
339 {
340 _CComObject<T> *pobj;
341 HRESULT hResult;
342
343 hResult = _CComObject<T>::CreateInstance(&pobj);
344 if (FAILED(hResult))
345 return hResult;
346
347 pobj->AddRef(); /* CreateInstance returns object with 0 ref count */
348
349 hResult = pobj->Initialize(initArg1, initArg2, initArg3);
350
351 if (SUCCEEDED(hResult))
352 hResult = pobj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
353
354 pobj->Release(); /* In case of failure the object will be released */
355
356 return hResult;
357 }
358
359 template<class T, class T1, class T2, class T3, class T4>
360 HRESULT inline ShellObjectCreatorInit(T1 initArg1, T2 initArg2, T3 initArg3, T4 initArg4, REFIID riid, void ** ppv)
361 {
362 _CComObject<T> *pobj;
363 HRESULT hResult;
364
365 hResult = _CComObject<T>::CreateInstance(&pobj);
366 if (FAILED(hResult))
367 return hResult;
368
369 pobj->AddRef(); /* CreateInstance returns object with 0 ref count */
370
371 hResult = pobj->Initialize(initArg1, initArg2, initArg3, initArg4);
372
373 if (SUCCEEDED(hResult))
374 hResult = pobj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
375
376 pobj->Release(); /* In case of failure the object will be released */
377
378 return hResult;
379 }
380
381 HRESULT inline SHSetStrRet(LPSTRRET pStrRet, LPCSTR pstrValue)
382 {
383 pStrRet->uType = STRRET_CSTR;
384 strcpy(pStrRet->cStr, pstrValue);
385 return S_OK;
386 }
387
388 HRESULT inline SHSetStrRet(LPSTRRET pStrRet, LPCWSTR pwstrValue)
389 {
390 SIZE_T cchr = wcslen(pwstrValue);
391 LPWSTR buffer = static_cast<LPWSTR>(CoTaskMemAlloc((cchr + 1) * sizeof(WCHAR)));
392 if (buffer == NULL)
393 return E_OUTOFMEMORY;
394
395 pStrRet->uType = STRRET_WSTR;
396 pStrRet->pOleStr = buffer;
397 wcscpy(buffer, pwstrValue);
398 return S_OK;
399 }
400
401 HRESULT inline SHSetStrRet(LPSTRRET pStrRet, HINSTANCE hInstance, DWORD resId)
402 {
403 WCHAR Buffer[MAX_PATH];
404
405 if (!LoadStringW(hInstance, resId, Buffer, MAX_PATH))
406 return E_FAIL;
407
408 return SHSetStrRet(pStrRet, Buffer);
409 }
410
411 static inline void DbgDumpMenuInternal(HMENU hmenu, char* padding, int padlevel)
412 {
413 WCHAR label[128];
414 int i;
415 int count = GetMenuItemCount(hmenu);
416
417 padding[padlevel] = '.';
418 padding[padlevel + 1] = '.';
419 padding[padlevel + 2] = 0;
420
421 for (i = 0; i < count; i++)
422 {
423 MENUITEMINFOW mii = { 0 };
424
425 mii.cbSize = sizeof(mii);
426 mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_SUBMENU | MIIM_STATE | MIIM_ID;
427 mii.dwTypeData = label;
428 mii.cch = _countof(label);
429
430 GetMenuItemInfoW(hmenu, i, TRUE, &mii);
431
432 if (mii.fType & MFT_BITMAP)
433 DbgPrint("%s%2d - %08x: BITMAP %08p (state=%d, has submenu=%s)\n", padding, i, mii.wID, mii.hbmpItem, mii.fState, mii.hSubMenu ? "TRUE" : "FALSE");
434 else if (mii.fType & MFT_SEPARATOR)
435 DbgPrint("%s%2d - %08x ---SEPARATOR---\n", padding, i, mii.wID);
436 else
437 DbgPrint("%s%2d - %08x: %S (state=%d, has submenu=%s)\n", padding, i, mii.wID, mii.dwTypeData, mii.fState, mii.hSubMenu ? "TRUE" : "FALSE");
438
439 if (mii.hSubMenu)
440 DbgDumpMenuInternal(mii.hSubMenu, padding, padlevel + 2);
441
442 }
443
444 padding[padlevel] = 0;
445 }
446
447 static __inline void DbgDumpMenu(HMENU hmenu)
448 {
449 char padding[128];
450 DbgDumpMenuInternal(hmenu, padding, 0);
451 }
452
453
454 static inline
455 void DumpIdList(LPCITEMIDLIST pcidl)
456 {
457 DbgPrint("Begin IDList Dump\n");
458
459 for (; pcidl != NULL; pcidl = ILGetNext(pcidl))
460 {
461 int i;
462 int cb = pcidl->mkid.cb;
463 BYTE * sh = (BYTE*) &(pcidl->mkid);
464 if (cb == 0) // ITEMIDLISTs are terminatedwith a null SHITEMID.
465 break;
466 DbgPrint("Begin SHITEMID (cb=%d)\n", cb);
467 if ((cb & 3) != 0)
468 DbgPrint(" - WARNING: cb is not a multiple of 4\n");
469 for (i = 0; (i + 4) <= cb; i += 4)
470 {
471 DbgPrint(" - abID[%08x]: %02x %02x %02x %02x\n",
472 i,
473 sh[i + 0],
474 sh[i + 1],
475 sh[i + 2],
476 sh[i + 3]);
477 }
478 if (i < cb)
479 {
480 cb -= i;
481 if (cb == 3)
482 {
483 DbgPrint(" - abID[%08x]: %02x %02x %02x --\n",
484 i,
485 sh[i + 0],
486 sh[i + 1],
487 sh[i + 2]);
488 }
489 else if (cb == 2)
490 {
491 DbgPrint(" - abID[%08x]: %02x %02x -- --\n",
492 i,
493 sh[i + 0],
494 sh[i + 1]);
495 }
496 else if (cb == 1)
497 {
498 DbgPrint(" - abID[%08x]: %02x -- -- --\n",
499 i,
500 sh[i + 0]);
501 }
502 }
503 DbgPrint("End SHITEMID\n");
504 }
505 DbgPrint("End IDList Dump.\n");
506 }
507
508 #endif /* __cplusplus */
509
510 #define S_LESSTHAN 0xffff
511 #define S_EQUAL S_OK
512 #define S_GREATERTHAN S_FALSE
513 #define MAKE_COMPARE_HRESULT(x) ((x)>0 ? S_GREATERTHAN : ((x)<0 ? S_LESSTHAN : S_EQUAL))
514
515 #endif /* __ROS_SHELL_UTILS_H */