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