Source code of Windows XP (NT5)
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.

1969 lines
56 KiB

  1. /*++
  2. Copyright (c) 1993-2000 Microsoft Corporation
  3. Module Name:
  4. devicon.c
  5. Abstract:
  6. Device Installer routines dealing with retrieval/display of icons.
  7. Author:
  8. Lonny McMichael (lonnym) 28-Aug--1995
  9. Notes:
  10. You must include "basetyps.h" first.
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include <shellapi.h>
  15. MINI_ICON_LIST GlobalMiniIconList;
  16. /*++
  17. Class-to-Icon conversion tables exist in two places. First, there
  18. is the built-in one defined below that is based on a hard-wired
  19. bitmap in the resource. The second is a linked list of CLASSICON
  20. structures that is created every time a new class with an icon
  21. comes along.
  22. Check out resource\ilwinmsd.bmp to see the mini-icons. The icons
  23. are referenced via their (zero-based) index (e.g., computer is 0,
  24. chip is 1, display is 2, etc.). Today, the bitmap indexes look as follows:
  25. 0 - computer
  26. 1 - chip
  27. 2 - display
  28. 3 - network
  29. 4 - windows
  30. 5 - mouse
  31. 6 - keyboard
  32. 7 - phone
  33. 8 - sound
  34. 9 - drives
  35. 10 - plugs
  36. 11 - generic
  37. 12 - check
  38. 13 - uncheck
  39. 14 - printer
  40. 15 - nettrans
  41. 16 - netclient
  42. 17 - netservice
  43. 18 - unknown
  44. 19 - Fax machine
  45. 20 - greyed check
  46. 21 - dial up networking
  47. 22 - direct cable connection
  48. 23 - briefcase (filesync)
  49. 24 - Exchange
  50. 25 - partial check
  51. 26 - Generic folder / Accessories
  52. 27 - media (music)
  53. 28 - Quick View
  54. 29 - old MSN
  55. 30 - calculator
  56. 31 - FAT32 Converter
  57. 32 - Document Templates
  58. 33 - disk compression
  59. 34 - Games
  60. 35 - HyperTerminal
  61. 36 - package
  62. 37 - mspaint
  63. 38 - Screensavers
  64. 39 - WordPad
  65. 40 - Clipboard Viewer
  66. 41 - Accessibility Options
  67. 42 - backup
  68. 43 - Desktop Wallpaper
  69. 44 - Character Map
  70. 45 - Mouse Pointers
  71. 46 - Net Watcher
  72. 47 - phone dialer
  73. 48 - resource monitor
  74. 49 - Online User's Guide
  75. 50 - Multilanguage Support
  76. 51 - Audio Compression
  77. 52 - CD player
  78. 53 - Media Player
  79. 54 - WAV sounds
  80. 55 - Sample Sounds
  81. 56 - Video Compression
  82. 57 - Volume Control
  83. 58 - Musica sound scheme
  84. 59 - Jungle sound scheme
  85. 60 - Robotz sound scheme
  86. 61 - Utopia sound scheme
  87. 62 - Eudcedit
  88. 63 - Minesweeper
  89. 64 - Pinball
  90. 65 - Imaging
  91. 66 - Clock
  92. 67 - Infrared
  93. 68 - MS Wallet
  94. 69 - FrontPage Express (aka FrontPad)
  95. 70 - MS Agent
  96. 71 - Internet Tools
  97. 72 - NetShow Player
  98. 73 - Net Meeting
  99. 74 - DVD Player
  100. 75 - Freecell
  101. 76 - Athena / Outlook Express / Internet Mail and News
  102. 77 - Desktop Themes
  103. 78 - Baseball theme
  104. 79 - Dangerous Creatures theme
  105. 80 - Inside your Computer theme
  106. 81 - Jungle theme
  107. 82 - Leonardo da Vinci theme
  108. 83 - More Windows theme
  109. 84 - Mystery theme
  110. 85 - Nature theme
  111. 86 - Science theme
  112. 87 - Space theme
  113. 88 - Sports theme
  114. 89 - The 60's USA theme
  115. 90 - The Golden Era theme
  116. 91 - Travel theme
  117. 92 - Underwater theme
  118. 93 - Windows 95 theme
  119. 94 - Personal Web Server
  120. 95 - Real Audio
  121. 96 - Web Publisher / WebPost
  122. 97 - WaveTop
  123. 98 - WebTV
  124. --*/
  125. CONST INT UnknownClassMiniIconIndex = 11;
  126. CONST CLASSICON MiniIconXlate[] = { {&GUID_DEVCLASS_COMPUTER, 0, NULL},
  127. {&GUID_DEVCLASS_DISPLAY, 2, NULL},
  128. {&GUID_DEVCLASS_MOUSE, 5, NULL},
  129. {&GUID_DEVCLASS_KEYBOARD, 6, NULL},
  130. {&GUID_DEVCLASS_FDC, 9, NULL},
  131. {&GUID_DEVCLASS_HDC, 9, NULL},
  132. {&GUID_DEVCLASS_PORTS, 10, NULL},
  133. {&GUID_DEVCLASS_NET, 15, NULL},
  134. {&GUID_DEVCLASS_SYSTEM, 0, NULL},
  135. {&GUID_DEVCLASS_SOUND, 8, NULL},
  136. {&GUID_DEVCLASS_PRINTER, 14, NULL},
  137. {&GUID_DEVCLASS_MONITOR, 2, NULL},
  138. {&GUID_DEVCLASS_NETTRANS, 3, NULL},
  139. {&GUID_DEVCLASS_NETCLIENT, 16, NULL},
  140. {&GUID_DEVCLASS_NETSERVICE, 17, NULL},
  141. {&GUID_DEVCLASS_UNKNOWN, 18, NULL},
  142. {&GUID_DEVCLASS_LEGACYDRIVER, 11, NULL},
  143. {&GUID_DEVCLASS_MTD, 9, NULL}
  144. };
  145. #define MINIX 16
  146. #define MINIY 16
  147. #define RGB_WHITE (RGB(255, 255, 255))
  148. #define RGB_BLACK (RGB(0, 0, 0))
  149. #define RGB_TRANSPARENT (RGB(0, 128, 128))
  150. // This should removed when WINVER defined >= 0x0500 for this project.
  151. #ifndef NOMIRRORBITMAP
  152. #ifdef UNICODE
  153. #define NOMIRRORBITMAP (DWORD)0x80000000 /* Do not Mirror the bitmap in this call */
  154. #else
  155. #define NOMIRRORBITMAP (DWORD)0x0
  156. #endif //UNICODE
  157. #endif
  158. //
  159. // Private function prototypes.
  160. //
  161. INT
  162. NewMiniIcon(
  163. IN CONST GUID *ClassGuid,
  164. IN HICON hIcon OPTIONAL
  165. );
  166. INT
  167. WINAPI
  168. SetupDiDrawMiniIcon(
  169. IN HDC hdc,
  170. IN RECT rc,
  171. IN INT MiniIconIndex,
  172. IN DWORD Flags
  173. )
  174. /*++
  175. Routine Description:
  176. This routine draws the specified mini-icon at the requested location.
  177. Arguments:
  178. hdc - Supplies the handle of the device context in which the mini-icon
  179. will be drawn.
  180. rc - Supplies the rectangle in the specified HDC to draw the icon in.
  181. MiniIconIndex - The index of the mini-icon, as retrieved from
  182. SetupDiLoadClassIcon or SetupDiGetClassBitmapIndex. The following are
  183. pre-defined indices that may be used.
  184. 0 Computer
  185. 2 display
  186. 5 mouse
  187. 6 keyboard
  188. 9 fdc
  189. 9 hdc
  190. 10 ports
  191. 15 net
  192. 0 system
  193. 8 sound
  194. 14 printer
  195. 2 monitor
  196. 3 nettrans
  197. 16 netclient
  198. 17 netservice
  199. 18 unknown
  200. Flags - Controls the drawing operation. The LOWORD contains the actual flags
  201. defined as follows:
  202. DMI_MASK - Draw the mini-icon's mask into HDC.
  203. DMI_BKCOLOR - Use the system color index specified in the HIWORD of Flags
  204. as the background color. If not specified, COLOR_WINDOW is used.
  205. DMI_USERECT - If set, SetupDiDrawMiniIcon will use the supplied rect,
  206. stretching the icon to fit as appropriate.
  207. Return Value:
  208. This function returns the offset from the left of rc where the string should
  209. start.
  210. Remarks:
  211. By default, the icon will be centered vertically and butted against the left
  212. corner of the specified rectangle.
  213. --*/
  214. {
  215. HBITMAP hbmOld;
  216. DWORD rgbBk, rgbText;
  217. INT ret = 0;
  218. if(!LockMiniIconList(&GlobalMiniIconList)) {
  219. return 0;
  220. }
  221. CreateMiniIcons();
  222. if(GlobalMiniIconList.hbmMiniImage) {
  223. //
  224. // Set the Foreground and background color for the
  225. // conversion of the Mono Mask image
  226. //
  227. if(Flags & DMI_MASK) {
  228. rgbBk = SetBkColor(hdc, RGB_WHITE);
  229. } else {
  230. rgbBk = SetBkColor(hdc,
  231. GetSysColor(((int)(Flags & DMI_BKCOLOR
  232. ? HIWORD(Flags)
  233. : COLOR_WINDOW)))
  234. );
  235. }
  236. rgbText = SetTextColor(hdc, RGB_BLACK);
  237. if(Flags & DMI_USERECT) {
  238. //
  239. // Copy the converted mask into the dest. The transparent
  240. // areas will be drawn with the current window color.
  241. //
  242. hbmOld = SelectObject(GlobalMiniIconList.hdcMiniMem,
  243. GlobalMiniIconList.hbmMiniMask
  244. );
  245. StretchBlt(hdc,
  246. rc.left,
  247. rc.top,
  248. rc.right - rc.left,
  249. rc.bottom - rc.top,
  250. GlobalMiniIconList.hdcMiniMem,
  251. MINIX * MiniIconIndex,
  252. 0,
  253. MINIX,
  254. MINIY,
  255. SRCCOPY | NOMIRRORBITMAP);
  256. if(!(Flags & DMI_MASK)) {
  257. //
  258. // OR the image into the dest
  259. //
  260. SelectObject(GlobalMiniIconList.hdcMiniMem,
  261. GlobalMiniIconList.hbmMiniImage
  262. );
  263. StretchBlt(hdc,
  264. rc.left,
  265. rc.top,
  266. rc.right - rc.left,
  267. rc.bottom - rc.top,
  268. GlobalMiniIconList.hdcMiniMem,
  269. MINIX * MiniIconIndex,
  270. 0,
  271. MINIX,
  272. MINIY,
  273. SRCPAINT | NOMIRRORBITMAP);
  274. }
  275. } else {
  276. //
  277. // Copy the converted mask into the dest. The transparent
  278. // areas will be drawn with the current window color.
  279. //
  280. hbmOld = SelectObject(GlobalMiniIconList.hdcMiniMem,
  281. GlobalMiniIconList.hbmMiniMask
  282. );
  283. BitBlt(hdc,
  284. rc.left,
  285. rc.top + (rc.bottom - rc.top - MINIY)/2,
  286. MINIX,
  287. MINIY,
  288. GlobalMiniIconList.hdcMiniMem,
  289. MINIX * MiniIconIndex,
  290. 0,
  291. SRCCOPY | NOMIRRORBITMAP
  292. );
  293. if(!(Flags & DMI_MASK)) {
  294. //
  295. // OR the image into the dest
  296. //
  297. SelectObject(GlobalMiniIconList.hdcMiniMem,
  298. GlobalMiniIconList.hbmMiniImage
  299. );
  300. BitBlt(hdc,
  301. rc.left,
  302. rc.top + (rc.bottom - rc.top - MINIY)/2,
  303. MINIX,
  304. MINIY,
  305. GlobalMiniIconList.hdcMiniMem,
  306. MINIX * MiniIconIndex,
  307. 0,
  308. SRCPAINT | NOMIRRORBITMAP
  309. );
  310. }
  311. }
  312. SetBkColor(hdc, rgbBk);
  313. SetTextColor(hdc, rgbText);
  314. SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
  315. if(Flags & DMI_USERECT) {
  316. ret = rc.right - rc.left + 2; // offset to string from left edge
  317. } else {
  318. ret = MINIX + 2; // offset to string from left edge
  319. }
  320. }
  321. UnlockMiniIconList(&GlobalMiniIconList);
  322. return ret;
  323. }
  324. BOOL
  325. WINAPI
  326. pSetupDiLoadClassIcon(
  327. IN CONST GUID *ClassGuid,
  328. OUT HICON *LargeIcon, OPTIONAL
  329. OUT HICON *SmallIcon, OPTIONAL
  330. OUT LPINT MiniIconIndex OPTIONAL
  331. )
  332. /*++
  333. Routine Description:
  334. This routine loads both the large and mini-icons for the specified class
  335. Arguments:
  336. ClassGuid - Supplies the GUID of the class for which the icon(s) should
  337. be loaded.
  338. LargeIcon - Optionally, supplies a pointer to a variable that will receive
  339. a handle to the loaded large icon for the specified class. If this
  340. parameter is not specified, the large icon will not be loaded.
  341. SmallIcon - Optionally, supplies a pointer to a variable that will receive
  342. a handle to the loaded small icon for the specified class. If this
  343. parameter is not specified, the small icon will not be loaded.
  344. MiniIconIndex - Optionally, supplies a pointer to a variable that will
  345. receive the index of the mini-icon for the specified class. The
  346. mini-icon is stored in the device installer's mini-icon cache.
  347. Return Value:
  348. If the function succeeds, the return value is TRUE.
  349. If the function fails, the return value is FALSE. To get extended error
  350. information, call GetLastError.
  351. Remarks:
  352. The icons of the class are either pre-defined, and loaded from the device
  353. installer's internal cache, or they are loaded directly from the class
  354. installer's executable. This function will query the registry value ICON in
  355. the specified class's section. If this value is specified then it indicates
  356. what mini icon to load. If the icon value is negative the absolute value
  357. represents a predefined icon. See SetupDiDrawMiniIcon for a list of pre-defined
  358. mini icons. If the icon value is positive it represents an icon in the class
  359. installer's executable, and will be extracted (the number one is reserved).
  360. This function also uses the INSTALLER value first and ENUMPROPPAGES value second
  361. to determine what executable to extract the icon(s) from.
  362. --*/
  363. {
  364. HKEY hk = INVALID_HANDLE_VALUE;
  365. DWORD Err;
  366. HICON hRetLargeIcon = NULL;
  367. HICON hRetSmallIcon = NULL;
  368. INT ClassIconIndex;
  369. DWORD RegDataType, StringSize;
  370. PTSTR EndPtr;
  371. BOOL bGetMini = FALSE;
  372. BOOL bDestroyLargeIcon = FALSE, bDestroySmallIcon = FALSE;
  373. TCHAR TempString[MAX_PATH];
  374. TCHAR FullPath[MAX_PATH];
  375. UINT IconsExtracted;
  376. if(!LockMiniIconList(&GlobalMiniIconList)) {
  377. SetLastError(ERROR_CANT_LOAD_CLASS_ICON);
  378. return FALSE;
  379. }
  380. try {
  381. if(MiniIconIndex) {
  382. *MiniIconIndex = -1;
  383. }
  384. if((hk = SetupDiOpenClassRegKey(ClassGuid, KEY_READ)) == INVALID_HANDLE_VALUE) {
  385. goto clean0;
  386. }
  387. StringSize = sizeof(TempString);
  388. Err = RegQueryValueEx(hk,
  389. pszInsIcon,
  390. NULL,
  391. &RegDataType,
  392. (PBYTE)TempString,
  393. &StringSize
  394. );
  395. if((Err == ERROR_SUCCESS) && (RegDataType == REG_SZ) && (StringSize > sizeof(TCHAR))) {
  396. if((ClassIconIndex = _tcstol(TempString, &EndPtr, 10)) == 1) {
  397. //
  398. // Positive values indicate that we should access an icon
  399. // directly using its ID. Since ExtractIconEx uses negative
  400. // values to indicate these IDs, and since the value -1 has
  401. // a special meaning to that API, we must disallow a ClassIconIndex
  402. // of +1.
  403. //
  404. goto clean1;
  405. }
  406. } else {
  407. //
  408. // Icon index not specified, so assume index is 0.
  409. //
  410. ClassIconIndex = 0;
  411. }
  412. if(MiniIconIndex) {
  413. //
  414. // If mini-icon is already around, then we're done with it.
  415. //
  416. if(!SetupDiGetClassBitmapIndex(ClassGuid, MiniIconIndex)) {
  417. //
  418. // mini-icon not around--set flag to show we didn't get it.
  419. //
  420. bGetMini = TRUE;
  421. }
  422. }
  423. if(ClassIconIndex < 0) {
  424. INT ClassIconIndexNeg = -ClassIconIndex;
  425. //
  426. // Icon index is negative. This means that this class is one
  427. // of our special classes with icons in setupapi.dll
  428. //
  429. if(LargeIcon) {
  430. hRetLargeIcon = LoadIcon(MyDllModuleHandle,
  431. MAKEINTRESOURCE(ClassIconIndexNeg)
  432. );
  433. }
  434. if(bGetMini || SmallIcon) {
  435. //
  436. // Retrieve the small icon as well. If the resource doesn't
  437. // have a small icon then the big one will get smushed, but it's
  438. // better than getting the default icon.
  439. //
  440. hRetSmallIcon = LoadImage(MyDllModuleHandle,
  441. MAKEINTRESOURCE(ClassIconIndexNeg),
  442. IMAGE_ICON,
  443. MINIX,
  444. MINIY,
  445. 0
  446. );
  447. if(hRetSmallIcon && bGetMini) {
  448. *MiniIconIndex = NewMiniIcon(ClassGuid, hRetSmallIcon);
  449. }
  450. }
  451. } else if(bGetMini || LargeIcon || SmallIcon) {
  452. //
  453. // Look for the binary containing the icon(s) first in the
  454. // "Installer32" entry, and if not found, then in the "EnumPropPages32"
  455. // entry.
  456. //
  457. lstrcpyn(FullPath, SystemDirectory, MAX_PATH);
  458. StringSize = sizeof(TempString);
  459. Err = RegQueryValueEx(hk,
  460. pszInstaller32,
  461. NULL,
  462. &RegDataType,
  463. (PBYTE)TempString,
  464. &StringSize
  465. );
  466. if((Err != ERROR_SUCCESS) || (RegDataType != REG_SZ) ||
  467. (StringSize < sizeof(TCHAR))) {
  468. StringSize = sizeof(TempString);
  469. Err = RegQueryValueEx(hk,
  470. pszEnumPropPages32,
  471. NULL,
  472. &RegDataType,
  473. (PBYTE)TempString,
  474. &StringSize
  475. );
  476. if((Err != ERROR_SUCCESS) || (RegDataType != REG_SZ) ||
  477. (StringSize < sizeof(TCHAR))) {
  478. goto clean1;
  479. }
  480. }
  481. //
  482. // Remove function name, if present, from installer name.
  483. //
  484. for(EndPtr = TempString + ((StringSize / sizeof(TCHAR)) - 1);
  485. EndPtr >= TempString;
  486. EndPtr--) {
  487. if(*EndPtr == TEXT(',')) {
  488. *EndPtr = TEXT('\0');
  489. break;
  490. }
  491. //
  492. // If we hit a double-quote mark, we terminate the search.
  493. //
  494. if(*EndPtr == TEXT('\"')) {
  495. break;
  496. }
  497. }
  498. pSetupConcatenatePaths(FullPath, TempString, MAX_PATH, NULL);
  499. IconsExtracted = ExtractIconEx(FullPath,
  500. -ClassIconIndex,
  501. LargeIcon ? &hRetLargeIcon : NULL,
  502. (bGetMini || SmallIcon) ? &hRetSmallIcon : NULL,
  503. 1
  504. );
  505. if((IconsExtracted != (UINT)-1) && (IconsExtracted > 0)) {
  506. if(hRetLargeIcon) {
  507. bDestroyLargeIcon = TRUE;
  508. }
  509. if(hRetSmallIcon) {
  510. *MiniIconIndex = NewMiniIcon(ClassGuid, hRetSmallIcon);
  511. bDestroySmallIcon = TRUE;
  512. }
  513. }
  514. }
  515. clean1:
  516. RegCloseKey(hk);
  517. hk = INVALID_HANDLE_VALUE;
  518. clean0:
  519. //
  520. // Assume success, unless we hit some really big problem below.
  521. //
  522. Err = NO_ERROR;
  523. if(LargeIcon && !hRetLargeIcon) {
  524. //
  525. // We didn't retrieve a large icon, so use a default.
  526. //
  527. if(!(hRetLargeIcon = LoadIcon(MyDllModuleHandle, MAKEINTRESOURCE(ICON_DEFAULT)))) {
  528. Err = GetLastError();
  529. }
  530. }
  531. if (SmallIcon && !hRetSmallIcon) {
  532. //
  533. // We didn't retrieve a small icon, so use a default.
  534. //
  535. if (!(hRetSmallIcon = LoadImage(MyDllModuleHandle,
  536. MAKEINTRESOURCE(ICON_DEFAULT),
  537. IMAGE_ICON,
  538. GetSystemMetrics(SM_CXSMICON),
  539. GetSystemMetrics(SM_CYSMICON),
  540. 0
  541. ))) {
  542. Err = GetLastError();
  543. }
  544. }
  545. if(Err == NO_ERROR) {
  546. if(LargeIcon) {
  547. *LargeIcon = hRetLargeIcon;
  548. }
  549. if (SmallIcon) {
  550. *SmallIcon = hRetSmallIcon;
  551. }
  552. if(MiniIconIndex && (*MiniIconIndex == -1)) {
  553. SetupDiGetClassBitmapIndex(NULL, MiniIconIndex);
  554. }
  555. }
  556. } except(EXCEPTION_EXECUTE_HANDLER) {
  557. Err = ERROR_INVALID_PARAMETER;
  558. if(hk != INVALID_HANDLE_VALUE) {
  559. RegCloseKey(hk);
  560. }
  561. }
  562. if(Err != NO_ERROR) {
  563. if (bDestroyLargeIcon) {
  564. DestroyIcon(hRetLargeIcon);
  565. }
  566. if (bDestroySmallIcon) {
  567. DestroyIcon(hRetSmallIcon);
  568. }
  569. }
  570. UnlockMiniIconList(&GlobalMiniIconList);
  571. SetLastError(Err);
  572. return (Err == NO_ERROR);
  573. }
  574. BOOL
  575. WINAPI
  576. SetupDiLoadClassIcon(
  577. IN CONST GUID *ClassGuid,
  578. OUT HICON *LargeIcon, OPTIONAL
  579. OUT LPINT MiniIconIndex OPTIONAL
  580. )
  581. /*++
  582. Routine Description:
  583. This routine loads both the large and mini-icons for the specified class
  584. Arguments:
  585. ClassGuid - Supplies the GUID of the class for which the icon(s) should
  586. be loaded.
  587. LargeIcon - Optionally, supplies a pointer to a variable that will receive
  588. a handle to the loaded large icon for the specified class. If this
  589. parameter is not specified, the large icon will not be loaded.
  590. MiniIconIndex - Optionally, supplies a pointer to a variable that will
  591. receive the index of the mini-icon for the specified class. The
  592. mini-icon is stored in the device installer's mini-icon cache.
  593. Return Value:
  594. If the function succeeds, the return value is TRUE.
  595. If the function fails, the return value is FALSE. To get extended error
  596. information, call GetLastError.
  597. Remarks:
  598. The icons of the class are either pre-defined, and loaded from the device
  599. installer's internal cache, or they are loaded directly from the class
  600. installer's executable. This function will query the registry value ICON in
  601. the specified class's section. If this value is specified then it indicates
  602. what mini icon to load. If the icon value is negative the absolute value
  603. represents a predefined icon. See SetupDiDrawMiniIcon for a list of pre-defined
  604. mini icons. If the icon value is positive it represents an icon in the class
  605. installer's executable, and will be extracted (the number one is reserved).
  606. This function also uses the INSTALLER value first and ENUMPROPPAGES value second
  607. to determine what executable to extract the icon(s) from.
  608. --*/
  609. {
  610. return (pSetupDiLoadClassIcon(ClassGuid,
  611. LargeIcon,
  612. NULL,
  613. MiniIconIndex
  614. ));
  615. }
  616. BOOL
  617. WINAPI
  618. SetupDiGetClassBitmapIndex(
  619. IN CONST GUID *ClassGuid, OPTIONAL
  620. OUT PINT MiniIconIndex
  621. )
  622. /*++
  623. Routine Description:
  624. This routine retrieves the index of the mini-icon for the specified class.
  625. Arguments:
  626. ClassGuid - Optionally, supplies the GUID of the class to get the mini-icon
  627. index for. If this parameter is not specified, the index of the 'unknown'
  628. icon is returned.
  629. MiniIconIndex - Supplies a pointer to a variable that receives the index of
  630. the mini-icon for the specified class. This buffer is always filled in,
  631. and receives the index of the unknown mini-icon if there is no mini-icon
  632. for the specified class (i.e., the return value is FALSE).
  633. Return Value:
  634. If there was a mini-icon for the specified class, the return value is TRUE.
  635. If there was not a mini-icon for the specified class, or if no class was
  636. specified, the return value is FALSE (and GetLastError returns
  637. ERROR_NO_DEVICE_CLASS_ICON). In this case, MiniIconIndex will contain the
  638. index of the unknown mini-icon.
  639. --*/
  640. {
  641. BOOL bRet = FALSE; // assume not found
  642. int i;
  643. PCLASSICON pci;
  644. DWORD Err;
  645. if(ClassGuid) {
  646. //
  647. // First check the built-in list.
  648. //
  649. for(i = 0; !bRet && (i < ARRAYSIZE(MiniIconXlate)); i++) {
  650. if(IsEqualGUID(MiniIconXlate[i].ClassGuid, ClassGuid)) {
  651. *MiniIconIndex = MiniIconXlate[i].MiniBitmapIndex;
  652. bRet = TRUE;
  653. }
  654. }
  655. //
  656. // Next check the "new stuff" list to see if it's there.
  657. //
  658. if(!bRet && LockMiniIconList(&GlobalMiniIconList)) {
  659. for(pci = GlobalMiniIconList.ClassIconList;
  660. !bRet && pci;
  661. pci = pci->Next) {
  662. if(IsEqualGUID(pci->ClassGuid, ClassGuid)) {
  663. *MiniIconIndex = pci->MiniBitmapIndex;
  664. bRet = TRUE;
  665. }
  666. }
  667. UnlockMiniIconList(&GlobalMiniIconList);
  668. }
  669. }
  670. //
  671. // If no match was found, snag the "unknown" class.
  672. //
  673. if(!bRet) {
  674. *MiniIconIndex = UnknownClassMiniIconIndex;
  675. Err = ERROR_NO_DEVICE_ICON;
  676. } else {
  677. Err = NO_ERROR;
  678. }
  679. SetLastError(Err);
  680. return bRet;
  681. }
  682. BOOL
  683. CreateMiniIcons(
  684. VOID
  685. )
  686. /*++
  687. Routine Description:
  688. This routine loads the default bitmap of mini-icons and turns it into
  689. the image/mask pair that will be the cornerstone of mini-icon management.
  690. THIS FUNCTION ASSUMES THE MINI-ICON LOCK HAS ALREADY BEEN ACQUIRED!
  691. Arguments:
  692. None.
  693. Return Value:
  694. If the function succeeds, the return value is TRUE, otherwise it is FALSE.
  695. --*/
  696. {
  697. HDC hdc, hdcMem;
  698. HBITMAP hbmOld;
  699. BITMAP bm;
  700. BOOL bRet = FALSE; // assume failure
  701. if(GlobalMiniIconList.hdcMiniMem) {
  702. //
  703. // Then the mini-icon list has already been built, so
  704. // return success.
  705. //
  706. return TRUE;
  707. }
  708. hdc = GetDC(NULL);
  709. if (!hdc) {
  710. goto clean0;
  711. }
  712. GlobalMiniIconList.hdcMiniMem = CreateCompatibleDC(hdc);
  713. ReleaseDC(NULL, hdc);
  714. if(!GlobalMiniIconList.hdcMiniMem) {
  715. goto clean0;
  716. }
  717. if(!(hdcMem = CreateCompatibleDC(GlobalMiniIconList.hdcMiniMem))) {
  718. goto clean0;
  719. }
  720. if(!(GlobalMiniIconList.hbmMiniImage = LoadBitmap(MyDllModuleHandle,
  721. MAKEINTRESOURCE(BMP_DRIVERTYPES)))) {
  722. goto clean1;
  723. }
  724. GetObject(GlobalMiniIconList.hbmMiniImage, sizeof(bm), &bm);
  725. if(!(GlobalMiniIconList.hbmMiniMask = CreateBitmap(bm.bmWidth,
  726. bm.bmHeight,
  727. 1,
  728. 1,
  729. NULL))) {
  730. goto clean1;
  731. }
  732. hbmOld = SelectObject(hdcMem, GlobalMiniIconList.hbmMiniImage);
  733. SelectObject(GlobalMiniIconList.hdcMiniMem,
  734. GlobalMiniIconList.hbmMiniMask
  735. );
  736. //
  737. // make the mask. white where transparent, black where opaque
  738. //
  739. SetBkColor(hdcMem, RGB_TRANSPARENT);
  740. BitBlt(GlobalMiniIconList.hdcMiniMem,
  741. 0,
  742. 0,
  743. bm.bmWidth,
  744. bm.bmHeight,
  745. hdcMem,
  746. 0,
  747. 0,
  748. SRCCOPY
  749. );
  750. //
  751. // black-out all of the transparent parts of the image, in preparation
  752. // for drawing.
  753. //
  754. SetBkColor(hdcMem, RGB_BLACK);
  755. SetTextColor(hdcMem, RGB_WHITE);
  756. BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, GlobalMiniIconList.hdcMiniMem, 0, 0, SRCAND);
  757. SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
  758. GlobalMiniIconList.NumClassImages = bm.bmWidth/MINIX;
  759. bRet = TRUE;
  760. SelectObject(hdcMem, hbmOld);
  761. clean1:
  762. DeleteObject(hdcMem);
  763. clean0:
  764. //
  765. // If failure, clean up anything we might have built
  766. //
  767. if(!bRet) {
  768. DestroyMiniIcons();
  769. }
  770. return bRet;
  771. }
  772. INT
  773. NewMiniIcon(
  774. IN CONST GUID *ClassGuid,
  775. IN HICON hIcon OPTIONAL
  776. )
  777. /*++
  778. Routine Description:
  779. It's a new class, and we have a mini-icon for it, so let's add it
  780. to the mini-icon database. First pull out the image and mask
  781. bitmaps. Then add these to the mini-icon bitmap. If this all
  782. works, add the new class to the list
  783. THIS FUNCTION ASSUMES THE MINI-ICON LOCK HAS ALREADY BEEN ACQUIRED!
  784. Arguments:
  785. ClassGuid - Supplies a pointer to the class GUID for this mini-icon.
  786. hIcon - Optionally, supplies a handle to the mini-icon to be added to
  787. the database. If this parameter is not specified, then the index
  788. for the "unknown class" icon will be returned.
  789. Return Value:
  790. Index for class (set to "unknown class" if error)
  791. --*/
  792. {
  793. INT iBitmap = -1;
  794. ICONINFO ii;
  795. PCLASSICON pci = NULL;
  796. if(hIcon && GetIconInfo(hIcon, &ii)) {
  797. try {
  798. if((iBitmap = pSetupAddMiniIconToList(ii.hbmColor, ii.hbmMask)) != -1) {
  799. //
  800. // Allocate an extra GUID's worth of memory, so we can store
  801. // the class GUID in the same chunk of memory as the CLASSICON
  802. // node.
  803. //
  804. if(pci = (PCLASSICON)MyMalloc(sizeof(CLASSICON) + sizeof(GUID))) {
  805. CopyMemory((PBYTE)pci + sizeof(CLASSICON),
  806. ClassGuid,
  807. sizeof(GUID)
  808. );
  809. pci->ClassGuid = (LPGUID)((PBYTE)pci + sizeof(CLASSICON));
  810. pci->MiniBitmapIndex = iBitmap;
  811. pci->Next = GlobalMiniIconList.ClassIconList;
  812. GlobalMiniIconList.ClassIconList = pci;
  813. }
  814. }
  815. } except(EXCEPTION_EXECUTE_HANDLER) {
  816. if(pci) {
  817. MyFree(pci);
  818. }
  819. iBitmap = -1;
  820. }
  821. DeleteObject(ii.hbmColor);
  822. DeleteObject(ii.hbmMask);
  823. }
  824. if(iBitmap == -1) {
  825. SetupDiGetClassBitmapIndex(NULL, &iBitmap);
  826. }
  827. return iBitmap;
  828. }
  829. INT
  830. pSetupAddMiniIconToList(
  831. IN HBITMAP hbmImage,
  832. IN HBITMAP hbmMask
  833. )
  834. /*++
  835. Routine Description:
  836. Given the image and mask bitmaps of a mini-icon, add these to the
  837. mini-icon bitmap.
  838. THIS FUNCTION ASSUMES THE MINI-ICON LOCK HAS ALREADY BEEN ACQUIRED!
  839. Arguments:
  840. hbmImage - Supplies the handle of the bitmap for the mini-icon.
  841. hbmMask - Supplies the handle of the bitmap for the mini-icon's mask.
  842. Return Value:
  843. If success, returns the index of the added mini-icon.
  844. If failure, returns -1.
  845. --*/
  846. {
  847. HBITMAP hbmNewImage, hbmNewMask, hbmOld;
  848. HDC hdcMem;
  849. BITMAP bm;
  850. INT iIcon = -1; // assume failure
  851. if(!CreateMiniIcons()) {
  852. goto AddIcon_Exit;
  853. }
  854. MYASSERT(GlobalMiniIconList.hdcMiniMem);
  855. if(!(hdcMem = CreateCompatibleDC(GlobalMiniIconList.hdcMiniMem))) {
  856. goto AddIcon_Exit;
  857. }
  858. //
  859. // Create a New global Bitmap for the minis
  860. //
  861. hbmOld = SelectObject(GlobalMiniIconList.hdcMiniMem,
  862. GlobalMiniIconList.hbmMiniImage
  863. );
  864. if(!(hbmNewImage = CreateCompatibleBitmap(GlobalMiniIconList.hdcMiniMem,
  865. MINIX * (GlobalMiniIconList.NumClassImages + 1),
  866. MINIY))) {
  867. goto AddIcon_Exit1;
  868. }
  869. //
  870. // Copy the current Mini bitmap
  871. //
  872. SelectObject(hdcMem, hbmNewImage);
  873. BitBlt(hdcMem,
  874. 0,
  875. 0,
  876. MINIX * GlobalMiniIconList.NumClassImages,
  877. MINIY,
  878. GlobalMiniIconList.hdcMiniMem,
  879. 0,
  880. 0,
  881. SRCCOPY
  882. );
  883. //
  884. // Fit the New icon into ours. We need to stretch it to fit correctly.
  885. //
  886. SelectObject(GlobalMiniIconList.hdcMiniMem, hbmImage);
  887. GetObject(hbmImage, sizeof(bm), &bm);
  888. StretchBlt(hdcMem,
  889. MINIX * GlobalMiniIconList.NumClassImages,
  890. 0,
  891. MINIX,
  892. MINIY,
  893. GlobalMiniIconList.hdcMiniMem,
  894. 0,
  895. 0,
  896. bm.bmWidth,
  897. bm.bmHeight,
  898. SRCCOPY
  899. );
  900. SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
  901. DeleteObject(GlobalMiniIconList.hbmMiniImage);
  902. GlobalMiniIconList.hbmMiniImage = hbmNewImage;
  903. //
  904. // Next, copy the mask.
  905. //
  906. hbmOld = SelectObject(GlobalMiniIconList.hdcMiniMem,
  907. GlobalMiniIconList.hbmMiniMask
  908. );
  909. if(!(hbmNewMask = CreateBitmap(MINIX * (GlobalMiniIconList.NumClassImages + 1),
  910. MINIY,
  911. 1,
  912. 1,
  913. NULL))) {
  914. goto AddIcon_Exit1;
  915. }
  916. SelectObject(hdcMem, hbmNewMask);
  917. BitBlt(hdcMem,
  918. 0,
  919. 0,
  920. MINIX * GlobalMiniIconList.NumClassImages,
  921. MINIY,
  922. GlobalMiniIconList.hdcMiniMem,
  923. 0,
  924. 0,
  925. SRCCOPY
  926. );
  927. SelectObject(GlobalMiniIconList.hdcMiniMem, hbmMask);
  928. GetObject(hbmMask, sizeof(bm), &bm);
  929. StretchBlt(hdcMem,
  930. MINIX * GlobalMiniIconList.NumClassImages,
  931. 0,
  932. MINIX,
  933. MINIY,
  934. GlobalMiniIconList.hdcMiniMem,
  935. 0,
  936. 0,
  937. bm.bmWidth,
  938. bm.bmHeight,
  939. SRCCOPY
  940. );
  941. SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
  942. DeleteObject(GlobalMiniIconList.hbmMiniMask);
  943. GlobalMiniIconList.hbmMiniMask = hbmNewMask;
  944. iIcon = GlobalMiniIconList.NumClassImages;
  945. GlobalMiniIconList.NumClassImages++; // one more image on the table
  946. AddIcon_Exit1:
  947. DeleteDC(hdcMem);
  948. AddIcon_Exit:
  949. return iIcon;
  950. }
  951. VOID
  952. DestroyMiniIcons(
  953. VOID
  954. )
  955. /*++
  956. Routine Description:
  957. This routine destroys the mini-icon bitmaps, if they exist.
  958. THIS FUNCTION ASSUMES THE MINI-ICON LOCK HAS ALREADY BEEN ACQUIRED!
  959. Arguments:
  960. None.
  961. Return Value:
  962. None.
  963. --*/
  964. {
  965. PCLASSICON pci;
  966. if(GlobalMiniIconList.hdcMiniMem) {
  967. DeleteDC(GlobalMiniIconList.hdcMiniMem);
  968. GlobalMiniIconList.hdcMiniMem = NULL;
  969. }
  970. if(GlobalMiniIconList.hbmMiniImage) {
  971. DeleteObject(GlobalMiniIconList.hbmMiniImage);
  972. GlobalMiniIconList.hbmMiniImage = NULL;
  973. }
  974. if(GlobalMiniIconList.hbmMiniMask) {
  975. DeleteObject(GlobalMiniIconList.hbmMiniMask);
  976. GlobalMiniIconList.hbmMiniMask = NULL;
  977. }
  978. GlobalMiniIconList.NumClassImages = 0;
  979. //
  980. // Free up any additional class icon guys that were created
  981. //
  982. while(GlobalMiniIconList.ClassIconList) {
  983. pci = GlobalMiniIconList.ClassIconList;
  984. GlobalMiniIconList.ClassIconList = pci->Next;
  985. MyFree(pci);
  986. }
  987. }
  988. BOOL
  989. WINAPI
  990. SetupDiGetClassImageList(
  991. OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
  992. )
  993. /*++
  994. Routine Description:
  995. See SetupDiGetClassImageListEx for details.
  996. --*/
  997. {
  998. return SetupDiGetClassImageListEx(ClassImageListData, NULL, NULL);
  999. }
  1000. #ifdef UNICODE
  1001. //
  1002. // ANSI version
  1003. //
  1004. BOOL
  1005. WINAPI
  1006. SetupDiGetClassImageListExA(
  1007. OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
  1008. IN PCSTR MachineName, OPTIONAL
  1009. IN PVOID Reserved
  1010. )
  1011. {
  1012. PCWSTR UnicodeMachineName;
  1013. DWORD rc;
  1014. BOOL b;
  1015. b = FALSE;
  1016. if(MachineName) {
  1017. rc = pSetupCaptureAndConvertAnsiArg(MachineName, &UnicodeMachineName);
  1018. } else {
  1019. UnicodeMachineName = NULL;
  1020. rc = NO_ERROR;
  1021. }
  1022. if(rc == NO_ERROR) {
  1023. b = SetupDiGetClassImageListExW(ClassImageListData, UnicodeMachineName, Reserved);
  1024. rc = GetLastError();
  1025. if(UnicodeMachineName) {
  1026. MyFree(UnicodeMachineName);
  1027. }
  1028. }
  1029. SetLastError(rc);
  1030. return b;
  1031. }
  1032. #else
  1033. //
  1034. // Unicode version
  1035. //
  1036. BOOL
  1037. WINAPI
  1038. SetupDiGetClassImageListExW(
  1039. OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
  1040. IN PCWSTR MachineName, OPTIONAL
  1041. IN PVOID Reserved
  1042. )
  1043. {
  1044. UNREFERENCED_PARAMETER(ClassImageListData);
  1045. UNREFERENCED_PARAMETER(MachineName);
  1046. UNREFERENCED_PARAMETER(Reserved);
  1047. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1048. return(FALSE);
  1049. }
  1050. #endif
  1051. BOOL
  1052. WINAPI
  1053. SetupDiGetClassImageListEx(
  1054. OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
  1055. IN PCTSTR MachineName, OPTIONAL
  1056. IN PVOID Reserved
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. This routine builds an image list containing bitmaps for every installed class,
  1061. and returns a data structure containing the list.
  1062. Arguments:
  1063. ClassImageListData - Supplies the address of a SP_CLASSIMAGELIST_DATA structure
  1064. that will receive information regarding the class list (including a handle
  1065. to the image list). The cbSize field of this structure must be initialized
  1066. with the size of the structure (in bytes) before calling this routine, or the
  1067. API will fail.
  1068. MachineName - Optionally, specifies the name of the remote machine whose installed
  1069. classes are to be used in building the class image list. If this parameter is
  1070. not specified, the local machine is used.
  1071. NOTE: Presently, class-specific icons can only be displayed if the class is
  1072. also present on the local machine. Thus, if the remote machine has
  1073. class x, but class x is not installed locally, then the generic (unknown)
  1074. icon will be returned.
  1075. Reserved - Reserved for future use--must be NULL.
  1076. Return Value:
  1077. If the function succeeds, the return value is TRUE.
  1078. If the function fails, the return value is FALSE. To get extended error
  1079. information, call GetLastError.
  1080. Remarks:
  1081. The image list contained in structure filled in by this API should NOT be
  1082. destroyed by calling ImageList_Destroy. Instead, SetupDiDestroyClassImageList
  1083. should be called, for proper clean-up to occur.
  1084. --*/
  1085. {
  1086. DWORD Err = NO_ERROR;
  1087. int cxMiniIcon, cyMiniIcon;
  1088. int MiniIconIndex = 0, DefaultIndex = 0;
  1089. int GuidCount, i;
  1090. int iIcon, iIndex;
  1091. HDC hDC = NULL, hMemImageDC = NULL;
  1092. HBITMAP hbmMiniImage = NULL, hbmMiniMask = NULL, hbmOldImage = NULL;
  1093. RECT rc;
  1094. CONST GUID *pClassGuid = NULL;
  1095. BOOL bUseBitmap, ComputerClassFound = FALSE;
  1096. HICON hiLargeIcon = NULL, hiSmallIcon = NULL, hIcon = NULL;
  1097. HBRUSH hOldBrush;
  1098. PCLASSICON pci = NULL;
  1099. PCLASS_IMAGE_LIST ImageData = NULL;
  1100. BOOL DestroyLock = FALSE;
  1101. HIMAGELIST ImageList = NULL;
  1102. DWORD dwLayout = 0;
  1103. UINT ImageListFlags = 0;
  1104. //
  1105. // Make sure the caller didn't pass us anything in the Reserved parameter.
  1106. //
  1107. if(Reserved) {
  1108. SetLastError(ERROR_INVALID_PARAMETER);
  1109. return FALSE;
  1110. }
  1111. try {
  1112. if(ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA)) {
  1113. Err = ERROR_INVALID_USER_BUFFER;
  1114. goto clean0;
  1115. }
  1116. //
  1117. // Allocate and initialize the image list, including setting up the
  1118. // synchronization lock. Destroy it when done.
  1119. //
  1120. if(ImageData = MyMalloc(sizeof(CLASS_IMAGE_LIST))) {
  1121. ZeroMemory(ImageData, sizeof(CLASS_IMAGE_LIST));
  1122. } else {
  1123. Err = ERROR_NOT_ENOUGH_MEMORY;
  1124. goto clean0;
  1125. }
  1126. if(InitializeSynchronizedAccess(&ImageData->Lock)) {
  1127. DestroyLock = TRUE;
  1128. }
  1129. //
  1130. // Build the class image list. Create an Image List with no mask,
  1131. // 1 image, and a growth factor of 1.
  1132. //
  1133. cxMiniIcon = GetSystemMetrics(SM_CXSMICON);
  1134. cyMiniIcon = GetSystemMetrics(SM_CYSMICON);
  1135. ImageListFlags = ILC_MASK;
  1136. //
  1137. // Check which color depth we are running in. Set the ILC_COLOR32
  1138. // imagelist create flag if we are running at greate than 8bit (256)
  1139. // color depth.
  1140. //
  1141. hDC = GetDC(NULL);
  1142. if (hDC) {
  1143. if (GetDeviceCaps(hDC, BITSPIXEL) > 8) {
  1144. ImageListFlags |= ILC_COLOR32;
  1145. }
  1146. ReleaseDC(NULL, hDC);
  1147. hDC = NULL;
  1148. }
  1149. #ifdef UNICODE
  1150. //
  1151. // If we are running on an RTL build then we need to set the ILC_MIRROR
  1152. // flag when calling ImageList_Create to un-mirror the icons. By
  1153. // default the icons are mirrored.
  1154. //
  1155. if (GetProcessDefaultLayout(&dwLayout) &&
  1156. (dwLayout & LAYOUT_RTL)) {
  1157. ImageListFlags |= ILC_MIRROR;
  1158. }
  1159. #endif
  1160. if(!(ImageList = ImageList_Create(cxMiniIcon,
  1161. cyMiniIcon,
  1162. ImageListFlags,
  1163. 1,
  1164. 1)))
  1165. {
  1166. Err = ERROR_NOT_ENOUGH_MEMORY;
  1167. goto clean0;
  1168. }
  1169. ImageList_SetBkColor(ImageList, GetSysColor(COLOR_WINDOW));
  1170. //
  1171. // Create a DC to draw the mini icons into. This is needed
  1172. // for the system defined Minis
  1173. //
  1174. if(!(hDC = GetDC(HWND_DESKTOP)) ||
  1175. !(hMemImageDC = CreateCompatibleDC(hDC)))
  1176. {
  1177. Err = ERROR_NOT_ENOUGH_MEMORY;
  1178. goto clean0;
  1179. }
  1180. //
  1181. // Create a bitmap to draw the icons on. Defer checking for creation
  1182. // of bitmap until afer freeing DC, so it only has to be done once.
  1183. //
  1184. hbmMiniImage = CreateCompatibleBitmap(hDC, cxMiniIcon, cyMiniIcon);
  1185. hbmMiniMask = CreateCompatibleBitmap(hDC, cxMiniIcon, cyMiniIcon);
  1186. ReleaseDC(HWND_DESKTOP, hDC);
  1187. hDC = NULL;
  1188. //
  1189. // Did the bitmap get created?
  1190. //
  1191. if (!hbmMiniImage || ! hbmMiniMask) {
  1192. Err = ERROR_NOT_ENOUGH_MEMORY;
  1193. goto clean0;
  1194. }
  1195. //
  1196. // Select our bitmap into the memory DC.
  1197. //
  1198. hbmOldImage = SelectObject(hMemImageDC, hbmMiniImage);
  1199. //
  1200. // Prepare to draw the mini icon onto the memory DC
  1201. //
  1202. rc.left = 0;
  1203. rc.top = 0;
  1204. rc.right = cxMiniIcon;
  1205. rc.bottom = cyMiniIcon;
  1206. //
  1207. // Get the Index of the Default mini icon.
  1208. //
  1209. SetupDiGetClassBitmapIndex(NULL, &DefaultIndex);
  1210. //
  1211. // Enumerate all classes, and for each class, draw its bitmap.
  1212. //
  1213. GuidCount = 32;
  1214. ImageData->ClassGuidList = (LPGUID)MyMalloc(sizeof(GUID) * GuidCount);
  1215. if (!SetupDiBuildClassInfoListEx(0,
  1216. ImageData->ClassGuidList,
  1217. GuidCount,
  1218. &GuidCount,
  1219. MachineName,
  1220. NULL)) {
  1221. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  1222. //
  1223. // Realloc buffer and try again.
  1224. //
  1225. MyFree(ImageData->ClassGuidList);
  1226. if(!(ImageData->ClassGuidList = MyMalloc(sizeof(GUID) * GuidCount))) {
  1227. Err = ERROR_NOT_ENOUGH_MEMORY;
  1228. goto clean0;
  1229. }
  1230. if (!SetupDiBuildClassInfoListEx(0,
  1231. ImageData->ClassGuidList,
  1232. GuidCount,
  1233. &GuidCount,
  1234. MachineName,
  1235. NULL)) {
  1236. Err = GetLastError();
  1237. goto clean0;
  1238. }
  1239. } else {
  1240. Err = GetLastError();
  1241. goto clean0;
  1242. }
  1243. }
  1244. //
  1245. // Retrieve the icon for each class in the class list.
  1246. //
  1247. for (pClassGuid = ImageData->ClassGuidList, i = 0;
  1248. i < GuidCount;
  1249. pClassGuid++, i++) {
  1250. if (!pSetupDiLoadClassIcon(pClassGuid,
  1251. &hiLargeIcon,
  1252. &hiSmallIcon,
  1253. &MiniIconIndex)) {
  1254. Err = GetLastError();
  1255. goto clean0;
  1256. }
  1257. //
  1258. // If the returned Mini Icon index is not the Default one, then
  1259. // we use the MiniBitmap, since it is a pre-defined one in SETUPAPI.
  1260. // If the Mini is not pre-defined, and there is no Class Installer
  1261. // then we use the Mini, since it is a valid default. If there
  1262. // is no Mini, and there is a class installer, then we will use
  1263. // the Class installer's big Icon, and have the Image list crunch
  1264. // it for us.
  1265. //
  1266. bUseBitmap = FALSE;
  1267. if (DefaultIndex != MiniIconIndex) {
  1268. SetupDiDrawMiniIcon(hMemImageDC,
  1269. rc,
  1270. MiniIconIndex,
  1271. DMI_USERECT);
  1272. SelectObject(hMemImageDC, hbmMiniMask);
  1273. SetupDiDrawMiniIcon(hMemImageDC,
  1274. rc,
  1275. MiniIconIndex,
  1276. DMI_MASK | DMI_USERECT);
  1277. bUseBitmap = TRUE;
  1278. }
  1279. //
  1280. // Deselect the bitmap from our DC BEFORE calling ImageList
  1281. // functions.
  1282. //
  1283. SelectObject(hMemImageDC, hbmOldImage);
  1284. //
  1285. // Add the image. Allocate a new PCI.
  1286. //
  1287. if(!(pci = (PCLASSICON)MyMalloc(sizeof(CLASSICON)))) {
  1288. Err = ERROR_NOT_ENOUGH_MEMORY;
  1289. goto clean0;
  1290. }
  1291. if (hiSmallIcon) {
  1292. pci->MiniBitmapIndex = (UINT)ImageList_AddIcon(ImageList, hiSmallIcon);
  1293. } else if (bUseBitmap) {
  1294. pci->MiniBitmapIndex = (UINT)ImageList_Add(ImageList, hbmMiniImage, hbmMiniMask);
  1295. } else {
  1296. pci->MiniBitmapIndex = (UINT)ImageList_AddIcon(ImageList, hiLargeIcon);
  1297. }
  1298. if (hiLargeIcon) {
  1299. DestroyIcon(hiLargeIcon);
  1300. hiLargeIcon = NULL;
  1301. }
  1302. if (hiSmallIcon) {
  1303. DestroyIcon(hiSmallIcon);
  1304. hiSmallIcon = NULL;
  1305. }
  1306. if(pci->MiniBitmapIndex == (UINT)-1) {
  1307. Err = ERROR_NOT_ENOUGH_MEMORY;
  1308. MyFree(pci);
  1309. pci = NULL;
  1310. goto clean0;
  1311. }
  1312. pci->ClassGuid = pClassGuid;
  1313. //
  1314. // Link it in.
  1315. //
  1316. pci->Next = ImageData->ClassIconList;
  1317. ImageData->ClassIconList = pci;
  1318. //
  1319. // Reset pci to NULL so we won't try to free it later.
  1320. //
  1321. pci = NULL;
  1322. //
  1323. // Select our bitmap back for the next ICON.
  1324. //
  1325. SelectObject(hMemImageDC, hbmMiniImage);
  1326. if(IsEqualGUID(pClassGuid, &GUID_DEVCLASS_UNKNOWN)) {
  1327. ImageData->UnknownImageIndex = i;
  1328. }
  1329. //
  1330. // Check to see if we've encountered the computer class. This used
  1331. // to be a special pseudo-class used solely by DevMgr to retrieve
  1332. // the icon for the root of the device tree. Now, we use this class
  1333. // for specifying the 'drivers' for the computer itself (i.e., the
  1334. // HALs and the appropriate versions of files that are different for
  1335. // MP vs. UP.
  1336. //
  1337. // We should encounter this class GUID, but if we don't, then we
  1338. // want to maintain the old behavior of adding this in manually
  1339. // later on.
  1340. //
  1341. if(!ComputerClassFound && IsEqualGUID(pClassGuid, &GUID_DEVCLASS_COMPUTER)) {
  1342. ComputerClassFound = TRUE;
  1343. }
  1344. }
  1345. if(!ComputerClassFound) {
  1346. //
  1347. // Special Case for the Internal Class "Computer"
  1348. //
  1349. if(!(pci = (PCLASSICON)MyMalloc(sizeof(CLASSICON)))) {
  1350. Err = ERROR_NOT_ENOUGH_MEMORY;
  1351. goto clean0;
  1352. }
  1353. pci->ClassGuid = &GUID_DEVCLASS_COMPUTER;
  1354. SelectObject(hMemImageDC, hbmMiniImage);
  1355. hOldBrush = SelectObject(hMemImageDC, GetSysColorBrush(COLOR_WINDOW));
  1356. PatBlt(hMemImageDC, 0, 0, cxMiniIcon, cyMiniIcon, PATCOPY);
  1357. SelectObject(hMemImageDC, hOldBrush);
  1358. SetupDiGetClassBitmapIndex((LPGUID)pci->ClassGuid, &MiniIconIndex);
  1359. SetupDiDrawMiniIcon(hMemImageDC,
  1360. rc,
  1361. MiniIconIndex,
  1362. DMI_USERECT);
  1363. SelectObject(hMemImageDC, hbmMiniMask);
  1364. SetupDiDrawMiniIcon(hMemImageDC,
  1365. rc,
  1366. MiniIconIndex,
  1367. DMI_MASK | DMI_USERECT);
  1368. //
  1369. // Deselect the bitmap from our DC BEFORE calling ImageList
  1370. // functions.
  1371. //
  1372. SelectObject(hMemImageDC, hbmOldImage);
  1373. pci->MiniBitmapIndex = ImageList_Add(ImageList, hbmMiniImage, hbmMiniMask);
  1374. if(pci->MiniBitmapIndex == (UINT)-1) {
  1375. Err = ERROR_NOT_ENOUGH_MEMORY;
  1376. MyFree(pci);
  1377. pci = NULL;
  1378. goto clean0;
  1379. }
  1380. //
  1381. // Link it in.
  1382. //
  1383. pci->Next = ImageData->ClassIconList;
  1384. ImageData->ClassIconList = pci;
  1385. //
  1386. // Reset pci to NULL so we won't try to free it later.
  1387. //
  1388. pci = NULL;
  1389. }
  1390. //
  1391. // Add the Overlay ICONs.
  1392. //
  1393. for (iIcon = IDI_CLASSICON_OVERLAYFIRST;
  1394. iIcon <= IDI_CLASSICON_OVERLAYLAST;
  1395. ++iIcon) {
  1396. if(!(hIcon = LoadIcon(MyDllModuleHandle, MAKEINTRESOURCE(iIcon)))) {
  1397. Err = GetLastError();
  1398. goto clean0;
  1399. }
  1400. iIndex = ImageList_AddIcon(ImageList, hIcon);
  1401. if(iIndex == -1) {
  1402. Err = ERROR_NOT_ENOUGH_MEMORY;
  1403. goto clean0;
  1404. }
  1405. if(!ImageList_SetOverlayImage(ImageList, iIndex, iIcon - IDI_CLASSICON_OVERLAYFIRST + 1)) {
  1406. Err = ERROR_INVALID_DATA;
  1407. goto clean0;
  1408. }
  1409. }
  1410. //
  1411. // If we get to this point, then we've successfully constructed the entire
  1412. // image list, and associated CLASSICON nodes. Now, store this information
  1413. // in the caller's SP_CLASSIMAGELIST_DATA buffer.
  1414. //
  1415. ClassImageListData->Reserved = (ULONG_PTR)ImageData;
  1416. ClassImageListData->ImageList = ImageList;
  1417. clean0: ; // nothing to do.
  1418. } except(EXCEPTION_EXECUTE_HANDLER) {
  1419. Err = ERROR_INVALID_USER_BUFFER;
  1420. if(hDC) {
  1421. ReleaseDC(HWND_DESKTOP, hDC);
  1422. }
  1423. if(pci) {
  1424. MyFree(pci);
  1425. }
  1426. //
  1427. // Reference the following variables so the compiler will respect statement
  1428. // ordering w.r.t. assignment.
  1429. //
  1430. ImageData = ImageData;
  1431. DestroyLock = DestroyLock;
  1432. ImageList = ImageList;
  1433. }
  1434. if (hbmMiniImage) {
  1435. DeleteObject(hbmMiniImage);
  1436. }
  1437. if (hbmMiniMask) {
  1438. DeleteObject(hbmMiniMask);
  1439. }
  1440. if (hMemImageDC) {
  1441. DeleteDC(hMemImageDC);
  1442. }
  1443. if(Err != NO_ERROR) {
  1444. if(ImageData) {
  1445. if(DestroyLock) {
  1446. DestroySynchronizedAccess(&ImageData->Lock);
  1447. }
  1448. if(ImageData->ClassGuidList) {
  1449. MyFree(ImageData->ClassGuidList);
  1450. }
  1451. while(ImageData->ClassIconList) {
  1452. pci = ImageData->ClassIconList;
  1453. ImageData->ClassIconList = pci->Next;
  1454. MyFree(pci);
  1455. }
  1456. MyFree(ImageData);
  1457. }
  1458. if(ImageList) {
  1459. ImageList_Destroy(ImageList);
  1460. }
  1461. }
  1462. SetLastError(Err);
  1463. return (Err == NO_ERROR);
  1464. }
  1465. BOOL
  1466. WINAPI
  1467. SetupDiDestroyClassImageList(
  1468. IN PSP_CLASSIMAGELIST_DATA ClassImageListData
  1469. )
  1470. /*++
  1471. Routine Description:
  1472. This routine destroys a class image list built by a call to SetupDiGetClassImageList.
  1473. Arguments:
  1474. ClassImageListData - Supplies the address of a SP_CLASSIMAGELIST_DATA structure
  1475. containing the class image list to be destroyed.
  1476. Return Value:
  1477. If the function succeeds, the return value is TRUE.
  1478. If the function fails, the return value is FALSE. To get extended error
  1479. information, call GetLastError.
  1480. --*/
  1481. {
  1482. DWORD Err = NO_ERROR;
  1483. PCLASS_IMAGE_LIST ImageData = NULL;
  1484. PCLASSICON pci;
  1485. try {
  1486. if(ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA)) {
  1487. Err = ERROR_INVALID_USER_BUFFER;
  1488. goto clean0;
  1489. }
  1490. if (ClassImageListData->Reserved == 0x0) {
  1491. Err = ERROR_INVALID_USER_BUFFER;
  1492. goto clean0;
  1493. }
  1494. ImageData = (PCLASS_IMAGE_LIST)ClassImageListData->Reserved;
  1495. if (!LockImageList(ImageData)) {
  1496. Err = ERROR_CANT_LOAD_CLASS_ICON;
  1497. goto clean0;
  1498. }
  1499. if (ClassImageListData->ImageList) {
  1500. ImageList_Destroy(ClassImageListData->ImageList);
  1501. }
  1502. if (ImageData->ClassGuidList) {
  1503. MyFree(ImageData->ClassGuidList);
  1504. }
  1505. while(ImageData->ClassIconList) {
  1506. pci = ImageData->ClassIconList;
  1507. ImageData->ClassIconList = pci->Next;
  1508. MyFree(pci);
  1509. }
  1510. DestroySynchronizedAccess(&ImageData->Lock);
  1511. MyFree(ImageData);
  1512. ClassImageListData->Reserved = 0;
  1513. clean0: ; // nothing to do.
  1514. } except(EXCEPTION_EXECUTE_HANDLER) {
  1515. Err = ERROR_INVALID_USER_BUFFER;
  1516. }
  1517. SetLastError(Err);
  1518. return (Err == NO_ERROR);
  1519. }
  1520. BOOL
  1521. WINAPI
  1522. SetupDiGetClassImageIndex(
  1523. IN PSP_CLASSIMAGELIST_DATA ClassImageListData,
  1524. IN CONST GUID *ClassGuid,
  1525. OUT PINT ImageIndex
  1526. )
  1527. /*++
  1528. Routine Description:
  1529. This routine retrieves the index within the class image list of a specified
  1530. class.
  1531. Arguments:
  1532. ClassImageListData - Supplies the address of a SP_CLASSIMAGELIST_DATA
  1533. structure containing the specified class's image.
  1534. ClassGuid - Supplies the address of the GUID for the class whose index is
  1535. to be retrieved.
  1536. ImageIndex - Supplies the address of a variable that receives the index of
  1537. the specified class's image within the class image list.
  1538. Return Value:
  1539. If the function succeeds, the return value is TRUE.
  1540. If the function fails, the return value is FALSE. To get extended error
  1541. information, call GetLastError.
  1542. --*/
  1543. {
  1544. DWORD Err = NO_ERROR;
  1545. BOOL bFound = FALSE, bLocked = FALSE;
  1546. PCLASS_IMAGE_LIST ImageData = NULL;
  1547. PCLASSICON pci;
  1548. try {
  1549. if(ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA)) {
  1550. Err = ERROR_INVALID_USER_BUFFER;
  1551. goto clean0;
  1552. }
  1553. if (ClassImageListData->Reserved == 0x0) {
  1554. Err = ERROR_INVALID_USER_BUFFER;
  1555. goto clean0;
  1556. }
  1557. ImageData = (PCLASS_IMAGE_LIST)ClassImageListData->Reserved;
  1558. if (!LockImageList(ImageData)) {
  1559. Err = ERROR_CANT_LOAD_CLASS_ICON;
  1560. goto clean0;
  1561. }
  1562. bLocked = TRUE;
  1563. if (ClassGuid) {
  1564. //
  1565. // check the "new stuff" list to see if it's there
  1566. //
  1567. for (pci = ImageData->ClassIconList;
  1568. !bFound && pci;
  1569. pci = pci->Next) {
  1570. if(IsEqualGUID(pci->ClassGuid, ClassGuid)) {
  1571. *ImageIndex = pci->MiniBitmapIndex;
  1572. bFound = TRUE;
  1573. }
  1574. }
  1575. }
  1576. //
  1577. // if no match was found, snag the "unknown" class
  1578. //
  1579. if (!bFound) {
  1580. *ImageIndex = ImageData->UnknownImageIndex;
  1581. }
  1582. clean0: ; // nothing to do.
  1583. } except(EXCEPTION_EXECUTE_HANDLER) {
  1584. Err = ERROR_INVALID_USER_BUFFER;
  1585. }
  1586. if (bLocked && ImageData) {
  1587. UnlockImageList(ImageData);
  1588. }
  1589. SetLastError(Err);
  1590. return (Err == NO_ERROR);
  1591. }