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 inline ULONG
Win32DbgPrint(const char * filename,int line,const char * lpFormat,...)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
34 fname = strrchr(filename, '\\');
35 if (fname == NULL)
36 {
37 fname = strrchr(filename, '/');
38 if (fname != NULL)
39 fname++;
40 }
41 else
42 fname++;
43
44 if (fname == NULL)
45 fname = filename;
46
47 szMsgStart = szMsg + sprintf(szMsg, "%s:%d: ", fname, line);
48
49 va_start(vl, lpFormat);
50 vsprintf(szMsgStart, lpFormat, vl);
51 va_end(vl);
52
53 OutputDebugStringA(szMsg);
54
55 /* Return STATUS_SUCCESS, since we are supposed to mimic DbgPrint */
56 return 0;
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
HResultFromWin32(DWORD hr)70 inline HRESULT HResultFromWin32(DWORD hr)
71 {
72 // HRESULT_FROM_WIN32 will evaluate its parameter twice, this function will not.
73 return HRESULT_FROM_WIN32(hr);
74 }
75
76 #if 1
77
_ROS_FAILED_HELPER(HRESULT hr,const char * expr,const char * filename,int line)78 inline BOOL _ROS_FAILED_HELPER(HRESULT hr, const char* expr, const char* filename, int line)
79 {
80 if (FAILED(hr))
81 {
82 Win32DbgPrint(filename, line, "Unexpected failure (%s)=%08x.\n", expr, hr);
83 return TRUE;
84 }
85 return FALSE;
86 }
87
88 #define FAILED_UNEXPECTEDLY(hr) _ROS_FAILED_HELPER((hr), #hr, __FILE__, __LINE__)
89 #else
90 #define FAILED_UNEXPECTEDLY(hr) FAILED(hr)
91 #endif
92
93 #ifdef __cplusplus
94 } /* extern "C" */
95 #endif /* defined(__cplusplus) */
96
97 static inline UINT
SHELL_ErrorBoxHelper(HWND hwndOwner,UINT Error)98 SHELL_ErrorBoxHelper(HWND hwndOwner, UINT Error)
99 {
100 WCHAR buf[400];
101 UINT cch;
102
103 if (!IsWindowVisible(hwndOwner))
104 hwndOwner = NULL;
105 if (Error == ERROR_SUCCESS)
106 Error = ERROR_INTERNAL_ERROR;
107
108 cch = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
109 NULL, Error, 0, buf, _countof(buf), NULL);
110 if (!cch)
111 {
112 enum { user32_IDS_ERROR = 2 }; // IDS_ERROR from user32 resource.h ("Error" string)
113 cch = LoadStringW(LoadLibraryW(L"USER32"), user32_IDS_ERROR, buf, _countof(buf));
114 wsprintfW(buf + cch, L"\n\n%#x (%d)", Error, Error);
115 }
116 MessageBoxW(hwndOwner, buf, NULL, MB_OK | MB_ICONSTOP);
117 return Error;
118 }
119 #ifdef __cplusplus
120 template<class H> static UINT
121 SHELL_ErrorBox(H hwndOwner, UINT Error = GetLastError())
122 {
123 return SHELL_ErrorBoxHelper(const_cast<HWND>(hwndOwner), Error);
124 }
125 #endif
126
127 #ifdef __cplusplus
128 template <typename T>
129 class CComCreatorCentralInstance
130 {
131 private:
132 static IUnknown *s_pInstance;
133
134 public:
CreateInstance(void * pv,REFIID riid,LPVOID * ppv)135 static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, LPVOID *ppv)
136 {
137 *ppv = NULL;
138 if (pv != NULL)
139 return CLASS_E_NOAGGREGATION;
140 if (!s_pInstance)
141 {
142 PVOID pObj;
143 HRESULT hr;
144 hr = ATL::CComCreator< T >::CreateInstance(NULL, IID_IUnknown, &pObj);
145 if (FAILED(hr))
146 return hr;
147 if (InterlockedCompareExchangePointer((PVOID *)&s_pInstance, pObj, NULL))
148 static_cast<IUnknown *>(pObj)->Release();
149 }
150 return s_pInstance->QueryInterface(riid, ppv);
151 }
Term()152 static void Term()
153 {
154 if (s_pInstance)
155 {
156 s_pInstance->Release();
157 s_pInstance = NULL;
158 }
159 }
160 };
161
162 template <typename T>
163 IUnknown *CComCreatorCentralInstance<T>::s_pInstance = NULL;
164
165 #define DECLARE_CENTRAL_INSTANCE_NOT_AGGREGATABLE(x) \
166 public: \
167 typedef CComCreatorCentralInstance< ATL::CComObject<x> > _CreatorClass;
168
169
170 template <class Base>
171 class CComDebugObject : public Base
172 {
173 public:
174 CComDebugObject(void * = NULL)
175 {
176 #if DEBUG_CCOMOBJECT_CREATION
177 DbgPrint("%S, this=%08p\n", __FUNCTION__, static_cast<Base*>(this));
178 #endif
179 _pAtlModule->Lock();
180 }
181
~CComDebugObject()182 virtual ~CComDebugObject()
183 {
184 this->FinalRelease();
185 _pAtlModule->Unlock();
186 }
187
STDMETHOD_(ULONG,AddRef)188 STDMETHOD_(ULONG, AddRef)()
189 {
190 int rc = this->InternalAddRef();
191 #if DEBUG_CCOMOBJECT_REFCOUNTING
192 DbgPrint("%s, RefCount is now %d(--)!\n", __FUNCTION__, rc);
193 #endif
194 return rc;
195 }
196
STDMETHOD_(ULONG,Release)197 STDMETHOD_(ULONG, Release)()
198 {
199 int rc = this->InternalRelease();
200
201 #if DEBUG_CCOMOBJECT_REFCOUNTING
202 DbgPrint("%s, RefCount is now %d(--)!\n", __FUNCTION__, rc);
203 #endif
204
205 if (rc == 0)
206 {
207 #if DEBUG_CCOMOBJECT_DESTRUCTION
208 DbgPrint("%s, RefCount reached 0 Deleting!\n", __FUNCTION__);
209 #endif
210 delete this;
211 }
212 return rc;
213 }
214
STDMETHOD(QueryInterface)215 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
216 {
217 return this->_InternalQueryInterface(iid, ppvObject);
218 }
219
CreateInstance(CComDebugObject<Base> ** pp)220 static HRESULT WINAPI CreateInstance(CComDebugObject<Base> **pp)
221 {
222 CComDebugObject<Base> *newInstance;
223 HRESULT hResult;
224
225 ATLASSERT(pp != NULL);
226 if (pp == NULL)
227 return E_POINTER;
228
229 hResult = E_OUTOFMEMORY;
230 newInstance = NULL;
231 ATLTRY(newInstance = new CComDebugObject<Base>());
232 if (newInstance != NULL)
233 {
234 newInstance->SetVoid(NULL);
235 newInstance->InternalFinalConstructAddRef();
236 hResult = newInstance->_AtlInitialConstruct();
237 if (SUCCEEDED(hResult))
238 hResult = newInstance->FinalConstruct();
239 if (SUCCEEDED(hResult))
240 hResult = newInstance->_AtlFinalConstruct();
241 newInstance->InternalFinalConstructRelease();
242 if (hResult != S_OK)
243 {
244 delete newInstance;
245 newInstance = NULL;
246 }
247 }
248 *pp = newInstance;
249 return hResult;
250 }
251 };
252
253 #ifdef DEBUG_CCOMOBJECT
254 # define _CComObject CComDebugObject
255 #else
256 # define _CComObject CComObject
257 #endif
258
259 template<class T>
260 ULONG ReleaseCComPtrExpectZeroHelper(const char *file, UINT line, CComPtr<T>& cptr, BOOL forceRelease = FALSE)
261 {
262 ULONG r = 0;
263 if (cptr.p != NULL)
264 {
265 T *raw = cptr.Detach();
266 int nrc = r = raw->Release();
267 if (nrc > 0)
268 Win32DbgPrint(file, line, "WARNING: Unexpected RefCount > 0 (%d)\n", nrc);
269 while (nrc > 0 && forceRelease)
270 {
271 nrc = raw->Release();
272 }
273 }
274 return r;
275 }
276 #define ReleaseCComPtrExpectZero(...) ReleaseCComPtrExpectZeroHelper(__FILE__, __LINE__, __VA_ARGS__)
277
278 template<class T, class R>
ShellDebugObjectCreator(REFIID riid,R ** ppv)279 HRESULT inline ShellDebugObjectCreator(REFIID riid, R ** ppv)
280 {
281 CComPtr<T> obj;
282 HRESULT hResult;
283
284 if (ppv == NULL)
285 return E_POINTER;
286 *ppv = NULL;
287 ATLTRY(obj = new CComDebugObject<T>);
288 if (obj.p == NULL)
289 return E_OUTOFMEMORY;
290 hResult = obj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
291 if (FAILED(hResult))
292 return hResult;
293 return S_OK;
294 }
295
296 template<class T>
ShellObjectCreator(CComPtr<T> & objref)297 HRESULT inline ShellObjectCreator(CComPtr<T> &objref)
298 {
299 _CComObject<T> *pobj;
300 HRESULT hResult = _CComObject<T>::CreateInstance(&pobj);
301 objref = pobj; // AddRef() gets called here
302 if (FAILED(hResult))
303 return hResult;
304 return S_OK;
305 }
306
307 template<class T>
ShellObjectCreator(REFIID riid,void ** ppv)308 HRESULT inline ShellObjectCreator(REFIID riid, void ** ppv)
309 {
310 _CComObject<T> *pobj;
311 HRESULT hResult;
312
313 hResult = _CComObject<T>::CreateInstance(&pobj);
314 if (FAILED(hResult))
315 return hResult;
316
317 pobj->AddRef(); /* CreateInstance returns object with 0 ref count */
318
319 hResult = pobj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
320
321 pobj->Release(); /* In case of failure the object will be released */
322
323 return hResult;
324 }
325
326 template<class T>
ShellObjectCreatorInit(REFIID riid,void ** ppv)327 HRESULT inline ShellObjectCreatorInit(REFIID riid, void ** ppv)
328 {
329 _CComObject<T> *pobj;
330 HRESULT hResult;
331
332 hResult = _CComObject<T>::CreateInstance(&pobj);
333 if (FAILED(hResult))
334 return hResult;
335
336 pobj->AddRef(); /* CreateInstance returns object with 0 ref count */
337
338 hResult = pobj->Initialize();
339
340 if (SUCCEEDED(hResult))
341 hResult = pobj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
342
343 pobj->Release(); /* In case of failure the object will be released */
344
345 return hResult;
346 }
347
348 template<class T, class T1>
ShellObjectCreatorInit(T1 initArg1,REFIID riid,void ** ppv)349 HRESULT inline ShellObjectCreatorInit(T1 initArg1, REFIID riid, void ** ppv)
350 {
351 _CComObject<T> *pobj;
352 HRESULT hResult;
353
354 hResult = _CComObject<T>::CreateInstance(&pobj);
355 if (FAILED(hResult))
356 return hResult;
357
358 pobj->AddRef(); /* CreateInstance returns object with 0 ref count */
359
360 hResult = pobj->Initialize(initArg1);
361
362 if (SUCCEEDED(hResult))
363 hResult = pobj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
364
365 pobj->Release(); /* In case of failure the object will be released */
366
367 return hResult;
368 }
369
370 template<class T, class T1, class T2>
ShellObjectCreatorInit(T1 initArg1,T2 initArg2,REFIID riid,void ** ppv)371 HRESULT inline ShellObjectCreatorInit(T1 initArg1, T2 initArg2, REFIID riid, void ** ppv)
372 {
373 _CComObject<T> *pobj;
374 HRESULT hResult;
375
376 hResult = _CComObject<T>::CreateInstance(&pobj);
377 if (FAILED(hResult))
378 return hResult;
379
380 pobj->AddRef(); /* CreateInstance returns object with 0 ref count */
381
382 hResult = pobj->Initialize(initArg1, initArg2);
383
384 if (SUCCEEDED(hResult))
385 hResult = pobj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
386
387 pobj->Release(); /* In case of failure the object will be released */
388
389 return hResult;
390 }
391
392 template<class T, class T1, class T2, class T3>
ShellObjectCreatorInit(T1 initArg1,T2 initArg2,T3 initArg3,REFIID riid,void ** ppv)393 HRESULT inline ShellObjectCreatorInit(T1 initArg1, T2 initArg2, T3 initArg3, REFIID riid, void ** ppv)
394 {
395 _CComObject<T> *pobj;
396 HRESULT hResult;
397
398 hResult = _CComObject<T>::CreateInstance(&pobj);
399 if (FAILED(hResult))
400 return hResult;
401
402 pobj->AddRef(); /* CreateInstance returns object with 0 ref count */
403
404 hResult = pobj->Initialize(initArg1, initArg2, initArg3);
405
406 if (SUCCEEDED(hResult))
407 hResult = pobj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
408
409 pobj->Release(); /* In case of failure the object will be released */
410
411 return hResult;
412 }
413
414 template<class T, class T1, class T2, class T3, class T4>
ShellObjectCreatorInit(T1 initArg1,T2 initArg2,T3 initArg3,T4 initArg4,REFIID riid,void ** ppv)415 HRESULT inline ShellObjectCreatorInit(T1 initArg1, T2 initArg2, T3 initArg3, T4 initArg4, REFIID riid, void ** ppv)
416 {
417 _CComObject<T> *pobj;
418 HRESULT hResult;
419
420 hResult = _CComObject<T>::CreateInstance(&pobj);
421 if (FAILED(hResult))
422 return hResult;
423
424 pobj->AddRef(); /* CreateInstance returns object with 0 ref count */
425
426 hResult = pobj->Initialize(initArg1, initArg2, initArg3, initArg4);
427
428 if (SUCCEEDED(hResult))
429 hResult = pobj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
430
431 pobj->Release(); /* In case of failure the object will be released */
432
433 return hResult;
434 }
435
436 template<class T, class T1, class T2, class T3, class T4, class T5>
ShellObjectCreatorInit(T1 initArg1,T2 initArg2,T3 initArg3,T4 initArg4,T5 initArg5,REFIID riid,void ** ppv)437 HRESULT inline ShellObjectCreatorInit(T1 initArg1, T2 initArg2, T3 initArg3, T4 initArg4, T5 initArg5, REFIID riid, void ** ppv)
438 {
439 _CComObject<T> *pobj;
440 HRESULT hResult;
441
442 hResult = _CComObject<T>::CreateInstance(&pobj);
443 if (FAILED(hResult))
444 return hResult;
445
446 pobj->AddRef(); /* CreateInstance returns object with 0 ref count */
447
448 hResult = pobj->Initialize(initArg1, initArg2, initArg3, initArg4, initArg5);
449
450 if (SUCCEEDED(hResult))
451 hResult = pobj->QueryInterface(riid, reinterpret_cast<void **>(ppv));
452
453 pobj->Release(); /* In case of failure the object will be released */
454
455 return hResult;
456 }
457
SHILClone(P pidl,R * ppOut)458 template<class P, class R> static HRESULT SHILClone(P pidl, R *ppOut)
459 {
460 R r = *ppOut = (R)ILClone((PIDLIST_RELATIVE)pidl);
461 return r ? S_OK : E_OUTOFMEMORY;
462 }
463
SHILCombine(B base,PCUIDLIST_RELATIVE sub,R * ppOut)464 template<class B, class R> static HRESULT SHILCombine(B base, PCUIDLIST_RELATIVE sub, R *ppOut)
465 {
466 R r = *ppOut = (R)ILCombine((PCIDLIST_ABSOLUTE)base, sub);
467 return r ? S_OK : E_OUTOFMEMORY;
468 }
469
StrIsNullOrEmpty(LPCSTR str)470 static inline bool StrIsNullOrEmpty(LPCSTR str) { return !str || !*str; }
StrIsNullOrEmpty(LPCWSTR str)471 static inline bool StrIsNullOrEmpty(LPCWSTR str) { return !str || !*str; }
472
SHSetStrRet(LPSTRRET pStrRet,LPCSTR pstrValue)473 HRESULT inline SHSetStrRet(LPSTRRET pStrRet, LPCSTR pstrValue)
474 {
475 pStrRet->uType = STRRET_CSTR;
476 strcpy(pStrRet->cStr, pstrValue);
477 return S_OK;
478 }
479
SHSetStrRet(LPSTRRET pStrRet,LPCWSTR pwstrValue)480 HRESULT inline SHSetStrRet(LPSTRRET pStrRet, LPCWSTR pwstrValue)
481 {
482 SIZE_T cchr = wcslen(pwstrValue);
483 LPWSTR buffer = static_cast<LPWSTR>(CoTaskMemAlloc((cchr + 1) * sizeof(WCHAR)));
484 if (buffer == NULL)
485 return E_OUTOFMEMORY;
486
487 pStrRet->uType = STRRET_WSTR;
488 pStrRet->pOleStr = buffer;
489 wcscpy(buffer, pwstrValue);
490 return S_OK;
491 }
492
SHSetStrRet(LPSTRRET pStrRet,HINSTANCE hInstance,DWORD resId)493 HRESULT inline SHSetStrRet(LPSTRRET pStrRet, HINSTANCE hInstance, DWORD resId)
494 {
495 WCHAR Buffer[MAX_PATH];
496
497 if (!LoadStringW(hInstance, resId, Buffer, MAX_PATH))
498 return E_FAIL;
499
500 return SHSetStrRet(pStrRet, Buffer);
501 }
502
DbgDumpMenuInternal(HMENU hmenu,char * padding,int padlevel)503 static inline void DbgDumpMenuInternal(HMENU hmenu, char* padding, int padlevel)
504 {
505 WCHAR label[128];
506 int i;
507 int count = GetMenuItemCount(hmenu);
508
509 padding[padlevel] = '.';
510 padding[padlevel + 1] = '.';
511 padding[padlevel + 2] = 0;
512
513 for (i = 0; i < count; i++)
514 {
515 MENUITEMINFOW mii = { 0 };
516
517 mii.cbSize = sizeof(mii);
518 mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_SUBMENU | MIIM_STATE | MIIM_ID;
519 mii.dwTypeData = label;
520 mii.cch = _countof(label);
521
522 GetMenuItemInfoW(hmenu, i, TRUE, &mii);
523
524 if (mii.fType & MFT_BITMAP)
525 DbgPrint("%s%2d - %08x: BITMAP %08p (state=%d, has submenu=%s)\n", padding, i, mii.wID, mii.hbmpItem, mii.fState, mii.hSubMenu ? "TRUE" : "FALSE");
526 else if (mii.fType & MFT_SEPARATOR)
527 DbgPrint("%s%2d - %08x ---SEPARATOR---\n", padding, i, mii.wID);
528 else
529 DbgPrint("%s%2d - %08x: %S (state=%d, has submenu=%s)\n", padding, i, mii.wID, mii.dwTypeData, mii.fState, mii.hSubMenu ? "TRUE" : "FALSE");
530
531 if (mii.hSubMenu)
532 DbgDumpMenuInternal(mii.hSubMenu, padding, padlevel + 2);
533
534 }
535
536 padding[padlevel] = 0;
537 }
538
DbgDumpMenu(HMENU hmenu)539 static __inline void DbgDumpMenu(HMENU hmenu)
540 {
541 char padding[128];
542 DbgDumpMenuInternal(hmenu, padding, 0);
543 }
544
545
546 static inline
DumpIdList(LPCITEMIDLIST pcidl)547 void DumpIdList(LPCITEMIDLIST pcidl)
548 {
549 DbgPrint("Begin IDList Dump\n");
550
551 for (; pcidl != NULL; pcidl = ILGetNext(pcidl))
552 {
553 int i;
554 int cb = pcidl->mkid.cb;
555 BYTE * sh = (BYTE*) &(pcidl->mkid);
556 if (cb == 0) // ITEMIDLISTs are terminatedwith a null SHITEMID.
557 break;
558 DbgPrint("Begin SHITEMID (cb=%d)\n", cb);
559 if ((cb & 3) != 0)
560 DbgPrint(" - WARNING: cb is not a multiple of 4\n");
561 for (i = 0; (i + 4) <= cb; i += 4)
562 {
563 DbgPrint(" - abID[%08x]: %02x %02x %02x %02x\n",
564 i,
565 sh[i + 0],
566 sh[i + 1],
567 sh[i + 2],
568 sh[i + 3]);
569 }
570 if (i < cb)
571 {
572 cb -= i;
573 if (cb == 3)
574 {
575 DbgPrint(" - abID[%08x]: %02x %02x %02x --\n",
576 i,
577 sh[i + 0],
578 sh[i + 1],
579 sh[i + 2]);
580 }
581 else if (cb == 2)
582 {
583 DbgPrint(" - abID[%08x]: %02x %02x -- --\n",
584 i,
585 sh[i + 0],
586 sh[i + 1]);
587 }
588 else if (cb == 1)
589 {
590 DbgPrint(" - abID[%08x]: %02x -- -- --\n",
591 i,
592 sh[i + 0]);
593 }
594 }
595 DbgPrint("End SHITEMID\n");
596 }
597 DbgPrint("End IDList Dump.\n");
598 }
599
600 template <HRESULT (WINAPI *InitFunc)(void*), void (WINAPI *UninitFunc)()>
601 struct CCoInitBase
602 {
603 HRESULT hr;
CCoInitBaseCCoInitBase604 CCoInitBase() : hr(InitFunc(NULL)) { }
~CCoInitBaseCCoInitBase605 ~CCoInitBase()
606 {
607 if (SUCCEEDED(hr))
608 UninitFunc();
609 }
610 };
611 typedef CCoInitBase<CoInitialize, CoUninitialize> CCoInit;
612 typedef CCoInitBase<OleInitialize, OleUninitialize> COleInit;
613
614 #endif /* __cplusplus */
615
616 #define S_LESSTHAN 0xffff
617 #define S_EQUAL S_OK
618 #define S_GREATERTHAN S_FALSE
619 #define MAKE_COMPARE_HRESULT(x) ((x)>0 ? S_GREATERTHAN : ((x)<0 ? S_LESSTHAN : S_EQUAL))
620
621 #define SEE_CMIC_COMMON_BASICFLAGS (SEE_MASK_NOASYNC | SEE_MASK_ASYNCOK | SEE_MASK_UNICODE | \
622 SEE_MASK_NO_CONSOLE | SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_SEPVDM | \
623 SEE_MASK_FLAG_LOG_USAGE | SEE_MASK_NOZONECHECKS)
624 #define SEE_CMIC_COMMON_FLAGS (SEE_CMIC_COMMON_BASICFLAGS | SEE_MASK_HOTKEY | SEE_MASK_ICON | \
625 SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE)
626
ILIsSingle(LPCITEMIDLIST pidl)627 static inline BOOL ILIsSingle(LPCITEMIDLIST pidl)
628 {
629 return pidl == ILFindLastID(pidl);
630 }
631
HIDA_GetPIDLFolder(CIDA const * pida)632 static inline PCUIDLIST_ABSOLUTE HIDA_GetPIDLFolder(CIDA const* pida)
633 {
634 return (PCUIDLIST_ABSOLUTE)(((LPBYTE)pida) + (pida)->aoffset[0]);
635 }
636
HIDA_GetPIDLItem(CIDA const * pida,SIZE_T i)637 static inline PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const* pida, SIZE_T i)
638 {
639 return (PCUIDLIST_RELATIVE)(((LPBYTE)pida) + (pida)->aoffset[i + 1]);
640 }
641
642
643 #ifdef __cplusplus
644
645 #if defined(CMIC_MASK_UNICODE) && defined(SEE_MASK_UNICODE)
IsUnicode(const CMINVOKECOMMANDINFOEX & ici)646 static inline bool IsUnicode(const CMINVOKECOMMANDINFOEX &ici)
647 {
648 const UINT minsize = FIELD_OFFSET(CMINVOKECOMMANDINFOEX, ptInvoke);
649 return (ici.fMask & CMIC_MASK_UNICODE) && ici.cbSize >= minsize;
650 }
651
IsUnicode(const CMINVOKECOMMANDINFO & ici)652 static inline bool IsUnicode(const CMINVOKECOMMANDINFO &ici)
653 {
654 return IsUnicode(*(CMINVOKECOMMANDINFOEX*)&ici);
655 }
656 #endif // CMIC_MASK_UNICODE
657
658 DECLSPEC_SELECTANY CLIPFORMAT g_cfHIDA = NULL;
659 DECLSPEC_SELECTANY CLIPFORMAT g_cfShellIdListOffsets = NULL;
660
661 // Allow to use the HIDA from an IDataObject without copying it
662 struct CDataObjectHIDA
663 {
664 private:
665 STGMEDIUM m_medium;
666 CIDA* m_cida;
667 HRESULT m_hr;
668
669 public:
CDataObjectHIDACDataObjectHIDA670 explicit CDataObjectHIDA(IDataObject* pDataObject)
671 : m_cida(nullptr)
672 {
673 m_hr = CreateCIDA(pDataObject, &m_cida, m_medium);
674 }
675
~CDataObjectHIDACDataObjectHIDA676 ~CDataObjectHIDA()
677 {
678 DestroyCIDA(m_cida, m_medium);
679 }
680
DestroyCIDACDataObjectHIDA681 static void DestroyCIDA(CIDA *pcida, STGMEDIUM &medium)
682 {
683 if (pcida)
684 ::GlobalUnlock(medium.hGlobal);
685 ReleaseStgMedium(&medium);
686 }
687
CreateCIDACDataObjectHIDA688 static HRESULT CreateCIDA(IDataObject* pDataObject, CIDA **ppcida, STGMEDIUM &medium)
689 {
690 *ppcida = NULL;
691 medium.pUnkForRelease = NULL;
692 if (g_cfHIDA == NULL)
693 g_cfHIDA = (CLIPFORMAT)RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
694
695 FORMATETC fmt = { g_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
696 HRESULT hr = pDataObject->GetData(&fmt, &medium);
697 if (SUCCEEDED(hr))
698 {
699 *ppcida = (CIDA*)::GlobalLock(medium.hGlobal);
700 if (*ppcida)
701 return S_OK;
702 ReleaseStgMedium(&medium);
703 hr = E_UNEXPECTED;
704 }
705 medium.tymed = TYMED_NULL;
706 return hr;
707 }
708
hrCDataObjectHIDA709 HRESULT hr() const
710 {
711 return m_hr;
712 }
713
714 operator bool() const
715 {
716 return m_cida != nullptr;
717 }
718
719 operator const CIDA* () const
720 {
721 return m_cida;
722 }
723
724 const CIDA* operator->() const
725 {
726 return m_cida;
727 }
728 };
729
730 inline
DataObject_GetData(IDataObject * pDataObject,CLIPFORMAT clipformat,PVOID pBuffer,SIZE_T dwBufferSize)731 HRESULT DataObject_GetData(IDataObject* pDataObject, CLIPFORMAT clipformat, PVOID pBuffer, SIZE_T dwBufferSize)
732 {
733 FORMATETC fmt = { clipformat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
734 STGMEDIUM medium = { TYMED_NULL };
735
736 HRESULT hr = pDataObject->GetData(&fmt, &medium);
737 if (SUCCEEDED(hr))
738 {
739 LPVOID blob = GlobalLock(medium.hGlobal);
740 if (blob)
741 {
742 SIZE_T size = GlobalSize(medium.hGlobal);
743 if (size <= dwBufferSize)
744 {
745 CopyMemory(pBuffer, blob, size);
746 hr = S_OK;
747 }
748 else
749 {
750 hr = E_OUTOFMEMORY;
751 }
752 GlobalUnlock(medium.hGlobal);
753 }
754 else
755 {
756 hr = STG_E_INVALIDHANDLE;
757 }
758
759 ReleaseStgMedium(&medium);
760 }
761 return hr;
762 }
763
764 inline
DataObject_SetData(IDataObject * pDataObject,CLIPFORMAT clipformat,PVOID pBuffer,SIZE_T dwBufferSize)765 HRESULT DataObject_SetData(IDataObject* pDataObject, CLIPFORMAT clipformat, PVOID pBuffer, SIZE_T dwBufferSize)
766 {
767 STGMEDIUM medium = { TYMED_HGLOBAL };
768
769 medium.hGlobal = GlobalAlloc(GHND, dwBufferSize);
770 if (!medium.hGlobal)
771 return E_OUTOFMEMORY;
772
773 HRESULT hr = E_UNEXPECTED;
774 LPVOID blob = GlobalLock(medium.hGlobal);
775 if (blob)
776 {
777 CopyMemory(blob, pBuffer, dwBufferSize);
778 GlobalUnlock(medium.hGlobal);
779
780 FORMATETC etc = { clipformat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
781 hr = pDataObject->SetData(&etc, &medium, TRUE);
782 }
783
784 if (FAILED(hr))
785 GlobalFree(medium.hGlobal);
786
787 return hr;
788 }
789
790
791 inline HRESULT
DataObject_GetOffset(IDataObject * pDataObject,POINT * point)792 DataObject_GetOffset(IDataObject *pDataObject, POINT *point)
793 {
794 if (g_cfShellIdListOffsets == NULL)
795 {
796 g_cfShellIdListOffsets = (CLIPFORMAT)RegisterClipboardFormatW(CFSTR_SHELLIDLISTOFFSETW);
797 }
798
799 point->x = point->y = 0;
800
801 return DataObject_GetData(pDataObject, g_cfShellIdListOffsets, point, sizeof(point[0]));
802 }
803
804 inline HRESULT
DataObject_SetOffset(IDataObject * pDataObject,POINT * point)805 DataObject_SetOffset(IDataObject* pDataObject, POINT* point)
806 {
807 if (g_cfShellIdListOffsets == NULL)
808 {
809 g_cfShellIdListOffsets = (CLIPFORMAT)RegisterClipboardFormatW(CFSTR_SHELLIDLISTOFFSETW);
810 }
811
812 return DataObject_SetData(pDataObject, g_cfShellIdListOffsets, point, sizeof(point[0]));
813 }
814
815 #endif // __cplusplus
816
817 #ifdef __cplusplus
818 struct SHELL_GetSettingImpl
819 {
820 SHELLSTATE ss;
SHELL_GetSettingImplSHELL_GetSettingImpl821 SHELL_GetSettingImpl(DWORD ssf) { SHGetSetSettings(&ss, ssf, FALSE); }
822 const SHELLSTATE* operator ->() { return &ss; }
823 };
824 #define SHELL_GetSetting(ssf, field) ( SHELL_GetSettingImpl(ssf)->field )
825 #else
826 #define SHELL_GetSetting(pss, ssf, field) ( SHGetSetSettings((pss), (ssf), FALSE), (pss)->field )
827 #endif
828
DumpIdListOneLine(LPCITEMIDLIST pidl)829 static inline void DumpIdListOneLine(LPCITEMIDLIST pidl)
830 {
831 char buf[1024], *data, drive = 0;
832 for (UINT depth = 0, type; ; pidl = ILGetNext(pidl), ++depth)
833 {
834 if (!pidl || !pidl->mkid.cb)
835 {
836 if (!depth)
837 {
838 wsprintfA(buf, "%p [] (%s)\n", pidl, pidl ? "Empty/Desktop" : "NULL");
839 OutputDebugStringA(buf);
840 }
841 break;
842 }
843 else if (!depth)
844 {
845 wsprintfA(buf, "%p", pidl);
846 OutputDebugStringA(buf);
847 }
848 type = pidl->mkid.abID[0] & 0x7f;
849 data = (char*)&pidl->mkid.abID[0];
850 if (depth == 0 && type == 0x1f && pidl->mkid.cb == 20 && *(UINT*)(&data[2]) == 0x20D04FE0)
851 {
852 wsprintfA(buf, " [%.2x ThisPC?]", type); /* "?" because we did not check the full GUID */
853 }
854 else if (depth == 1 && type >= 0x20 && type < 0x30 && type != 0x2E && pidl->mkid.cb > 4)
855 {
856 drive = data[1];
857 wsprintfA(buf, " [%.2x %c: %ub]", type, drive, pidl->mkid.cb);
858 }
859 else if (depth >= 2 && drive && (type & 0x70) == 0x30) /* PT_FS */
860 {
861 if (type & 4)
862 wsprintfA(buf, " [%.2x FS %.256ls %ub]", type, data + 12, pidl->mkid.cb);
863 else
864 wsprintfA(buf, " [%.2x FS %.256hs %ub]", type, data + 12, pidl->mkid.cb);
865 }
866 else
867 {
868 wsprintfA(buf, " [%.2x ? %ub]", type, pidl->mkid.cb);
869 }
870 OutputDebugStringA(buf);
871 }
872 OutputDebugStringA("\n");
873 }
874
875 #endif /* __ROS_SHELL_UTILS_H */
876