You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2134 lines
65 KiB
2134 lines
65 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
devicon.c
|
|
|
|
Abstract:
|
|
|
|
Device Installer routines dealing with retrieval/display of icons.
|
|
|
|
Author:
|
|
|
|
Lonny McMichael (lonnym) 28-Aug--1995
|
|
|
|
Notes:
|
|
|
|
You must include "basetyps.h" first.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include <shellapi.h>
|
|
|
|
|
|
MINI_ICON_LIST GlobalMiniIconList;
|
|
|
|
|
|
/*++
|
|
|
|
Class-to-Icon conversion tables exist in two places. First, there
|
|
is the built-in one defined below that is based on a hard-wired
|
|
bitmap in the resource. The second is a linked list of CLASSICON
|
|
structures that is created every time a new class with an icon
|
|
comes along.
|
|
|
|
Check out resource\ilwinmsd.bmp to see the mini-icons. The icons
|
|
are referenced via their (zero-based) index (e.g., computer is 0,
|
|
chip is 1, display is 2, etc.). Today, the bitmap indexes look as follows:
|
|
|
|
0 - computer
|
|
1 - chip
|
|
2 - display
|
|
3 - network
|
|
4 - windows
|
|
5 - mouse
|
|
6 - keyboard
|
|
7 - phone
|
|
8 - sound
|
|
9 - drives
|
|
10 - plugs
|
|
11 - generic
|
|
12 - check
|
|
13 - uncheck
|
|
14 - printer
|
|
15 - nettrans
|
|
16 - netclient
|
|
17 - netservice
|
|
18 - unknown
|
|
19 - Fax machine
|
|
20 - greyed check
|
|
21 - dial up networking
|
|
22 - direct cable connection
|
|
23 - briefcase (filesync)
|
|
24 - Exchange
|
|
25 - partial check
|
|
26 - Generic folder / Accessories
|
|
27 - media (music)
|
|
28 - Quick View
|
|
29 - old MSN
|
|
30 - calculator
|
|
31 - FAT32 Converter
|
|
32 - Document Templates
|
|
33 - disk compression
|
|
34 - Games
|
|
35 - HyperTerminal
|
|
36 - package
|
|
37 - mspaint
|
|
38 - Screensavers
|
|
39 - WordPad
|
|
40 - Clipboard Viewer
|
|
41 - Accessibility Options
|
|
42 - backup
|
|
43 - Desktop Wallpaper
|
|
44 - Character Map
|
|
45 - Mouse Pointers
|
|
46 - Net Watcher
|
|
47 - phone dialer
|
|
48 - resource monitor
|
|
49 - Online User's Guide
|
|
50 - Multilanguage Support
|
|
51 - Audio Compression
|
|
52 - CD player
|
|
53 - Media Player
|
|
54 - WAV sounds
|
|
55 - Sample Sounds
|
|
56 - Video Compression
|
|
57 - Volume Control
|
|
58 - Musica sound scheme
|
|
59 - Jungle sound scheme
|
|
60 - Robotz sound scheme
|
|
61 - Utopia sound scheme
|
|
62 - Eudcedit
|
|
63 - Minesweeper
|
|
64 - Pinball
|
|
65 - Imaging
|
|
66 - Clock
|
|
67 - Infrared
|
|
68 - MS Wallet
|
|
69 - FrontPage Express (aka FrontPad)
|
|
70 - MS Agent
|
|
71 - Internet Tools
|
|
72 - NetShow Player
|
|
73 - Net Meeting
|
|
74 - DVD Player
|
|
75 - Freecell
|
|
76 - Athena / Outlook Express / Internet Mail and News
|
|
77 - Desktop Themes
|
|
78 - Baseball theme
|
|
79 - Dangerous Creatures theme
|
|
80 - Inside your Computer theme
|
|
81 - Jungle theme
|
|
82 - Leonardo da Vinci theme
|
|
83 - More Windows theme
|
|
84 - Mystery theme
|
|
85 - Nature theme
|
|
86 - Science theme
|
|
87 - Space theme
|
|
88 - Sports theme
|
|
89 - The 60's USA theme
|
|
90 - The Golden Era theme
|
|
91 - Travel theme
|
|
92 - Underwater theme
|
|
93 - Windows 95 theme
|
|
94 - Personal Web Server
|
|
95 - Real Audio
|
|
96 - Web Publisher / WebPost
|
|
97 - WaveTop
|
|
98 - WebTV
|
|
|
|
--*/
|
|
|
|
CONST INT UnknownClassMiniIconIndex = 11;
|
|
|
|
CONST CLASSICON MiniIconXlate[] = { {&GUID_DEVCLASS_COMPUTER, 0, NULL},
|
|
{&GUID_DEVCLASS_DISPLAY, 2, NULL},
|
|
{&GUID_DEVCLASS_MOUSE, 5, NULL},
|
|
{&GUID_DEVCLASS_KEYBOARD, 6, NULL},
|
|
{&GUID_DEVCLASS_FDC, 9, NULL},
|
|
{&GUID_DEVCLASS_HDC, 9, NULL},
|
|
{&GUID_DEVCLASS_PORTS, 10, NULL},
|
|
{&GUID_DEVCLASS_NET, 15, NULL},
|
|
{&GUID_DEVCLASS_SYSTEM, 0, NULL},
|
|
{&GUID_DEVCLASS_SOUND, 8, NULL},
|
|
{&GUID_DEVCLASS_PRINTER, 14, NULL},
|
|
{&GUID_DEVCLASS_MONITOR, 2, NULL},
|
|
{&GUID_DEVCLASS_NETTRANS, 3, NULL},
|
|
{&GUID_DEVCLASS_NETCLIENT, 16, NULL},
|
|
{&GUID_DEVCLASS_NETSERVICE, 17, NULL},
|
|
{&GUID_DEVCLASS_UNKNOWN, 18, NULL},
|
|
{&GUID_DEVCLASS_LEGACYDRIVER, 11, NULL},
|
|
{&GUID_DEVCLASS_MTD, 9, NULL}
|
|
};
|
|
|
|
//
|
|
// ISSUE-2002/05/21-lonnym -- Mini-icon list uses hard-coded dimensions
|
|
// We must hard-code the dimensions of the mini-icons we store in our global
|
|
// mini-icon list. This is tied to the size of the mini-icon images contained
|
|
// in the ilwinmsd.bmp "strip".
|
|
//
|
|
#define MINIX 16
|
|
#define MINIY 16
|
|
|
|
#define RGB_WHITE (RGB(255, 255, 255))
|
|
#define RGB_BLACK (RGB(0, 0, 0))
|
|
#define RGB_TRANSPARENT (RGB(0, 128, 128))
|
|
|
|
|
|
//
|
|
// Private function prototypes.
|
|
//
|
|
INT
|
|
NewMiniIcon(
|
|
IN CONST GUID *ClassGuid,
|
|
IN HICON hIcon OPTIONAL
|
|
);
|
|
|
|
|
|
INT
|
|
WINAPI
|
|
SetupDiDrawMiniIcon(
|
|
IN HDC hdc,
|
|
IN RECT rc,
|
|
IN INT MiniIconIndex,
|
|
IN DWORD Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine draws the specified mini-icon at the requested location.
|
|
|
|
Arguments:
|
|
|
|
hdc - Supplies the handle of the device context in which the mini-icon
|
|
will be drawn.
|
|
|
|
rc - Supplies the rectangle in the specified HDC to draw the icon in.
|
|
|
|
MiniIconIndex - The index of the mini-icon, as retrieved from
|
|
SetupDiLoadClassIcon or SetupDiGetClassBitmapIndex. The following are
|
|
pre-defined indices that may be used.
|
|
|
|
0 Computer
|
|
2 display
|
|
5 mouse
|
|
6 keyboard
|
|
9 fdc
|
|
9 hdc
|
|
10 ports
|
|
15 net
|
|
0 system
|
|
8 sound
|
|
14 printer
|
|
2 monitor
|
|
3 nettrans
|
|
16 netclient
|
|
17 netservice
|
|
18 unknown
|
|
|
|
Flags - Controls the drawing operation. The LOWORD contains the actual flags
|
|
defined as follows:
|
|
|
|
DMI_MASK - Draw the mini-icon's mask into HDC.
|
|
|
|
DMI_BKCOLOR - Use the system color index specified in the HIWORD of Flags
|
|
as the background color. If not specified, COLOR_WINDOW is used.
|
|
|
|
DMI_USERECT - If set, SetupDiDrawMiniIcon will use the supplied rect,
|
|
stretching the icon to fit as appropriate.
|
|
|
|
Return Value:
|
|
|
|
This function returns the offset from the left of rc where the string should
|
|
start.
|
|
|
|
Remarks:
|
|
|
|
By default, the icon will be centered vertically and butted against the left
|
|
corner of the specified rectangle.
|
|
|
|
If the specified mini-icon index falls outside the range of our mini-icon
|
|
cache, the unknown class mini-icon will be drawn instead.
|
|
|
|
--*/
|
|
{
|
|
HBITMAP hbmOld = NULL;
|
|
COLORREF rgbBk = CLR_INVALID;
|
|
COLORREF rgbText = CLR_INVALID;
|
|
INT ret = 0;
|
|
BOOL MiniIconListLocked = FALSE;
|
|
DWORD Err = NO_ERROR;
|
|
|
|
try {
|
|
|
|
if(LockMiniIconList(&GlobalMiniIconList)) {
|
|
MiniIconListLocked = TRUE;
|
|
} else {
|
|
leave;
|
|
}
|
|
|
|
CreateMiniIcons();
|
|
|
|
if((MiniIconIndex >= 0) && ((UINT)MiniIconIndex >= GlobalMiniIconList.NumClassImages)) {
|
|
MiniIconIndex = UnknownClassMiniIconIndex;
|
|
}
|
|
|
|
if(GlobalMiniIconList.hbmMiniImage) {
|
|
//
|
|
// Set the Foreground and background color for the
|
|
// conversion of the Mono Mask image
|
|
//
|
|
if(Flags & DMI_MASK) {
|
|
rgbBk = SetBkColor(hdc, RGB_WHITE);
|
|
} else {
|
|
rgbBk = SetBkColor(hdc,
|
|
GetSysColor(((int)(Flags & DMI_BKCOLOR
|
|
? HIWORD(Flags)
|
|
: COLOR_WINDOW)))
|
|
);
|
|
}
|
|
|
|
if(rgbBk == CLR_INVALID) {
|
|
leave;
|
|
}
|
|
|
|
rgbText = SetTextColor(hdc, RGB_BLACK);
|
|
|
|
if(rgbText == CLR_INVALID) {
|
|
leave;
|
|
}
|
|
|
|
if(Flags & DMI_USERECT) {
|
|
//
|
|
// Copy the converted mask into the dest. The transparent
|
|
// areas will be drawn with the current window color.
|
|
//
|
|
hbmOld = SelectObject(GlobalMiniIconList.hdcMiniMem,
|
|
GlobalMiniIconList.hbmMiniMask
|
|
);
|
|
if(!hbmOld) {
|
|
leave;
|
|
}
|
|
|
|
StretchBlt(hdc,
|
|
rc.left,
|
|
rc.top,
|
|
rc.right - rc.left,
|
|
rc.bottom - rc.top,
|
|
GlobalMiniIconList.hdcMiniMem,
|
|
MINIX * MiniIconIndex,
|
|
0,
|
|
MINIX,
|
|
MINIY,
|
|
SRCCOPY | NOMIRRORBITMAP);
|
|
|
|
if(!(Flags & DMI_MASK)) {
|
|
//
|
|
// OR the image into the dest
|
|
//
|
|
SelectObject(GlobalMiniIconList.hdcMiniMem,
|
|
GlobalMiniIconList.hbmMiniImage
|
|
);
|
|
StretchBlt(hdc,
|
|
rc.left,
|
|
rc.top,
|
|
rc.right - rc.left,
|
|
rc.bottom - rc.top,
|
|
GlobalMiniIconList.hdcMiniMem,
|
|
MINIX * MiniIconIndex,
|
|
0,
|
|
MINIX,
|
|
MINIY,
|
|
SRCPAINT | NOMIRRORBITMAP);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Copy the converted mask into the dest. The transparent
|
|
// areas will be drawn with the current window color.
|
|
//
|
|
hbmOld = SelectObject(GlobalMiniIconList.hdcMiniMem,
|
|
GlobalMiniIconList.hbmMiniMask
|
|
);
|
|
if(!hbmOld) {
|
|
leave;
|
|
}
|
|
|
|
BitBlt(hdc,
|
|
rc.left,
|
|
rc.top + (rc.bottom - rc.top - MINIY)/2,
|
|
MINIX,
|
|
MINIY,
|
|
GlobalMiniIconList.hdcMiniMem,
|
|
MINIX * MiniIconIndex,
|
|
0,
|
|
SRCCOPY | NOMIRRORBITMAP
|
|
);
|
|
|
|
|
|
if(!(Flags & DMI_MASK)) {
|
|
//
|
|
// OR the image into the dest
|
|
//
|
|
SelectObject(GlobalMiniIconList.hdcMiniMem,
|
|
GlobalMiniIconList.hbmMiniImage
|
|
);
|
|
BitBlt(hdc,
|
|
rc.left,
|
|
rc.top + (rc.bottom - rc.top - MINIY)/2,
|
|
MINIX,
|
|
MINIY,
|
|
GlobalMiniIconList.hdcMiniMem,
|
|
MINIX * MiniIconIndex,
|
|
0,
|
|
SRCPAINT | NOMIRRORBITMAP
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// ISSUE-2002/05/21-lonnym -- String offset returned by SetupDiDrawMiniIcon assumes LTR reading
|
|
// This may not work properly in an RTL reading configuration
|
|
//
|
|
if(Flags & DMI_USERECT) {
|
|
ret = rc.right - rc.left + 2; // offset to string from left edge
|
|
} else {
|
|
ret = MINIX + 2; // offset to string from left edge
|
|
}
|
|
}
|
|
|
|
} except(pSetupExceptionFilter(GetExceptionCode())) {
|
|
pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
|
|
}
|
|
|
|
if(hbmOld) {
|
|
SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
|
|
}
|
|
|
|
if(MiniIconListLocked) {
|
|
UnlockMiniIconList(&GlobalMiniIconList);
|
|
}
|
|
|
|
if(rgbBk != CLR_INVALID) {
|
|
SetBkColor(hdc, rgbBk);
|
|
}
|
|
|
|
if(rgbText != CLR_INVALID) {
|
|
SetTextColor(hdc, rgbText);
|
|
}
|
|
|
|
return ((Err == NO_ERROR) ? ret : 0);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupDiLoadClassIcon(
|
|
IN CONST GUID *ClassGuid,
|
|
OUT HICON *LargeIcon, OPTIONAL
|
|
OUT HICON *SmallIcon, OPTIONAL
|
|
OUT LPINT MiniIconIndex OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine loads both the large and mini-icons for the specified class
|
|
|
|
Arguments:
|
|
|
|
ClassGuid - Supplies the GUID of the class for which the icon(s) should
|
|
be loaded.
|
|
|
|
LargeIcon - Optionally, supplies a pointer to a variable that will receive
|
|
a handle to the loaded large icon for the specified class. If this
|
|
parameter is not specified, the large icon will not be loaded.
|
|
|
|
The caller must free this icon handle by calling DestroyIcon when they
|
|
no longer need the icon.
|
|
|
|
SmallIcon - Optionally, supplies a pointer to a variable that will receive
|
|
a handle to the loaded small icon for the specified class. If this
|
|
parameter is not specified, the small icon will not be loaded.
|
|
|
|
The caller must free this icon handle by calling DestroyIcon when they
|
|
no longer need the icon.
|
|
|
|
MiniIconIndex - Optionally, supplies a pointer to a variable that will
|
|
receive the index of the mini-icon for the specified class. The
|
|
mini-icon is stored in the device installer's mini-icon cache.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is NO_ERROR. Otherwise, it is
|
|
a Win32 error code indicating the cause of failure.
|
|
|
|
Remarks:
|
|
|
|
The icons of the class are either pre-defined, and loaded from the device
|
|
installer's internal cache, or they are loaded directly from the class
|
|
installer's executable. This function will query the registry value ICON in
|
|
the specified class's section. If this value is specified then it indicates
|
|
what mini icon to load. If the icon value is negative the absolute value
|
|
represents a predefined icon. See SetupDiDrawMiniIcon for a list of
|
|
pre-defined mini icons. If the icon value is positive it represents an icon
|
|
in the class installer's executable, and will be extracted (the number one
|
|
is reserved). This function also uses the INSTALLER32 value first and
|
|
ENUMPROPPAGES32 value second to determine what executable to extract the
|
|
icon(s) from.
|
|
|
|
--*/
|
|
{
|
|
HKEY hk = INVALID_HANDLE_VALUE;
|
|
DWORD Err;
|
|
HICON hRetLargeIcon = NULL;
|
|
HICON hRetSmallIcon = NULL;
|
|
INT ClassIconIndex;
|
|
DWORD RegDataType, StringSize;
|
|
PTSTR EndPtr;
|
|
BOOL bGetMini = FALSE;
|
|
TCHAR TempString[MAX_PATH];
|
|
TCHAR FullPath[MAX_PATH];
|
|
UINT IconsExtracted;
|
|
HRESULT hr;
|
|
|
|
if(!LockMiniIconList(&GlobalMiniIconList)) {
|
|
return ERROR_CANT_LOAD_CLASS_ICON;
|
|
}
|
|
|
|
try {
|
|
|
|
if(MiniIconIndex) {
|
|
*MiniIconIndex = -1;
|
|
}
|
|
|
|
if((hk = SetupDiOpenClassRegKey(ClassGuid, KEY_READ)) == INVALID_HANDLE_VALUE) {
|
|
goto LoadIconFinalize;
|
|
}
|
|
|
|
StringSize = sizeof(TempString);
|
|
Err = RegQueryValueEx(hk,
|
|
pszInsIcon,
|
|
NULL,
|
|
&RegDataType,
|
|
(PBYTE)TempString,
|
|
&StringSize
|
|
);
|
|
|
|
if((Err == ERROR_SUCCESS) && (RegDataType == REG_SZ) && TempString[0]) {
|
|
|
|
if((ClassIconIndex = _tcstol(TempString, &EndPtr, 10)) == 1) {
|
|
//
|
|
// Positive values indicate that we should access an icon
|
|
// directly using its ID. Since ExtractIconEx uses negative
|
|
// values to indicate these IDs, and since the value -1 has
|
|
// a special meaning to that API, we must disallow a
|
|
// ClassIconIndex of +1.
|
|
//
|
|
goto LoadIconFinalize;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Icon index not specified, so assume index is 0.
|
|
//
|
|
ClassIconIndex = 0;
|
|
}
|
|
|
|
if(MiniIconIndex) {
|
|
//
|
|
// If mini-icon is already around, then we're done with it.
|
|
//
|
|
if(!SetupDiGetClassBitmapIndex(ClassGuid, MiniIconIndex)) {
|
|
//
|
|
// mini-icon not around--set flag to show we didn't get it.
|
|
//
|
|
bGetMini = TRUE;
|
|
}
|
|
}
|
|
|
|
if(ClassIconIndex < 0) {
|
|
|
|
INT ClassIconIndexNeg = -ClassIconIndex;
|
|
|
|
//
|
|
// Icon index is negative. This means that this class is one of
|
|
// our special classes with icons in setupapi.dll. We still want
|
|
// to return copies of our icons (both large and small) in this
|
|
// case, since:
|
|
//
|
|
// (a) icon's origin is opaque to callers, and we want them to
|
|
// treat resultant HICONs consistently
|
|
//
|
|
// (b) we don't want any back-door dependency created between
|
|
// these icons and the presence/absence of setupapi.dll
|
|
// (i.e., they should be able to unload setupapi.dll and the
|
|
// icon handle(s) should still be valid.
|
|
//
|
|
if(LargeIcon) {
|
|
|
|
hRetLargeIcon = LoadImage(MyDllModuleHandle,
|
|
MAKEINTRESOURCE(ClassIconIndexNeg),
|
|
IMAGE_ICON,
|
|
0,
|
|
0,
|
|
LR_DEFAULTSIZE
|
|
);
|
|
}
|
|
|
|
if(bGetMini || SmallIcon) {
|
|
//
|
|
// Retrieve the small icon as well. If the resource doesn't
|
|
// have a small icon then the big one will get smushed, but
|
|
// it's better than getting the default icon.
|
|
//
|
|
hRetSmallIcon = LoadImage(MyDllModuleHandle,
|
|
MAKEINTRESOURCE(ClassIconIndexNeg),
|
|
IMAGE_ICON,
|
|
GetSystemMetrics(SM_CXSMICON),
|
|
GetSystemMetrics(SM_CYSMICON),
|
|
0
|
|
);
|
|
|
|
if(hRetSmallIcon && bGetMini) {
|
|
*MiniIconIndex = NewMiniIcon(ClassGuid, hRetSmallIcon);
|
|
}
|
|
}
|
|
|
|
} else if(bGetMini || LargeIcon || SmallIcon) {
|
|
//
|
|
// Look for the binary containing the icon(s) first in the
|
|
// "Installer32" entry, and if not found, then in the
|
|
// "EnumPropPages32" entry.
|
|
//
|
|
hr = StringCchCopy(FullPath,
|
|
SIZECHARS(FullPath),
|
|
SystemDirectory
|
|
);
|
|
|
|
if(FAILED(hr)) {
|
|
goto LoadIconFinalize;
|
|
}
|
|
|
|
StringSize = sizeof(TempString);
|
|
Err = RegQueryValueEx(hk,
|
|
pszInstaller32,
|
|
NULL,
|
|
&RegDataType,
|
|
(PBYTE)TempString,
|
|
&StringSize
|
|
);
|
|
|
|
if((Err != ERROR_SUCCESS) || (RegDataType != REG_SZ) ||
|
|
!TempString[0]) {
|
|
|
|
StringSize = sizeof(TempString);
|
|
Err = RegQueryValueEx(hk,
|
|
pszEnumPropPages32,
|
|
NULL,
|
|
&RegDataType,
|
|
(PBYTE)TempString,
|
|
&StringSize
|
|
);
|
|
|
|
if((Err != ERROR_SUCCESS) || (RegDataType != REG_SZ) ||
|
|
!TempString[0]) {
|
|
|
|
goto LoadIconFinalize;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Remove function name, if present, from installer name.
|
|
//
|
|
for(EndPtr = TempString + (lstrlen(TempString) - 1);
|
|
EndPtr >= TempString;
|
|
EndPtr--) {
|
|
|
|
if(*EndPtr == TEXT(',')) {
|
|
*EndPtr = TEXT('\0');
|
|
break;
|
|
}
|
|
//
|
|
// If we hit a double-quote mark, we terminate the search.
|
|
//
|
|
if(*EndPtr == TEXT('\"')) {
|
|
goto LoadIconFinalize;
|
|
}
|
|
}
|
|
if(!pSetupConcatenatePaths(FullPath,
|
|
TempString,
|
|
SIZECHARS(FullPath),
|
|
NULL)) {
|
|
goto LoadIconFinalize;
|
|
}
|
|
|
|
IconsExtracted = ExtractIconEx(FullPath,
|
|
-ClassIconIndex,
|
|
LargeIcon ? &hRetLargeIcon : NULL,
|
|
(bGetMini || SmallIcon) ? &hRetSmallIcon : NULL,
|
|
1
|
|
);
|
|
if((IconsExtracted != (UINT)-1) && (IconsExtracted > 0)) {
|
|
|
|
if(hRetSmallIcon && bGetMini) {
|
|
*MiniIconIndex = NewMiniIcon(ClassGuid, hRetSmallIcon);
|
|
}
|
|
}
|
|
}
|
|
|
|
LoadIconFinalize:
|
|
//
|
|
// Assume success, unless we hit some really big problem below.
|
|
//
|
|
Err = NO_ERROR;
|
|
|
|
if(LargeIcon && !hRetLargeIcon) {
|
|
//
|
|
// We didn't retrieve a large icon, so use a default.
|
|
//
|
|
Err = GLE_FN_CALL(NULL,
|
|
hRetLargeIcon = LoadImage(
|
|
MyDllModuleHandle,
|
|
MAKEINTRESOURCE(ICON_DEFAULT),
|
|
IMAGE_ICON,
|
|
0,
|
|
0,
|
|
LR_DEFAULTSIZE)
|
|
);
|
|
|
|
if(Err != NO_ERROR) {
|
|
leave;
|
|
}
|
|
}
|
|
|
|
if(SmallIcon && !hRetSmallIcon) {
|
|
//
|
|
// We didn't retrieve a small icon, so use a default.
|
|
//
|
|
Err = GLE_FN_CALL(NULL,
|
|
hRetSmallIcon = LoadImage(
|
|
MyDllModuleHandle,
|
|
MAKEINTRESOURCE(ICON_DEFAULT),
|
|
IMAGE_ICON,
|
|
GetSystemMetrics(SM_CXSMICON),
|
|
GetSystemMetrics(SM_CYSMICON),
|
|
0)
|
|
);
|
|
|
|
if(Err != NO_ERROR) {
|
|
leave;
|
|
}
|
|
}
|
|
|
|
if(LargeIcon) {
|
|
*LargeIcon = hRetLargeIcon;
|
|
hRetLargeIcon = NULL; // so we won't try to destroy it later
|
|
}
|
|
|
|
if(SmallIcon) {
|
|
*SmallIcon = hRetSmallIcon;
|
|
hRetSmallIcon = NULL; // so we won't try to destroy it later
|
|
}
|
|
|
|
if(MiniIconIndex && (*MiniIconIndex == -1)) {
|
|
SetupDiGetClassBitmapIndex(NULL, MiniIconIndex);
|
|
}
|
|
|
|
} except(pSetupExceptionFilter(GetExceptionCode())) {
|
|
pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
|
|
}
|
|
|
|
UnlockMiniIconList(&GlobalMiniIconList);
|
|
|
|
if(hk != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(hk);
|
|
}
|
|
|
|
if(hRetLargeIcon) {
|
|
DestroyIcon(hRetLargeIcon);
|
|
}
|
|
|
|
if(hRetSmallIcon) {
|
|
DestroyIcon(hRetSmallIcon);
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiLoadClassIcon(
|
|
IN CONST GUID *ClassGuid,
|
|
OUT HICON *LargeIcon, OPTIONAL
|
|
OUT LPINT MiniIconIndex OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine loads both the large and mini-icons for the specified class
|
|
|
|
Arguments:
|
|
|
|
ClassGuid - Supplies the GUID of the class for which the icon(s) should
|
|
be loaded.
|
|
|
|
LargeIcon - Optionally, supplies a pointer to a variable that will receive
|
|
a handle to the loaded large icon for the specified class. If this
|
|
parameter is not specified, the large icon will not be loaded.
|
|
|
|
The caller must free this icon handle by calling DestroyIcon when they
|
|
no longer need the icon.
|
|
|
|
MiniIconIndex - Optionally, supplies a pointer to a variable that will
|
|
receive the index of the mini-icon for the specified class. The
|
|
mini-icon is stored in the device installer's mini-icon cache.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is TRUE.
|
|
|
|
If the function fails, the return value is FALSE. To get extended error
|
|
information, call GetLastError.
|
|
|
|
Remarks:
|
|
|
|
The icons of the class are either pre-defined, and loaded from the device
|
|
installer's internal cache, or they are loaded directly from the class
|
|
installer's executable. This function will query the registry value ICON
|
|
in the specified class's section. If this value is specified then it
|
|
indicates what mini icon to load. If the icon value is negative the
|
|
absolute value represents a predefined icon. See SetupDiDrawMiniIcon for a
|
|
list of pre-defined mini icons. If the icon value is positive it
|
|
represents an icon in the class installer's executable, and will be
|
|
extracted (the number one is reserved). This function also uses the
|
|
INSTALLER32 value first and ENUMPROPPAGES32 value second to determine what
|
|
executable to extract the icon(s) from.
|
|
|
|
--*/
|
|
{
|
|
DWORD Err;
|
|
|
|
//
|
|
// Wrap call in try/except to catch stack overflow
|
|
//
|
|
try {
|
|
|
|
Err = pSetupDiLoadClassIcon(ClassGuid,
|
|
LargeIcon,
|
|
NULL,
|
|
MiniIconIndex
|
|
);
|
|
|
|
} except(pSetupExceptionFilter(GetExceptionCode())) {
|
|
pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
|
|
}
|
|
|
|
SetLastError(Err);
|
|
return (Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetClassBitmapIndex(
|
|
IN CONST GUID *ClassGuid, OPTIONAL
|
|
OUT PINT MiniIconIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves the index of the mini-icon for the specified class.
|
|
|
|
Arguments:
|
|
|
|
ClassGuid - Optionally, supplies the GUID of the class to get the mini-icon
|
|
index for. If this parameter is not specified, the index of the 'unknown'
|
|
icon is returned.
|
|
|
|
MiniIconIndex - Supplies a pointer to a variable that receives the index of
|
|
the mini-icon for the specified class. This buffer is always filled in,
|
|
and receives the index of the unknown mini-icon if there is no mini-icon
|
|
for the specified class (i.e., the return value is FALSE).
|
|
|
|
Return Value:
|
|
|
|
If there was a mini-icon for the specified class, the return value is TRUE.
|
|
|
|
If there was not a mini-icon for the specified class, or if no class was
|
|
specified, the return value is FALSE (and GetLastError returns
|
|
ERROR_NO_DEVICE_CLASS_ICON). In this case, MiniIconIndex will contain the
|
|
index of the unknown mini-icon.
|
|
|
|
--*/
|
|
{
|
|
BOOL bRet = FALSE; // assume not found
|
|
int i;
|
|
PCLASSICON pci;
|
|
DWORD Err;
|
|
BOOL MiniIconListLocked = FALSE;
|
|
|
|
try {
|
|
|
|
if(ClassGuid) {
|
|
//
|
|
// First check the built-in list.
|
|
//
|
|
for(i = 0; !bRet && (i < ARRAYSIZE(MiniIconXlate)); i++) {
|
|
|
|
if(IsEqualGUID(MiniIconXlate[i].ClassGuid, ClassGuid)) {
|
|
*MiniIconIndex = MiniIconXlate[i].MiniBitmapIndex;
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Next check the "new stuff" list to see if it's there.
|
|
//
|
|
if(!bRet && LockMiniIconList(&GlobalMiniIconList)) {
|
|
|
|
MiniIconListLocked = TRUE;
|
|
|
|
for(pci = GlobalMiniIconList.ClassIconList;
|
|
!bRet && pci;
|
|
pci = pci->Next) {
|
|
|
|
if(IsEqualGUID(pci->ClassGuid, ClassGuid)) {
|
|
*MiniIconIndex = pci->MiniBitmapIndex;
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If no match was found, snag the "unknown" class.
|
|
//
|
|
if(!bRet) {
|
|
*MiniIconIndex = UnknownClassMiniIconIndex;
|
|
Err = ERROR_NO_DEVICE_ICON;
|
|
} else {
|
|
Err = NO_ERROR;
|
|
}
|
|
|
|
} except(pSetupExceptionFilter(GetExceptionCode())) {
|
|
pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
|
|
}
|
|
|
|
if(MiniIconListLocked) {
|
|
UnlockMiniIconList(&GlobalMiniIconList);
|
|
}
|
|
|
|
SetLastError(Err);
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CreateMiniIcons(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine loads the default bitmap of mini-icons and turns it into
|
|
the image/mask pair that will be the cornerstone of mini-icon management.
|
|
THIS FUNCTION ASSUMES THE MINI-ICON LOCK HAS ALREADY BEEN ACQUIRED!
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is TRUE, otherwise it is FALSE.
|
|
|
|
--*/
|
|
{
|
|
HDC hdc = NULL;
|
|
HDC hdcMem = NULL;
|
|
HBITMAP hbmOld = NULL;
|
|
BITMAP bm;
|
|
BOOL bRet = FALSE; // assume failure
|
|
|
|
if(GlobalMiniIconList.hdcMiniMem) {
|
|
//
|
|
// Then the mini-icon list has already been built, so
|
|
// return success.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
try {
|
|
|
|
hdc = GetDC(NULL);
|
|
if(!hdc) {
|
|
leave;
|
|
}
|
|
GlobalMiniIconList.hdcMiniMem = CreateCompatibleDC(hdc);
|
|
if(!GlobalMiniIconList.hdcMiniMem) {
|
|
leave;
|
|
}
|
|
|
|
hdcMem = CreateCompatibleDC(GlobalMiniIconList.hdcMiniMem);
|
|
|
|
if(!hdcMem) {
|
|
leave;
|
|
}
|
|
|
|
if(!(GlobalMiniIconList.hbmMiniImage = LoadBitmap(MyDllModuleHandle,
|
|
MAKEINTRESOURCE(BMP_DRIVERTYPES)))) {
|
|
leave;
|
|
}
|
|
|
|
GetObject(GlobalMiniIconList.hbmMiniImage, sizeof(bm), &bm);
|
|
|
|
if(!(GlobalMiniIconList.hbmMiniMask = CreateBitmap(bm.bmWidth,
|
|
bm.bmHeight,
|
|
1,
|
|
1,
|
|
NULL))) {
|
|
leave;
|
|
}
|
|
|
|
hbmOld = SelectObject(hdcMem, GlobalMiniIconList.hbmMiniImage);
|
|
if(!hbmOld) {
|
|
leave;
|
|
}
|
|
|
|
SelectObject(GlobalMiniIconList.hdcMiniMem,
|
|
GlobalMiniIconList.hbmMiniMask
|
|
);
|
|
|
|
//
|
|
// make the mask. white where transparent, black where opaque
|
|
//
|
|
SetBkColor(hdcMem, RGB_TRANSPARENT);
|
|
BitBlt(GlobalMiniIconList.hdcMiniMem,
|
|
0,
|
|
0,
|
|
bm.bmWidth,
|
|
bm.bmHeight,
|
|
hdcMem,
|
|
0,
|
|
0,
|
|
SRCCOPY
|
|
);
|
|
|
|
//
|
|
// black-out all of the transparent parts of the image, in preparation
|
|
// for drawing.
|
|
//
|
|
SetBkColor(hdcMem, RGB_BLACK);
|
|
SetTextColor(hdcMem, RGB_WHITE);
|
|
BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, GlobalMiniIconList.hdcMiniMem, 0, 0, SRCAND);
|
|
|
|
SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
|
|
|
|
GlobalMiniIconList.NumClassImages = bm.bmWidth/MINIX;
|
|
bRet = TRUE;
|
|
|
|
} except(pSetupExceptionFilter(GetExceptionCode())) {
|
|
pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
|
|
bRet = FALSE;
|
|
}
|
|
|
|
if(hdc) {
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
|
|
if(hdcMem) {
|
|
if(hbmOld) {
|
|
SelectObject(hdcMem, hbmOld);
|
|
}
|
|
DeleteObject(hdcMem);
|
|
}
|
|
|
|
//
|
|
// If failure, clean up anything we might have built
|
|
//
|
|
if(!bRet) {
|
|
DestroyMiniIcons();
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
INT
|
|
NewMiniIcon(
|
|
IN CONST GUID *ClassGuid,
|
|
IN HICON hIcon OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
It's a new class, and we have a mini-icon for it, so let's add it
|
|
to the mini-icon database. First pull out the image and mask
|
|
bitmaps. Then add these to the mini-icon bitmap. If this all
|
|
works, add the new class to the list
|
|
|
|
THIS FUNCTION ASSUMES THE MINI-ICON LOCK HAS ALREADY BEEN ACQUIRED!
|
|
|
|
Arguments:
|
|
|
|
ClassGuid - Supplies a pointer to the class GUID for this mini-icon.
|
|
|
|
hIcon - Optionally, supplies a handle to the mini-icon to be added to
|
|
the database. If this parameter is not specified, then the index
|
|
for the "unknown class" icon will be returned.
|
|
|
|
Return Value:
|
|
|
|
Index for class (set to "unknown class" if error)
|
|
|
|
--*/
|
|
{
|
|
INT iBitmap = -1;
|
|
ICONINFO ii;
|
|
PCLASSICON pci = NULL;
|
|
|
|
if(hIcon && GetIconInfo(hIcon, &ii)) {
|
|
|
|
try {
|
|
|
|
if((iBitmap = pSetupAddMiniIconToList(ii.hbmColor, ii.hbmMask)) != -1) {
|
|
//
|
|
// Allocate an extra GUID's worth of memory, so we can store
|
|
// the class GUID in the same chunk of memory as the CLASSICON
|
|
// node.
|
|
//
|
|
if(pci = (PCLASSICON)MyMalloc(sizeof(CLASSICON) + sizeof(GUID))) {
|
|
|
|
CopyMemory((PBYTE)pci + sizeof(CLASSICON),
|
|
ClassGuid,
|
|
sizeof(GUID)
|
|
);
|
|
pci->ClassGuid = (LPGUID)((PBYTE)pci + sizeof(CLASSICON));
|
|
pci->MiniBitmapIndex = iBitmap;
|
|
|
|
pci->Next = GlobalMiniIconList.ClassIconList;
|
|
GlobalMiniIconList.ClassIconList = pci;
|
|
}
|
|
}
|
|
|
|
} except(pSetupExceptionFilter(GetExceptionCode())) {
|
|
|
|
pSetupExceptionHandler(GetExceptionCode(),
|
|
ERROR_INVALID_PARAMETER,
|
|
NULL
|
|
);
|
|
|
|
if(pci) {
|
|
MyFree(pci);
|
|
}
|
|
|
|
iBitmap = -1;
|
|
}
|
|
|
|
DeleteObject(ii.hbmColor);
|
|
DeleteObject(ii.hbmMask);
|
|
}
|
|
|
|
if(iBitmap == -1) {
|
|
SetupDiGetClassBitmapIndex(NULL, &iBitmap);
|
|
}
|
|
|
|
return iBitmap;
|
|
}
|
|
|
|
|
|
INT
|
|
pSetupAddMiniIconToList(
|
|
IN HBITMAP hbmImage,
|
|
IN HBITMAP hbmMask
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given the image and mask bitmaps of a mini-icon, add these to the
|
|
mini-icon bitmap.
|
|
|
|
THIS FUNCTION ASSUMES THE MINI-ICON LOCK HAS ALREADY BEEN ACQUIRED!
|
|
|
|
Arguments:
|
|
|
|
hbmImage - Supplies the handle of the bitmap for the mini-icon.
|
|
|
|
hbmMask - Supplies the handle of the bitmap for the mini-icon's mask.
|
|
|
|
Return Value:
|
|
|
|
If success, returns the index of the added mini-icon.
|
|
If failure, returns -1.
|
|
|
|
--*/
|
|
{
|
|
HBITMAP hbmNewImage = NULL, hbmNewMask = NULL;
|
|
HBITMAP hbmOld;
|
|
HDC hdcMem = NULL;
|
|
BITMAP bm;
|
|
BOOL bSelectOldBitmap = FALSE;
|
|
INT iIcon = -1; // assume failure
|
|
|
|
if(!CreateMiniIcons()) {
|
|
return iIcon;
|
|
}
|
|
|
|
MYASSERT(GlobalMiniIconList.hdcMiniMem);
|
|
|
|
try {
|
|
|
|
hdcMem = CreateCompatibleDC(GlobalMiniIconList.hdcMiniMem);
|
|
|
|
if(!hdcMem) {
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Create a New global Bitmap for the minis
|
|
//
|
|
hbmOld = SelectObject(GlobalMiniIconList.hdcMiniMem,
|
|
GlobalMiniIconList.hbmMiniImage
|
|
);
|
|
|
|
bSelectOldBitmap = TRUE;
|
|
|
|
if(!(hbmNewImage = CreateCompatibleBitmap(
|
|
GlobalMiniIconList.hdcMiniMem,
|
|
MINIX * (GlobalMiniIconList.NumClassImages + 1),
|
|
MINIY))) {
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Copy the current Mini bitmap
|
|
//
|
|
SelectObject(hdcMem, hbmNewImage);
|
|
BitBlt(hdcMem,
|
|
0,
|
|
0,
|
|
MINIX * GlobalMiniIconList.NumClassImages,
|
|
MINIY,
|
|
GlobalMiniIconList.hdcMiniMem,
|
|
0,
|
|
0,
|
|
SRCCOPY
|
|
);
|
|
|
|
//
|
|
// Fit the New icon into ours. We need to stretch it to fit correctly.
|
|
//
|
|
SelectObject(GlobalMiniIconList.hdcMiniMem, hbmImage);
|
|
GetObject(hbmImage, sizeof(bm), &bm);
|
|
StretchBlt(hdcMem,
|
|
MINIX * GlobalMiniIconList.NumClassImages,
|
|
0,
|
|
MINIX,
|
|
MINIY,
|
|
GlobalMiniIconList.hdcMiniMem,
|
|
0,
|
|
0,
|
|
bm.bmWidth,
|
|
bm.bmHeight,
|
|
SRCCOPY
|
|
);
|
|
|
|
SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
|
|
bSelectOldBitmap = FALSE;
|
|
|
|
//
|
|
// Next, copy the mask.
|
|
//
|
|
hbmOld = SelectObject(GlobalMiniIconList.hdcMiniMem,
|
|
GlobalMiniIconList.hbmMiniMask
|
|
);
|
|
|
|
bSelectOldBitmap = TRUE;
|
|
|
|
if(!(hbmNewMask = CreateBitmap(MINIX * (GlobalMiniIconList.NumClassImages + 1),
|
|
MINIY,
|
|
1,
|
|
1,
|
|
NULL))) {
|
|
leave;
|
|
}
|
|
|
|
SelectObject(hdcMem, hbmNewMask);
|
|
BitBlt(hdcMem,
|
|
0,
|
|
0,
|
|
MINIX * GlobalMiniIconList.NumClassImages,
|
|
MINIY,
|
|
GlobalMiniIconList.hdcMiniMem,
|
|
0,
|
|
0,
|
|
SRCCOPY
|
|
);
|
|
|
|
SelectObject(GlobalMiniIconList.hdcMiniMem, hbmMask);
|
|
GetObject(hbmMask, sizeof(bm), &bm);
|
|
StretchBlt(hdcMem,
|
|
MINIX * GlobalMiniIconList.NumClassImages,
|
|
0,
|
|
MINIX,
|
|
MINIY,
|
|
GlobalMiniIconList.hdcMiniMem,
|
|
0,
|
|
0,
|
|
bm.bmWidth,
|
|
bm.bmHeight,
|
|
SRCCOPY
|
|
);
|
|
|
|
SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
|
|
bSelectOldBitmap = FALSE;
|
|
|
|
//
|
|
// Now that we've successfully constructed new image and mask bitmaps,
|
|
// store those into our mini-icon list.
|
|
//
|
|
DeleteObject(GlobalMiniIconList.hbmMiniImage);
|
|
GlobalMiniIconList.hbmMiniImage = hbmNewImage;
|
|
hbmNewImage = NULL; // so we won't try to delete this later
|
|
|
|
DeleteObject(GlobalMiniIconList.hbmMiniMask);
|
|
GlobalMiniIconList.hbmMiniMask = hbmNewMask;
|
|
hbmNewMask = NULL; // so we won't try to delete this later
|
|
|
|
iIcon = GlobalMiniIconList.NumClassImages;
|
|
GlobalMiniIconList.NumClassImages++; // one more image in the list
|
|
|
|
} except(pSetupExceptionFilter(GetExceptionCode())) {
|
|
pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
|
|
iIcon = -1;
|
|
}
|
|
|
|
if(bSelectOldBitmap) {
|
|
SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
|
|
}
|
|
|
|
if(hbmNewImage) {
|
|
DeleteObject(hbmNewImage);
|
|
}
|
|
|
|
if(hbmNewMask) {
|
|
DeleteObject(hbmNewMask);
|
|
}
|
|
|
|
if(hdcMem) {
|
|
DeleteDC(hdcMem);
|
|
}
|
|
|
|
return iIcon;
|
|
}
|
|
|
|
|
|
VOID
|
|
DestroyMiniIcons(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine destroys the mini-icon bitmaps, if they exist.
|
|
THIS FUNCTION ASSUMES THE MINI-ICON LOCK HAS ALREADY BEEN ACQUIRED!
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PCLASSICON pci;
|
|
|
|
if(GlobalMiniIconList.hdcMiniMem) {
|
|
DeleteDC(GlobalMiniIconList.hdcMiniMem);
|
|
GlobalMiniIconList.hdcMiniMem = NULL;
|
|
}
|
|
|
|
if(GlobalMiniIconList.hbmMiniImage) {
|
|
DeleteObject(GlobalMiniIconList.hbmMiniImage);
|
|
GlobalMiniIconList.hbmMiniImage = NULL;
|
|
}
|
|
|
|
if(GlobalMiniIconList.hbmMiniMask) {
|
|
DeleteObject(GlobalMiniIconList.hbmMiniMask);
|
|
GlobalMiniIconList.hbmMiniMask = NULL;
|
|
}
|
|
|
|
GlobalMiniIconList.NumClassImages = 0;
|
|
|
|
//
|
|
// Free up any additional class icon guys that were created
|
|
//
|
|
while(GlobalMiniIconList.ClassIconList) {
|
|
pci = GlobalMiniIconList.ClassIconList;
|
|
GlobalMiniIconList.ClassIconList = pci->Next;
|
|
MyFree(pci);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetClassImageList(
|
|
OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
See SetupDiGetClassImageListEx for details.
|
|
|
|
--*/
|
|
{
|
|
DWORD Err;
|
|
|
|
//
|
|
// Wrap call in try/except to catch stack overflow
|
|
//
|
|
try {
|
|
|
|
Err = GLE_FN_CALL(FALSE,
|
|
SetupDiGetClassImageListEx(ClassImageListData,
|
|
NULL,
|
|
NULL)
|
|
);
|
|
|
|
} except(pSetupExceptionFilter(GetExceptionCode())) {
|
|
pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
|
|
}
|
|
|
|
SetLastError(Err);
|
|
return (Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetClassImageListExA(
|
|
OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
|
|
IN PCSTR MachineName, OPTIONAL
|
|
IN PVOID Reserved
|
|
)
|
|
{
|
|
PCWSTR UnicodeMachineName = NULL;
|
|
DWORD rc;
|
|
|
|
try {
|
|
|
|
if(MachineName) {
|
|
rc = pSetupCaptureAndConvertAnsiArg(MachineName,
|
|
&UnicodeMachineName
|
|
);
|
|
if(rc != NO_ERROR) {
|
|
leave;
|
|
}
|
|
}
|
|
|
|
rc = GLE_FN_CALL(FALSE,
|
|
SetupDiGetClassImageListExW(ClassImageListData,
|
|
UnicodeMachineName,
|
|
Reserved)
|
|
);
|
|
|
|
} except(pSetupExceptionFilter(GetExceptionCode())) {
|
|
pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &rc);
|
|
}
|
|
|
|
if(UnicodeMachineName) {
|
|
MyFree(UnicodeMachineName);
|
|
}
|
|
|
|
SetLastError(rc);
|
|
return (rc == NO_ERROR);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetClassImageListEx(
|
|
OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
|
|
IN PCTSTR MachineName, OPTIONAL
|
|
IN PVOID Reserved
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine builds an image list containing bitmaps for every installed class,
|
|
and returns a data structure containing the list.
|
|
|
|
Arguments:
|
|
|
|
ClassImageListData - Supplies the address of a SP_CLASSIMAGELIST_DATA structure
|
|
that will receive information regarding the class list (including a handle
|
|
to the image list). The cbSize field of this structure must be initialized
|
|
with the size of the structure (in bytes) before calling this routine, or the
|
|
API will fail.
|
|
|
|
MachineName - Optionally, specifies the name of the remote machine whose installed
|
|
classes are to be used in building the class image list. If this parameter is
|
|
not specified, the local machine is used.
|
|
|
|
NOTE: Presently, class-specific icons can only be displayed if the class is
|
|
also present on the local machine. Thus, if the remote machine has
|
|
class x, but class x is not installed locally, then the generic (unknown)
|
|
icon will be returned.
|
|
|
|
Reserved - Reserved for future use--must be NULL.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is TRUE.
|
|
|
|
If the function fails, the return value is FALSE. To get extended error
|
|
information, call GetLastError.
|
|
|
|
Remarks:
|
|
|
|
The image list contained in structure filled in by this API should NOT be
|
|
destroyed by calling ImageList_Destroy. Instead, SetupDiDestroyClassImageList
|
|
should be called, for proper clean-up to occur.
|
|
|
|
--*/
|
|
{
|
|
DWORD Err = NO_ERROR;
|
|
int cxMiniIcon, cyMiniIcon;
|
|
int MiniIconIndex = 0, DefaultIndex = 0;
|
|
int GuidCount, i;
|
|
int iIcon, iIndex;
|
|
HDC hDC = NULL, hMemImageDC = NULL;
|
|
HBITMAP hbmMiniImage = NULL, hbmMiniMask = NULL, hbmOldImage = NULL;
|
|
RECT rc;
|
|
CONST GUID *pClassGuid = NULL;
|
|
BOOL bUseBitmap, ComputerClassFound = FALSE;
|
|
HICON hiLargeIcon = NULL, hiSmallIcon = NULL;
|
|
HICON hIcon;
|
|
HBRUSH hOldBrush;
|
|
PCLASSICON pci = NULL;
|
|
PCLASS_IMAGE_LIST ImageData = NULL;
|
|
BOOL DestroyLock = FALSE;
|
|
HIMAGELIST ImageList = NULL;
|
|
DWORD dwLayout = 0;
|
|
UINT ImageListFlags = 0;
|
|
|
|
//
|
|
// Make sure the caller didn't pass us anything in the Reserved parameter.
|
|
//
|
|
if(Reserved) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
try {
|
|
|
|
if(ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA)) {
|
|
Err = ERROR_INVALID_USER_BUFFER;
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Allocate and initialize the image list, including setting up the
|
|
// synchronization lock. Destroy it when done.
|
|
//
|
|
if(ImageData = MyMalloc(sizeof(CLASS_IMAGE_LIST))) {
|
|
ZeroMemory(ImageData, sizeof(CLASS_IMAGE_LIST));
|
|
} else {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
leave;
|
|
}
|
|
|
|
if(InitializeSynchronizedAccess(&ImageData->Lock)) {
|
|
DestroyLock = TRUE;
|
|
}
|
|
|
|
//
|
|
// Build the class image list. Create an Image List with no mask,
|
|
// 1 image, and a growth factor of 1.
|
|
//
|
|
cxMiniIcon = GetSystemMetrics(SM_CXSMICON);
|
|
cyMiniIcon = GetSystemMetrics(SM_CYSMICON);
|
|
|
|
ImageListFlags = ILC_MASK;
|
|
|
|
//
|
|
// Check which color depth we are running in. Set the ILC_COLOR32
|
|
// imagelist create flag if we are running at greate than 8bit (256)
|
|
// color depth.
|
|
//
|
|
hDC = GetDC(NULL);
|
|
if (hDC) {
|
|
if (GetDeviceCaps(hDC, BITSPIXEL) > 8) {
|
|
ImageListFlags |= ILC_COLOR32;
|
|
}
|
|
|
|
ReleaseDC(NULL, hDC);
|
|
hDC = NULL;
|
|
}
|
|
|
|
//
|
|
// If we are running on an RTL build then we need to set the ILC_MIRROR
|
|
// flag when calling ImageList_Create to un-mirror the icons. By
|
|
// default the icons are mirrored.
|
|
//
|
|
if (GetProcessDefaultLayout(&dwLayout) &&
|
|
(dwLayout & LAYOUT_RTL)) {
|
|
ImageListFlags |= ILC_MIRROR;
|
|
}
|
|
|
|
if(!(ImageList = ImageList_Create(cxMiniIcon,
|
|
cyMiniIcon,
|
|
ImageListFlags,
|
|
1,
|
|
1)))
|
|
{
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
leave;
|
|
}
|
|
|
|
ImageList_SetBkColor(ImageList, GetSysColor(COLOR_WINDOW));
|
|
|
|
//
|
|
// Create a DC to draw the mini icons into. This is needed
|
|
// for the system defined Minis
|
|
//
|
|
if(!(hDC = GetDC(HWND_DESKTOP)) ||
|
|
!(hMemImageDC = CreateCompatibleDC(hDC)))
|
|
{
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Create a bitmap to draw the icons on. Defer checking for creation
|
|
// of bitmap until afer freeing DC, so it only has to be done once.
|
|
//
|
|
hbmMiniImage = CreateCompatibleBitmap(hDC, cxMiniIcon, cyMiniIcon);
|
|
hbmMiniMask = CreateCompatibleBitmap(hDC, cxMiniIcon, cyMiniIcon);
|
|
|
|
ReleaseDC(HWND_DESKTOP, hDC);
|
|
hDC = NULL;
|
|
|
|
//
|
|
// Did the bitmap get created?
|
|
//
|
|
if (!hbmMiniImage || ! hbmMiniMask) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Select our bitmap into the memory DC.
|
|
//
|
|
hbmOldImage = SelectObject(hMemImageDC, hbmMiniImage);
|
|
|
|
//
|
|
// Prepare to draw the mini icon onto the memory DC
|
|
//
|
|
rc.left = 0;
|
|
rc.top = 0;
|
|
rc.right = cxMiniIcon;
|
|
rc.bottom = cyMiniIcon;
|
|
|
|
//
|
|
// Get the Index of the Default mini icon.
|
|
//
|
|
SetupDiGetClassBitmapIndex(NULL, &DefaultIndex);
|
|
|
|
//
|
|
// Enumerate all classes, and for each class, draw its bitmap.
|
|
//
|
|
GuidCount = 32; // reasonable sized list to start out with.
|
|
|
|
ImageData->ClassGuidList = (LPGUID)MyMalloc(sizeof(GUID) * GuidCount);
|
|
|
|
Err = GLE_FN_CALL(FALSE,
|
|
SetupDiBuildClassInfoListEx(0,
|
|
ImageData->ClassGuidList,
|
|
GuidCount,
|
|
&GuidCount,
|
|
MachineName,
|
|
NULL)
|
|
);
|
|
|
|
|
|
if(Err == ERROR_INSUFFICIENT_BUFFER) {
|
|
//
|
|
// Realloc buffer and try again.
|
|
//
|
|
MyFree(ImageData->ClassGuidList);
|
|
|
|
if(!(ImageData->ClassGuidList = MyMalloc(sizeof(GUID) * GuidCount))) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
leave;
|
|
}
|
|
|
|
Err = GLE_FN_CALL(FALSE,
|
|
SetupDiBuildClassInfoListEx(
|
|
0,
|
|
ImageData->ClassGuidList,
|
|
GuidCount,
|
|
&GuidCount,
|
|
MachineName,
|
|
NULL)
|
|
);
|
|
}
|
|
|
|
if(Err != NO_ERROR) {
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Retrieve the icon for each class in the class list.
|
|
//
|
|
for(pClassGuid = ImageData->ClassGuidList, i = 0;
|
|
i < GuidCount;
|
|
pClassGuid++, i++) {
|
|
|
|
Err = pSetupDiLoadClassIcon(pClassGuid,
|
|
&hiLargeIcon,
|
|
&hiSmallIcon,
|
|
&MiniIconIndex
|
|
);
|
|
if(Err != NO_ERROR) {
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// If the returned Mini Icon index is not the Default one, then
|
|
// we use the MiniBitmap, since it is a pre-defined one in SETUPAPI.
|
|
// If the Mini is not pre-defined, and there is no Class Installer
|
|
// then we use the Mini, since it is a valid default. If there
|
|
// is no Mini, and there is a class installer, then we will use
|
|
// the Class installer's big Icon, and have the Image list crunch
|
|
// it for us.
|
|
//
|
|
bUseBitmap = FALSE;
|
|
|
|
if(DefaultIndex != MiniIconIndex) {
|
|
|
|
SetupDiDrawMiniIcon(hMemImageDC,
|
|
rc,
|
|
MiniIconIndex,
|
|
DMI_USERECT);
|
|
|
|
SelectObject(hMemImageDC, hbmMiniMask);
|
|
|
|
SetupDiDrawMiniIcon(hMemImageDC,
|
|
rc,
|
|
MiniIconIndex,
|
|
DMI_MASK | DMI_USERECT);
|
|
bUseBitmap = TRUE;
|
|
}
|
|
|
|
//
|
|
// Deselect the bitmap from our DC BEFORE calling ImageList
|
|
// functions.
|
|
//
|
|
SelectObject(hMemImageDC, hbmOldImage);
|
|
|
|
//
|
|
// Add the image. Allocate a new PCI.
|
|
//
|
|
if(!(pci = (PCLASSICON)MyMalloc(sizeof(CLASSICON)))) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
leave;
|
|
}
|
|
|
|
if(hiSmallIcon) {
|
|
pci->MiniBitmapIndex = (UINT)ImageList_AddIcon(ImageList, hiSmallIcon);
|
|
} else if(bUseBitmap) {
|
|
pci->MiniBitmapIndex = (UINT)ImageList_Add(ImageList, hbmMiniImage, hbmMiniMask);
|
|
} else {
|
|
pci->MiniBitmapIndex = (UINT)ImageList_AddIcon(ImageList, hiLargeIcon);
|
|
}
|
|
|
|
if(hiLargeIcon) {
|
|
DestroyIcon(hiLargeIcon);
|
|
hiLargeIcon = NULL;
|
|
}
|
|
|
|
if(hiSmallIcon) {
|
|
DestroyIcon(hiSmallIcon);
|
|
hiSmallIcon = NULL;
|
|
}
|
|
|
|
if(pci->MiniBitmapIndex == (UINT)-1) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
MyFree(pci);
|
|
pci = NULL;
|
|
leave;
|
|
}
|
|
|
|
pci->ClassGuid = pClassGuid;
|
|
|
|
//
|
|
// Link it in.
|
|
//
|
|
pci->Next = ImageData->ClassIconList;
|
|
ImageData->ClassIconList = pci;
|
|
|
|
//
|
|
// Reset pci to NULL so we won't try to free it later.
|
|
//
|
|
pci = NULL;
|
|
|
|
//
|
|
// Select our bitmap back for the next ICON.
|
|
//
|
|
SelectObject(hMemImageDC, hbmMiniImage);
|
|
|
|
if(IsEqualGUID(pClassGuid, &GUID_DEVCLASS_UNKNOWN)) {
|
|
ImageData->UnknownImageIndex = i;
|
|
}
|
|
|
|
//
|
|
// Check to see if we've encountered the computer class. This used
|
|
// to be a special pseudo-class used solely by DevMgr to retrieve
|
|
// the icon for the root of the device tree. Now, we use this class
|
|
// for specifying the 'drivers' for the computer itself (i.e., the
|
|
// HALs and the appropriate versions of files that are different for
|
|
// MP vs. UP.
|
|
//
|
|
// We should encounter this class GUID, but if we don't, then we
|
|
// want to maintain the old behavior of adding this in manually
|
|
// later on.
|
|
//
|
|
if(!ComputerClassFound && IsEqualGUID(pClassGuid, &GUID_DEVCLASS_COMPUTER)) {
|
|
ComputerClassFound = TRUE;
|
|
}
|
|
}
|
|
|
|
if(!ComputerClassFound) {
|
|
//
|
|
// Special Case for the Internal Class "Computer"
|
|
//
|
|
if(!(pci = (PCLASSICON)MyMalloc(sizeof(CLASSICON)))) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
leave;
|
|
}
|
|
|
|
pci->ClassGuid = &GUID_DEVCLASS_COMPUTER;
|
|
SelectObject(hMemImageDC, hbmMiniImage);
|
|
hOldBrush = SelectObject(hMemImageDC, GetSysColorBrush(COLOR_WINDOW));
|
|
PatBlt(hMemImageDC, 0, 0, cxMiniIcon, cyMiniIcon, PATCOPY);
|
|
SelectObject(hMemImageDC, hOldBrush);
|
|
|
|
SetupDiGetClassBitmapIndex((LPGUID)pci->ClassGuid, &MiniIconIndex);
|
|
|
|
SetupDiDrawMiniIcon(hMemImageDC,
|
|
rc,
|
|
MiniIconIndex,
|
|
DMI_USERECT);
|
|
|
|
SelectObject(hMemImageDC, hbmMiniMask);
|
|
SetupDiDrawMiniIcon(hMemImageDC,
|
|
rc,
|
|
MiniIconIndex,
|
|
DMI_MASK | DMI_USERECT);
|
|
|
|
//
|
|
// Deselect the bitmap from our DC BEFORE calling ImageList
|
|
// functions.
|
|
//
|
|
SelectObject(hMemImageDC, hbmOldImage);
|
|
|
|
pci->MiniBitmapIndex = ImageList_Add(ImageList, hbmMiniImage, hbmMiniMask);
|
|
|
|
if(pci->MiniBitmapIndex == (UINT)-1) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
MyFree(pci);
|
|
pci = NULL;
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Link it in.
|
|
//
|
|
pci->Next = ImageData->ClassIconList;
|
|
ImageData->ClassIconList = pci;
|
|
|
|
//
|
|
// Reset pci to NULL so we won't try to free it later.
|
|
//
|
|
pci = NULL;
|
|
}
|
|
|
|
//
|
|
// Add the Overlay ICONs.
|
|
//
|
|
for(iIcon = IDI_CLASSICON_OVERLAYFIRST;
|
|
iIcon <= IDI_CLASSICON_OVERLAYLAST;
|
|
iIcon++) {
|
|
|
|
Err = GLE_FN_CALL(NULL,
|
|
hIcon = LoadIcon(MyDllModuleHandle,
|
|
MAKEINTRESOURCE(iIcon))
|
|
);
|
|
|
|
if(Err != NO_ERROR) {
|
|
leave;
|
|
}
|
|
|
|
iIndex = ImageList_AddIcon(ImageList, hIcon);
|
|
|
|
if(iIndex == -1) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
leave;
|
|
}
|
|
|
|
if(!ImageList_SetOverlayImage(ImageList, iIndex, iIcon - IDI_CLASSICON_OVERLAYFIRST + 1)) {
|
|
Err = ERROR_INVALID_DATA;
|
|
leave;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we get to this point, then we've successfully constructed the entire
|
|
// image list, and associated CLASSICON nodes. Now, store this information
|
|
// in the caller's SP_CLASSIMAGELIST_DATA buffer.
|
|
//
|
|
ClassImageListData->Reserved = (ULONG_PTR)ImageData;
|
|
ClassImageListData->ImageList = ImageList;
|
|
|
|
} except(pSetupExceptionFilter(GetExceptionCode())) {
|
|
pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_USER_BUFFER, &Err);
|
|
}
|
|
|
|
if(hiLargeIcon) {
|
|
DestroyIcon(hiLargeIcon);
|
|
}
|
|
if(hiSmallIcon) {
|
|
DestroyIcon(hiSmallIcon);
|
|
}
|
|
if(pci) {
|
|
MyFree(pci);
|
|
}
|
|
if(hDC) {
|
|
ReleaseDC(HWND_DESKTOP, hDC);
|
|
}
|
|
if(hbmMiniImage) {
|
|
DeleteObject(hbmMiniImage);
|
|
}
|
|
if(hbmMiniMask) {
|
|
DeleteObject(hbmMiniMask);
|
|
}
|
|
if(hMemImageDC) {
|
|
DeleteDC(hMemImageDC);
|
|
}
|
|
|
|
if(Err != NO_ERROR) {
|
|
|
|
if(ImageData) {
|
|
if(DestroyLock) {
|
|
DestroySynchronizedAccess(&ImageData->Lock);
|
|
}
|
|
if(ImageData->ClassGuidList) {
|
|
MyFree(ImageData->ClassGuidList);
|
|
}
|
|
while(ImageData->ClassIconList) {
|
|
pci = ImageData->ClassIconList;
|
|
ImageData->ClassIconList = pci->Next;
|
|
MyFree(pci);
|
|
}
|
|
MyFree(ImageData);
|
|
}
|
|
|
|
if(ImageList) {
|
|
ImageList_Destroy(ImageList);
|
|
}
|
|
}
|
|
|
|
SetLastError(Err);
|
|
return (Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiDestroyClassImageList(
|
|
IN PSP_CLASSIMAGELIST_DATA ClassImageListData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine destroys a class image list built by a call to
|
|
SetupDiGetClassImageList.
|
|
|
|
Arguments:
|
|
|
|
ClassImageListData - Supplies the address of a SP_CLASSIMAGELIST_DATA
|
|
structure containing the class image list to be destroyed.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is TRUE.
|
|
|
|
If the function fails, the return value is FALSE. To get extended error
|
|
information, call GetLastError.
|
|
|
|
--*/
|
|
{
|
|
DWORD Err = NO_ERROR;
|
|
PCLASS_IMAGE_LIST ImageData = NULL;
|
|
PCLASSICON pci;
|
|
|
|
try {
|
|
|
|
if(ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA)) {
|
|
Err = ERROR_INVALID_USER_BUFFER;
|
|
leave;
|
|
}
|
|
|
|
if (ClassImageListData->Reserved == 0x0) {
|
|
Err = ERROR_INVALID_USER_BUFFER;
|
|
leave;
|
|
}
|
|
|
|
ImageData = (PCLASS_IMAGE_LIST)ClassImageListData->Reserved;
|
|
|
|
if (!LockImageList(ImageData)) {
|
|
Err = ERROR_CANT_LOAD_CLASS_ICON;
|
|
leave;
|
|
}
|
|
|
|
if (ClassImageListData->ImageList) {
|
|
ImageList_Destroy(ClassImageListData->ImageList);
|
|
}
|
|
|
|
if (ImageData->ClassGuidList) {
|
|
MyFree(ImageData->ClassGuidList);
|
|
}
|
|
|
|
while(ImageData->ClassIconList) {
|
|
pci = ImageData->ClassIconList;
|
|
ImageData->ClassIconList = pci->Next;
|
|
MyFree(pci);
|
|
}
|
|
|
|
DestroySynchronizedAccess(&ImageData->Lock);
|
|
MyFree(ImageData);
|
|
ClassImageListData->Reserved = 0;
|
|
|
|
} except(pSetupExceptionFilter(GetExceptionCode())) {
|
|
pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_USER_BUFFER, &Err);
|
|
}
|
|
|
|
SetLastError(Err);
|
|
return (Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetClassImageIndex(
|
|
IN PSP_CLASSIMAGELIST_DATA ClassImageListData,
|
|
IN CONST GUID *ClassGuid,
|
|
OUT PINT ImageIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves the index within the class image list of a specified
|
|
class.
|
|
|
|
Arguments:
|
|
|
|
ClassImageListData - Supplies the address of a SP_CLASSIMAGELIST_DATA
|
|
structure containing the specified class's image.
|
|
|
|
ClassGuid - Supplies the address of the GUID for the class whose index is
|
|
to be retrieved.
|
|
|
|
ImageIndex - Supplies the address of a variable that receives the index of
|
|
the specified class's image within the class image list.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is TRUE.
|
|
|
|
If the function fails, the return value is FALSE. To get extended error
|
|
information, call GetLastError.
|
|
|
|
--*/
|
|
{
|
|
DWORD Err = NO_ERROR;
|
|
BOOL bFound = FALSE, bLocked = FALSE;
|
|
PCLASS_IMAGE_LIST ImageData = NULL;
|
|
PCLASSICON pci;
|
|
|
|
try {
|
|
|
|
if(ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA)) {
|
|
Err = ERROR_INVALID_USER_BUFFER;
|
|
leave;
|
|
}
|
|
|
|
if(ClassImageListData->Reserved == 0x0) {
|
|
Err = ERROR_INVALID_USER_BUFFER;
|
|
leave;
|
|
}
|
|
|
|
ImageData = (PCLASS_IMAGE_LIST)ClassImageListData->Reserved;
|
|
|
|
if(!LockImageList(ImageData)) {
|
|
Err = ERROR_CANT_LOAD_CLASS_ICON;
|
|
leave;
|
|
}
|
|
bLocked = TRUE;
|
|
|
|
if(ClassGuid) {
|
|
//
|
|
// check the "new stuff" list to see if it's there
|
|
//
|
|
for(pci = ImageData->ClassIconList;
|
|
!bFound && pci;
|
|
pci = pci->Next) {
|
|
|
|
if(IsEqualGUID(pci->ClassGuid, ClassGuid)) {
|
|
*ImageIndex = pci->MiniBitmapIndex;
|
|
bFound = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// if no match was found, snag the "unknown" class
|
|
//
|
|
if(!bFound) {
|
|
*ImageIndex = ImageData->UnknownImageIndex;
|
|
}
|
|
|
|
} except(pSetupExceptionFilter(GetExceptionCode())) {
|
|
pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_USER_BUFFER, &Err);
|
|
}
|
|
|
|
if(bLocked) {
|
|
UnlockImageList(ImageData);
|
|
}
|
|
|
|
SetLastError(Err);
|
|
return (Err == NO_ERROR);
|
|
}
|
|
|