xref: /reactos/dll/win32/shell32/shlfolder.cpp (revision e4930be4)
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