Changed my name, so update copyright info.
[wine] / dlls / shell32 / folders.c
1 /*
2  *      Copyright 1997  Marcus Meissner
3  *      Copyright 1998  Juergen Schmied
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "config.h"
21 #include "wine/port.h"
22
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
31 #include "undocshell.h"
32 #include "shlguid.h"
33 #include "winreg.h"
34 #include "shlwapi.h"
35
36 #include "wine/debug.h"
37 #include "winerror.h"
38
39 #include "pidl.h"
40 #include "shell32_main.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(shell);
43
44 /***********************************************************************
45 *   IExtractIconW implementation
46 */
47 typedef struct
48 {
49         ICOM_VFIELD(IExtractIconW);
50         DWORD   ref;
51         ICOM_VTABLE(IPersistFile)*      lpvtblPersistFile;
52         ICOM_VTABLE(IExtractIconA)*     lpvtblExtractIconA;
53         LPITEMIDLIST    pidl;
54 } IExtractIconWImpl;
55
56 static struct ICOM_VTABLE(IExtractIconA) eiavt;
57 static struct ICOM_VTABLE(IExtractIconW) eivt;
58 static struct ICOM_VTABLE(IPersistFile) pfvt;
59
60 #define _IPersistFile_Offset ((int)(&(((IExtractIconWImpl*)0)->lpvtblPersistFile)))
61 #define _ICOM_THIS_From_IPersistFile(class, name) class* This = (class*)(((char*)name)-_IPersistFile_Offset);
62
63 #define _IExtractIconA_Offset ((int)(&(((IExtractIconWImpl*)0)->lpvtblExtractIconA)))
64 #define _ICOM_THIS_From_IExtractIconA(class, name) class* This = (class*)(((char*)name)-_IExtractIconA_Offset);
65
66 /**************************************************************************
67 *  IExtractIconW_Constructor
68 */
69 IExtractIconW* IExtractIconW_Constructor(LPCITEMIDLIST pidl)
70 {
71         IExtractIconWImpl* ei;
72         
73         TRACE("%p\n", pidl);
74
75         ei = (IExtractIconWImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IExtractIconWImpl));
76         ei->ref=1;
77         ei->lpVtbl = &eivt;
78         ei->lpvtblPersistFile = &pfvt;
79         ei->lpvtblExtractIconA = &eiavt;
80         ei->pidl=ILClone(pidl);
81
82         pdump(pidl);
83
84         TRACE("(%p)\n", ei);
85         return (IExtractIconW *)ei;
86 }
87 /**************************************************************************
88  *  IExtractIconW_QueryInterface
89  */
90 static HRESULT WINAPI IExtractIconW_fnQueryInterface(IExtractIconW *iface, REFIID riid, LPVOID *ppvObj)
91 {
92         ICOM_THIS(IExtractIconWImpl, iface);
93
94         TRACE("(%p)->(\n\tIID:\t%s,%p)\n", This, debugstr_guid(riid), ppvObj);
95
96         *ppvObj = NULL;
97
98         if (IsEqualIID(riid, &IID_IUnknown))                            /*IUnknown*/
99         {
100           *ppvObj = This;
101         }
102         else if (IsEqualIID(riid, &IID_IPersistFile))   /*IExtractIcon*/
103         {
104           *ppvObj = (IPersistFile*)&(This->lpvtblPersistFile);
105         }
106         else if (IsEqualIID(riid, &IID_IExtractIconA))  /*IExtractIcon*/
107         {
108           *ppvObj = (IExtractIconA*)&(This->lpvtblExtractIconA);
109         }
110         else if (IsEqualIID(riid, &IID_IExtractIconW))  /*IExtractIcon*/
111         {
112           *ppvObj = (IExtractIconW*)This;
113         }
114
115         if(*ppvObj)
116         {
117           IExtractIconW_AddRef((IExtractIconW*) *ppvObj);
118           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
119           return S_OK;
120         }
121         TRACE("-- Interface: E_NOINTERFACE\n");
122         return E_NOINTERFACE;
123 }
124
125 /**************************************************************************
126 *  IExtractIconW_AddRef
127 */
128 static ULONG WINAPI IExtractIconW_fnAddRef(IExtractIconW * iface)
129 {
130         ICOM_THIS(IExtractIconWImpl, iface);
131
132         TRACE("(%p)->(count=%lu)\n",This, This->ref );
133
134         return ++(This->ref);
135 }
136 /**************************************************************************
137 *  IExtractIconW_Release
138 */
139 static ULONG WINAPI IExtractIconW_fnRelease(IExtractIconW * iface)
140 {
141         ICOM_THIS(IExtractIconWImpl, iface);
142
143         TRACE("(%p)->()\n",This);
144
145         if (!--(This->ref))
146         {
147           TRACE(" destroying IExtractIcon(%p)\n",This);
148           SHFree(This->pidl);
149           HeapFree(GetProcessHeap(),0,This);
150           return 0;
151         }
152         return This->ref;
153 }
154
155 static HRESULT getIconLocationForFolder(IExtractIconW *iface, UINT uFlags,
156  LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
157 {
158     ICOM_THIS(IExtractIconWImpl, iface);
159
160     WCHAR path[MAX_PATH];
161     BOOL found = FALSE;
162     DWORD dwNr;
163
164     if (SUCCEEDED(SHGetPathFromIDListW(This->pidl, path)))
165     {
166         static const WCHAR desktopIni[] = { 'D','e','s','k','t','o','p','.',
167          'i','n','i',0 };
168         HANDLE hFile;
169
170         PathAppendW(path, desktopIni);
171         if ((hFile = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL,
172          OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
173         {
174             static const WCHAR shellClassInfo[] = { '.','S','h','e','l','l',
175              'C','l','a','s','s','I','n','f','o',0 };
176             static const WCHAR iconFile[] =
177              { 'I','c','o','n','F','i','l','e',0 };
178             static const WCHAR clsid[] = { 'C','L','S','I','D',0 };
179             static const WCHAR clsid2[] = { 'C','L','S','I','D','2',0 };
180             static const WCHAR defStr[] = { 0 };
181             WCHAR clsidStr[39];
182
183             CloseHandle(hFile);
184             if (GetPrivateProfileStringW(shellClassInfo, iconFile, defStr,
185              szIconFile, cchMax, path) && strlenW(szIconFile))
186             {
187                 static const WCHAR iconIndex[] = { 'I','c','o','n',
188                  'I','n','d','e','x',0 };
189
190                 found = TRUE;
191                 *piIndex = (int)GetPrivateProfileIntW(shellClassInfo, iconIndex,
192                  0, path);
193             }
194             else if (GetPrivateProfileStringW(shellClassInfo, clsid, defStr,
195              clsidStr, sizeof(clsidStr) / sizeof(WCHAR), path) &&
196              strlenW(clsidStr))
197             {
198                 if (HCR_GetDefaultIconW(clsidStr, szIconFile, cchMax, &dwNr))
199                 {
200                     *piIndex = dwNr;
201                     found = TRUE;
202                 }
203             }
204             else if (GetPrivateProfileStringW(shellClassInfo, clsid2, defStr,
205              clsidStr, sizeof(clsidStr) / sizeof(WCHAR), path) &&
206              strlenW(clsidStr))
207             {
208                 if (HCR_GetDefaultIconW(clsidStr, szIconFile, cchMax, &dwNr))
209                 {
210                     *piIndex = dwNr;
211                     found = TRUE;
212                 }
213             }
214         }
215     }
216     if (!found)
217     {
218         static const WCHAR folder[] = { 'F','o','l','d','e','r',0 };
219
220         if (!HCR_GetDefaultIconW(folder, szIconFile, cchMax, &dwNr))
221         {
222             lstrcpynW(szIconFile, swShell32Name, cchMax);
223             dwNr = 3;
224         }
225         *piIndex = (uFlags & GIL_OPENICON) ? dwNr + 1 : dwNr;
226     }
227     return S_OK;
228 }
229
230 WCHAR swShell32Name[MAX_PATH];
231
232 /**************************************************************************
233 *  IExtractIconW_GetIconLocation
234 *
235 * mapping filetype to icon
236 */
237 static HRESULT WINAPI IExtractIconW_fnGetIconLocation(
238         IExtractIconW * iface,
239         UINT uFlags,            /* GIL_ flags */
240         LPWSTR szIconFile,
241         UINT cchMax,
242         int * piIndex,
243         UINT * pwFlags)         /* returned GIL_ flags */
244 {
245         ICOM_THIS(IExtractIconWImpl, iface);
246
247         char    sTemp[MAX_PATH];
248         DWORD   dwNr;
249         GUID const * riid;
250         LPITEMIDLIST    pSimplePidl = ILFindLastID(This->pidl);
251
252         TRACE("(%p) (flags=%u %p %u %p %p)\n", This, uFlags, szIconFile, cchMax, piIndex, pwFlags);
253
254         if (pwFlags)
255           *pwFlags = 0;
256
257         if (_ILIsDesktop(pSimplePidl))
258         {
259           lstrcpynW(szIconFile, swShell32Name, cchMax);
260           *piIndex = 34;
261         }
262
263         /* my computer and other shell extensions */
264         else if ((riid = _ILGetGUIDPointer(pSimplePidl)))
265         {
266           static const WCHAR fmt[] = { 'C','L','S','I','D','\\',
267        '{','%','0','8','l','x','-','%','0','4','x','-','%','0','4','x','-',
268        '%','0','2','x','%','0','2','x','-','%','0','2','x', '%','0','2','x',
269        '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0 };
270           WCHAR xriid[50];
271
272           sprintfW(xriid, fmt,
273                   riid->Data1, riid->Data2, riid->Data3,
274                   riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
275                   riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]);
276
277           if (HCR_GetDefaultIconW(xriid, szIconFile, cchMax, &dwNr))
278           {
279             *piIndex = dwNr;
280           }
281           else
282           {
283             lstrcpynW(szIconFile, swShell32Name, cchMax);
284             *piIndex = 15;
285           }
286         }
287
288         else if (_ILIsDrive (pSimplePidl))
289         {
290           static const WCHAR drive[] = { 'D','r','i','v','e',0 };
291
292           if (HCR_GetDefaultIconW(drive, szIconFile, cchMax, &dwNr))
293           {
294             *piIndex = dwNr;
295           }
296           else
297           {
298             lstrcpynW(szIconFile, swShell32Name, cchMax);
299             *piIndex = 8;
300           }
301         }
302         else if (_ILIsFolder (pSimplePidl))
303         {
304           getIconLocationForFolder(iface, uFlags, szIconFile, cchMax, piIndex,
305            pwFlags);
306         }
307         else
308         {
309           BOOL found = FALSE;
310
311           if (_ILIsCPanelStruct(pSimplePidl))
312           {
313             if (SUCCEEDED(CPanel_GetIconLocationW(pSimplePidl, szIconFile, cchMax, piIndex)))
314                 found = TRUE;
315           }
316           else if (_ILGetExtension(pSimplePidl, sTemp, MAX_PATH))
317           {
318             if (HCR_MapTypeToValueA(sTemp, sTemp, MAX_PATH, TRUE)
319                 && HCR_GetDefaultIconA(sTemp, sTemp, MAX_PATH, &dwNr))
320             {
321               if (!lstrcmpA("%1", sTemp))               /* icon is in the file */
322               {
323                 SHGetPathFromIDListW(This->pidl, szIconFile);
324                 *piIndex = 0;
325               }
326               else
327               {
328                 MultiByteToWideChar(CP_ACP, 0, sTemp, -1, szIconFile, cchMax);
329                 *piIndex = dwNr;
330               }
331
332               found = TRUE;
333             }
334             else if (!strcasecmp(sTemp, "lnkfile"))
335             {
336               /* extract icon from shell shortcut */
337               IShellFolder* dsf;
338               IShellLinkW* psl;
339
340               if (SUCCEEDED(SHGetDesktopFolder(&dsf)))
341               {
342                 HRESULT hr = IShellFolder_GetUIObjectOf(dsf, NULL, 1, (LPCITEMIDLIST*)&This->pidl, &IID_IShellLinkW, NULL, (LPVOID*)&psl);
343
344                 if (SUCCEEDED(hr))
345                 {
346                   hr = IShellLinkW_GetIconLocation(psl, szIconFile, MAX_PATH, piIndex);
347
348                   if (SUCCEEDED(hr) && *szIconFile)
349                     found = TRUE;
350
351                   IShellLinkW_Release(psl);
352                 }
353
354                 IShellFolder_Release(dsf);
355               }
356             }
357           }
358
359           if (!found)                                   /* default icon */
360           {
361             lstrcpynW(szIconFile, swShell32Name, cchMax);
362             *piIndex = 0;
363           }
364         }
365
366         TRACE("-- %s %x\n", debugstr_w(szIconFile), *piIndex);
367         return NOERROR;
368 }
369
370 /**************************************************************************
371 *  IExtractIconW_Extract
372 */
373 static HRESULT WINAPI IExtractIconW_fnExtract(IExtractIconW * iface, LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
374 {
375         ICOM_THIS(IExtractIconWImpl, iface);
376
377         FIXME("(%p) (file=%p index=%u %p %p size=%u) semi-stub\n", This, debugstr_w(pszFile), nIconIndex, phiconLarge, phiconSmall, nIconSize);
378
379         if (phiconLarge)
380           *phiconLarge = ImageList_GetIcon(ShellBigIconList, nIconIndex, ILD_TRANSPARENT);
381
382         if (phiconSmall)
383           *phiconSmall = ImageList_GetIcon(ShellSmallIconList, nIconIndex, ILD_TRANSPARENT);
384
385         return S_OK;
386 }
387
388 static struct ICOM_VTABLE(IExtractIconW) eivt =
389 {
390         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
391         IExtractIconW_fnQueryInterface,
392         IExtractIconW_fnAddRef,
393         IExtractIconW_fnRelease,
394         IExtractIconW_fnGetIconLocation,
395         IExtractIconW_fnExtract
396 };
397
398 /**************************************************************************
399 *  IExtractIconA_Constructor
400 */
401 IExtractIconA* IExtractIconA_Constructor(LPCITEMIDLIST pidl)
402 {
403         ICOM_THIS(IExtractIconWImpl, IExtractIconW_Constructor(pidl));
404         IExtractIconA *eia = (IExtractIconA *)&This->lpvtblExtractIconA;
405         
406         TRACE("(%p)->(%p)\n", This, eia);
407         return eia;
408 }
409 /**************************************************************************
410  *  IExtractIconA_QueryInterface
411  */
412 static HRESULT WINAPI IExtractIconA_fnQueryInterface(IExtractIconA * iface, REFIID riid, LPVOID *ppvObj)
413 {
414         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
415
416         return IExtractIconW_QueryInterface(This, riid, ppvObj);
417 }
418
419 /**************************************************************************
420 *  IExtractIconA_AddRef
421 */
422 static ULONG WINAPI IExtractIconA_fnAddRef(IExtractIconA * iface)
423 {
424         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
425
426         return IExtractIconW_AddRef(This);
427 }
428 /**************************************************************************
429 *  IExtractIconA_Release
430 */
431 static ULONG WINAPI IExtractIconA_fnRelease(IExtractIconA * iface)
432 {
433         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
434
435         return IExtractIconW_AddRef(This);
436 }
437 /**************************************************************************
438 *  IExtractIconA_GetIconLocation
439 *
440 * mapping filetype to icon
441 */
442 static HRESULT WINAPI IExtractIconA_fnGetIconLocation(
443         IExtractIconA * iface,
444         UINT uFlags,
445         LPSTR szIconFile,
446         UINT cchMax,
447         int * piIndex,
448         UINT * pwFlags)
449 {
450         HRESULT ret;
451         LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, cchMax * sizeof(WCHAR));
452         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
453         
454         TRACE("(%p) (flags=%u %p %u %p %p)\n", This, uFlags, szIconFile, cchMax, piIndex, pwFlags);
455
456         ret = IExtractIconW_GetIconLocation(This, uFlags, lpwstrFile, cchMax, piIndex, pwFlags);
457         WideCharToMultiByte(CP_ACP, 0, lpwstrFile, -1, szIconFile, cchMax, NULL, NULL);
458         HeapFree(GetProcessHeap(), 0, lpwstrFile);
459
460         TRACE("-- %s %x\n", szIconFile, *piIndex);
461         return ret;
462 }
463 /**************************************************************************
464 *  IExtractIconA_Extract
465 */
466 static HRESULT WINAPI IExtractIconA_fnExtract(IExtractIconA * iface, LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
467 {
468         HRESULT ret;
469         INT len = MultiByteToWideChar(CP_ACP, 0, pszFile, -1, NULL, 0);
470         LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
471         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
472
473         TRACE("(%p) (file=%p index=%u %p %p size=%u)\n", This, pszFile, nIconIndex, phiconLarge, phiconSmall, nIconSize);
474
475         MultiByteToWideChar(CP_ACP, 0, pszFile, -1, lpwstrFile, len);
476         ret = IExtractIconW_Extract(This, lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIconSize);
477         HeapFree(GetProcessHeap(), 0, lpwstrFile);
478         return ret;
479 }
480
481 static struct ICOM_VTABLE(IExtractIconA) eiavt =
482 {
483         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
484         IExtractIconA_fnQueryInterface,
485         IExtractIconA_fnAddRef,
486         IExtractIconA_fnRelease,
487         IExtractIconA_fnGetIconLocation,
488         IExtractIconA_fnExtract
489 };
490
491 /************************************************************************
492  * IEIPersistFile_QueryInterface (IUnknown)
493  */
494 static HRESULT WINAPI IEIPersistFile_fnQueryInterface(
495         IPersistFile    *iface,
496         REFIID          iid,
497         LPVOID          *ppvObj)
498 {
499         _ICOM_THIS_From_IPersistFile(IExtractIconW, iface);
500
501         return IExtractIconW_QueryInterface(This, iid, ppvObj);
502 }
503
504 /************************************************************************
505  * IEIPersistFile_AddRef (IUnknown)
506  */
507 static ULONG WINAPI IEIPersistFile_fnAddRef(
508         IPersistFile    *iface)
509 {
510         _ICOM_THIS_From_IPersistFile(IExtractIconW, iface);
511
512         return IExtractIconW_AddRef(This);
513 }
514
515 /************************************************************************
516  * IEIPersistFile_Release (IUnknown)
517  */
518 static ULONG WINAPI IEIPersistFile_fnRelease(
519         IPersistFile    *iface)
520 {
521         _ICOM_THIS_From_IPersistFile(IExtractIconW, iface);
522
523         return IExtractIconW_Release(This);
524 }
525
526 /************************************************************************
527  * IEIPersistFile_GetClassID (IPersist)
528  */
529 static HRESULT WINAPI IEIPersistFile_fnGetClassID(
530         IPersistFile    *iface,
531         LPCLSID         lpClassId)
532 {
533         CLSID StdFolderID = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} };
534
535         if (lpClassId==NULL)
536           return E_POINTER;
537
538         memcpy(lpClassId, &StdFolderID, sizeof(StdFolderID));
539
540         return S_OK;
541 }
542
543 /************************************************************************
544  * IEIPersistFile_Load (IPersistFile)
545  */
546 static HRESULT WINAPI IEIPersistFile_fnLoad(IPersistFile* iface, LPCOLESTR pszFileName, DWORD dwMode)
547 {
548         _ICOM_THIS_From_IPersistFile(IExtractIconW, iface);
549         FIXME("%p\n", This);
550         return E_NOTIMPL;
551
552 }
553
554 static struct ICOM_VTABLE(IPersistFile) pfvt =
555 {
556         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
557         IEIPersistFile_fnQueryInterface,
558         IEIPersistFile_fnAddRef,
559         IEIPersistFile_fnRelease,
560         IEIPersistFile_fnGetClassID,
561         (void *) 0xdeadbeef /* IEIPersistFile_fnIsDirty */,
562         IEIPersistFile_fnLoad,
563         (void *) 0xdeadbeef /* IEIPersistFile_fnSave */,
564         (void *) 0xdeadbeef /* IEIPersistFile_fnSaveCompleted */,
565         (void *) 0xdeadbeef /* IEIPersistFile_fnGetCurFile */
566 };