iconcache.c 11.7 KB
Newer Older
1 2 3 4 5
/*
 *	shell icon cache (SIC)
 *
 */
#include <string.h>
6 7
#include <sys/types.h>
#include <unistd.h>
8
#include "winbase.h"
9 10
#include "windef.h"
#include "wingdi.h"
11
#include "winuser.h"
12
#include "wine/winuser16.h"
13
#include "wine/winbase16.h"
14
#include "heap.h"
15
#include "debugtools.h"
16 17

#include "shellapi.h"
18
#include "shlguid.h"
19 20
#include "pidl.h"
#include "shell32_main.h"
21
#include "undocshell.h"
22
#include "shlwapi.h"
23

24
DEFAULT_DEBUG_CHANNEL(shell);
25 26 27

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

28 29
#define INVALID_INDEX -1

30
typedef struct
31 32
{
	LPSTR sSourceFile;	/* file (not path!) containing the icon */
33
	DWORD dwSourceIndex;	/* index within the file, if it is a resoure ID it will be negated */
34
	DWORD dwListIndex;	/* index within the iconlist */
35 36
	DWORD dwFlags;		/* GIL_* flags */
	DWORD dwAccessTime;
37 38
} SIC_ENTRY, * LPSIC_ENTRY;

39
static HDPA		sic_hdpa = 0;
40
static CRITICAL_SECTION SHELL32_SicCS = CRITICAL_SECTION_INIT("SHELL32_SicCS");
41

42
/*****************************************************************************
43 44 45 46 47
 * SIC_CompareEntrys			[called by comctl32.dll]
 *
 * NOTES
 *  Callback for DPA_Search
 */
48
INT CALLBACK SIC_CompareEntrys( LPVOID p1, LPVOID p2, LPARAM lparam)
49
{	TRACE("%p %p\n", p1, p2);
50 51 52 53

	if (((LPSIC_ENTRY)p1)->dwSourceIndex != ((LPSIC_ENTRY)p2)->dwSourceIndex) /* first the faster one*/
	  return 1;

54
	if (strcasecmp(((LPSIC_ENTRY)p1)->sSourceFile,((LPSIC_ENTRY)p2)->sSourceFile))
55 56 57 58 59
	  return 1;

	return 0;  
}
/*****************************************************************************
60 61 62 63 64
 * SIC_IconAppend			[internal]
 *
 * NOTES
 *  appends a icon pair to the end of the cache
 */
65
static INT SIC_IconAppend (LPCSTR sSourceFile, INT dwSourceIndex, HICON hSmallIcon, HICON hBigIcon)
66
{	LPSIC_ENTRY lpsice;
67
	INT ret, index, index1;
68
	char *path;
69
	TRACE("%s %i %x %x\n", sSourceFile, dwSourceIndex, hSmallIcon ,hBigIcon);
70 71 72

	lpsice = (LPSIC_ENTRY) SHAlloc (sizeof (SIC_ENTRY));

73 74 75 76
        path = PathFindFileNameA(sSourceFile);
        lpsice->sSourceFile = HeapAlloc( GetProcessHeap(), 0, strlen(path)+1 );
        strcpy( lpsice->sSourceFile, path );

77 78
	lpsice->dwSourceIndex = dwSourceIndex;
	
79 80
	EnterCriticalSection(&SHELL32_SicCS);

81
	index = pDPA_InsertPtr(sic_hdpa, 0x7fff, lpsice);
82
	if ( INVALID_INDEX == index )
83 84 85
	{
	  SHFree(lpsice);
	  ret = INVALID_INDEX;
86
	}
87 88
	else
	{
89 90
	  index = ImageList_AddIcon (ShellSmallIconList, hSmallIcon);
	  index1= ImageList_AddIcon (ShellBigIconList, hBigIcon);
91

92 93 94 95 96 97
	  if (index!=index1)
	  {
	    FIXME("iconlists out of sync 0x%x 0x%x\n", index, index1);
	  }
	  lpsice->dwListIndex = index;
	  ret = lpsice->dwListIndex;
98
	}
99 100 101

	LeaveCriticalSection(&SHELL32_SicCS);
	return ret;	
102
}
103
/****************************************************************************
104 105 106 107 108
 * SIC_LoadIcon				[internal]
 *
 * NOTES
 *  gets small/big icon by number from a file
 */
109 110 111
static INT SIC_LoadIcon (LPCSTR sSourceFile, INT dwSourceIndex)
{	HICON	hiconLarge=0;
	HICON	hiconSmall=0;
112

113 114
        PrivateExtractIconsA( sSourceFile, dwSourceIndex, 32, 32, &hiconLarge, 0, 1, 0 ); 
        PrivateExtractIconsA( sSourceFile, dwSourceIndex, 16, 16, &hiconSmall, 0, 1, 0 ); 
115 116

	if ( !hiconLarge ||  !hiconSmall)
117 118
	{
	  WARN("failure loading icon %i from %s (%x %x)\n", dwSourceIndex, sSourceFile, hiconLarge, hiconSmall);
119 120 121 122
	  return -1;
	}
	return SIC_IconAppend (sSourceFile, dwSourceIndex, hiconSmall, hiconLarge);		
}
123
/*****************************************************************************
124 125
 * SIC_GetIconIndex			[internal]
 *
126 127 128 129
 * Parameters
 *	sSourceFile	[IN]	filename of file containing the icon
 *	index		[IN]	index/resID (negated) in this file
 *
130 131 132 133
 * NOTES
 *  look in the cache for a proper icon. if not available the icon is taken
 *  from the file and cached
 */
134
INT SIC_GetIconIndex (LPCSTR sSourceFile, INT dwSourceIndex )
135
{	SIC_ENTRY sice;
136
	INT ret, index = INVALID_INDEX;
137
		
138
	TRACE("%s %i\n", sSourceFile, dwSourceIndex);
139

140
	sice.sSourceFile = PathFindFileNameA(sSourceFile);
141 142
	sice.dwSourceIndex = dwSourceIndex;
	
143 144
	EnterCriticalSection(&SHELL32_SicCS);

145
	if (NULL != pDPA_GetPtr (sic_hdpa, 0))
146 147
	{
	  index = pDPA_Search (sic_hdpa, &sice, -1L, SIC_CompareEntrys, 0, 0);
148
	}
149

150
	if ( INVALID_INDEX == index )
151 152
	{
	  ret = SIC_LoadIcon (sSourceFile, dwSourceIndex);
153
	}
154 155 156 157 158 159 160 161
	else
	{
	  TRACE("-- found\n");
	  ret = ((LPSIC_ENTRY)pDPA_GetPtr(sic_hdpa, index))->dwListIndex;
	}

	LeaveCriticalSection(&SHELL32_SicCS);
	return ret;
162 163
}
/****************************************************************************
164
 * SIC_GetIcon				[internal]
165 166 167 168
 *
 * NOTES
 *  retrives the specified icon from the iconcache. if not found try's to load the icon
 */
169
static HICON WINE_UNUSED SIC_GetIcon (LPCSTR sSourceFile, INT dwSourceIndex, BOOL bSmallIcon )
170
{	INT index;
171

172
	TRACE("%s %i\n", sSourceFile, dwSourceIndex);
173

174
	index = SIC_GetIconIndex(sSourceFile, dwSourceIndex);
175

176
	if (INVALID_INDEX == index)
177 178
	{
	  return INVALID_INDEX;
179 180
	}

181
	if (bSmallIcon)
182 183
	  return ImageList_GetIcon(ShellSmallIconList, index, ILD_NORMAL);
	return ImageList_GetIcon(ShellBigIconList, index, ILD_NORMAL);
184 185 186
	
}
/*****************************************************************************
187 188 189 190 191 192
 * SIC_Initialize			[internal]
 *
 * NOTES
 *  hack to load the resources from the shell32.dll under a different dll name 
 *  will be removed when the resource-compiler is ready
 */
193
BOOL SIC_Initialize(void)
194 195
{
	HICON		hSm, hLg;
196
	UINT		index;
197

198
	TRACE("\n");
199

200
	if (sic_hdpa)	/* already initialized?*/
201 202
	  return TRUE;
	  
203 204
	sic_hdpa = pDPA_Create(16);
	
205
	if (!sic_hdpa)
206 207
	{
	  return(FALSE);
208 209
	}

210 211
	ShellSmallIconList = ImageList_Create(16,16,ILC_COLORDDB | ILC_MASK,0,0x20);
	ShellBigIconList = ImageList_Create(32,32,ILC_COLORDDB | ILC_MASK,0,0x20);
212

213 214
	ImageList_SetBkColor(ShellSmallIconList, GetSysColor(COLOR_WINDOW));
	ImageList_SetBkColor(ShellBigIconList, GetSysColor(COLOR_WINDOW));
215

216 217 218 219 220 221 222 223 224
	for (index=1; index<39; index++)
	{
	  hSm = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(index), IMAGE_ICON, 16, 16,LR_SHARED);
	  hLg = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(index), IMAGE_ICON, 32, 32,LR_SHARED);

	  if(!hSm)
	  {
	    hSm = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(0), IMAGE_ICON, 16, 16,LR_SHARED);
	    hLg = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(0), IMAGE_ICON, 32, 32,LR_SHARED);
225
	  }
226
	  SIC_IconAppend ("shell32.dll", index, hSm, hLg);
227 228
	}

229
	TRACE("hIconSmall=%p hIconBig=%p\n",ShellSmallIconList, ShellBigIconList);
230 231 232

	return TRUE;
}
233 234 235 236 237 238 239 240 241
/*************************************************************************
 * SIC_Destroy
 *
 * frees the cache
 */
void SIC_Destroy(void)
{
	LPSIC_ENTRY lpsice;
	int i;
242

243 244
	TRACE("\n");

245 246
	EnterCriticalSection(&SHELL32_SicCS);

247 248 249 250 251
	if (sic_hdpa && NULL != pDPA_GetPtr (sic_hdpa, 0))
	{
	  for (i=0; i < pDPA_GetPtrCount(sic_hdpa); ++i)
	  {
	    lpsice = pDPA_GetPtr(sic_hdpa, i); 
252 253
	    SHFree(lpsice);
	  }
254
	  pDPA_Destroy(sic_hdpa);
255
	}
256 257

	sic_hdpa = NULL;
258 259

	LeaveCriticalSection(&SHELL32_SicCS);
Juergen Schmied's avatar
Juergen Schmied committed
260
	DeleteCriticalSection(&SHELL32_SicCS);
261
}
262
/*************************************************************************
263
 * Shell_GetImageList			[SHELL32.71]
264 265 266 267 268
 *
 * PARAMETERS
 *  imglist[1|2] [OUT] pointer which recive imagelist handles
 *
 */
269
BOOL WINAPI Shell_GetImageList(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList)
270
{	TRACE("(%p,%p)\n",lpBigList,lpSmallList);
Juergen Schmied's avatar
Juergen Schmied committed
271 272
	if (lpBigList)
	{ *lpBigList = ShellBigIconList;
273
	}
Juergen Schmied's avatar
Juergen Schmied committed
274 275
	if (lpSmallList)
	{ *lpSmallList = ShellSmallIconList;
276 277 278 279
	}

	return TRUE;
}
280 281 282 283 284 285 286
/*************************************************************************
 * PidlToSicIndex			[INTERNAL]
 *
 * PARAMETERS
 *	sh	[IN]	IShellFolder
 *	pidl	[IN]
 *	bBigIcon [IN]
Juergen Schmied's avatar
Juergen Schmied committed
287
 *	uFlags	[IN]	GIL_*
288 289 290
 *	pIndex	[OUT]	index within the SIC
 *
 */
Juergen Schmied's avatar
Juergen Schmied committed
291 292 293 294 295 296
BOOL PidlToSicIndex (
	IShellFolder * sh,
	LPITEMIDLIST pidl,
	BOOL bBigIcon,
	UINT uFlags,
	UINT * pIndex)
297
{	
Juergen Schmied's avatar
Juergen Schmied committed
298
	IExtractIconA	*ei;
299 300 301 302 303
	char		szIconFile[MAX_PATH];	/* file containing the icon */
	INT		iSourceIndex;		/* index or resID(negated) in this file */
	BOOL		ret = FALSE;
	UINT		dwFlags = 0;
	
Juergen Schmied's avatar
Juergen Schmied committed
304
	TRACE("sf=%p pidl=%p %s\n", sh, pidl, bBigIcon?"Big":"Small");
305

306 307
	if (SUCCEEDED (IShellFolder_GetUIObjectOf(sh, 0, 1, &pidl, &IID_IExtractIconA, 0, (void **)&ei)))
	{
Juergen Schmied's avatar
Juergen Schmied committed
308 309 310
	  if (SUCCEEDED(IExtractIconA_GetIconLocation(ei, uFlags, szIconFile, MAX_PATH, &iSourceIndex, &dwFlags)))
	  {
	    *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex);
311
	    ret = TRUE;
312 313 314 315 316 317 318 319 320 321
	  }
	  IExtractIconA_Release(ei);
	}

	if (INVALID_INDEX == *pIndex)	/* default icon when failed */
	  *pIndex = 1;

	return ret;

}
322 323

/*************************************************************************
324
 * SHMapPIDLToSystemImageListIndex	[SHELL32.77]
325 326
 *
 * PARAMETERS
327 328 329
 *	sh	[IN]		pointer to an instance of IShellFolder 
 *	pidl	[IN]
 *	pIndex	[OUT][OPTIONAL]	SIC index for big icon
330 331
 *
 */
332 333 334 335
int WINAPI SHMapPIDLToSystemImageListIndex(
	LPSHELLFOLDER sh,
	LPCITEMIDLIST pidl,
	UINT * pIndex)
336 337
{
	UINT	Index;
338

339
	TRACE("(SF=%p,pidl=%p,%p)\n",sh,pidl,pIndex);
340
	pdump(pidl);
341 342
	
	if (pIndex)
Juergen Schmied's avatar
Juergen Schmied committed
343 344
	  PidlToSicIndex ( sh, pidl, 1, 0, pIndex);
	PidlToSicIndex ( sh, pidl, 0, 0, &Index);
345
	return Index;
346 347
}

348
/*************************************************************************
349
 * Shell_GetCachedImageIndex		[SHELL32.72]
350 351
 *
 */
352 353
INT WINAPI Shell_GetCachedImageIndexA(LPCSTR szPath, INT nIndex, BOOL bSimulateDoc) 
{
354
	WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_a(szPath), nIndex, bSimulateDoc);
355 356 357
	return SIC_GetIconIndex(szPath, nIndex);
}

358
INT WINAPI Shell_GetCachedImageIndexW(LPCWSTR szPath, INT nIndex, BOOL bSimulateDoc) 
359
{	INT ret;
360
	LPSTR sTemp = HEAP_strdupWtoA (GetProcessHeap(),0,szPath);
361
	
362
	WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_w(szPath), nIndex, bSimulateDoc);
363 364 365

	ret = SIC_GetIconIndex(sTemp, nIndex);
	HeapFree(GetProcessHeap(),0,sTemp);
366
	return ret;
367 368
}

369
INT WINAPI Shell_GetCachedImageIndexAW(LPCVOID szPath, INT nIndex, BOOL bSimulateDoc)
370
{	if( SHELL_OsIsUnicode())
371 372
	  return Shell_GetCachedImageIndexW(szPath, nIndex, bSimulateDoc);
	return Shell_GetCachedImageIndexA(szPath, nIndex, bSimulateDoc);
373 374
}

375
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
376
 * ExtractIconEx			[SHELL32.@]
377
 */
378
HICON WINAPI ExtractIconExAW ( LPCVOID lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons )
379
{	if (SHELL_OsIsUnicode())
380 381
	  return ExtractIconExW ( lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
	return ExtractIconExA ( lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
382 383
}
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
384
 * ExtractIconExA			[SHELL32.@]
385 386 387 388 389
 * RETURNS
 *  0 no icon found 
 *  1 file is not valid
 *  HICON handle of a icon (phiconLarge/Small == NULL)
 */
390 391
HICON WINAPI ExtractIconExA ( LPCSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons )
{	HICON ret=0;
392
	
393
	TRACE("file=%s idx=%i %p %p num=%i\n", lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons );
394 395

	if (nIconIndex==-1)	/* Number of icons requested */
396 397
            return PrivateExtractIconsA( lpszFile, -1, 0, 0, NULL, 0, 0, 0 );

398
	if (phiconLarge)
399 400
        {
          ret = PrivateExtractIconsA( lpszFile, nIconIndex, 32, 32, phiconLarge, 0, nIcons, 0 );
401 402 403 404 405 406 407 408 409 410
	  if ( nIcons==1)
	  { ret = phiconLarge[0];	    
	  }
	}

	/* if no pointers given and one icon expected, return the handle directly*/
	if (!phiconLarge && ! phiconSmall && nIcons==1 )
	  phiconSmall = &ret;
	
	if (phiconSmall)
411 412
        {
          ret = PrivateExtractIconsA( lpszFile, nIconIndex, 16, 16, phiconSmall, 0, nIcons, 0 );
413
	  if ( nIcons==1 )
414
	  { ret = phiconSmall[0];
415 416 417 418 419 420
	  }
	}

	return ret;
}
/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
421
 * ExtractIconExW			[SHELL32.@]
422
 */
423
HICON WINAPI ExtractIconExW ( LPCWSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons )
424 425 426
{	LPSTR sFile;
	DWORD ret;
	
427
	TRACE("file=%s idx=%i %p %p num=%i\n", debugstr_w(lpszFile), nIconIndex, phiconLarge, phiconSmall, nIcons );
428 429

	sFile = HEAP_strdupWtoA (GetProcessHeap(),0,lpszFile);
430
	ret = ExtractIconExA ( sFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
431 432 433
	HeapFree(GetProcessHeap(),0,sFile);
	return ret;
}