iconcache.c 26.9 KB
Newer Older
1 2 3
/*
 *	shell icon cache (SIC)
 *
4 5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright 1998, 1999 Juergen Schmied
 *
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19
 */
20

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

24
#include <stdarg.h>
25
#include <string.h>
26
#include <sys/types.h>
27 28 29
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
30 31 32

#define COBJMACROS

33
#include "windef.h"
34
#include "winbase.h"
35
#include "wingdi.h"
36
#include "winuser.h"
37
#include "winreg.h"
38
#include "wine/debug.h"
39 40

#include "shellapi.h"
41
#include "objbase.h"
42 43
#include "pidl.h"
#include "shell32_main.h"
44
#include "undocshell.h"
45
#include "shresdef.h"
46

47
WINE_DEFAULT_DEBUG_CHANNEL(shell);
48 49 50

/********************** THE ICON CACHE ********************************/

51 52
#define INVALID_INDEX -1

53
typedef struct
54
{
55
	LPWSTR sSourceFile;	/* file (not path!) containing the icon */
56
	DWORD dwSourceIndex;	/* index within the file, if it is a resource ID it will be negated */
57
	DWORD dwListIndex;	/* index within the iconlist */
58 59
	DWORD dwFlags;		/* GIL_* flags */
	DWORD dwAccessTime;
60 61
} SIC_ENTRY, * LPSIC_ENTRY;

62
static HDPA		sic_hdpa = 0;
63 64 65 66 67 68

static CRITICAL_SECTION SHELL32_SicCS;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
    0, 0, &SHELL32_SicCS,
    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
69
      0, 0, { (DWORD_PTR)(__FILE__ ": SHELL32_SicCS") }
70 71
};
static CRITICAL_SECTION SHELL32_SicCS = { &critsect_debug, -1, 0, 0, 0, 0 };
72

73
/*****************************************************************************
74
 * SIC_CompareEntries
75 76 77 78
 *
 * NOTES
 *  Callback for DPA_Search
 */
79
static INT CALLBACK SIC_CompareEntries( LPVOID p1, LPVOID p2, LPARAM lparam)
80 81 82
{
        LPSIC_ENTRY e1 = p1, e2 = p2;

83 84 85 86 87 88 89 90
	TRACE("%p %p %8lx\n", p1, p2, lparam);

	/* Icons in the cache are keyed by the name of the file they are
	 * loaded from, their resource index and the fact if they have a shortcut
	 * icon overlay or not. 
	 */
	if (e1->dwSourceIndex != e2->dwSourceIndex || /* first the faster one */
	    (e1->dwFlags & GIL_FORSHORTCUT) != (e2->dwFlags & GIL_FORSHORTCUT)) 
91 92
	  return 1;

93
	if (strcmpiW(e1->sSourceFile,e2->sSourceFile))
94 95
	  return 1;

96
	return 0;
97
}
98

99
/* declare SIC_LoadOverlayIcon() */
100
static int SIC_LoadOverlayIcon(int icon_idx);
101

102 103 104 105 106 107 108
/*****************************************************************************
 * SIC_OverlayShortcutImage			[internal]
 *
 * NOTES
 *  Creates a new icon as a copy of the passed-in icon, overlayed with a
 *  shortcut image. 
 */
109
static HICON SIC_OverlayShortcutImage(HICON SourceIcon, BOOL large)
110 111 112 113 114 115 116 117 118 119 120
{	ICONINFO SourceIconInfo, ShortcutIconInfo, TargetIconInfo;
	HICON ShortcutIcon, TargetIcon;
	BITMAP SourceBitmapInfo, ShortcutBitmapInfo;
	HDC SourceDC = NULL,
	  ShortcutDC = NULL,
	  TargetDC = NULL,
	  ScreenDC = NULL;
	HBITMAP OldSourceBitmap = NULL,
	  OldShortcutBitmap = NULL,
	  OldTargetBitmap = NULL;

121 122
	static int s_imgListIdx = -1;

123 124 125 126 127 128
	/* Get information about the source icon and shortcut overlay */
	if (! GetIconInfo(SourceIcon, &SourceIconInfo)
	    || 0 == GetObjectW(SourceIconInfo.hbmColor, sizeof(BITMAP), &SourceBitmapInfo))
	{
	  return NULL;
	}
129 130 131

	/* search for the shortcut icon only once */
	if (s_imgListIdx == -1)
132 133 134 135
	    s_imgListIdx = SIC_LoadOverlayIcon(- IDI_SHELL_SHORTCUT);
                           /* FIXME should use icon index 29 instead of the
                              resource id, but not all icons are present yet
                              so we can't use icon indices */
136 137 138 139 140 141 142 143 144 145

	if (s_imgListIdx != -1)
	{
	    if (large)
	        ShortcutIcon = ImageList_GetIcon(ShellBigIconList, s_imgListIdx, ILD_TRANSPARENT);
	    else
	        ShortcutIcon = ImageList_GetIcon(ShellSmallIconList, s_imgListIdx, ILD_TRANSPARENT);
	} else
	    ShortcutIcon = NULL;

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
	if (NULL == ShortcutIcon
	    || ! GetIconInfo(ShortcutIcon, &ShortcutIconInfo)
	    || 0 == GetObjectW(ShortcutIconInfo.hbmColor, sizeof(BITMAP), &ShortcutBitmapInfo))
	{
	  return NULL;
	}

	TargetIconInfo = SourceIconInfo;
	TargetIconInfo.hbmMask = NULL;
	TargetIconInfo.hbmColor = NULL;

	/* Setup the source, shortcut and target masks */
	SourceDC = CreateCompatibleDC(NULL);
	if (NULL == SourceDC) goto fail;
	OldSourceBitmap = SelectObject(SourceDC, SourceIconInfo.hbmMask);
	if (NULL == OldSourceBitmap) goto fail;

	ShortcutDC = CreateCompatibleDC(NULL);
	if (NULL == ShortcutDC) goto fail;
	OldShortcutBitmap = SelectObject(ShortcutDC, ShortcutIconInfo.hbmMask);
	if (NULL == OldShortcutBitmap) goto fail;

	TargetDC = CreateCompatibleDC(NULL);
	if (NULL == TargetDC) goto fail;
	TargetIconInfo.hbmMask = CreateCompatibleBitmap(TargetDC, SourceBitmapInfo.bmWidth,
	                                                SourceBitmapInfo.bmHeight);
	if (NULL == TargetIconInfo.hbmMask) goto fail;
	ScreenDC = GetDC(NULL);
	if (NULL == ScreenDC) goto fail;
	TargetIconInfo.hbmColor = CreateCompatibleBitmap(ScreenDC, SourceBitmapInfo.bmWidth,
	                                                 SourceBitmapInfo.bmHeight);
	ReleaseDC(NULL, ScreenDC);
	if (NULL == TargetIconInfo.hbmColor) goto fail;
	OldTargetBitmap = SelectObject(TargetDC, TargetIconInfo.hbmMask);
	if (NULL == OldTargetBitmap) goto fail;

	/* Create the target mask by ANDing the source and shortcut masks */
	if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight,
	             SourceDC, 0, 0, SRCCOPY) ||
	    ! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
	             ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
	             ShortcutDC, 0, 0, SRCAND))
	{
	  goto fail;
	}

	/* Setup the source and target xor bitmap */
	if (NULL == SelectObject(SourceDC, SourceIconInfo.hbmColor) ||
	    NULL == SelectObject(TargetDC, TargetIconInfo.hbmColor))
	{
	  goto fail;
	}

	/* Copy the source xor bitmap to the target and clear out part of it by using
	   the shortcut mask */
	if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight,
	             SourceDC, 0, 0, SRCCOPY) ||
	    ! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
	             ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
	             ShortcutDC, 0, 0, SRCAND))
	{
	  goto fail;
	}

	if (NULL == SelectObject(ShortcutDC, ShortcutIconInfo.hbmColor)) goto fail;

	/* Now put in the shortcut xor mask */
	if (! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
	             ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
	             ShortcutDC, 0, 0, SRCINVERT))
	{
	  goto fail;
	}

	/* Clean up, we're not goto'ing to 'fail' after this so we can be lazy and not set
	   handles to NULL */
	SelectObject(TargetDC, OldTargetBitmap);
	DeleteObject(TargetDC);
	SelectObject(ShortcutDC, OldShortcutBitmap);
	DeleteObject(ShortcutDC);
	SelectObject(SourceDC, OldSourceBitmap);
	DeleteObject(SourceDC);

	/* Create the icon using the bitmaps prepared earlier */
	TargetIcon = CreateIconIndirect(&TargetIconInfo);

	/* CreateIconIndirect copies the bitmaps, so we can release our bitmaps now */
	DeleteObject(TargetIconInfo.hbmColor);
	DeleteObject(TargetIconInfo.hbmMask);

	return TargetIcon;

fail:
	/* Clean up scratch resources we created */
	if (NULL != OldTargetBitmap) SelectObject(TargetDC, OldTargetBitmap);
	if (NULL != TargetIconInfo.hbmColor) DeleteObject(TargetIconInfo.hbmColor);
	if (NULL != TargetIconInfo.hbmMask) DeleteObject(TargetIconInfo.hbmMask);
	if (NULL != TargetDC) DeleteObject(TargetDC);
	if (NULL != OldShortcutBitmap) SelectObject(ShortcutDC, OldShortcutBitmap);
	if (NULL != ShortcutDC) DeleteObject(ShortcutDC);
	if (NULL != OldSourceBitmap) SelectObject(SourceDC, OldSourceBitmap);
	if (NULL != SourceDC) DeleteObject(SourceDC);

	return NULL;
}

252
/*****************************************************************************
253 254 255
 * SIC_IconAppend			[internal]
 *
 * NOTES
256
 *  appends an icon pair to the end of the cache
257
 */
258
static INT SIC_IconAppend (LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallIcon, HICON hBigIcon, DWORD dwFlags)
259
{	LPSIC_ENTRY lpsice;
260
	INT ret, index, index1;
261 262
	WCHAR path[MAX_PATH];
	TRACE("%s %i %p %p\n", debugstr_w(sSourceFile), dwSourceIndex, hSmallIcon ,hBigIcon);
263

264
	lpsice = SHAlloc(sizeof(SIC_ENTRY));
265

266
	GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL);
267 268
	lpsice->sSourceFile = HeapAlloc( GetProcessHeap(), 0, (strlenW(path)+1)*sizeof(WCHAR) );
	strcpyW( lpsice->sSourceFile, path );
269

270
	lpsice->dwSourceIndex = dwSourceIndex;
271
	lpsice->dwFlags = dwFlags;
272

273 274
	EnterCriticalSection(&SHELL32_SicCS);

275
	index = DPA_InsertPtr(sic_hdpa, 0x7fff, lpsice);
276
	if ( INVALID_INDEX == index )
277
	{
278
	  HeapFree(GetProcessHeap(), 0, lpsice->sSourceFile);
279 280
	  SHFree(lpsice);
	  ret = INVALID_INDEX;
281
	}
282 283
	else
	{
284 285
	  index = ImageList_AddIcon (ShellSmallIconList, hSmallIcon);
	  index1= ImageList_AddIcon (ShellBigIconList, hBigIcon);
286

287 288 289 290 291 292
	  if (index!=index1)
	  {
	    FIXME("iconlists out of sync 0x%x 0x%x\n", index, index1);
	  }
	  lpsice->dwListIndex = index;
	  ret = lpsice->dwListIndex;
293
	}
294 295

	LeaveCriticalSection(&SHELL32_SicCS);
296
	return ret;
297
}
298
/****************************************************************************
299 300 301 302 303
 * SIC_LoadIcon				[internal]
 *
 * NOTES
 *  gets small/big icon by number from a file
 */
304
static INT SIC_LoadIcon (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags)
305 306
{	HICON	hiconLarge=0;
	HICON	hiconSmall=0;
307 308
	HICON 	hiconLargeShortcut;
	HICON	hiconSmallShortcut;
309

310 311
        PrivateExtractIconsW( sSourceFile, dwSourceIndex, 32, 32, &hiconLarge, 0, 1, 0 );
        PrivateExtractIconsW( sSourceFile, dwSourceIndex, 16, 16, &hiconSmall, 0, 1, 0 );
312 313

	if ( !hiconLarge ||  !hiconSmall)
314
	{
315
	  WARN("failure loading icon %i from %s (%p %p)\n", dwSourceIndex, debugstr_w(sSourceFile), hiconLarge, hiconSmall);
316 317
	  return -1;
	}
318 319 320

	if (0 != (dwFlags & GIL_FORSHORTCUT))
	{
321 322
	  hiconLargeShortcut = SIC_OverlayShortcutImage(hiconLarge, TRUE);
	  hiconSmallShortcut = SIC_OverlayShortcutImage(hiconSmall, FALSE);
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
	  if (NULL != hiconLargeShortcut && NULL != hiconSmallShortcut)
	  {
	    hiconLarge = hiconLargeShortcut;
	    hiconSmall = hiconSmallShortcut;
	  }
	  else
	  {
	    WARN("Failed to create shortcut overlayed icons\n");
	    if (NULL != hiconLargeShortcut) DestroyIcon(hiconLargeShortcut);
	    if (NULL != hiconSmallShortcut) DestroyIcon(hiconSmallShortcut);
	    dwFlags &= ~ GIL_FORSHORTCUT;
	  }
	}

	return SIC_IconAppend (sSourceFile, dwSourceIndex, hiconSmall, hiconLarge, dwFlags);
338
}
339
/*****************************************************************************
340 341
 * SIC_GetIconIndex			[internal]
 *
342 343 344 345
 * Parameters
 *	sSourceFile	[IN]	filename of file containing the icon
 *	index		[IN]	index/resID (negated) in this file
 *
346 347 348 349
 * NOTES
 *  look in the cache for a proper icon. if not available the icon is taken
 *  from the file and cached
 */
350
INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags )
351 352
{
	SIC_ENTRY sice;
353
	INT ret, index = INVALID_INDEX;
354
	WCHAR path[MAX_PATH];
355

356
	TRACE("%s %i\n", debugstr_w(sSourceFile), dwSourceIndex);
357

358 359
	GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL);
	sice.sSourceFile = path;
360
	sice.dwSourceIndex = dwSourceIndex;
361
	sice.dwFlags = dwFlags;
362

363 364
	EnterCriticalSection(&SHELL32_SicCS);

365
	if (NULL != DPA_GetPtr (sic_hdpa, 0))
366
	{
367
	  /* search linear from position 0*/
368
	  index = DPA_Search (sic_hdpa, &sice, 0, SIC_CompareEntries, 0, 0);
369
	}
370

371
	if ( INVALID_INDEX == index )
372
	{
373
          ret = SIC_LoadIcon (sSourceFile, dwSourceIndex, dwFlags);
374
	}
375 376 377
	else
	{
	  TRACE("-- found\n");
378
	  ret = ((LPSIC_ENTRY)DPA_GetPtr(sic_hdpa, index))->dwListIndex;
379 380 381 382
	}

	LeaveCriticalSection(&SHELL32_SicCS);
	return ret;
383
}
384
/*****************************************************************************
385 386
 * SIC_Initialize			[internal]
 */
387
BOOL SIC_Initialize(void)
388 389
{
	HICON		hSm, hLg;
390 391 392 393 394 395 396
	int		cx_small, cy_small;
	int		cx_large, cy_large;

	cx_small = GetSystemMetrics(SM_CXSMICON);
	cy_small = GetSystemMetrics(SM_CYSMICON);
	cx_large = GetSystemMetrics(SM_CXICON);
	cy_large = GetSystemMetrics(SM_CYICON);
397

398
	TRACE("\n");
399

400
	if (sic_hdpa)	/* already initialized?*/
401
	  return TRUE;
402

403
	sic_hdpa = DPA_Create(16);
404

405
	if (!sic_hdpa)
406 407
	{
	  return(FALSE);
408 409
	}

410 411
        ShellSmallIconList = ImageList_Create(cx_small,cy_small,ILC_COLOR32|ILC_MASK,0,0x20);
        ShellBigIconList = ImageList_Create(cx_large,cy_large,ILC_COLOR32|ILC_MASK,0,0x20);
412

413 414
        ImageList_SetBkColor(ShellSmallIconList, CLR_NONE);
        ImageList_SetBkColor(ShellBigIconList, CLR_NONE);
415

416
        /* Load the document icon, which is used as the default if an icon isn't found. */
417
        hSm = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(IDI_SHELL_DOCUMENT),
418
                                IMAGE_ICON, cx_small, cy_small, LR_SHARED);
419
        hLg = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(IDI_SHELL_DOCUMENT),
420
                                IMAGE_ICON, cx_large, cy_large, LR_SHARED);
421

422 423 424 425 426
        if (!hSm || !hLg) 
        {
          FIXME("Failed to load IDI_SHELL_DOCUMENT icon!\n");
          return FALSE;
        }
427

428 429 430
        SIC_IconAppend (swShell32Name, IDI_SHELL_DOCUMENT-1, hSm, hLg, 0);
        SIC_IconAppend (swShell32Name, -IDI_SHELL_DOCUMENT, hSm, hLg, 0);
   
431
	TRACE("hIconSmall=%p hIconBig=%p\n",ShellSmallIconList, ShellBigIconList);
432 433 434

	return TRUE;
}
435 436 437 438 439
/*************************************************************************
 * SIC_Destroy
 *
 * frees the cache
 */
440
static INT CALLBACK sic_free( LPVOID ptr, LPVOID lparam )
441
{
442 443 444
	HeapFree(GetProcessHeap(), 0, ((LPSIC_ENTRY)ptr)->sSourceFile);
	SHFree(ptr);
	return TRUE;
445
}
446

447 448
void SIC_Destroy(void)
{
449 450
	TRACE("\n");

451 452
	EnterCriticalSection(&SHELL32_SicCS);

453
	if (sic_hdpa) DPA_DestroyCallback(sic_hdpa, sic_free, NULL );
454 455

	sic_hdpa = NULL;
456 457 458 459
	ImageList_Destroy(ShellSmallIconList);
	ShellSmallIconList = 0;
	ImageList_Destroy(ShellBigIconList);
	ShellBigIconList = 0;
460 461

	LeaveCriticalSection(&SHELL32_SicCS);
Juergen Schmied's avatar
Juergen Schmied committed
462
	DeleteCriticalSection(&SHELL32_SicCS);
463
}
464

465 466 467 468 469
/*****************************************************************************
 * SIC_LoadOverlayIcon			[internal]
 *
 * Load a shell overlay icon and return its icon cache index.
 */
470
static int SIC_LoadOverlayIcon(int icon_idx)
471 472 473 474 475 476 477 478 479 480 481 482 483 484
{
	WCHAR buffer[1024], wszIdx[8];
	HKEY hKeyShellIcons;
	LPCWSTR iconPath;
	int iconIdx;

	static const WCHAR wszShellIcons[] = {
	    'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
	    'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
	    'E','x','p','l','o','r','e','r','\\','S','h','e','l','l',' ','I','c','o','n','s',0
	}; 
	static const WCHAR wszNumFmt[] = {'%','d',0};

	iconPath = swShell32Name;	/* default: load icon from shell32.dll */
485
	iconIdx = icon_idx;
486 487 488 489 490

	if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszShellIcons, 0, KEY_READ, &hKeyShellIcons) == ERROR_SUCCESS)
	{
	    DWORD count = sizeof(buffer);

491
	    sprintfW(wszIdx, wszNumFmt, icon_idx);
492 493 494 495 496 497

	    /* read icon path and index */
	    if (RegQueryValueExW(hKeyShellIcons, wszIdx, NULL, NULL, (LPBYTE)buffer, &count) == ERROR_SUCCESS)
	    {
		LPWSTR p = strchrW(buffer, ',');

498 499 500 501 502 503 504
		if (!p)
		{
		    ERR("Icon index in %s/%s corrupted, no comma.\n", debugstr_w(wszShellIcons),debugstr_w(wszIdx));
		    RegCloseKey(hKeyShellIcons);
		    return -1;
		}
		*p++ = 0;
505 506 507 508 509 510 511 512 513 514
		iconPath = buffer;
		iconIdx = atoiW(p);
	    }

	    RegCloseKey(hKeyShellIcons);
	}

	return SIC_LoadIcon(iconPath, iconIdx, 0);
}

515
/*************************************************************************
516
 * Shell_GetImageLists			[SHELL32.71]
517 518
 *
 * PARAMETERS
519
 *  imglist[1|2] [OUT] pointer which receives imagelist handles
520 521
 *
 */
522
BOOL WINAPI Shell_GetImageLists(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList)
523
{	TRACE("(%p,%p)\n",lpBigList,lpSmallList);
Juergen Schmied's avatar
Juergen Schmied committed
524 525
	if (lpBigList)
	{ *lpBigList = ShellBigIconList;
526
	}
Juergen Schmied's avatar
Juergen Schmied committed
527 528
	if (lpSmallList)
	{ *lpSmallList = ShellSmallIconList;
529 530 531 532
	}

	return TRUE;
}
533 534 535 536 537 538 539
/*************************************************************************
 * PidlToSicIndex			[INTERNAL]
 *
 * PARAMETERS
 *	sh	[IN]	IShellFolder
 *	pidl	[IN]
 *	bBigIcon [IN]
Juergen Schmied's avatar
Juergen Schmied committed
540
 *	uFlags	[IN]	GIL_*
541 542 543
 *	pIndex	[OUT]	index within the SIC
 *
 */
Juergen Schmied's avatar
Juergen Schmied committed
544 545
BOOL PidlToSicIndex (
	IShellFolder * sh,
546
	LPCITEMIDLIST pidl,
Juergen Schmied's avatar
Juergen Schmied committed
547 548
	BOOL bBigIcon,
	UINT uFlags,
549
	int * pIndex)
550
{
551 552
	IExtractIconW	*ei;
	WCHAR		szIconFile[MAX_PATH];	/* file containing the icon */
553 554 555
	INT		iSourceIndex;		/* index or resID(negated) in this file */
	BOOL		ret = FALSE;
	UINT		dwFlags = 0;
556
	int		iShortcutDefaultIndex = INVALID_INDEX;
557

Juergen Schmied's avatar
Juergen Schmied committed
558
	TRACE("sf=%p pidl=%p %s\n", sh, pidl, bBigIcon?"Big":"Small");
559

560
	if (SUCCEEDED (IShellFolder_GetUIObjectOf(sh, 0, 1, &pidl, &IID_IExtractIconW, 0, (void **)&ei)))
561
	{
562
	  if (SUCCEEDED(IExtractIconW_GetIconLocation(ei, uFlags, szIconFile, MAX_PATH, &iSourceIndex, &dwFlags)))
Juergen Schmied's avatar
Juergen Schmied committed
563
	  {
564
	    *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex, uFlags);
565
	    ret = TRUE;
566
	  }
567
	  IExtractIconW_Release(ei);
568 569 570
	}

	if (INVALID_INDEX == *pIndex)	/* default icon when failed */
571 572 573 574 575 576 577 578 579 580 581 582 583 584
	{
	  if (0 == (uFlags & GIL_FORSHORTCUT))
	  {
	    *pIndex = 0;
	  }
	  else
	  {
	    if (INVALID_INDEX == iShortcutDefaultIndex)
	    {
	      iShortcutDefaultIndex = SIC_LoadIcon(swShell32Name, 0, GIL_FORSHORTCUT);
	    }
	    *pIndex = (INVALID_INDEX != iShortcutDefaultIndex ? iShortcutDefaultIndex : 0);
	  }
	}
585 586 587 588

	return ret;

}
589 590

/*************************************************************************
591
 * SHMapPIDLToSystemImageListIndex	[SHELL32.77]
592 593
 *
 * PARAMETERS
594
 *	sh	[IN]		pointer to an instance of IShellFolder
595 596
 *	pidl	[IN]
 *	pIndex	[OUT][OPTIONAL]	SIC index for big icon
597 598
 *
 */
599
int WINAPI SHMapPIDLToSystemImageListIndex(
600
	IShellFolder *sh,
601
	LPCITEMIDLIST pidl,
602
	int *pIndex)
603
{
604
	int Index;
605
	UINT uGilFlags = 0;
606

607
	TRACE("(SF=%p,pidl=%p,%p)\n",sh,pidl,pIndex);
608
	pdump(pidl);
609

610 611 612
	if (SHELL_IsShortcut(pidl))
	    uGilFlags |= GIL_FORSHORTCUT;

613
	if (pIndex)
614 615 616 617 618 619
	    if (!PidlToSicIndex ( sh, pidl, 1, uGilFlags, pIndex))
	        *pIndex = -1;

	if (!PidlToSicIndex ( sh, pidl, 0, uGilFlags, &Index))
	    return -1;

620
	return Index;
621 622
}

623 624 625 626 627 628 629 630 631 632 633 634 635
/*************************************************************************
 * SHMapIDListToImageListIndexAsync  [SHELL32.148]
 */
HRESULT WINAPI SHMapIDListToImageListIndexAsync(IUnknown *pts, IShellFolder *psf,
                                                LPCITEMIDLIST pidl, UINT flags,
                                                void *pfn, void *pvData, void *pvHint,
                                                int *piIndex, int *piIndexSel)
{
    FIXME("(%p, %p, %p, 0x%08x, %p, %p, %p, %p, %p)\n",
            pts, psf, pidl, flags, pfn, pvData, pvHint, piIndex, piIndexSel);
    return E_FAIL;
}

636
/*************************************************************************
637
 * Shell_GetCachedImageIndex		[SHELL32.72]
638 639
 *
 */
640
static INT Shell_GetCachedImageIndexA(LPCSTR szPath, INT nIndex, BOOL bSimulateDoc)
641
{
642 643 644
	INT ret, len;
	LPWSTR szTemp;

645
	WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_a(szPath), nIndex, bSimulateDoc);
646 647 648 649 650

	len = MultiByteToWideChar( CP_ACP, 0, szPath, -1, NULL, 0 );
	szTemp = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
	MultiByteToWideChar( CP_ACP, 0, szPath, -1, szTemp, len );

651
	ret = SIC_GetIconIndex( szTemp, nIndex, 0 );
652 653 654 655

	HeapFree( GetProcessHeap(), 0, szTemp );

	return ret;
656 657
}

658
static INT Shell_GetCachedImageIndexW(LPCWSTR szPath, INT nIndex, BOOL bSimulateDoc)
659
{
660
	WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_w(szPath), nIndex, bSimulateDoc);
661

662
	return SIC_GetIconIndex(szPath, nIndex, 0);
663 664
}

665
INT WINAPI Shell_GetCachedImageIndexAW(LPCVOID szPath, INT nIndex, BOOL bSimulateDoc)
666
{	if( SHELL_OsIsUnicode())
667 668
	  return Shell_GetCachedImageIndexW(szPath, nIndex, bSimulateDoc);
	return Shell_GetCachedImageIndexA(szPath, nIndex, bSimulateDoc);
669 670
}

671
/*************************************************************************
672
 * ExtractIconExW			[SHELL32.@]
673
 * RETURNS
674
 *  0 no icon found
675 676
 *  -1 file is not valid
 *  or number of icons extracted
677
 */
678
UINT WINAPI ExtractIconExW(LPCWSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
679
{
680 681 682
	TRACE("%s %i %p %p %i\n", debugstr_w(lpszFile), nIconIndex, phiconLarge, phiconSmall, nIcons);

	return PrivateExtractIconExW(lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
683
}
684

685
/*************************************************************************
686
 * ExtractIconExA			[SHELL32.@]
687
 */
688
UINT WINAPI ExtractIconExA(LPCSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
689
{
690
    UINT ret = 0;
691 692
    INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0);
    LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
693

694
    TRACE("%s %i %p %p %i\n", lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
695

696 697 698 699 700 701
    if (lpwstrFile)
    {
        MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len);
        ret = ExtractIconExW(lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
        HeapFree(GetProcessHeap(), 0, lpwstrFile);
    }
702
    return ret;
703
}
704 705 706 707 708 709 710 711

/*************************************************************************
 *				ExtractAssociatedIconA (SHELL32.@)
 *
 * Return icon for given file (either from file itself or from associated
 * executable) and patch parameters if needed.
 */
HICON WINAPI ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIcon)
712
{	
713 714
    HICON hIcon = NULL;
    INT len = MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, NULL, 0);
715 716 717 718 719 720
    /* Note that we need to allocate MAX_PATH, since we are supposed to fill
     * the correct executable if there is no icon in lpIconPath directly.
     * lpIconPath itself is supposed to be large enough, so make sure lpIconPathW
     * is large enough too. Yes, I am puking too.
     */
    LPWSTR lpIconPathW = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
721 722 723 724 725 726 727

    TRACE("%p %s %p\n", hInst, debugstr_a(lpIconPath), lpiIcon);

    if (lpIconPathW)
    {
        MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, lpIconPathW, len);
        hIcon = ExtractAssociatedIconW(hInst, lpIconPathW, lpiIcon);
728
        WideCharToMultiByte(CP_ACP, 0, lpIconPathW, -1, lpIconPath, MAX_PATH , NULL, NULL);
729 730 731 732
        HeapFree(GetProcessHeap(), 0, lpIconPathW);
    }
    return hIcon;
}
733

734 735 736 737 738 739
/*************************************************************************
 *				ExtractAssociatedIconW (SHELL32.@)
 *
 * Return icon for given file (either from file itself or from associated
 * executable) and patch parameters if needed.
 */
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773
HICON WINAPI ExtractAssociatedIconW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIcon)
{
    HICON hIcon = NULL;
    WORD wDummyIcon = 0;

    TRACE("%p %s %p\n", hInst, debugstr_w(lpIconPath), lpiIcon);

    if(lpiIcon == NULL)
        lpiIcon = &wDummyIcon;

    hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon);

    if( hIcon < (HICON)2 )
    { if( hIcon == (HICON)1 ) /* no icons found in given file */
      { WCHAR tempPath[MAX_PATH];
        HINSTANCE uRet = FindExecutableW(lpIconPath,NULL,tempPath);

        if( uRet > (HINSTANCE)32 && tempPath[0] )
        { lstrcpyW(lpIconPath,tempPath);
          hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon);
          if( hIcon > (HICON)2 )
            return hIcon;
        }
      }

      if( hIcon == (HICON)1 )
        *lpiIcon = 2;   /* MSDOS icon - we found .exe but no icons in it */
      else
        *lpiIcon = 6;   /* generic icon - found nothing */

      if (GetModuleFileNameW(hInst, lpIconPath, MAX_PATH))
        hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(*lpiIcon));
    }
    return hIcon;
774 775 776
}

/*************************************************************************
777
 *				ExtractAssociatedIconExW (SHELL32.@)
778 779 780 781
 *
 * Return icon for given file (either from file itself or from associated
 * executable) and patch parameters if needed.
 */
782
HICON WINAPI ExtractAssociatedIconExW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId)
783
{
784
  FIXME("%p %s %p %p): stub\n", hInst, debugstr_w(lpIconPath), lpiIconIdx, lpiIconId);
785 786 787 788
  return 0;
}

/*************************************************************************
789
 *				ExtractAssociatedIconExA (SHELL32.@)
790 791 792 793
 *
 * Return icon for given file (either from file itself or from associated
 * executable) and patch parameters if needed.
 */
794
HICON WINAPI ExtractAssociatedIconExA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId)
795
{
796 797 798 799 800 801 802 803 804 805
  HICON ret;
  INT len = MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, NULL, 0 );
  LPWSTR lpwstrFile = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );

  TRACE("%p %s %p %p)\n", hInst, lpIconPath, lpiIconIdx, lpiIconId);

  MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, lpwstrFile, len );
  ret = ExtractAssociatedIconExW(hInst, lpwstrFile, lpiIconIdx, lpiIconId);
  HeapFree(GetProcessHeap(), 0, lpwstrFile);
  return ret;
806
}
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823


/****************************************************************************
 * SHDefExtractIconW		[SHELL32.@]
 */
HRESULT WINAPI SHDefExtractIconW(LPCWSTR pszIconFile, int iIndex, UINT uFlags,
                                 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize)
{
	UINT ret;
	HICON hIcons[2];
	WARN("%s %d 0x%08x %p %p %d, semi-stub\n", debugstr_w(pszIconFile), iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);

	ret = PrivateExtractIconsW(pszIconFile, iIndex, nIconSize, nIconSize, hIcons, NULL, 2, LR_DEFAULTCOLOR);
	/* FIXME: deal with uFlags parameter which contains GIL_ flags */
	if (ret == 0xFFFFFFFF)
	  return E_FAIL;
	if (ret > 0) {
824 825 826 827 828 829 830 831
	  if (phiconLarge)
	    *phiconLarge = hIcons[0];
	  else
	    DestroyIcon(hIcons[0]);
	  if (phiconSmall)
	    *phiconSmall = hIcons[1];
	  else
	    DestroyIcon(hIcons[1]);
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853
	  return S_OK;
	}
	return S_FALSE;
}

/****************************************************************************
 * SHDefExtractIconA		[SHELL32.@]
 */
HRESULT WINAPI SHDefExtractIconA(LPCSTR pszIconFile, int iIndex, UINT uFlags,
                                 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize)
{
  HRESULT ret;
  INT len = MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, NULL, 0);
  LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));

  TRACE("%s %d 0x%08x %p %p %d\n", pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);

  MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, lpwstrFile, len);
  ret = SHDefExtractIconW(lpwstrFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
  HeapFree(GetProcessHeap(), 0, lpwstrFile);
  return ret;
}
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878


/****************************************************************************
 * SHGetIconOverlayIndexA    [SHELL32.@]
 *
 * Returns the index of the overlay icon in the system image list.
 */
INT WINAPI SHGetIconOverlayIndexA(LPCSTR pszIconPath, INT iIconIndex)
{
  FIXME("%s, %d\n", debugstr_a(pszIconPath), iIconIndex);

  return -1;
}

/****************************************************************************
 * SHGetIconOverlayIndexW    [SHELL32.@]
 *
 * Returns the index of the overlay icon in the system image list.
 */
INT WINAPI SHGetIconOverlayIndexW(LPCWSTR pszIconPath, INT iIconIndex)
{
  FIXME("%s, %d\n", debugstr_w(pszIconPath), iIconIndex);

  return -1;
}