1 /*
2 * Shell Folder stuff
3 *
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 * Copyright 2018 Katayama Hirofumi MZ
7 *
8 * IShellFolder2 and related interfaces
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25 #include "precomp.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(shell);
28
SHELL_GetDefaultFolderEnumSHCONTF()29 SHCONTF SHELL_GetDefaultFolderEnumSHCONTF()
30 {
31 SHCONTF Flags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
32 SHELLSTATE ss;
33 SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS | SSF_SHOWSUPERHIDDEN, FALSE);
34 if (ss.fShowAllObjects)
35 Flags |= SHCONTF_INCLUDEHIDDEN;
36 if (ss.fShowSuperHidden)
37 Flags |= SHCONTF_INCLUDESUPERHIDDEN;
38 return Flags;
39 }
40
SHELL_IncludeItemInFolderEnum(IShellFolder * pSF,PCUITEMID_CHILD pidl,SFGAOF Query,SHCONTF Flags)41 BOOL SHELL_IncludeItemInFolderEnum(IShellFolder *pSF, PCUITEMID_CHILD pidl, SFGAOF Query, SHCONTF Flags)
42 {
43 if (SUCCEEDED(pSF->GetAttributesOf(1, &pidl, &Query)))
44 {
45 if (Query & SFGAO_NONENUMERATED)
46 return FALSE;
47 if ((Query & SFGAO_HIDDEN) && !(Flags & SHCONTF_INCLUDEHIDDEN))
48 return FALSE;
49 if ((Query & (SFGAO_HIDDEN | SFGAO_SYSTEM)) == (SFGAO_HIDDEN | SFGAO_SYSTEM) && !(Flags & SHCONTF_INCLUDESUPERHIDDEN))
50 return FALSE;
51 if ((Flags & (SHCONTF_FOLDERS | SHCONTF_NONFOLDERS)) != (SHCONTF_FOLDERS | SHCONTF_NONFOLDERS))
52 return (Flags & SHCONTF_FOLDERS) ? (Query & SFGAO_FOLDER) : !(Query & SFGAO_FOLDER);
53 }
54 return TRUE;
55 }
56
57 HRESULT
Shell_NextElement(_Inout_ LPWSTR * ppch,_Out_ LPWSTR pszOut,_In_ INT cchOut,_In_ BOOL bValidate)58 Shell_NextElement(
59 _Inout_ LPWSTR *ppch,
60 _Out_ LPWSTR pszOut,
61 _In_ INT cchOut,
62 _In_ BOOL bValidate)
63 {
64 *pszOut = UNICODE_NULL;
65
66 if (!*ppch)
67 return S_FALSE;
68
69 HRESULT hr;
70 LPWSTR pchNext = wcschr(*ppch, L'\\');
71 if (pchNext)
72 {
73 if (*ppch < pchNext)
74 {
75 /* Get an element */
76 StringCchCopyNW(pszOut, cchOut, *ppch, pchNext - *ppch);
77 ++pchNext;
78
79 if (!*pchNext)
80 pchNext = NULL; /* No next */
81
82 hr = S_OK;
83 }
84 else /* Double backslashes found? */
85 {
86 pchNext = NULL;
87 hr = E_INVALIDARG;
88 }
89 }
90 else /* No more next */
91 {
92 StringCchCopyW(pszOut, cchOut, *ppch);
93 hr = S_OK;
94 }
95
96 *ppch = pchNext; /* Go next */
97
98 if (hr == S_OK && bValidate && !PathIsValidElement(pszOut))
99 {
100 *pszOut = UNICODE_NULL;
101 hr = E_INVALIDARG;
102 }
103
104 return hr;
105 }
106
SHELL32_ParseNextElement(IShellFolder2 * psf,HWND hwndOwner,LPBC pbc,LPITEMIDLIST * pidlInOut,LPOLESTR szNext,DWORD * pEaten,DWORD * pdwAttributes)107 HRESULT SHELL32_ParseNextElement (IShellFolder2 * psf, HWND hwndOwner, LPBC pbc,
108 LPITEMIDLIST * pidlInOut, LPOLESTR szNext, DWORD * pEaten, DWORD * pdwAttributes)
109 {
110 HRESULT hr = E_INVALIDARG;
111 LPITEMIDLIST pidlIn = pidlInOut ? *pidlInOut : NULL;
112 LPITEMIDLIST pidlOut = NULL;
113 LPITEMIDLIST pidlTemp = NULL;
114 CComPtr<IShellFolder> psfChild;
115
116 TRACE ("(%p, %p, %p, %s)\n", psf, pbc, pidlIn, debugstr_w (szNext));
117
118 /* get the shellfolder for the child pidl and let it analyse further */
119 hr = psf->BindToObject(pidlIn, pbc, IID_PPV_ARG(IShellFolder, &psfChild));
120 if (FAILED(hr))
121 return hr;
122
123 hr = psfChild->ParseDisplayName(hwndOwner, pbc, szNext, pEaten, &pidlOut, pdwAttributes);
124 if (FAILED(hr))
125 return hr;
126
127 pidlTemp = ILCombine (pidlIn, pidlOut);
128 if (!pidlTemp)
129 {
130 hr = E_OUTOFMEMORY;
131 if (pidlOut)
132 ILFree(pidlOut);
133 return hr;
134 }
135
136 if (pidlOut)
137 ILFree (pidlOut);
138
139 if (pidlIn)
140 ILFree (pidlIn);
141
142 *pidlInOut = pidlTemp;
143
144 TRACE ("-- pidl=%p ret=0x%08x\n", pidlInOut ? *pidlInOut : NULL, hr);
145 return S_OK;
146 }
147
148 /***********************************************************************
149 * SHELL32_CoCreateInitSF
150 *
151 * Creates a shell folder and initializes it with a pidl and a root folder
152 * via IPersistFolder3 or IPersistFolder.
153 *
154 * NOTES
155 * pathRoot can be NULL for Folders being a drive.
156 * In this case the absolute path is built from pidlChild (eg. C:)
157 */
SHELL32_CoCreateInitSF(LPCITEMIDLIST pidlRoot,PERSIST_FOLDER_TARGET_INFO * ppfti,LPCITEMIDLIST pidlChild,const GUID * clsid,REFIID riid,LPVOID * ppvOut)158 HRESULT SHELL32_CoCreateInitSF (LPCITEMIDLIST pidlRoot, PERSIST_FOLDER_TARGET_INFO* ppfti,
159 LPCITEMIDLIST pidlChild, const GUID* clsid, REFIID riid, LPVOID *ppvOut)
160 {
161 HRESULT hr;
162 CComPtr<IShellFolder> pShellFolder;
163
164 hr = SHCoCreateInstance(NULL, clsid, NULL, IID_PPV_ARG(IShellFolder, &pShellFolder));
165 if (FAILED(hr))
166 return hr;
167
168 LPITEMIDLIST pidlAbsolute = ILCombine (pidlRoot, pidlChild);
169 CComPtr<IPersistFolder> ppf;
170 CComPtr<IPersistFolder3> ppf3;
171
172 if (ppfti && SUCCEEDED(pShellFolder->QueryInterface(IID_PPV_ARG(IPersistFolder3, &ppf3))))
173 {
174 ppf3->InitializeEx(NULL, pidlAbsolute, ppfti);
175 }
176 else if (SUCCEEDED(pShellFolder->QueryInterface(IID_PPV_ARG(IPersistFolder, &ppf))))
177 {
178 ppf->Initialize(pidlAbsolute);
179 }
180 ILFree (pidlAbsolute);
181
182 return pShellFolder->QueryInterface(riid, ppvOut);
183 }
184
SHELL32_CoCreateInitSF(LPCITEMIDLIST pidlRoot,const GUID * clsid,int csidl,REFIID riid,LPVOID * ppvOut)185 HRESULT SHELL32_CoCreateInitSF (LPCITEMIDLIST pidlRoot, const GUID* clsid,
186 int csidl, REFIID riid, LPVOID *ppvOut)
187 {
188 /* fill the PERSIST_FOLDER_TARGET_INFO */
189 PERSIST_FOLDER_TARGET_INFO pfti = {0};
190 pfti.dwAttributes = -1;
191 pfti.csidl = csidl;
192
193 return SHELL32_CoCreateInitSF(pidlRoot, &pfti, NULL, clsid, riid, ppvOut);
194 }
195
SHELL32_BindToSF(LPCITEMIDLIST pidlRoot,PERSIST_FOLDER_TARGET_INFO * ppfti,LPCITEMIDLIST pidl,const GUID * clsid,REFIID riid,LPVOID * ppvOut)196 HRESULT SHELL32_BindToSF (LPCITEMIDLIST pidlRoot, PERSIST_FOLDER_TARGET_INFO* ppfti,
197 LPCITEMIDLIST pidl, const GUID* clsid, REFIID riid, LPVOID *ppvOut)
198 {
199 PITEMID_CHILD pidlChild = ILCloneFirst (pidl);
200 if (!pidlChild)
201 return E_FAIL;
202
203 CComPtr<IShellFolder> psf;
204 HRESULT hr = SHELL32_CoCreateInitSF(pidlRoot,
205 ppfti,
206 pidlChild,
207 clsid,
208 IID_PPV_ARG(IShellFolder, &psf));
209 ILFree(pidlChild);
210
211 if (FAILED_UNEXPECTEDLY(hr))
212 return hr;
213
214 if (_ILIsPidlSimple (pidl))
215 return psf->QueryInterface(riid, ppvOut);
216 else
217 return psf->BindToObject(ILGetNext (pidl), NULL, riid, ppvOut);
218 }
219
220 /***********************************************************************
221 * SHELL32_GetDisplayNameOfChild
222 *
223 * Retrieves the display name of a child object of a shellfolder.
224 *
225 * For a pidl eg. [subpidl1][subpidl2][subpidl3]:
226 * - it binds to the child shellfolder [subpidl1]
227 * - asks it for the displayname of [subpidl2][subpidl3]
228 *
229 * Is possible the pidl is a simple pidl. In this case it asks the
230 * subfolder for the displayname of an empty pidl. The subfolder
231 * returns the own displayname eg. "::{guid}". This is used for
232 * virtual folders with the registry key WantsFORPARSING set.
233 */
SHELL32_GetDisplayNameOfChild(IShellFolder2 * psf,LPCITEMIDLIST pidl,DWORD dwFlags,LPSTRRET strRet)234 HRESULT SHELL32_GetDisplayNameOfChild (IShellFolder2 * psf,
235 LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
236 {
237 LPITEMIDLIST pidlFirst = ILCloneFirst(pidl);
238 if (!pidlFirst)
239 return E_OUTOFMEMORY;
240
241 CComPtr<IShellFolder> psfChild;
242 HRESULT hr = psf->BindToObject(pidlFirst, NULL, IID_PPV_ARG(IShellFolder, &psfChild));
243 if (SUCCEEDED (hr))
244 {
245 hr = psfChild->GetDisplayNameOf(ILGetNext (pidl), dwFlags, strRet);
246 }
247 ILFree (pidlFirst);
248
249 return hr;
250 }
251
SHELL32_CompareChildren(IShellFolder2 * psf,LPARAM lParam,LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)252 HRESULT SHELL32_CompareChildren(IShellFolder2* psf, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
253 {
254 PUIDLIST_RELATIVE nextpidl1 = ILGetNext (pidl1);
255 PUIDLIST_RELATIVE nextpidl2 = ILGetNext (pidl2);
256
257 bool isEmpty1 = _ILIsDesktop(nextpidl1);
258 bool isEmpty2 = _ILIsDesktop(nextpidl2);
259 if (isEmpty1 || isEmpty2)
260 return MAKE_COMPARE_HRESULT(isEmpty2 - isEmpty1);
261
262 PITEMID_CHILD firstpidl = ILCloneFirst (pidl1);
263 if (!firstpidl)
264 return E_OUTOFMEMORY;
265
266 CComPtr<IShellFolder> psf2;
267 HRESULT hr = psf->BindToObject(firstpidl, 0, IID_PPV_ARG(IShellFolder, &psf2));
268 ILFree(firstpidl);
269 if (FAILED(hr))
270 return MAKE_COMPARE_HRESULT(0);
271
272 return psf2->CompareIDs(lParam, nextpidl1, nextpidl2);
273 }
274
SHELL32_CompareDetails(IShellFolder2 * isf,LPARAM lParam,LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)275 HRESULT SHELL32_CompareDetails(IShellFolder2* isf, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
276 {
277 SHELLDETAILS sd;
278 WCHAR wszItem1[MAX_PATH], wszItem2[MAX_PATH];
279 HRESULT hres;
280 UINT col = LOWORD(lParam); // Column index without SHCIDS_* flags
281
282 hres = isf->GetDetailsOf(pidl1, col, &sd);
283 if (FAILED(hres))
284 return MAKE_COMPARE_HRESULT(1);
285
286 hres = StrRetToBufW(&sd.str, pidl1, wszItem1, MAX_PATH);
287 if (FAILED(hres))
288 return MAKE_COMPARE_HRESULT(1);
289
290 hres = isf->GetDetailsOf(pidl2, col, &sd);
291 if (FAILED(hres))
292 return MAKE_COMPARE_HRESULT(1);
293
294 hres = StrRetToBufW(&sd.str, pidl2, wszItem2, MAX_PATH);
295 if (FAILED(hres))
296 return MAKE_COMPARE_HRESULT(1);
297
298 int ret = _wcsicmp(wszItem1, wszItem2);
299 if (ret == 0)
300 return SHELL32_CompareChildren(isf, lParam, pidl1, pidl2);
301
302 return MAKE_COMPARE_HRESULT(ret);
303 }
304
AddClassKeyToArray(const WCHAR * szClass,HKEY * array,UINT * cKeys)305 LSTATUS AddClassKeyToArray(const WCHAR* szClass, HKEY* array, UINT* cKeys)
306 {
307 if (*cKeys >= 16)
308 return ERROR_MORE_DATA;
309
310 HKEY hkey;
311 LSTATUS result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szClass, 0, KEY_READ | KEY_QUERY_VALUE, &hkey);
312 if (result == ERROR_SUCCESS)
313 {
314 array[*cKeys] = hkey;
315 *cKeys += 1;
316 }
317 return result;
318 }
319
AddClsidKeyToArray(REFCLSID clsid,HKEY * array,UINT * cKeys)320 LSTATUS AddClsidKeyToArray(REFCLSID clsid, HKEY* array, UINT* cKeys)
321 {
322 WCHAR path[6 + 38 + 1] = L"CLSID\\";
323 StringFromGUID2(clsid, path + 6, 38 + 1);
324 return AddClassKeyToArray(path, array, cKeys);
325 }
326
AddFSClassKeysToArray(UINT cidl,PCUITEMID_CHILD_ARRAY apidl,HKEY * array,UINT * cKeys)327 void AddFSClassKeysToArray(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, HKEY* array, UINT* cKeys)
328 {
329 // This function opens the association array keys in canonical order for filesystem items.
330 // The order is documented: learn.microsoft.com/en-us/windows/win32/shell/fa-associationarray
331
332 ASSERT(cidl >= 1 && apidl);
333 PCUITEMID_CHILD pidl = apidl[0];
334 if (_ILIsValue(pidl))
335 {
336 WCHAR buf[MAX_PATH];
337 PWSTR name;
338 FileStructW* pFileData = _ILGetFileStructW(pidl);
339 if (pFileData)
340 {
341 name = pFileData->wszName;
342 }
343 else
344 {
345 _ILSimpleGetTextW(pidl, buf, _countof(buf));
346 name = buf;
347 }
348 LPCWSTR extension = PathFindExtension(name);
349
350 if (extension)
351 {
352 WCHAR wszClass[MAX_PATH], wszSFA[23 + _countof(wszClass)];
353 DWORD dwSize = sizeof(wszClass);
354 if (RegGetValueW(HKEY_CLASSES_ROOT, extension, NULL, RRF_RT_REG_SZ, NULL, wszClass, &dwSize) != ERROR_SUCCESS ||
355 !*wszClass || AddClassKeyToArray(wszClass, array, cKeys) != ERROR_SUCCESS)
356 {
357 // Only add the extension key if the ProgId is not valid
358 AddClassKeyToArray(extension, array, cKeys);
359
360 // "Open With" becomes the default when there are no verbs in the above keys
361 if (cidl == 1)
362 AddClassKeyToArray(L"Unknown", array, cKeys);
363 }
364
365 swprintf(wszSFA, L"SystemFileAssociations\\%s", extension);
366 AddClassKeyToArray(wszSFA, array, cKeys);
367
368 dwSize = sizeof(wszClass);
369 if (RegGetValueW(HKEY_CLASSES_ROOT, extension, L"PerceivedType ", RRF_RT_REG_SZ, NULL, wszClass, &dwSize) == ERROR_SUCCESS)
370 {
371 swprintf(wszSFA, L"SystemFileAssociations\\%s", wszClass);
372 AddClassKeyToArray(wszSFA, array, cKeys);
373 }
374 }
375
376 AddClassKeyToArray(L"*", array, cKeys);
377 AddClassKeyToArray(L"AllFilesystemObjects", array, cKeys);
378 }
379 else if (_ILIsFolder(pidl))
380 {
381 // FIXME: Directory > Folder > AFO is the correct order and it's
382 // the order Windows reports in its undocumented association array
383 // but it is somehow not the order Windows adds the items to its menu!
384 // Until the correct algorithm in CDefaultContextMenu can be determined,
385 // we add the folder keys in "menu order".
386 AddClassKeyToArray(L"Folder", array, cKeys);
387 AddClassKeyToArray(L"AllFilesystemObjects", array, cKeys);
388 AddClassKeyToArray(L"Directory", array, cKeys);
389 }
390 else
391 {
392 ERR("Got non FS pidl\n");
393 }
394 }
395
SH_GetApidlFromDataObject(IDataObject * pDataObject,PIDLIST_ABSOLUTE * ppidlfolder,PUITEMID_CHILD ** apidlItems,UINT * pcidl)396 HRESULT SH_GetApidlFromDataObject(IDataObject *pDataObject, PIDLIST_ABSOLUTE* ppidlfolder, PUITEMID_CHILD **apidlItems, UINT *pcidl)
397 {
398 CDataObjectHIDA cida(pDataObject);
399
400 if (FAILED_UNEXPECTEDLY(cida.hr()))
401 return cida.hr();
402
403 /* convert the data into pidl */
404 LPITEMIDLIST pidl;
405 LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, cida);
406 if (!apidl)
407 {
408 return E_OUTOFMEMORY;
409 }
410
411 *ppidlfolder = pidl;
412 *apidlItems = apidl;
413 *pcidl = cida->cidl;
414
415 return S_OK;
416 }
417
418 /***********************************************************************
419 * SHCreateLinks
420 *
421 * Undocumented.
422 */
SHCreateLinks(HWND hWnd,LPCSTR lpszDir,IDataObject * lpDataObject,UINT uFlags,LPITEMIDLIST * lppidlLinks)423 HRESULT WINAPI SHCreateLinks( HWND hWnd, LPCSTR lpszDir, IDataObject * lpDataObject,
424 UINT uFlags, LPITEMIDLIST *lppidlLinks)
425 {
426 FIXME("%p %s %p %08x %p\n", hWnd, lpszDir, lpDataObject, uFlags, lppidlLinks);
427 return E_NOTIMPL;
428 }
429
430 /***********************************************************************
431 * SHOpenFolderAndSelectItems
432 *
433 * Unimplemented.
434 */
435 EXTERN_C HRESULT
436 WINAPI
SHOpenFolderAndSelectItems(PCIDLIST_ABSOLUTE pidlFolder,UINT cidl,PCUITEMID_CHILD_ARRAY apidl,DWORD dwFlags)437 SHOpenFolderAndSelectItems(PCIDLIST_ABSOLUTE pidlFolder,
438 UINT cidl,
439 PCUITEMID_CHILD_ARRAY apidl,
440 DWORD dwFlags)
441 {
442 ERR("SHOpenFolderAndSelectItems() is hackplemented\n");
443 CComHeapPtr<ITEMIDLIST> freeItem;
444 PCIDLIST_ABSOLUTE pidlItem;
445 if (cidl)
446 {
447 /* Firefox sends a full pidl here dispite the fact it is a PCUITEMID_CHILD_ARRAY -_- */
448 if (!ILIsSingle(apidl[0]))
449 {
450 pidlItem = apidl[0];
451 }
452 else
453 {
454 HRESULT hr = SHILCombine(pidlFolder, apidl[0], &pidlItem);
455 if (FAILED_UNEXPECTEDLY(hr))
456 return hr;
457 freeItem.Attach(const_cast<PIDLIST_ABSOLUTE>(pidlItem));
458 }
459 }
460 else
461 {
462 pidlItem = pidlFolder;
463 }
464
465 CComPtr<IShellFolder> psfDesktop;
466
467 HRESULT hr = SHGetDesktopFolder(&psfDesktop);
468 if (FAILED_UNEXPECTEDLY(hr))
469 return hr;
470
471 STRRET strret;
472 hr = psfDesktop->GetDisplayNameOf(pidlItem, SHGDN_FORPARSING, &strret);
473 if (FAILED_UNEXPECTEDLY(hr))
474 return hr;
475
476 WCHAR wszBuf[MAX_PATH];
477 hr = StrRetToBufW(&strret, pidlItem, wszBuf, _countof(wszBuf));
478 if (FAILED_UNEXPECTEDLY(hr))
479 return hr;
480
481 WCHAR wszParams[MAX_PATH];
482 wcscpy(wszParams, L"/select,");
483 wcscat(wszParams, wszBuf);
484
485 SHELLEXECUTEINFOW sei;
486 memset(&sei, 0, sizeof sei);
487 sei.cbSize = sizeof sei;
488 sei.fMask = SEE_MASK_WAITFORINPUTIDLE;
489 sei.lpFile = L"explorer.exe";
490 sei.lpParameters = wszParams;
491
492 if (ShellExecuteExW(&sei))
493 return S_OK;
494 else
495 return E_FAIL;
496 }
497
498 static
499 DWORD WINAPI
_ShowPropertiesDialogThread(LPVOID lpParameter)500 _ShowPropertiesDialogThread(LPVOID lpParameter)
501 {
502 CComPtr<IDataObject> pDataObject;
503 pDataObject.Attach((IDataObject*)lpParameter);
504
505 CDataObjectHIDA cida(pDataObject);
506
507 if (FAILED_UNEXPECTEDLY(cida.hr()))
508 return cida.hr();
509
510 if (cida->cidl > 1)
511 {
512 ERR("SHMultiFileProperties is not yet implemented\n");
513 return E_FAIL;
514 }
515
516 CComHeapPtr<ITEMIDLIST> completePidl(ILCombine(HIDA_GetPIDLFolder(cida), HIDA_GetPIDLItem(cida, 0)));
517 CComHeapPtr<WCHAR> wszName;
518 if (FAILED_UNEXPECTEDLY(SHGetNameFromIDList(completePidl, SIGDN_PARENTRELATIVEPARSING, &wszName)))
519 return 0;
520
521 BOOL bSuccess = SH_ShowPropertiesDialog(wszName, pDataObject);
522 if (!bSuccess)
523 ERR("SH_ShowPropertiesDialog failed\n");
524
525 return 0;
526 }
527
528 /*
529 * for internal use
530 */
531 HRESULT
SHELL32_ShowPropertiesDialog(IDataObject * pdtobj)532 SHELL32_ShowPropertiesDialog(IDataObject *pdtobj)
533 {
534 if (!pdtobj)
535 return E_INVALIDARG;
536
537 pdtobj->AddRef();
538 if (!SHCreateThread(_ShowPropertiesDialogThread, pdtobj, CTF_INSIST | CTF_COINIT | CTF_PROCESS_REF, NULL))
539 {
540 pdtobj->Release();
541 return HResultFromWin32(GetLastError());
542 }
543 else
544 {
545 return S_OK;
546 }
547 }
548
549 HRESULT
SHELL32_DefaultContextMenuCallBack(IShellFolder * psf,IDataObject * pdo,UINT msg)550 SHELL32_DefaultContextMenuCallBack(IShellFolder *psf, IDataObject *pdo, UINT msg)
551 {
552 switch (msg)
553 {
554 case DFM_MERGECONTEXTMENU:
555 return S_OK; // Yes, I want verbs
556 case DFM_INVOKECOMMAND:
557 return S_FALSE; // Do it for me please
558 case DFM_GETDEFSTATICID:
559 return S_FALSE; // Supposedly "required for Windows 7 to pick a default"
560 }
561 return E_NOTIMPL;
562 }
563