Implemented NtCreatelFile using the new symlink scheme.
[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
34 #include "wine/debug.h"
35 #include "winerror.h"
36
37 #include "pidl.h"
38 #include "shell32_main.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(shell);
41
42 /***********************************************************************
43 *   IExtractIconW implementation
44 */
45 typedef struct
46 {
47         ICOM_VFIELD(IExtractIconW);
48         DWORD   ref;
49         ICOM_VTABLE(IPersistFile)*      lpvtblPersistFile;
50         ICOM_VTABLE(IExtractIconA)*     lpvtblExtractIconA;
51         LPITEMIDLIST    pidl;
52 } IExtractIconWImpl;
53
54 static struct ICOM_VTABLE(IExtractIconA) eiavt;
55 static struct ICOM_VTABLE(IExtractIconW) eivt;
56 static struct ICOM_VTABLE(IPersistFile) pfvt;
57
58 #define _IPersistFile_Offset ((int)(&(((IExtractIconWImpl*)0)->lpvtblPersistFile)))
59 #define _ICOM_THIS_From_IPersistFile(class, name) class* This = (class*)(((char*)name)-_IPersistFile_Offset);
60
61 #define _IExtractIconA_Offset ((int)(&(((IExtractIconWImpl*)0)->lpvtblExtractIconA)))
62 #define _ICOM_THIS_From_IExtractIconA(class, name) class* This = (class*)(((char*)name)-_IExtractIconA_Offset);
63
64 /**************************************************************************
65 *  IExtractIconW_Constructor
66 */
67 IExtractIconW* IExtractIconW_Constructor(LPCITEMIDLIST pidl)
68 {
69         IExtractIconWImpl* ei;
70         
71         TRACE("%p\n", pidl);
72
73         ei = (IExtractIconWImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IExtractIconWImpl));
74         ei->ref=1;
75         ei->lpVtbl = &eivt;
76         ei->lpvtblPersistFile = &pfvt;
77         ei->lpvtblExtractIconA = &eiavt;
78         ei->pidl=ILClone(pidl);
79
80         pdump(pidl);
81
82         TRACE("(%p)\n", ei);
83         return (IExtractIconW *)ei;
84 }
85 /**************************************************************************
86  *  IExtractIconW_QueryInterface
87  */
88 static HRESULT WINAPI IExtractIconW_fnQueryInterface(IExtractIconW *iface, REFIID riid, LPVOID *ppvObj)
89 {
90         ICOM_THIS(IExtractIconWImpl, iface);
91
92         TRACE("(%p)->(\n\tIID:\t%s,%p)\n", This, debugstr_guid(riid), ppvObj);
93
94         *ppvObj = NULL;
95
96         if (IsEqualIID(riid, &IID_IUnknown))                            /*IUnknown*/
97         {
98           *ppvObj = This;
99         }
100         else if (IsEqualIID(riid, &IID_IPersistFile))   /*IExtractIcon*/
101         {
102           *ppvObj = (IPersistFile*)&(This->lpvtblPersistFile);
103         }
104         else if (IsEqualIID(riid, &IID_IExtractIconA))  /*IExtractIcon*/
105         {
106           *ppvObj = (IExtractIconA*)&(This->lpvtblExtractIconA);
107         }
108         else if (IsEqualIID(riid, &IID_IExtractIconW))  /*IExtractIcon*/
109         {
110           *ppvObj = (IExtractIconW*)This;
111         }
112
113         if(*ppvObj)
114         {
115           IExtractIconW_AddRef((IExtractIconW*) *ppvObj);
116           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
117           return S_OK;
118         }
119         TRACE("-- Interface: E_NOINTERFACE\n");
120         return E_NOINTERFACE;
121 }
122
123 /**************************************************************************
124 *  IExtractIconW_AddRef
125 */
126 static ULONG WINAPI IExtractIconW_fnAddRef(IExtractIconW * iface)
127 {
128         ICOM_THIS(IExtractIconWImpl, iface);
129
130         TRACE("(%p)->(count=%lu)\n",This, This->ref );
131
132         return ++(This->ref);
133 }
134 /**************************************************************************
135 *  IExtractIconW_Release
136 */
137 static ULONG WINAPI IExtractIconW_fnRelease(IExtractIconW * iface)
138 {
139         ICOM_THIS(IExtractIconWImpl, iface);
140
141         TRACE("(%p)->()\n",This);
142
143         if (!--(This->ref))
144         {
145           TRACE(" destroying IExtractIcon(%p)\n",This);
146           SHFree(This->pidl);
147           HeapFree(GetProcessHeap(),0,This);
148           return 0;
149         }
150         return This->ref;
151 }
152
153 WCHAR swShell32Name[MAX_PATH];
154
155 /**************************************************************************
156 *  IExtractIconW_GetIconLocation
157 *
158 * mapping filetype to icon
159 */
160 static HRESULT WINAPI IExtractIconW_fnGetIconLocation(
161         IExtractIconW * iface,
162         UINT uFlags,            /* GIL_ flags */
163         LPWSTR szIconFile,
164         UINT cchMax,
165         int * piIndex,
166         UINT * pwFlags)         /* returned GIL_ flags */
167 {
168         ICOM_THIS(IExtractIconWImpl, iface);
169
170         char    sTemp[MAX_PATH];
171         DWORD   dwNr;
172         GUID const * riid;
173         LPITEMIDLIST    pSimplePidl = ILFindLastID(This->pidl);
174
175         TRACE("(%p) (flags=%u %p %u %p %p)\n", This, uFlags, szIconFile, cchMax, piIndex, pwFlags);
176
177         if (pwFlags)
178           *pwFlags = 0;
179
180         if (_ILIsDesktop(pSimplePidl))
181         {
182           lstrcpynW(szIconFile, swShell32Name, cchMax);
183           *piIndex = 34;
184         }
185
186         /* my computer and other shell extensions */
187         else if ((riid = _ILGetGUIDPointer(pSimplePidl)))
188         {
189           static WCHAR fmt[] = { 'C','L','S','I','D','\\','{','%','0','8','l','x',
190        '-','%','0','4','x','-','%','0','4','x','-','%','0','2','x',
191        '%','0','2','x','-','%','0','2','x', '%','0','2','x', '%','0','2','x',
192        '%','0','2','x','%','0','2','x','%','0','2','x','}',0 };
193           WCHAR xriid[50];
194
195           sprintfW(xriid, fmt,
196                   riid->Data1, riid->Data2, riid->Data3,
197                   riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
198                   riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]);
199
200           if (HCR_GetDefaultIconW(xriid, szIconFile, cchMax, &dwNr))
201           {
202             *piIndex = dwNr;
203           }
204           else
205           {
206             lstrcpynW(szIconFile, swShell32Name, cchMax);
207             *piIndex = 15;
208           }
209         }
210
211         else if (_ILIsDrive (pSimplePidl))
212         {
213           static WCHAR drive[] = { 'D','r','i','v','e',0 };
214
215           if (HCR_GetDefaultIconW(drive, szIconFile, cchMax, &dwNr))
216           {
217             *piIndex = dwNr;
218           }
219           else
220           {
221             lstrcpynW(szIconFile, swShell32Name, cchMax);
222             *piIndex = 8;
223           }
224         }
225         else if (_ILIsFolder (pSimplePidl))
226         {
227           static WCHAR folder[] = { 'F','o','l','d','e','r',0 };
228
229           if (!HCR_GetDefaultIconW(folder, szIconFile, cchMax, &dwNr))
230           {
231             lstrcpynW(szIconFile, swShell32Name, cchMax);
232             dwNr = 3;
233           }
234           *piIndex = (uFlags & GIL_OPENICON) ? dwNr + 1 : dwNr;
235         }
236
237         else
238         {
239           BOOL found = FALSE;
240
241           if (_ILIsCPanelStruct(pSimplePidl))
242           {
243             if (SUCCEEDED(CPanel_GetIconLocationW(pSimplePidl, szIconFile, cchMax, piIndex)))
244                 found = TRUE;
245           }
246           else if (_ILGetExtension(pSimplePidl, sTemp, MAX_PATH))
247           {
248             if (HCR_MapTypeToValueA(sTemp, sTemp, MAX_PATH, TRUE)
249                 && HCR_GetDefaultIconA(sTemp, sTemp, MAX_PATH, &dwNr))
250             {
251               if (!lstrcmpA("%1", sTemp))               /* icon is in the file */
252               {
253                 SHGetPathFromIDListW(This->pidl, szIconFile);
254                 *piIndex = 0;
255               }
256               else
257               {
258                 MultiByteToWideChar(CP_ACP, 0, sTemp, -1, szIconFile, cchMax);
259                 *piIndex = dwNr;
260               }
261
262               found = TRUE;
263             }
264             else if (!strcasecmp(sTemp, "lnkfile"))
265             {
266               /* extract icon from shell shortcut */
267               IShellFolder* dsf;
268               IShellLinkW* psl;
269
270               if (SUCCEEDED(SHGetDesktopFolder(&dsf)))
271               {
272                 HRESULT hr = IShellFolder_GetUIObjectOf(dsf, NULL, 1, (LPCITEMIDLIST*)&This->pidl, &IID_IShellLinkW, NULL, (LPVOID*)&psl);
273
274                 if (SUCCEEDED(hr))
275                 {
276                   hr = IShellLinkW_GetIconLocation(psl, szIconFile, MAX_PATH, piIndex);
277
278                   if (SUCCEEDED(hr) && *szIconFile)
279                     found = TRUE;
280
281                   IShellLinkW_Release(psl);
282                 }
283
284                 IShellFolder_Release(dsf);
285               }
286             }
287           }
288
289           if (!found)                                   /* default icon */
290           {
291             lstrcpynW(szIconFile, swShell32Name, cchMax);
292             *piIndex = 0;
293           }
294         }
295
296         TRACE("-- %s %x\n", debugstr_w(szIconFile), *piIndex);
297         return NOERROR;
298 }
299
300 /**************************************************************************
301 *  IExtractIconW_Extract
302 */
303 static HRESULT WINAPI IExtractIconW_fnExtract(IExtractIconW * iface, LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
304 {
305         ICOM_THIS(IExtractIconWImpl, iface);
306
307         FIXME("(%p) (file=%p index=%u %p %p size=%u) semi-stub\n", This, debugstr_w(pszFile), nIconIndex, phiconLarge, phiconSmall, nIconSize);
308
309         if (phiconLarge)
310           *phiconLarge = ImageList_GetIcon(ShellBigIconList, nIconIndex, ILD_TRANSPARENT);
311
312         if (phiconSmall)
313           *phiconSmall = ImageList_GetIcon(ShellSmallIconList, nIconIndex, ILD_TRANSPARENT);
314
315         return S_OK;
316 }
317
318 static struct ICOM_VTABLE(IExtractIconW) eivt =
319 {
320         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
321         IExtractIconW_fnQueryInterface,
322         IExtractIconW_fnAddRef,
323         IExtractIconW_fnRelease,
324         IExtractIconW_fnGetIconLocation,
325         IExtractIconW_fnExtract
326 };
327
328 /**************************************************************************
329 *  IExtractIconA_Constructor
330 */
331 IExtractIconA* IExtractIconA_Constructor(LPCITEMIDLIST pidl)
332 {
333         ICOM_THIS(IExtractIconWImpl, IExtractIconW_Constructor(pidl));
334         IExtractIconA *eia = (IExtractIconA *)&This->lpvtblExtractIconA;
335         
336         TRACE("(%p)->(%p)\n", This, eia);
337         return eia;
338 }
339 /**************************************************************************
340  *  IExtractIconA_QueryInterface
341  */
342 static HRESULT WINAPI IExtractIconA_fnQueryInterface(IExtractIconA * iface, REFIID riid, LPVOID *ppvObj)
343 {
344         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
345
346         return IExtractIconW_QueryInterface(This, riid, ppvObj);
347 }
348
349 /**************************************************************************
350 *  IExtractIconA_AddRef
351 */
352 static ULONG WINAPI IExtractIconA_fnAddRef(IExtractIconA * iface)
353 {
354         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
355
356         return IExtractIconW_AddRef(This);
357 }
358 /**************************************************************************
359 *  IExtractIconA_Release
360 */
361 static ULONG WINAPI IExtractIconA_fnRelease(IExtractIconA * iface)
362 {
363         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
364
365         return IExtractIconW_AddRef(This);
366 }
367 /**************************************************************************
368 *  IExtractIconA_GetIconLocation
369 *
370 * mapping filetype to icon
371 */
372 static HRESULT WINAPI IExtractIconA_fnGetIconLocation(
373         IExtractIconA * iface,
374         UINT uFlags,
375         LPSTR szIconFile,
376         UINT cchMax,
377         int * piIndex,
378         UINT * pwFlags)
379 {
380         HRESULT ret;
381         LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, cchMax * sizeof(WCHAR));
382         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
383         
384         TRACE("(%p) (flags=%u %p %u %p %p)\n", This, uFlags, szIconFile, cchMax, piIndex, pwFlags);
385
386         ret = IExtractIconW_GetIconLocation(This, uFlags, lpwstrFile, cchMax, piIndex, pwFlags);
387         WideCharToMultiByte(CP_ACP, 0, lpwstrFile, -1, szIconFile, cchMax, NULL, NULL);
388         HeapFree(GetProcessHeap(), 0, lpwstrFile);
389
390         TRACE("-- %s %x\n", szIconFile, *piIndex);
391         return ret;
392 }
393 /**************************************************************************
394 *  IExtractIconA_Extract
395 */
396 static HRESULT WINAPI IExtractIconA_fnExtract(IExtractIconA * iface, LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
397 {
398         HRESULT ret;
399         INT len = MultiByteToWideChar(CP_ACP, 0, pszFile, -1, NULL, 0);
400         LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
401         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
402
403         TRACE("(%p) (file=%p index=%u %p %p size=%u)\n", This, pszFile, nIconIndex, phiconLarge, phiconSmall, nIconSize);
404
405         MultiByteToWideChar(CP_ACP, 0, pszFile, -1, lpwstrFile, len);
406         ret = IExtractIconW_Extract(This, lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIconSize);
407         HeapFree(GetProcessHeap(), 0, lpwstrFile);
408         return ret;
409 }
410
411 static struct ICOM_VTABLE(IExtractIconA) eiavt =
412 {
413         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
414         IExtractIconA_fnQueryInterface,
415         IExtractIconA_fnAddRef,
416         IExtractIconA_fnRelease,
417         IExtractIconA_fnGetIconLocation,
418         IExtractIconA_fnExtract
419 };
420
421 /************************************************************************
422  * IEIPersistFile_QueryInterface (IUnknown)
423  */
424 static HRESULT WINAPI IEIPersistFile_fnQueryInterface(
425         IPersistFile    *iface,
426         REFIID          iid,
427         LPVOID          *ppvObj)
428 {
429         _ICOM_THIS_From_IPersistFile(IExtractIconW, iface);
430
431         return IExtractIconW_QueryInterface(This, iid, ppvObj);
432 }
433
434 /************************************************************************
435  * IEIPersistFile_AddRef (IUnknown)
436  */
437 static ULONG WINAPI IEIPersistFile_fnAddRef(
438         IPersistFile    *iface)
439 {
440         _ICOM_THIS_From_IPersistFile(IExtractIconW, iface);
441
442         return IExtractIconW_AddRef(This);
443 }
444
445 /************************************************************************
446  * IEIPersistFile_Release (IUnknown)
447  */
448 static ULONG WINAPI IEIPersistFile_fnRelease(
449         IPersistFile    *iface)
450 {
451         _ICOM_THIS_From_IPersistFile(IExtractIconW, iface);
452
453         return IExtractIconW_Release(This);
454 }
455
456 /************************************************************************
457  * IEIPersistFile_GetClassID (IPersist)
458  */
459 static HRESULT WINAPI IEIPersistFile_fnGetClassID(
460         IPersistFile    *iface,
461         LPCLSID         lpClassId)
462 {
463         CLSID StdFolderID = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} };
464
465         if (lpClassId==NULL)
466           return E_POINTER;
467
468         memcpy(lpClassId, &StdFolderID, sizeof(StdFolderID));
469
470         return S_OK;
471 }
472
473 /************************************************************************
474  * IEIPersistFile_Load (IPersistFile)
475  */
476 static HRESULT WINAPI IEIPersistFile_fnLoad(IPersistFile* iface, LPCOLESTR pszFileName, DWORD dwMode)
477 {
478         _ICOM_THIS_From_IPersistFile(IExtractIconW, iface);
479         FIXME("%p\n", This);
480         return E_NOTIMPL;
481
482 }
483
484 static struct ICOM_VTABLE(IPersistFile) pfvt =
485 {
486         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
487         IEIPersistFile_fnQueryInterface,
488         IEIPersistFile_fnAddRef,
489         IEIPersistFile_fnRelease,
490         IEIPersistFile_fnGetClassID,
491         (void *) 0xdeadbeef /* IEIPersistFile_fnIsDirty */,
492         IEIPersistFile_fnLoad,
493         (void *) 0xdeadbeef /* IEIPersistFile_fnSave */,
494         (void *) 0xdeadbeef /* IEIPersistFile_fnSaveCompleted */,
495         (void *) 0xdeadbeef /* IEIPersistFile_fnGetCurFile */
496 };