folders.c 16.6 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 *	Copyright 1997	Marcus Meissner
 *	Copyright 1998	Juergen Schmied
 *
5 6 7 8 9 10 11 12 13 14 15 16
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
18 19
 */

20 21 22
#include "config.h"
#include "wine/port.h"

Alexandre Julliard's avatar
Alexandre Julliard committed
23
#include <stdlib.h>
24
#include <stdarg.h>
25
#include <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
26
#include <string.h>
27

28 29
#define COBJMACROS

30
#include "windef.h"
31
#include "winbase.h"
32
#include "winerror.h"
33
#include "objbase.h"
34
#include "undocshell.h"
35
#include "shlguid.h"
36

37
#include "wine/debug.h"
38

39
#include "pidl.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
40
#include "shell32_main.h"
41
#include "shfldr.h"
42
#include "shresdef.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
43

44
WINE_DEFAULT_DEBUG_CHANNEL(shell);
45

46
/***********************************************************************
47
*   IExtractIconW implementation
Alexandre Julliard's avatar
Alexandre Julliard committed
48
*/
49
typedef struct
50
{
51
        IExtractIconW      IExtractIconW_iface;
52
        IExtractIconA      IExtractIconA_iface;
53
        IPersistFile       IPersistFile_iface;
Mike McCormack's avatar
Mike McCormack committed
54
	LONG               ref;
55
	LPITEMIDLIST       pidl;
56
} IExtractIconWImpl;
57

58 59 60 61 62
static inline IExtractIconWImpl *impl_from_IExtractIconW(IExtractIconW *iface)
{
    return CONTAINING_RECORD(iface, IExtractIconWImpl, IExtractIconW_iface);
}

63 64 65 66 67
static inline IExtractIconWImpl *impl_from_IExtractIconA(IExtractIconA *iface)
{
    return CONTAINING_RECORD(iface, IExtractIconWImpl, IExtractIconA_iface);
}

68 69 70 71 72
static inline IExtractIconWImpl *impl_from_IPersistFile(IPersistFile *iface)
{
    return CONTAINING_RECORD(iface, IExtractIconWImpl, IPersistFile_iface);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
73 74

/**************************************************************************
75
 *  IExtractIconW::QueryInterface
Alexandre Julliard's avatar
Alexandre Julliard committed
76
 */
77 78
static HRESULT WINAPI IExtractIconW_fnQueryInterface(IExtractIconW *iface, REFIID riid,
        void **ppv)
79
{
80
    IExtractIconWImpl *This = impl_from_IExtractIconW(iface);
81

82
    TRACE("(%p)->(\n\tIID:\t%s,%p)\n", This, debugstr_guid(riid), ppv);
83

84 85 86 87
    *ppv = NULL;
    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IExtractIconW))
        *ppv = iface;
    else if (IsEqualIID(riid, &IID_IPersistFile))
88
        *ppv = &This->IPersistFile_iface;
89
    else if (IsEqualIID(riid, &IID_IExtractIconA))
90
        *ppv = &This->IExtractIconA_iface;
91

92 93 94 95 96 97 98 99
    if(*ppv)
    {
        IUnknown_AddRef((IUnknown*)*ppv);
        TRACE("-- Interface: (%p)->(%p)\n", ppv, *ppv);
        return S_OK;
    }
    TRACE("-- Interface: E_NOINTERFACE\n");
    return E_NOINTERFACE;
100
}
Alexandre Julliard's avatar
Alexandre Julliard committed
101 102

/**************************************************************************
103
*  IExtractIconW::AddRef
Alexandre Julliard's avatar
Alexandre Julliard committed
104
*/
105
static ULONG WINAPI IExtractIconW_fnAddRef(IExtractIconW * iface)
106
{
107
        IExtractIconWImpl *This = impl_from_IExtractIconW(iface);
108
	ULONG refCount = InterlockedIncrement(&This->ref);
109

110
	TRACE("(%p)->(count=%u)\n", This, refCount - 1);
111

112
	return refCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
113 114
}
/**************************************************************************
115
*  IExtractIconW::Release
Alexandre Julliard's avatar
Alexandre Julliard committed
116
*/
117
static ULONG WINAPI IExtractIconW_fnRelease(IExtractIconW * iface)
118
{
119
        IExtractIconWImpl *This = impl_from_IExtractIconW(iface);
120
	ULONG refCount = InterlockedDecrement(&This->ref);
121

122
	TRACE("(%p)->(count=%u)\n", This, refCount + 1);
123

124
	if (!refCount)
125 126
	{
	  TRACE(" destroying IExtractIcon(%p)\n",This);
127 128 129 130
	  SHFree(This->pidl);
	  HeapFree(GetProcessHeap(),0,This);
	  return 0;
	}
131
	return refCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
132
}
133

134 135
static HRESULT getIconLocationForFolder(IExtractIconWImpl *This, UINT uFlags, LPWSTR szIconFile,
        UINT cchMax, int *piIndex, UINT *pwFlags)
136
{
137
    int icon_idx;
138 139 140 141 142 143 144 145 146 147
    WCHAR wszPath[MAX_PATH];
    WCHAR wszCLSIDValue[CHARS_IN_GUID];
    static const WCHAR shellClassInfo[] = { '.','S','h','e','l','l','C','l','a','s','s','I','n','f','o',0 };
    static const WCHAR iconFile[] = { 'I','c','o','n','F','i','l','e',0 };
    static const WCHAR clsid[] = { 'C','L','S','I','D',0 };
    static const WCHAR clsid2[] = { 'C','L','S','I','D','2',0 };
    static const WCHAR iconIndex[] = { 'I','c','o','n','I','n','d','e','x',0 };

    if (SHELL32_GetCustomFolderAttribute(This->pidl, shellClassInfo, iconFile,
        wszPath, MAX_PATH))
148
    {
149 150 151 152 153 154 155
        WCHAR wszIconIndex[10];
        SHELL32_GetCustomFolderAttribute(This->pidl, shellClassInfo, iconIndex,
            wszIconIndex, 10);
        *piIndex = atoiW(wszIconIndex);
    }
    else if (SHELL32_GetCustomFolderAttribute(This->pidl, shellClassInfo, clsid,
        wszCLSIDValue, CHARS_IN_GUID) &&
156
        HCR_GetDefaultIconW(wszCLSIDValue, szIconFile, cchMax, &icon_idx))
157
    {
158
       *piIndex = icon_idx;
159 160 161
    }
    else if (SHELL32_GetCustomFolderAttribute(This->pidl, shellClassInfo, clsid2,
        wszCLSIDValue, CHARS_IN_GUID) &&
162
        HCR_GetDefaultIconW(wszCLSIDValue, szIconFile, cchMax, &icon_idx))
163
    {
164
       *piIndex = icon_idx;
165
    }
166
    else
167 168 169
    {
        static const WCHAR folder[] = { 'F','o','l','d','e','r',0 };

170
        if (!HCR_GetDefaultIconW(folder, szIconFile, cchMax, &icon_idx))
171 172
        {
            lstrcpynW(szIconFile, swShell32Name, cchMax);
173
            icon_idx = -IDI_SHELL_FOLDER;
174
        }
175 176 177 178 179

        if (uFlags & GIL_OPENICON)
            *piIndex = icon_idx<0? icon_idx-1: icon_idx+1;
        else
            *piIndex = icon_idx;
180
    }
181

182 183 184
    return S_OK;
}

185
WCHAR swShell32Name[MAX_PATH];
186

Alexandre Julliard's avatar
Alexandre Julliard committed
187
/**************************************************************************
188
*  IExtractIconW::GetIconLocation
189 190
*
* mapping filetype to icon
Alexandre Julliard's avatar
Alexandre Julliard committed
191
*/
192 193
static HRESULT WINAPI IExtractIconW_fnGetIconLocation(IExtractIconW * iface, UINT uFlags,
        LPWSTR szIconFile, UINT cchMax, int * piIndex, UINT * pwFlags)
194
{
195
        IExtractIconWImpl *This = impl_from_IExtractIconW(iface);
196
	char	sTemp[MAX_PATH];
197
	int		icon_idx;
198
	GUID const * riid;
199
	LPITEMIDLIST	pSimplePidl = ILFindLastID(This->pidl);
200

201
	TRACE("(%p) (flags=%u %p %u %p %p)\n", This, uFlags, szIconFile, cchMax, piIndex, pwFlags);
202

203 204
	if (pwFlags)
	  *pwFlags = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
205

206
	if (_ILIsDesktop(pSimplePidl))
207
	{
208
	  lstrcpynW(szIconFile, swShell32Name, cchMax);
209
	  *piIndex = -IDI_SHELL_DESKTOP;
210
	}
211 212

	/* my computer and other shell extensions */
213
	else if ((riid = _ILGetGUIDPointer(pSimplePidl)))
214
	{
215 216 217 218
	  static const WCHAR fmt[] = { 'C','L','S','I','D','\\',
       '{','%','0','8','l','x','-','%','0','4','x','-','%','0','4','x','-',
       '%','0','2','x','%','0','2','x','-','%','0','2','x', '%','0','2','x',
       '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0 };
219
	  WCHAR xriid[50];
220

221
	  sprintfW(xriid, fmt,
222 223 224
	          riid->Data1, riid->Data2, riid->Data3,
	          riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
	          riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]);
225

226
	  if (HCR_GetDefaultIconW(xriid, szIconFile, cchMax, &icon_idx))
227
	  {
228
	    *piIndex = icon_idx;
229 230
	  }
	  else
231
	  {
232
	    lstrcpynW(szIconFile, swShell32Name, cchMax);
233 234 235
            if(IsEqualGUID(riid, &CLSID_MyComputer))
                *piIndex = -IDI_SHELL_MY_COMPUTER;
            else if(IsEqualGUID(riid, &CLSID_MyDocuments))
236
                *piIndex = -IDI_SHELL_MY_DOCUMENTS;
237 238
            else if(IsEqualGUID(riid, &CLSID_NetworkPlaces))
                *piIndex = -IDI_SHELL_MY_NETWORK_PLACES;
239 240
            else if(IsEqualGUID(riid, &CLSID_UnixFolder) ||
                    IsEqualGUID(riid, &CLSID_UnixDosFolder))
241
                *piIndex = -IDI_SHELL_DRIVE;
242 243
            else
                *piIndex = -IDI_SHELL_FOLDER;
244 245
	  }
	}
246

247
	else if (_ILIsDrive (pSimplePidl))
248
	{
249
	  static const WCHAR drive[] = { 'D','r','i','v','e',0 };
250

251 252 253
	  int icon_idx = -1;

	  if (_ILGetDrive(pSimplePidl, sTemp, MAX_PATH))
254
	  {
255 256
		switch(GetDriveTypeA(sTemp))
		{
257 258 259 260
                  case DRIVE_REMOVABLE:   icon_idx = IDI_SHELL_FLOPPY;        break;
                  case DRIVE_CDROM:       icon_idx = IDI_SHELL_CDROM;         break;
                  case DRIVE_REMOTE:      icon_idx = IDI_SHELL_NETDRIVE;      break;
                  case DRIVE_RAMDISK:     icon_idx = IDI_SHELL_RAMDISK;       break;
261 262 263 264 265 266
		}
	  }

	  if (icon_idx != -1)
	  {
		lstrcpynW(szIconFile, swShell32Name, cchMax);
267
		*piIndex = -icon_idx;
268 269
	  }
	  else
270
	  {
271
		if (HCR_GetDefaultIconW(drive, szIconFile, cchMax, &icon_idx))
272
		{
273
		  *piIndex = icon_idx;
274 275 276 277
		}
		else
		{
		  lstrcpynW(szIconFile, swShell32Name, cchMax);
278
		  *piIndex = -IDI_SHELL_DRIVE;
279
		}
280 281 282
	  }
	}
	else if (_ILIsFolder (pSimplePidl))
283
	{
284
            getIconLocationForFolder(This, uFlags, szIconFile, cchMax, piIndex, pwFlags);
285
	}
286
	else
287
	{
288 289 290 291 292 293 294 295
	  BOOL found = FALSE;

	  if (_ILIsCPanelStruct(pSimplePidl))
	  {
	    if (SUCCEEDED(CPanel_GetIconLocationW(pSimplePidl, szIconFile, cchMax, piIndex)))
		found = TRUE;
	  }
	  else if (_ILGetExtension(pSimplePidl, sTemp, MAX_PATH))
296
	  {
297
	    if (HCR_MapTypeToValueA(sTemp, sTemp, MAX_PATH, TRUE)
298
		&& HCR_GetDefaultIconA(sTemp, sTemp, MAX_PATH, &icon_idx))
299
	    {
300 301 302 303 304 305 306 307
	      if (!lstrcmpA("%1", sTemp))		/* icon is in the file */
	      {
		SHGetPathFromIDListW(This->pidl, szIconFile);
		*piIndex = 0;
	      }
	      else
	      {
		MultiByteToWideChar(CP_ACP, 0, sTemp, -1, szIconFile, cchMax);
308
		*piIndex = icon_idx;
309 310 311
	      }

	      found = TRUE;
312
	    }
313
	    else if (!lstrcmpiA(sTemp, "lnkfile"))
314
	    {
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
	      /* extract icon from shell shortcut */
	      IShellFolder* dsf;
	      IShellLinkW* psl;

	      if (SUCCEEDED(SHGetDesktopFolder(&dsf)))
	      {
		HRESULT hr = IShellFolder_GetUIObjectOf(dsf, NULL, 1, (LPCITEMIDLIST*)&This->pidl, &IID_IShellLinkW, NULL, (LPVOID*)&psl);

		if (SUCCEEDED(hr))
		{
		  hr = IShellLinkW_GetIconLocation(psl, szIconFile, MAX_PATH, piIndex);

		  if (SUCCEEDED(hr) && *szIconFile)
		    found = TRUE;

		  IShellLinkW_Release(psl);
		}

		IShellFolder_Release(dsf);
	      }
335
	    }
336
	  }
337 338 339 340 341 342

	  if (!found)					/* default icon */
	  {
	    lstrcpynW(szIconFile, swShell32Name, cchMax);
	    *piIndex = 0;
	  }
343
	}
344

345
	TRACE("-- %s %x\n", debugstr_w(szIconFile), *piIndex);
346
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
347
}
348

Alexandre Julliard's avatar
Alexandre Julliard committed
349
/**************************************************************************
350
*  IExtractIconW::Extract
Alexandre Julliard's avatar
Alexandre Julliard committed
351
*/
352 353
static HRESULT WINAPI IExtractIconW_fnExtract(IExtractIconW * iface, LPCWSTR pszFile,
        UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
354
{
355
        IExtractIconWImpl *This = impl_from_IExtractIconW(iface);
356
        int index;
357

358 359
        FIXME("(%p) (file=%s index=%d %p %p size=%08x) semi-stub\n", This, debugstr_w(pszFile),
                (signed)nIconIndex, phiconLarge, phiconSmall, nIconSize);
360

361
        index = SIC_GetIconIndex(pszFile, nIconIndex, 0);
362 363

	if (phiconLarge)
364
	  *phiconLarge = ImageList_GetIcon(ShellBigIconList, index, ILD_TRANSPARENT);
365 366

	if (phiconSmall)
367
	  *phiconSmall = ImageList_GetIcon(ShellSmallIconList, index, ILD_TRANSPARENT);
368 369

	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
370 371
}

372
static const IExtractIconWVtbl eivt =
373 374 375 376 377 378 379 380 381
{
	IExtractIconW_fnQueryInterface,
	IExtractIconW_fnAddRef,
	IExtractIconW_fnRelease,
	IExtractIconW_fnGetIconLocation,
	IExtractIconW_fnExtract
};

/**************************************************************************
382
 *  IExtractIconA::QueryInterface
383
 */
384 385
static HRESULT WINAPI IExtractIconA_fnQueryInterface(IExtractIconA * iface, REFIID riid,
        void **ppv)
386
{
387
    IExtractIconWImpl *This = impl_from_IExtractIconA(iface);
388

389
    return IExtractIconW_QueryInterface(&This->IExtractIconW_iface, riid, ppv);
390 391 392
}

/**************************************************************************
393
*  IExtractIconA::AddRef
394 395 396
*/
static ULONG WINAPI IExtractIconA_fnAddRef(IExtractIconA * iface)
{
397
    IExtractIconWImpl *This = impl_from_IExtractIconA(iface);
398

399
    return IExtractIconW_AddRef(&This->IExtractIconW_iface);
400 401
}
/**************************************************************************
402
*  IExtractIconA::Release
403 404 405
*/
static ULONG WINAPI IExtractIconA_fnRelease(IExtractIconA * iface)
{
406
    IExtractIconWImpl *This = impl_from_IExtractIconA(iface);
407

408
    return IExtractIconW_Release(&This->IExtractIconW_iface);
409 410
}
/**************************************************************************
411
*  IExtractIconA::GetIconLocation
412 413 414
*
* mapping filetype to icon
*/
415 416
static HRESULT WINAPI IExtractIconA_fnGetIconLocation(IExtractIconA * iface, UINT uFlags,
        LPSTR szIconFile, UINT cchMax, int * piIndex, UINT * pwFlags)
417
{
418
        IExtractIconWImpl *This = impl_from_IExtractIconA(iface);
419 420
	HRESULT ret;
	LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, cchMax * sizeof(WCHAR));
421

422 423
	TRACE("(%p) (flags=%u %p %u %p %p)\n", This, uFlags, szIconFile, cchMax, piIndex, pwFlags);

424 425
        ret = IExtractIconW_GetIconLocation(&This->IExtractIconW_iface, uFlags, lpwstrFile, cchMax,
                piIndex, pwFlags);
426
	WideCharToMultiByte(CP_ACP, 0, lpwstrFile, -1, szIconFile, cchMax, NULL, NULL);
427 428 429 430 431 432
	HeapFree(GetProcessHeap(), 0, lpwstrFile);

	TRACE("-- %s %x\n", szIconFile, *piIndex);
	return ret;
}
/**************************************************************************
433
*  IExtractIconA::Extract
434
*/
435 436
static HRESULT WINAPI IExtractIconA_fnExtract(IExtractIconA * iface, LPCSTR pszFile,
        UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
437
{
438
        IExtractIconWImpl *This = impl_from_IExtractIconA(iface);
439 440 441 442 443 444 445
	HRESULT ret;
	INT len = MultiByteToWideChar(CP_ACP, 0, pszFile, -1, NULL, 0);
	LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));

	TRACE("(%p) (file=%p index=%u %p %p size=%u)\n", This, pszFile, nIconIndex, phiconLarge, phiconSmall, nIconSize);

	MultiByteToWideChar(CP_ACP, 0, pszFile, -1, lpwstrFile, len);
446 447
        ret = IExtractIconW_Extract(&This->IExtractIconW_iface, lpwstrFile, nIconIndex, phiconLarge,
                phiconSmall, nIconSize);
448 449 450 451
	HeapFree(GetProcessHeap(), 0, lpwstrFile);
	return ret;
}

452
static const IExtractIconAVtbl eiavt =
453
{
454
	IExtractIconA_fnQueryInterface,
455 456 457 458 459
	IExtractIconA_fnAddRef,
	IExtractIconA_fnRelease,
	IExtractIconA_fnGetIconLocation,
	IExtractIconA_fnExtract
};
460 461

/************************************************************************
462
 * IEIPersistFile::QueryInterface
463
 */
464 465
static HRESULT WINAPI IEIPersistFile_fnQueryInterface(IPersistFile *iface, REFIID iid,
        void **ppv)
466
{
467
    IExtractIconWImpl *This = impl_from_IPersistFile(iface);
468

469
    return IExtractIconW_QueryInterface(&This->IExtractIconW_iface, iid, ppv);
470 471 472
}

/************************************************************************
473
 * IEIPersistFile::AddRef
474
 */
475
static ULONG WINAPI IEIPersistFile_fnAddRef(IPersistFile *iface)
476
{
477
    IExtractIconWImpl *This = impl_from_IPersistFile(iface);
478

479
    return IExtractIconW_AddRef(&This->IExtractIconW_iface);
480 481 482
}

/************************************************************************
483
 * IEIPersistFile::Release
484
 */
485
static ULONG WINAPI IEIPersistFile_fnRelease(IPersistFile *iface)
486
{
487
    IExtractIconWImpl *This = impl_from_IPersistFile(iface);
488

489
    return IExtractIconW_Release(&This->IExtractIconW_iface);
490 491 492
}

/************************************************************************
493
 * IEIPersistFile::GetClassID
494
 */
495
static HRESULT WINAPI IEIPersistFile_fnGetClassID(IPersistFile *iface, LPCLSID lpClassId)
496 497 498 499 500 501
{
	CLSID StdFolderID = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} };

	if (lpClassId==NULL)
	  return E_POINTER;

502
	*lpClassId = StdFolderID;
503 504 505 506 507

	return S_OK;
}

/************************************************************************
508
 * IEIPersistFile_Load
509
 */
510 511
static HRESULT WINAPI IEIPersistFile_fnLoad(IPersistFile* iface, LPCOLESTR pszFileName,
        DWORD dwMode)
512
{
513
    IExtractIconWImpl *This = impl_from_IPersistFile(iface);
514

515 516
    FIXME("%p\n", This);
    return E_NOTIMPL;
517 518
}

519
static const IPersistFileVtbl pfvt =
520 521 522 523 524 525 526 527 528 529 530
{
	IEIPersistFile_fnQueryInterface,
	IEIPersistFile_fnAddRef,
	IEIPersistFile_fnRelease,
	IEIPersistFile_fnGetClassID,
	(void *) 0xdeadbeef /* IEIPersistFile_fnIsDirty */,
	IEIPersistFile_fnLoad,
	(void *) 0xdeadbeef /* IEIPersistFile_fnSave */,
	(void *) 0xdeadbeef /* IEIPersistFile_fnSaveCompleted */,
	(void *) 0xdeadbeef /* IEIPersistFile_fnGetCurFile */
};
531

532
static IExtractIconWImpl *extracticon_create(LPCITEMIDLIST pidl)
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
{
    IExtractIconWImpl *ei;

    TRACE("%p\n", pidl);

    ei = HeapAlloc(GetProcessHeap(), 0, sizeof(*ei));
    ei->ref=1;
    ei->IExtractIconW_iface.lpVtbl = &eivt;
    ei->IExtractIconA_iface.lpVtbl = &eiavt;
    ei->IPersistFile_iface.lpVtbl = &pfvt;
    ei->pidl=ILClone(pidl);

    pdump(pidl);

    TRACE("(%p)\n", ei);
    return ei;
}

IExtractIconW *IExtractIconW_Constructor(LPCITEMIDLIST pidl)
{
    IExtractIconWImpl *ei = extracticon_create(pidl);

    return &ei->IExtractIconW_iface;
}

IExtractIconA *IExtractIconA_Constructor(LPCITEMIDLIST pidl)
{
    IExtractIconWImpl *ei = extracticon_create(pidl);

    return &ei->IExtractIconA_iface;
}