windows-nt/Source/XPSP1/NT/base/pnp/setupapi/devicon.c
2020-09-26 16:20:57 +08:00

1970 lines
56 KiB
C

/*++
Copyright (c) 1993-2000 Microsoft Corporation
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}
};
#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))
// This should removed when WINVER defined >= 0x0500 for this project.
#ifndef NOMIRRORBITMAP
#ifdef UNICODE
#define NOMIRRORBITMAP (DWORD)0x80000000 /* Do not Mirror the bitmap in this call */
#else
#define NOMIRRORBITMAP (DWORD)0x0
#endif //UNICODE
#endif
//
// 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.
--*/
{
HBITMAP hbmOld;
DWORD rgbBk, rgbText;
INT ret = 0;
if(!LockMiniIconList(&GlobalMiniIconList)) {
return 0;
}
CreateMiniIcons();
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)))
);
}
rgbText = SetTextColor(hdc, RGB_BLACK);
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
);
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
);
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
);
}
}
SetBkColor(hdc, rgbBk);
SetTextColor(hdc, rgbText);
SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
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
}
}
UnlockMiniIconList(&GlobalMiniIconList);
return ret;
}
BOOL
WINAPI
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.
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.
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 INSTALLER value first and ENUMPROPPAGES 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;
BOOL bDestroyLargeIcon = FALSE, bDestroySmallIcon = FALSE;
TCHAR TempString[MAX_PATH];
TCHAR FullPath[MAX_PATH];
UINT IconsExtracted;
if(!LockMiniIconList(&GlobalMiniIconList)) {
SetLastError(ERROR_CANT_LOAD_CLASS_ICON);
return FALSE;
}
try {
if(MiniIconIndex) {
*MiniIconIndex = -1;
}
if((hk = SetupDiOpenClassRegKey(ClassGuid, KEY_READ)) == INVALID_HANDLE_VALUE) {
goto clean0;
}
StringSize = sizeof(TempString);
Err = RegQueryValueEx(hk,
pszInsIcon,
NULL,
&RegDataType,
(PBYTE)TempString,
&StringSize
);
if((Err == ERROR_SUCCESS) && (RegDataType == REG_SZ) && (StringSize > sizeof(TCHAR))) {
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 clean1;
}
} 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
//
if(LargeIcon) {
hRetLargeIcon = LoadIcon(MyDllModuleHandle,
MAKEINTRESOURCE(ClassIconIndexNeg)
);
}
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,
MINIX,
MINIY,
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.
//
lstrcpyn(FullPath, SystemDirectory, MAX_PATH);
StringSize = sizeof(TempString);
Err = RegQueryValueEx(hk,
pszInstaller32,
NULL,
&RegDataType,
(PBYTE)TempString,
&StringSize
);
if((Err != ERROR_SUCCESS) || (RegDataType != REG_SZ) ||
(StringSize < sizeof(TCHAR))) {
StringSize = sizeof(TempString);
Err = RegQueryValueEx(hk,
pszEnumPropPages32,
NULL,
&RegDataType,
(PBYTE)TempString,
&StringSize
);
if((Err != ERROR_SUCCESS) || (RegDataType != REG_SZ) ||
(StringSize < sizeof(TCHAR))) {
goto clean1;
}
}
//
// Remove function name, if present, from installer name.
//
for(EndPtr = TempString + ((StringSize / sizeof(TCHAR)) - 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('\"')) {
break;
}
}
pSetupConcatenatePaths(FullPath, TempString, MAX_PATH, NULL);
IconsExtracted = ExtractIconEx(FullPath,
-ClassIconIndex,
LargeIcon ? &hRetLargeIcon : NULL,
(bGetMini || SmallIcon) ? &hRetSmallIcon : NULL,
1
);
if((IconsExtracted != (UINT)-1) && (IconsExtracted > 0)) {
if(hRetLargeIcon) {
bDestroyLargeIcon = TRUE;
}
if(hRetSmallIcon) {
*MiniIconIndex = NewMiniIcon(ClassGuid, hRetSmallIcon);
bDestroySmallIcon = TRUE;
}
}
}
clean1:
RegCloseKey(hk);
hk = INVALID_HANDLE_VALUE;
clean0:
//
// 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.
//
if(!(hRetLargeIcon = LoadIcon(MyDllModuleHandle, MAKEINTRESOURCE(ICON_DEFAULT)))) {
Err = GetLastError();
}
}
if (SmallIcon && !hRetSmallIcon) {
//
// We didn't retrieve a small icon, so use a default.
//
if (!(hRetSmallIcon = LoadImage(MyDllModuleHandle,
MAKEINTRESOURCE(ICON_DEFAULT),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
0
))) {
Err = GetLastError();
}
}
if(Err == NO_ERROR) {
if(LargeIcon) {
*LargeIcon = hRetLargeIcon;
}
if (SmallIcon) {
*SmallIcon = hRetSmallIcon;
}
if(MiniIconIndex && (*MiniIconIndex == -1)) {
SetupDiGetClassBitmapIndex(NULL, MiniIconIndex);
}
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
if(hk != INVALID_HANDLE_VALUE) {
RegCloseKey(hk);
}
}
if(Err != NO_ERROR) {
if (bDestroyLargeIcon) {
DestroyIcon(hRetLargeIcon);
}
if (bDestroySmallIcon) {
DestroyIcon(hRetSmallIcon);
}
}
UnlockMiniIconList(&GlobalMiniIconList);
SetLastError(Err);
return (Err == NO_ERROR);
}
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.
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 INSTALLER value first and ENUMPROPPAGES value second
to determine what executable to extract the icon(s) from.
--*/
{
return (pSetupDiLoadClassIcon(ClassGuid,
LargeIcon,
NULL,
MiniIconIndex
));
}
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;
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)) {
for(pci = GlobalMiniIconList.ClassIconList;
!bRet && pci;
pci = pci->Next) {
if(IsEqualGUID(pci->ClassGuid, ClassGuid)) {
*MiniIconIndex = pci->MiniBitmapIndex;
bRet = TRUE;
}
}
UnlockMiniIconList(&GlobalMiniIconList);
}
}
//
// If no match was found, snag the "unknown" class.
//
if(!bRet) {
*MiniIconIndex = UnknownClassMiniIconIndex;
Err = ERROR_NO_DEVICE_ICON;
} else {
Err = NO_ERROR;
}
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, hdcMem;
HBITMAP hbmOld;
BITMAP bm;
BOOL bRet = FALSE; // assume failure
if(GlobalMiniIconList.hdcMiniMem) {
//
// Then the mini-icon list has already been built, so
// return success.
//
return TRUE;
}
hdc = GetDC(NULL);
if (!hdc) {
goto clean0;
}
GlobalMiniIconList.hdcMiniMem = CreateCompatibleDC(hdc);
ReleaseDC(NULL, hdc);
if(!GlobalMiniIconList.hdcMiniMem) {
goto clean0;
}
if(!(hdcMem = CreateCompatibleDC(GlobalMiniIconList.hdcMiniMem))) {
goto clean0;
}
if(!(GlobalMiniIconList.hbmMiniImage = LoadBitmap(MyDllModuleHandle,
MAKEINTRESOURCE(BMP_DRIVERTYPES)))) {
goto clean1;
}
GetObject(GlobalMiniIconList.hbmMiniImage, sizeof(bm), &bm);
if(!(GlobalMiniIconList.hbmMiniMask = CreateBitmap(bm.bmWidth,
bm.bmHeight,
1,
1,
NULL))) {
goto clean1;
}
hbmOld = SelectObject(hdcMem, GlobalMiniIconList.hbmMiniImage);
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;
SelectObject(hdcMem, hbmOld);
clean1:
DeleteObject(hdcMem);
clean0:
//
// 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(EXCEPTION_EXECUTE_HANDLER) {
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, hbmNewMask, hbmOld;
HDC hdcMem;
BITMAP bm;
INT iIcon = -1; // assume failure
if(!CreateMiniIcons()) {
goto AddIcon_Exit;
}
MYASSERT(GlobalMiniIconList.hdcMiniMem);
if(!(hdcMem = CreateCompatibleDC(GlobalMiniIconList.hdcMiniMem))) {
goto AddIcon_Exit;
}
//
// Create a New global Bitmap for the minis
//
hbmOld = SelectObject(GlobalMiniIconList.hdcMiniMem,
GlobalMiniIconList.hbmMiniImage
);
if(!(hbmNewImage = CreateCompatibleBitmap(GlobalMiniIconList.hdcMiniMem,
MINIX * (GlobalMiniIconList.NumClassImages + 1),
MINIY))) {
goto AddIcon_Exit1;
}
//
// 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);
DeleteObject(GlobalMiniIconList.hbmMiniImage);
GlobalMiniIconList.hbmMiniImage = hbmNewImage;
//
// Next, copy the mask.
//
hbmOld = SelectObject(GlobalMiniIconList.hdcMiniMem,
GlobalMiniIconList.hbmMiniMask
);
if(!(hbmNewMask = CreateBitmap(MINIX * (GlobalMiniIconList.NumClassImages + 1),
MINIY,
1,
1,
NULL))) {
goto AddIcon_Exit1;
}
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);
DeleteObject(GlobalMiniIconList.hbmMiniMask);
GlobalMiniIconList.hbmMiniMask = hbmNewMask;
iIcon = GlobalMiniIconList.NumClassImages;
GlobalMiniIconList.NumClassImages++; // one more image on the table
AddIcon_Exit1:
DeleteDC(hdcMem);
AddIcon_Exit:
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.
--*/
{
return SetupDiGetClassImageListEx(ClassImageListData, NULL, NULL);
}
#ifdef UNICODE
//
// ANSI version
//
BOOL
WINAPI
SetupDiGetClassImageListExA(
OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
IN PCSTR MachineName, OPTIONAL
IN PVOID Reserved
)
{
PCWSTR UnicodeMachineName;
DWORD rc;
BOOL b;
b = FALSE;
if(MachineName) {
rc = pSetupCaptureAndConvertAnsiArg(MachineName, &UnicodeMachineName);
} else {
UnicodeMachineName = NULL;
rc = NO_ERROR;
}
if(rc == NO_ERROR) {
b = SetupDiGetClassImageListExW(ClassImageListData, UnicodeMachineName, Reserved);
rc = GetLastError();
if(UnicodeMachineName) {
MyFree(UnicodeMachineName);
}
}
SetLastError(rc);
return b;
}
#else
//
// Unicode version
//
BOOL
WINAPI
SetupDiGetClassImageListExW(
OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
IN PCWSTR MachineName, OPTIONAL
IN PVOID Reserved
)
{
UNREFERENCED_PARAMETER(ClassImageListData);
UNREFERENCED_PARAMETER(MachineName);
UNREFERENCED_PARAMETER(Reserved);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(FALSE);
}
#endif
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 = NULL;
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;
goto clean0;
}
//
// 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;
goto clean0;
}
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;
}
#ifdef UNICODE
//
// 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;
}
#endif
if(!(ImageList = ImageList_Create(cxMiniIcon,
cyMiniIcon,
ImageListFlags,
1,
1)))
{
Err = ERROR_NOT_ENOUGH_MEMORY;
goto clean0;
}
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;
goto clean0;
}
//
// 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;
goto clean0;
}
//
// 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;
ImageData->ClassGuidList = (LPGUID)MyMalloc(sizeof(GUID) * GuidCount);
if (!SetupDiBuildClassInfoListEx(0,
ImageData->ClassGuidList,
GuidCount,
&GuidCount,
MachineName,
NULL)) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
//
// Realloc buffer and try again.
//
MyFree(ImageData->ClassGuidList);
if(!(ImageData->ClassGuidList = MyMalloc(sizeof(GUID) * GuidCount))) {
Err = ERROR_NOT_ENOUGH_MEMORY;
goto clean0;
}
if (!SetupDiBuildClassInfoListEx(0,
ImageData->ClassGuidList,
GuidCount,
&GuidCount,
MachineName,
NULL)) {
Err = GetLastError();
goto clean0;
}
} else {
Err = GetLastError();
goto clean0;
}
}
//
// Retrieve the icon for each class in the class list.
//
for (pClassGuid = ImageData->ClassGuidList, i = 0;
i < GuidCount;
pClassGuid++, i++) {
if (!pSetupDiLoadClassIcon(pClassGuid,
&hiLargeIcon,
&hiSmallIcon,
&MiniIconIndex)) {
Err = GetLastError();
goto clean0;
}
//
// 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;
goto clean0;
}
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;
goto clean0;
}
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;
goto clean0;
}
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;
goto clean0;
}
//
// 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) {
if(!(hIcon = LoadIcon(MyDllModuleHandle, MAKEINTRESOURCE(iIcon)))) {
Err = GetLastError();
goto clean0;
}
iIndex = ImageList_AddIcon(ImageList, hIcon);
if(iIndex == -1) {
Err = ERROR_NOT_ENOUGH_MEMORY;
goto clean0;
}
if(!ImageList_SetOverlayImage(ImageList, iIndex, iIcon - IDI_CLASSICON_OVERLAYFIRST + 1)) {
Err = ERROR_INVALID_DATA;
goto clean0;
}
}
//
// 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;
clean0: ; // nothing to do.
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_USER_BUFFER;
if(hDC) {
ReleaseDC(HWND_DESKTOP, hDC);
}
if(pci) {
MyFree(pci);
}
//
// Reference the following variables so the compiler will respect statement
// ordering w.r.t. assignment.
//
ImageData = ImageData;
DestroyLock = DestroyLock;
ImageList = ImageList;
}
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;
goto clean0;
}
if (ClassImageListData->Reserved == 0x0) {
Err = ERROR_INVALID_USER_BUFFER;
goto clean0;
}
ImageData = (PCLASS_IMAGE_LIST)ClassImageListData->Reserved;
if (!LockImageList(ImageData)) {
Err = ERROR_CANT_LOAD_CLASS_ICON;
goto clean0;
}
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;
clean0: ; // nothing to do.
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_USER_BUFFER;
}
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;
goto clean0;
}
if (ClassImageListData->Reserved == 0x0) {
Err = ERROR_INVALID_USER_BUFFER;
goto clean0;
}
ImageData = (PCLASS_IMAGE_LIST)ClassImageListData->Reserved;
if (!LockImageList(ImageData)) {
Err = ERROR_CANT_LOAD_CLASS_ICON;
goto clean0;
}
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;
}
clean0: ; // nothing to do.
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_USER_BUFFER;
}
if (bLocked && ImageData) {
UnlockImageList(ImageData);
}
SetLastError(Err);
return (Err == NO_ERROR);
}