[SHELL32]
[reactos.git] / reactos / dll / win32 / shell32 / shlfolder.cpp
1 /*
2 * Shell Folder stuff
3 *
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 *
7 * IShellFolder2 and related interfaces
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24 #include <precomp.h>
25
26 WINE_DEFAULT_DEBUG_CHANNEL(shell);
27
28 static const WCHAR wszDotShellClassInfo[] = {
29 '.','S','h','e','l','l','C','l','a','s','s','I','n','f','o',0};
30
31 /***************************************************************************
32 * SHELL32_GetCustomFolderAttribute (internal function)
33 *
34 * Gets a value from the folder's desktop.ini file, if one exists.
35 *
36 * PARAMETERS
37 * pidl [I] Folder containing the desktop.ini file.
38 * pwszHeading [I] Heading in .ini file.
39 * pwszAttribute [I] Attribute in .ini file.
40 * pwszValue [O] Buffer to store value into.
41 * cchValue [I] Size in characters including NULL of buffer pointed to
42 * by pwszValue.
43 *
44 * RETURNS
45 * TRUE if returned non-NULL value.
46 * FALSE otherwise.
47 */
48 static BOOL __inline SHELL32_GetCustomFolderAttributeFromPath(
49 LPWSTR pwszFolderPath, LPCWSTR pwszHeading, LPCWSTR pwszAttribute,
50 LPWSTR pwszValue, DWORD cchValue)
51 {
52 static const WCHAR wszDesktopIni[] =
53 {'d','e','s','k','t','o','p','.','i','n','i',0};
54 static const WCHAR wszDefault[] = {0};
55
56 PathAddBackslashW(pwszFolderPath);
57 PathAppendW(pwszFolderPath, wszDesktopIni);
58 return GetPrivateProfileStringW(pwszHeading, pwszAttribute, wszDefault,
59 pwszValue, cchValue, pwszFolderPath);
60 }
61
62 BOOL SHELL32_GetCustomFolderAttribute(
63 LPCITEMIDLIST pidl, LPCWSTR pwszHeading, LPCWSTR pwszAttribute,
64 LPWSTR pwszValue, DWORD cchValue)
65 {
66 DWORD dwAttrib = FILE_ATTRIBUTE_SYSTEM;
67 WCHAR wszFolderPath[MAX_PATH];
68
69 /* Hack around not having system attribute on non-Windows file systems */
70 if (0)
71 dwAttrib = _ILGetFileAttributes(pidl, NULL, 0);
72
73 if (dwAttrib & FILE_ATTRIBUTE_SYSTEM)
74 {
75 if (!SHGetPathFromIDListW(pidl, wszFolderPath))
76 return FALSE;
77
78 return SHELL32_GetCustomFolderAttributeFromPath(wszFolderPath, pwszHeading,
79 pwszAttribute, pwszValue, cchValue);
80 }
81 return FALSE;
82 }
83
84 /***************************************************************************
85 * GetNextElement (internal function)
86 *
87 * Gets a part of a string till the first backslash.
88 *
89 * PARAMETERS
90 * pszNext [IN] string to get the element from
91 * pszOut [IN] pointer to buffer which receives string
92 * dwOut [IN] length of pszOut
93 *
94 * RETURNS
95 * LPSTR pointer to first, not yet parsed char
96 */
97
98 LPCWSTR GetNextElementW (LPCWSTR pszNext, LPWSTR pszOut, DWORD dwOut)
99 {
100 LPCWSTR pszTail = pszNext;
101 DWORD dwCopy;
102
103 TRACE ("(%s %p 0x%08x)\n", debugstr_w (pszNext), pszOut, dwOut);
104
105 *pszOut = 0x0000;
106
107 if (!pszNext || !*pszNext)
108 return NULL;
109
110 while (*pszTail && (*pszTail != (WCHAR) '\\'))
111 pszTail++;
112
113 dwCopy = pszTail - pszNext + 1;
114 lstrcpynW (pszOut, pszNext, (dwOut < dwCopy) ? dwOut : dwCopy);
115
116 if (*pszTail)
117 pszTail++;
118 else
119 pszTail = NULL;
120
121 TRACE ("--(%s %s 0x%08x %p)\n", debugstr_w (pszNext), debugstr_w (pszOut), dwOut, pszTail);
122 return pszTail;
123 }
124
125 HRESULT SHELL32_ParseNextElement (IShellFolder2 * psf, HWND hwndOwner, LPBC pbc,
126 LPITEMIDLIST * pidlInOut, LPOLESTR szNext, DWORD * pEaten, DWORD * pdwAttributes)
127 {
128 HRESULT hr = E_INVALIDARG;
129 LPITEMIDLIST pidlOut = NULL,
130 pidlTemp = NULL;
131 IShellFolder *psfChild;
132
133 TRACE ("(%p, %p, %p, %s)\n", psf, pbc, pidlInOut ? *pidlInOut : NULL, debugstr_w (szNext));
134
135 /* get the shellfolder for the child pidl and let it analyse further */
136 hr = psf->BindToObject(*pidlInOut, pbc, IID_IShellFolder, (LPVOID *)&psfChild);
137
138 if (SUCCEEDED(hr)) {
139 hr = psfChild->ParseDisplayName(hwndOwner, pbc, szNext, pEaten, &pidlOut, pdwAttributes);
140 psfChild->Release();
141
142 if (SUCCEEDED(hr)) {
143 pidlTemp = ILCombine (*pidlInOut, pidlOut);
144
145 if (!pidlTemp)
146 hr = E_OUTOFMEMORY;
147 }
148
149 if (pidlOut)
150 ILFree (pidlOut);
151 }
152
153 ILFree (*pidlInOut);
154 *pidlInOut = pidlTemp;
155
156 TRACE ("-- pidl=%p ret=0x%08x\n", pidlInOut ? *pidlInOut : NULL, hr);
157 return hr;
158 }
159
160 /***********************************************************************
161 * SHELL32_CoCreateInitSF
162 *
163 * Creates a shell folder and initializes it with a pidl and a root folder
164 * via IPersistFolder3 or IPersistFolder.
165 *
166 * NOTES
167 * pathRoot can be NULL for Folders being a drive.
168 * In this case the absolute path is built from pidlChild (eg. C:)
169 */
170 static HRESULT SHELL32_CoCreateInitSF (LPCITEMIDLIST pidlRoot, LPCWSTR pathRoot,
171 LPCITEMIDLIST pidlChild, REFCLSID clsid, LPVOID * ppvOut)
172 {
173 HRESULT hr;
174
175 TRACE ("%p %s %p\n", pidlRoot, debugstr_w(pathRoot), pidlChild);
176
177 hr = SHCoCreateInstance(NULL, &clsid, NULL, IID_IShellFolder, ppvOut);
178 if (SUCCEEDED (hr))
179 {
180 LPITEMIDLIST pidlAbsolute = ILCombine (pidlRoot, pidlChild);
181 IPersistFolder *pPF;
182 IPersistFolder3 *ppf;
183
184 if (_ILIsFolder(pidlChild) &&
185 SUCCEEDED (((IUnknown *)(*ppvOut))->QueryInterface(IID_IPersistFolder3, (LPVOID *) & ppf)))
186 {
187 PERSIST_FOLDER_TARGET_INFO ppfti;
188
189 ZeroMemory (&ppfti, sizeof (ppfti));
190
191 /* fill the PERSIST_FOLDER_TARGET_INFO */
192 ppfti.dwAttributes = -1;
193 ppfti.csidl = -1;
194
195 /* build path */
196 if (pathRoot)
197 {
198 lstrcpynW (ppfti.szTargetParsingName, pathRoot, MAX_PATH - 1);
199 PathAddBackslashW(ppfti.szTargetParsingName); /* FIXME: why have drives a backslash here ? */
200 }
201
202 if (pidlChild)
203 {
204 int len = wcslen(ppfti.szTargetParsingName);
205
206 if (!_ILSimpleGetTextW(pidlChild, ppfti.szTargetParsingName + len, MAX_PATH - len))
207 hr = E_INVALIDARG;
208 }
209
210 ppf->InitializeEx(NULL, pidlAbsolute, &ppfti);
211 ppf->Release();
212 }
213 else if (SUCCEEDED ((hr = ((IUnknown *)(*ppvOut))->QueryInterface (IID_IPersistFolder, (LPVOID *) & pPF))))
214 {
215 pPF->Initialize(pidlAbsolute);
216 pPF->Release();
217 }
218 ILFree (pidlAbsolute);
219 }
220 TRACE ("-- (%p) ret=0x%08x\n", *ppvOut, hr);
221 return hr;
222 }
223
224 /***********************************************************************
225 * SHELL32_BindToChild [Internal]
226 *
227 * Common code for IShellFolder_BindToObject.
228 *
229 * PARAMS
230 * pidlRoot [I] The parent shell folder's absolute pidl.
231 * pathRoot [I] Absolute dos path of the parent shell folder.
232 * pidlComplete [I] PIDL of the child. Relative to pidlRoot.
233 * riid [I] GUID of the interface, which ppvOut shall be bound to.
234 * ppvOut [O] A reference to the child's interface (riid).
235 *
236 * NOTES
237 * pidlComplete has to contain at least one non empty SHITEMID.
238 * This function makes special assumptions on the shell namespace, which
239 * means you probably can't use it for your IShellFolder implementation.
240 */
241 HRESULT SHELL32_BindToChild (LPCITEMIDLIST pidlRoot,
242 LPCWSTR pathRoot, LPCITEMIDLIST pidlComplete, REFIID riid, LPVOID * ppvOut)
243 {
244 GUID const *clsid;
245 IShellFolder *pSF;
246 HRESULT hr;
247 LPITEMIDLIST pidlChild;
248
249 if (!pidlRoot || !ppvOut || !pidlComplete || !pidlComplete->mkid.cb)
250 return E_INVALIDARG;
251
252 *ppvOut = NULL;
253
254 pidlChild = ILCloneFirst (pidlComplete);
255
256 if ((clsid = _ILGetGUIDPointer (pidlChild))) {
257 /* virtual folder */
258 hr = SHELL32_CoCreateInitSF (pidlRoot, pathRoot, pidlChild, *clsid, (LPVOID *)&pSF);
259 } else {
260 /* file system folder */
261 CLSID clsidFolder = CLSID_ShellFSFolder;
262 static const WCHAR wszCLSID[] = {'C','L','S','I','D',0};
263 WCHAR wszCLSIDValue[CHARS_IN_GUID], wszFolderPath[MAX_PATH], *pwszPathTail = wszFolderPath;
264
265 /* see if folder CLSID should be overridden by desktop.ini file */
266 if (pathRoot) {
267 lstrcpynW(wszFolderPath, pathRoot, MAX_PATH);
268 pwszPathTail = PathAddBackslashW(wszFolderPath);
269 }
270
271 _ILSimpleGetTextW(pidlChild,pwszPathTail,MAX_PATH - (int)(pwszPathTail - wszFolderPath));
272
273 if (SHELL32_GetCustomFolderAttributeFromPath (wszFolderPath,
274 wszDotShellClassInfo, wszCLSID, wszCLSIDValue, CHARS_IN_GUID))
275 CLSIDFromString (wszCLSIDValue, &clsidFolder);
276
277 hr = SHELL32_CoCreateInitSF (pidlRoot, pathRoot, pidlChild,
278 clsidFolder, (LPVOID *)&pSF);
279 }
280 ILFree (pidlChild);
281
282 if (SUCCEEDED (hr)) {
283 if (_ILIsPidlSimple (pidlComplete)) {
284 /* no sub folders */
285 hr = pSF->QueryInterface(riid, ppvOut);
286 } else {
287 /* go deeper */
288 hr = pSF->BindToObject(ILGetNext (pidlComplete), NULL, riid, ppvOut);
289 }
290 pSF->Release();
291 }
292
293 TRACE ("-- returning (%p) %08x\n", *ppvOut, hr);
294
295 return hr;
296 }
297
298 /***********************************************************************
299 * SHELL32_GetDisplayNameOfChild
300 *
301 * Retrieves the display name of a child object of a shellfolder.
302 *
303 * For a pidl eg. [subpidl1][subpidl2][subpidl3]:
304 * - it binds to the child shellfolder [subpidl1]
305 * - asks it for the displayname of [subpidl2][subpidl3]
306 *
307 * Is possible the pidl is a simple pidl. In this case it asks the
308 * subfolder for the displayname of an empty pidl. The subfolder
309 * returns the own displayname eg. "::{guid}". This is used for
310 * virtual folders with the registry key WantsFORPARSING set.
311 */
312 HRESULT SHELL32_GetDisplayNameOfChild (IShellFolder2 * psf,
313 LPCITEMIDLIST pidl, DWORD dwFlags, LPWSTR szOut, DWORD dwOutLen)
314 {
315 LPITEMIDLIST pidlFirst;
316 HRESULT hr = E_INVALIDARG;
317
318 TRACE ("(%p)->(pidl=%p 0x%08x %p 0x%08x)\n", psf, pidl, dwFlags, szOut, dwOutLen);
319 pdump (pidl);
320
321 pidlFirst = ILCloneFirst (pidl);
322 if (pidlFirst) {
323 IShellFolder2 *psfChild;
324
325 hr = psf->BindToObject(pidlFirst, NULL, IID_IShellFolder, (LPVOID *) & psfChild);
326 if (SUCCEEDED (hr)) {
327 STRRET strTemp;
328 LPITEMIDLIST pidlNext = ILGetNext (pidl);
329
330 hr = psfChild->GetDisplayNameOf(pidlNext, dwFlags, &strTemp);
331 if (SUCCEEDED (hr)) {
332 if(!StrRetToStrNW (szOut, dwOutLen, &strTemp, pidlNext))
333 hr = E_FAIL;
334 }
335 psfChild->Release();
336 }
337 ILFree (pidlFirst);
338 } else
339 hr = E_OUTOFMEMORY;
340
341 TRACE ("-- ret=0x%08x %s\n", hr, debugstr_w(szOut));
342
343 return hr;
344 }
345
346 /***********************************************************************
347 * SHELL32_GetItemAttributes
348 *
349 * NOTES
350 * Observed values:
351 * folder: 0xE0000177 FILESYSTEM | HASSUBFOLDER | FOLDER
352 * file: 0x40000177 FILESYSTEM
353 * drive: 0xf0000144 FILESYSTEM | HASSUBFOLDER | FOLDER | FILESYSANCESTOR
354 * mycomputer: 0xb0000154 HASSUBFOLDER | FOLDER | FILESYSANCESTOR
355 * (seems to be default for shell extensions if no registry entry exists)
356 *
357 * win2k:
358 * folder: 0xF0400177 FILESYSTEM | HASSUBFOLDER | FOLDER | FILESYSANCESTOR | CANMONIKER
359 * file: 0x40400177 FILESYSTEM | CANMONIKER
360 * drive 0xF0400154 FILESYSTEM | HASSUBFOLDER | FOLDER | FILESYSANCESTOR | CANMONIKER | CANRENAME (LABEL)
361 *
362 * According to the MSDN documentation this function should not set flags. It claims only to reset flags when necessary.
363 * However it turns out the native shell32.dll _sets_ flags in several cases - so do we.
364 */
365 HRESULT SHELL32_GetItemAttributes (IShellFolder * psf, LPCITEMIDLIST pidl, LPDWORD pdwAttributes)
366 {
367 DWORD dwAttributes;
368 BOOL has_guid;
369 static const DWORD dwSupportedAttr=
370 SFGAO_CANCOPY | /*0x00000001 */
371 SFGAO_CANMOVE | /*0x00000002 */
372 SFGAO_CANLINK | /*0x00000004 */
373 SFGAO_CANRENAME | /*0x00000010 */
374 SFGAO_CANDELETE | /*0x00000020 */
375 SFGAO_HASPROPSHEET | /*0x00000040 */
376 SFGAO_DROPTARGET | /*0x00000100 */
377 SFGAO_LINK | /*0x00010000 */
378 SFGAO_READONLY | /*0x00040000 */
379 SFGAO_HIDDEN | /*0x00080000 */
380 SFGAO_FILESYSANCESTOR | /*0x10000000 */
381 SFGAO_FOLDER | /*0x20000000 */
382 SFGAO_FILESYSTEM | /*0x40000000 */
383 SFGAO_HASSUBFOLDER; /*0x80000000 */
384
385 TRACE ("0x%08x\n", *pdwAttributes);
386
387 if (*pdwAttributes & ~dwSupportedAttr)
388 {
389 WARN ("attributes 0x%08x not implemented\n", (*pdwAttributes & ~dwSupportedAttr));
390 *pdwAttributes &= dwSupportedAttr;
391 }
392
393 has_guid = _ILGetGUIDPointer(pidl) != NULL;
394
395 dwAttributes = *pdwAttributes;
396
397 if (_ILIsDrive (pidl)) {
398 *pdwAttributes &= SFGAO_HASSUBFOLDER|SFGAO_FILESYSTEM|SFGAO_FOLDER|SFGAO_FILESYSANCESTOR|
399 SFGAO_DROPTARGET|SFGAO_HASPROPSHEET|SFGAO_CANRENAME;
400 } else if (has_guid && HCR_GetFolderAttributes(pidl, &dwAttributes)) {
401 *pdwAttributes = dwAttributes;
402 } else if (_ILGetDataPointer (pidl)) {
403 dwAttributes = _ILGetFileAttributes (pidl, NULL, 0);
404
405 if (!dwAttributes && has_guid) {
406 WCHAR path[MAX_PATH];
407 STRRET strret;
408
409 /* File attributes are not present in the internal PIDL structure, so get them from the file system. */
410
411 HRESULT hr = psf->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strret);
412
413 if (SUCCEEDED(hr)) {
414 hr = StrRetToBufW(&strret, pidl, path, MAX_PATH);
415
416 /* call GetFileAttributes() only for file system paths, not for parsing names like "::{...}" */
417 if (SUCCEEDED(hr) && path[0]!=':')
418 dwAttributes = GetFileAttributesW(path);
419 }
420 }
421
422 /* Set common attributes */
423 *pdwAttributes |= SFGAO_FILESYSTEM | SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANDELETE |
424 SFGAO_CANRENAME | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANCOPY;
425
426 if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
427 {
428 *pdwAttributes |= (SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR);
429 *pdwAttributes &= ~SFGAO_CANLINK;
430 }
431 else
432 *pdwAttributes &= ~(SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR);
433
434 if (dwAttributes & FILE_ATTRIBUTE_HIDDEN)
435 *pdwAttributes |= SFGAO_HIDDEN;
436 else
437 *pdwAttributes &= ~SFGAO_HIDDEN;
438
439 if (dwAttributes & FILE_ATTRIBUTE_READONLY)
440 *pdwAttributes |= SFGAO_READONLY;
441 else
442 *pdwAttributes &= ~SFGAO_READONLY;
443
444 if (SFGAO_LINK & *pdwAttributes) {
445 char ext[MAX_PATH];
446
447 if (!_ILGetExtension(pidl, ext, MAX_PATH) || lstrcmpiA(ext, "lnk"))
448 *pdwAttributes &= ~SFGAO_LINK;
449 }
450
451 if (SFGAO_HASSUBFOLDER & *pdwAttributes)
452 {
453 IShellFolder *psf2;
454 if (SUCCEEDED(psf->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID *)&psf2)))
455 {
456 IEnumIDList *pEnumIL = NULL;
457 if (SUCCEEDED(psf2->EnumObjects(0, SHCONTF_FOLDERS, &pEnumIL)))
458 {
459 if (pEnumIL->Skip(1) != S_OK)
460 *pdwAttributes &= ~SFGAO_HASSUBFOLDER;
461 pEnumIL->Release();
462 }
463 psf2->Release();
464 }
465 }
466 } else {
467 *pdwAttributes &= SFGAO_HASSUBFOLDER|SFGAO_FOLDER|SFGAO_FILESYSANCESTOR|SFGAO_DROPTARGET|SFGAO_HASPROPSHEET|SFGAO_CANRENAME|SFGAO_CANLINK;
468 }
469 TRACE ("-- 0x%08x\n", *pdwAttributes);
470 return S_OK;
471 }
472
473 /***********************************************************************
474 * SHELL32_CompareIDs
475 */
476 HRESULT SHELL32_CompareIDs (IShellFolder * iface, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
477 {
478 int type1,
479 type2;
480 char szTemp1[MAX_PATH];
481 char szTemp2[MAX_PATH];
482 HRESULT nReturn;
483 LPITEMIDLIST firstpidl,
484 nextpidl1,
485 nextpidl2;
486 IShellFolder *psf;
487
488 /* test for empty pidls */
489 BOOL isEmpty1 = _ILIsDesktop (pidl1);
490 BOOL isEmpty2 = _ILIsDesktop (pidl2);
491
492 if (isEmpty1 && isEmpty2)
493 return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 0 );
494 if (isEmpty1)
495 return MAKE_HRESULT( SEVERITY_SUCCESS, 0, (WORD)-1 );
496 if (isEmpty2)
497 return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 );
498
499 /* test for different types. Sort order is the PT_* constant */
500 type1 = _ILGetDataPointer (pidl1)->type;
501 type2 = _ILGetDataPointer (pidl2)->type;
502 if (type1 < type2)
503 return MAKE_HRESULT( SEVERITY_SUCCESS, 0, (WORD)-1 );
504 else if (type1 > type2)
505 return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 );
506
507 /* test for name of pidl */
508 _ILSimpleGetText (pidl1, szTemp1, MAX_PATH);
509 _ILSimpleGetText (pidl2, szTemp2, MAX_PATH);
510 nReturn = lstrcmpiA (szTemp1, szTemp2);
511 if (nReturn < 0)
512 return MAKE_HRESULT( SEVERITY_SUCCESS, 0, (WORD)-1 );
513 else if (nReturn > 0)
514 return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 );
515
516 /* test of complex pidls */
517 firstpidl = ILCloneFirst (pidl1);
518 nextpidl1 = ILGetNext (pidl1);
519 nextpidl2 = ILGetNext (pidl2);
520
521 /* optimizing: test special cases and bind not deeper */
522 /* the deeper shellfolder would do the same */
523 isEmpty1 = _ILIsDesktop (nextpidl1);
524 isEmpty2 = _ILIsDesktop (nextpidl2);
525
526 if (isEmpty1 && isEmpty2) {
527 return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 0 );
528 } else if (isEmpty1) {
529 return MAKE_HRESULT( SEVERITY_SUCCESS, 0, (WORD)-1 );
530 } else if (isEmpty2) {
531 return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 );
532 /* optimizing end */
533 } else if (SUCCEEDED (iface->BindToObject(firstpidl, NULL, IID_IShellFolder, (LPVOID *)&psf))) {
534 nReturn = psf->CompareIDs(lParam, nextpidl1, nextpidl2);
535 psf->Release();
536 }
537 ILFree (firstpidl);
538 return nReturn;
539 }
540
541 /***********************************************************************
542 * SHCreateLinks
543 *
544 * Undocumented.
545 */
546 HRESULT WINAPI SHCreateLinks( HWND hWnd, LPCSTR lpszDir, LPDATAOBJECT lpDataObject,
547 UINT uFlags, LPITEMIDLIST *lppidlLinks)
548 {
549 FIXME("%p %s %p %08x %p\n",hWnd,lpszDir,lpDataObject,uFlags,lppidlLinks);
550 return E_NOTIMPL;
551 }
552
553 /***********************************************************************
554 * SHOpenFolderAndSelectItems
555 *
556 * Unimplemented.
557 */
558 EXTERN_C HRESULT
559 WINAPI
560 SHOpenFolderAndSelectItems(LPITEMIDLIST pidlFolder,
561 UINT cidl,
562 PCUITEMID_CHILD_ARRAY apidl,
563 DWORD dwFlags)
564 {
565 FIXME("SHOpenFolderAndSelectItems() stub\n");
566 return E_NOTIMPL;
567 }