xref: /reactos/sdk/include/reactos/shellutils.h (revision 6ae11ba0)
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 struct CCoInit
601 {
CCoInitCCoInit602     CCoInit()
603     {
604         hr = CoInitialize(NULL);
605     }
~CCoInitCCoInit606     ~CCoInit()
607     {
608         if (SUCCEEDED(hr))
609         {
610             CoUninitialize();
611         }
612     }
613     HRESULT hr;
614 };
615 
616 #endif /* __cplusplus */
617 
618 #define S_LESSTHAN 0xffff
619 #define S_EQUAL S_OK
620 #define S_GREATERTHAN S_FALSE
621 #define MAKE_COMPARE_HRESULT(x) ((x)>0 ? S_GREATERTHAN : ((x)<0 ? S_LESSTHAN : S_EQUAL))
622 
623 #define SEE_CMIC_COMMON_BASICFLAGS (SEE_MASK_NOASYNC | SEE_MASK_ASYNCOK | SEE_MASK_UNICODE | \
624                                     SEE_MASK_NO_CONSOLE | SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_SEPVDM | \
625                                     SEE_MASK_FLAG_LOG_USAGE | SEE_MASK_NOZONECHECKS)
626 #define SEE_CMIC_COMMON_FLAGS      (SEE_CMIC_COMMON_BASICFLAGS | SEE_MASK_HOTKEY | SEE_MASK_ICON | \
627                                     SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE)
628 
ILIsSingle(LPCITEMIDLIST pidl)629 static inline BOOL ILIsSingle(LPCITEMIDLIST pidl)
630 {
631     return pidl == ILFindLastID(pidl);
632 }
633 
HIDA_GetPIDLFolder(CIDA const * pida)634 static inline PCUIDLIST_ABSOLUTE HIDA_GetPIDLFolder(CIDA const* pida)
635 {
636     return (PCUIDLIST_ABSOLUTE)(((LPBYTE)pida) + (pida)->aoffset[0]);
637 }
638 
HIDA_GetPIDLItem(CIDA const * pida,SIZE_T i)639 static inline PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const* pida, SIZE_T i)
640 {
641     return (PCUIDLIST_RELATIVE)(((LPBYTE)pida) + (pida)->aoffset[i + 1]);
642 }
643 
644 
645 #ifdef __cplusplus
646 
647 #if defined(CMIC_MASK_UNICODE) && defined(SEE_MASK_UNICODE)
IsUnicode(const CMINVOKECOMMANDINFOEX & ici)648 static inline bool IsUnicode(const CMINVOKECOMMANDINFOEX &ici)
649 {
650     const UINT minsize = FIELD_OFFSET(CMINVOKECOMMANDINFOEX, ptInvoke);
651     return (ici.fMask & CMIC_MASK_UNICODE) && ici.cbSize >= minsize;
652 }
653 
IsUnicode(const CMINVOKECOMMANDINFO & ici)654 static inline bool IsUnicode(const CMINVOKECOMMANDINFO &ici)
655 {
656     return IsUnicode(*(CMINVOKECOMMANDINFOEX*)&ici);
657 }
658 #endif // CMIC_MASK_UNICODE
659 
660 DECLSPEC_SELECTANY CLIPFORMAT g_cfHIDA = NULL;
661 DECLSPEC_SELECTANY CLIPFORMAT g_cfShellIdListOffsets = NULL;
662 
663 // Allow to use the HIDA from an IDataObject without copying it
664 struct CDataObjectHIDA
665 {
666 private:
667     STGMEDIUM m_medium;
668     CIDA* m_cida;
669     HRESULT m_hr;
670 
671 public:
CDataObjectHIDACDataObjectHIDA672     explicit CDataObjectHIDA(IDataObject* pDataObject)
673         : m_cida(nullptr)
674     {
675         m_hr = CreateCIDA(pDataObject, &m_cida, m_medium);
676     }
677 
~CDataObjectHIDACDataObjectHIDA678     ~CDataObjectHIDA()
679     {
680         DestroyCIDA(m_cida, m_medium);
681     }
682 
DestroyCIDACDataObjectHIDA683     static void DestroyCIDA(CIDA *pcida, STGMEDIUM &medium)
684     {
685         if (pcida)
686             ::GlobalUnlock(medium.hGlobal);
687         ReleaseStgMedium(&medium);
688     }
689 
CreateCIDACDataObjectHIDA690     static HRESULT CreateCIDA(IDataObject* pDataObject, CIDA **ppcida, STGMEDIUM &medium)
691     {
692         *ppcida = NULL;
693         medium.pUnkForRelease = NULL;
694         if (g_cfHIDA == NULL)
695             g_cfHIDA = (CLIPFORMAT)RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
696 
697         FORMATETC fmt = { g_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
698         HRESULT hr = pDataObject->GetData(&fmt, &medium);
699         if (SUCCEEDED(hr))
700         {
701             *ppcida = (CIDA*)::GlobalLock(medium.hGlobal);
702             if (*ppcida)
703                 return S_OK;
704             ReleaseStgMedium(&medium);
705             hr = E_UNEXPECTED;
706         }
707         medium.tymed = TYMED_NULL;
708         return hr;
709     }
710 
hrCDataObjectHIDA711     HRESULT hr() const
712     {
713         return m_hr;
714     }
715 
716     operator bool() const
717     {
718         return m_cida != nullptr;
719     }
720 
721     operator const CIDA* () const
722     {
723         return m_cida;
724     }
725 
726     const CIDA* operator->() const
727     {
728         return m_cida;
729     }
730 };
731 
732 inline
DataObject_GetData(IDataObject * pDataObject,CLIPFORMAT clipformat,PVOID pBuffer,SIZE_T dwBufferSize)733 HRESULT DataObject_GetData(IDataObject* pDataObject, CLIPFORMAT clipformat, PVOID pBuffer, SIZE_T dwBufferSize)
734 {
735     FORMATETC fmt = { clipformat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
736     STGMEDIUM medium = { TYMED_NULL };
737 
738     HRESULT hr = pDataObject->GetData(&fmt, &medium);
739     if (SUCCEEDED(hr))
740     {
741         LPVOID blob = GlobalLock(medium.hGlobal);
742         if (blob)
743         {
744             SIZE_T size = GlobalSize(medium.hGlobal);
745             if (size <= dwBufferSize)
746             {
747                 CopyMemory(pBuffer, blob, size);
748                 hr = S_OK;
749             }
750             else
751             {
752                 hr = E_OUTOFMEMORY;
753             }
754             GlobalUnlock(medium.hGlobal);
755         }
756         else
757         {
758             hr = STG_E_INVALIDHANDLE;
759         }
760 
761         ReleaseStgMedium(&medium);
762     }
763     return hr;
764 }
765 
766 inline
DataObject_SetData(IDataObject * pDataObject,CLIPFORMAT clipformat,PVOID pBuffer,SIZE_T dwBufferSize)767 HRESULT DataObject_SetData(IDataObject* pDataObject, CLIPFORMAT clipformat, PVOID pBuffer, SIZE_T dwBufferSize)
768 {
769     STGMEDIUM medium = { TYMED_HGLOBAL };
770 
771     medium.hGlobal = GlobalAlloc(GHND, dwBufferSize);
772     if (!medium.hGlobal)
773         return E_OUTOFMEMORY;
774 
775     HRESULT hr = E_UNEXPECTED;
776     LPVOID blob = GlobalLock(medium.hGlobal);
777     if (blob)
778     {
779         CopyMemory(blob, pBuffer, dwBufferSize);
780         GlobalUnlock(medium.hGlobal);
781 
782         FORMATETC etc = { clipformat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
783         hr = pDataObject->SetData(&etc, &medium, TRUE);
784     }
785 
786     if (FAILED(hr))
787         GlobalFree(medium.hGlobal);
788 
789     return hr;
790 }
791 
792 
793 inline HRESULT
DataObject_GetOffset(IDataObject * pDataObject,POINT * point)794 DataObject_GetOffset(IDataObject *pDataObject, POINT *point)
795 {
796     if (g_cfShellIdListOffsets == NULL)
797     {
798         g_cfShellIdListOffsets = (CLIPFORMAT)RegisterClipboardFormatW(CFSTR_SHELLIDLISTOFFSETW);
799     }
800 
801     point->x = point->y = 0;
802 
803     return DataObject_GetData(pDataObject, g_cfShellIdListOffsets, point, sizeof(point[0]));
804 }
805 
806 inline HRESULT
DataObject_SetOffset(IDataObject * pDataObject,POINT * point)807 DataObject_SetOffset(IDataObject* pDataObject, POINT* point)
808 {
809     if (g_cfShellIdListOffsets == NULL)
810     {
811         g_cfShellIdListOffsets = (CLIPFORMAT)RegisterClipboardFormatW(CFSTR_SHELLIDLISTOFFSETW);
812     }
813 
814     return DataObject_SetData(pDataObject, g_cfShellIdListOffsets, point, sizeof(point[0]));
815 }
816 
817 #endif // __cplusplus
818 
819 #ifdef __cplusplus
820 struct SHELL_GetSettingImpl
821 {
822     SHELLSTATE ss;
SHELL_GetSettingImplSHELL_GetSettingImpl823     SHELL_GetSettingImpl(DWORD ssf) { SHGetSetSettings(&ss, ssf, FALSE); }
824     const SHELLSTATE* operator ->() { return &ss; }
825 };
826 #define SHELL_GetSetting(ssf, field) ( SHELL_GetSettingImpl(ssf)->field )
827 #else
828 #define SHELL_GetSetting(pss, ssf, field) ( SHGetSetSettings((pss), (ssf), FALSE), (pss)->field )
829 #endif
830 
831 
832 #endif /* __ROS_SHELL_UTILS_H */
833