Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2134 lines
65 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  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. //
  146. // ISSUE-2002/05/21-lonnym -- Mini-icon list uses hard-coded dimensions
  147. // We must hard-code the dimensions of the mini-icons we store in our global
  148. // mini-icon list. This is tied to the size of the mini-icon images contained
  149. // in the ilwinmsd.bmp "strip".
  150. //
  151. #define MINIX 16
  152. #define MINIY 16
  153. #define RGB_WHITE (RGB(255, 255, 255))
  154. #define RGB_BLACK (RGB(0, 0, 0))
  155. #define RGB_TRANSPARENT (RGB(0, 128, 128))
  156. //
  157. // Private function prototypes.
  158. //
  159. INT
  160. NewMiniIcon(
  161. IN CONST GUID *ClassGuid,
  162. IN HICON hIcon OPTIONAL
  163. );
  164. INT
  165. WINAPI
  166. SetupDiDrawMiniIcon(
  167. IN HDC hdc,
  168. IN RECT rc,
  169. IN INT MiniIconIndex,
  170. IN DWORD Flags
  171. )
  172. /*++
  173. Routine Description:
  174. This routine draws the specified mini-icon at the requested location.
  175. Arguments:
  176. hdc - Supplies the handle of the device context in which the mini-icon
  177. will be drawn.
  178. rc - Supplies the rectangle in the specified HDC to draw the icon in.
  179. MiniIconIndex - The index of the mini-icon, as retrieved from
  180. SetupDiLoadClassIcon or SetupDiGetClassBitmapIndex. The following are
  181. pre-defined indices that may be used.
  182. 0 Computer
  183. 2 display
  184. 5 mouse
  185. 6 keyboard
  186. 9 fdc
  187. 9 hdc
  188. 10 ports
  189. 15 net
  190. 0 system
  191. 8 sound
  192. 14 printer
  193. 2 monitor
  194. 3 nettrans
  195. 16 netclient
  196. 17 netservice
  197. 18 unknown
  198. Flags - Controls the drawing operation. The LOWORD contains the actual flags
  199. defined as follows:
  200. DMI_MASK - Draw the mini-icon's mask into HDC.
  201. DMI_BKCOLOR - Use the system color index specified in the HIWORD of Flags
  202. as the background color. If not specified, COLOR_WINDOW is used.
  203. DMI_USERECT - If set, SetupDiDrawMiniIcon will use the supplied rect,
  204. stretching the icon to fit as appropriate.
  205. Return Value:
  206. This function returns the offset from the left of rc where the string should
  207. start.
  208. Remarks:
  209. By default, the icon will be centered vertically and butted against the left
  210. corner of the specified rectangle.
  211. If the specified mini-icon index falls outside the range of our mini-icon
  212. cache, the unknown class mini-icon will be drawn instead.
  213. --*/
  214. {
  215. HBITMAP hbmOld = NULL;
  216. COLORREF rgbBk = CLR_INVALID;
  217. COLORREF rgbText = CLR_INVALID;
  218. INT ret = 0;
  219. BOOL MiniIconListLocked = FALSE;
  220. DWORD Err = NO_ERROR;
  221. try {
  222. if(LockMiniIconList(&GlobalMiniIconList)) {
  223. MiniIconListLocked = TRUE;
  224. } else {
  225. leave;
  226. }
  227. CreateMiniIcons();
  228. if((MiniIconIndex >= 0) && ((UINT)MiniIconIndex >= GlobalMiniIconList.NumClassImages)) {
  229. MiniIconIndex = UnknownClassMiniIconIndex;
  230. }
  231. if(GlobalMiniIconList.hbmMiniImage) {
  232. //
  233. // Set the Foreground and background color for the
  234. // conversion of the Mono Mask image
  235. //
  236. if(Flags & DMI_MASK) {
  237. rgbBk = SetBkColor(hdc, RGB_WHITE);
  238. } else {
  239. rgbBk = SetBkColor(hdc,
  240. GetSysColor(((int)(Flags & DMI_BKCOLOR
  241. ? HIWORD(Flags)
  242. : COLOR_WINDOW)))
  243. );
  244. }
  245. if(rgbBk == CLR_INVALID) {
  246. leave;
  247. }
  248. rgbText = SetTextColor(hdc, RGB_BLACK);
  249. if(rgbText == CLR_INVALID) {
  250. leave;
  251. }
  252. if(Flags & DMI_USERECT) {
  253. //
  254. // Copy the converted mask into the dest. The transparent
  255. // areas will be drawn with the current window color.
  256. //
  257. hbmOld = SelectObject(GlobalMiniIconList.hdcMiniMem,
  258. GlobalMiniIconList.hbmMiniMask
  259. );
  260. if(!hbmOld) {
  261. leave;
  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. SRCCOPY | NOMIRRORBITMAP);
  274. if(!(Flags & DMI_MASK)) {
  275. //
  276. // OR the image into the dest
  277. //
  278. SelectObject(GlobalMiniIconList.hdcMiniMem,
  279. GlobalMiniIconList.hbmMiniImage
  280. );
  281. StretchBlt(hdc,
  282. rc.left,
  283. rc.top,
  284. rc.right - rc.left,
  285. rc.bottom - rc.top,
  286. GlobalMiniIconList.hdcMiniMem,
  287. MINIX * MiniIconIndex,
  288. 0,
  289. MINIX,
  290. MINIY,
  291. SRCPAINT | NOMIRRORBITMAP);
  292. }
  293. } else {
  294. //
  295. // Copy the converted mask into the dest. The transparent
  296. // areas will be drawn with the current window color.
  297. //
  298. hbmOld = SelectObject(GlobalMiniIconList.hdcMiniMem,
  299. GlobalMiniIconList.hbmMiniMask
  300. );
  301. if(!hbmOld) {
  302. leave;
  303. }
  304. BitBlt(hdc,
  305. rc.left,
  306. rc.top + (rc.bottom - rc.top - MINIY)/2,
  307. MINIX,
  308. MINIY,
  309. GlobalMiniIconList.hdcMiniMem,
  310. MINIX * MiniIconIndex,
  311. 0,
  312. SRCCOPY | NOMIRRORBITMAP
  313. );
  314. if(!(Flags & DMI_MASK)) {
  315. //
  316. // OR the image into the dest
  317. //
  318. SelectObject(GlobalMiniIconList.hdcMiniMem,
  319. GlobalMiniIconList.hbmMiniImage
  320. );
  321. BitBlt(hdc,
  322. rc.left,
  323. rc.top + (rc.bottom - rc.top - MINIY)/2,
  324. MINIX,
  325. MINIY,
  326. GlobalMiniIconList.hdcMiniMem,
  327. MINIX * MiniIconIndex,
  328. 0,
  329. SRCPAINT | NOMIRRORBITMAP
  330. );
  331. }
  332. }
  333. //
  334. // ISSUE-2002/05/21-lonnym -- String offset returned by SetupDiDrawMiniIcon assumes LTR reading
  335. // This may not work properly in an RTL reading configuration
  336. //
  337. if(Flags & DMI_USERECT) {
  338. ret = rc.right - rc.left + 2; // offset to string from left edge
  339. } else {
  340. ret = MINIX + 2; // offset to string from left edge
  341. }
  342. }
  343. } except(pSetupExceptionFilter(GetExceptionCode())) {
  344. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  345. }
  346. if(hbmOld) {
  347. SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
  348. }
  349. if(MiniIconListLocked) {
  350. UnlockMiniIconList(&GlobalMiniIconList);
  351. }
  352. if(rgbBk != CLR_INVALID) {
  353. SetBkColor(hdc, rgbBk);
  354. }
  355. if(rgbText != CLR_INVALID) {
  356. SetTextColor(hdc, rgbText);
  357. }
  358. return ((Err == NO_ERROR) ? ret : 0);
  359. }
  360. DWORD
  361. pSetupDiLoadClassIcon(
  362. IN CONST GUID *ClassGuid,
  363. OUT HICON *LargeIcon, OPTIONAL
  364. OUT HICON *SmallIcon, OPTIONAL
  365. OUT LPINT MiniIconIndex OPTIONAL
  366. )
  367. /*++
  368. Routine Description:
  369. This routine loads both the large and mini-icons for the specified class
  370. Arguments:
  371. ClassGuid - Supplies the GUID of the class for which the icon(s) should
  372. be loaded.
  373. LargeIcon - Optionally, supplies a pointer to a variable that will receive
  374. a handle to the loaded large icon for the specified class. If this
  375. parameter is not specified, the large icon will not be loaded.
  376. The caller must free this icon handle by calling DestroyIcon when they
  377. no longer need the icon.
  378. SmallIcon - Optionally, supplies a pointer to a variable that will receive
  379. a handle to the loaded small icon for the specified class. If this
  380. parameter is not specified, the small icon will not be loaded.
  381. The caller must free this icon handle by calling DestroyIcon when they
  382. no longer need the icon.
  383. MiniIconIndex - Optionally, supplies a pointer to a variable that will
  384. receive the index of the mini-icon for the specified class. The
  385. mini-icon is stored in the device installer's mini-icon cache.
  386. Return Value:
  387. If the function succeeds, the return value is NO_ERROR. Otherwise, it is
  388. a Win32 error code indicating the cause of failure.
  389. Remarks:
  390. The icons of the class are either pre-defined, and loaded from the device
  391. installer's internal cache, or they are loaded directly from the class
  392. installer's executable. This function will query the registry value ICON in
  393. the specified class's section. If this value is specified then it indicates
  394. what mini icon to load. If the icon value is negative the absolute value
  395. represents a predefined icon. See SetupDiDrawMiniIcon for a list of
  396. pre-defined mini icons. If the icon value is positive it represents an icon
  397. in the class installer's executable, and will be extracted (the number one
  398. is reserved). This function also uses the INSTALLER32 value first and
  399. ENUMPROPPAGES32 value second to determine what executable to extract the
  400. icon(s) from.
  401. --*/
  402. {
  403. HKEY hk = INVALID_HANDLE_VALUE;
  404. DWORD Err;
  405. HICON hRetLargeIcon = NULL;
  406. HICON hRetSmallIcon = NULL;
  407. INT ClassIconIndex;
  408. DWORD RegDataType, StringSize;
  409. PTSTR EndPtr;
  410. BOOL bGetMini = FALSE;
  411. TCHAR TempString[MAX_PATH];
  412. TCHAR FullPath[MAX_PATH];
  413. UINT IconsExtracted;
  414. HRESULT hr;
  415. if(!LockMiniIconList(&GlobalMiniIconList)) {
  416. return ERROR_CANT_LOAD_CLASS_ICON;
  417. }
  418. try {
  419. if(MiniIconIndex) {
  420. *MiniIconIndex = -1;
  421. }
  422. if((hk = SetupDiOpenClassRegKey(ClassGuid, KEY_READ)) == INVALID_HANDLE_VALUE) {
  423. goto LoadIconFinalize;
  424. }
  425. StringSize = sizeof(TempString);
  426. Err = RegQueryValueEx(hk,
  427. pszInsIcon,
  428. NULL,
  429. &RegDataType,
  430. (PBYTE)TempString,
  431. &StringSize
  432. );
  433. if((Err == ERROR_SUCCESS) && (RegDataType == REG_SZ) && TempString[0]) {
  434. if((ClassIconIndex = _tcstol(TempString, &EndPtr, 10)) == 1) {
  435. //
  436. // Positive values indicate that we should access an icon
  437. // directly using its ID. Since ExtractIconEx uses negative
  438. // values to indicate these IDs, and since the value -1 has
  439. // a special meaning to that API, we must disallow a
  440. // ClassIconIndex of +1.
  441. //
  442. goto LoadIconFinalize;
  443. }
  444. } else {
  445. //
  446. // Icon index not specified, so assume index is 0.
  447. //
  448. ClassIconIndex = 0;
  449. }
  450. if(MiniIconIndex) {
  451. //
  452. // If mini-icon is already around, then we're done with it.
  453. //
  454. if(!SetupDiGetClassBitmapIndex(ClassGuid, MiniIconIndex)) {
  455. //
  456. // mini-icon not around--set flag to show we didn't get it.
  457. //
  458. bGetMini = TRUE;
  459. }
  460. }
  461. if(ClassIconIndex < 0) {
  462. INT ClassIconIndexNeg = -ClassIconIndex;
  463. //
  464. // Icon index is negative. This means that this class is one of
  465. // our special classes with icons in setupapi.dll. We still want
  466. // to return copies of our icons (both large and small) in this
  467. // case, since:
  468. //
  469. // (a) icon's origin is opaque to callers, and we want them to
  470. // treat resultant HICONs consistently
  471. //
  472. // (b) we don't want any back-door dependency created between
  473. // these icons and the presence/absence of setupapi.dll
  474. // (i.e., they should be able to unload setupapi.dll and the
  475. // icon handle(s) should still be valid.
  476. //
  477. if(LargeIcon) {
  478. hRetLargeIcon = LoadImage(MyDllModuleHandle,
  479. MAKEINTRESOURCE(ClassIconIndexNeg),
  480. IMAGE_ICON,
  481. 0,
  482. 0,
  483. LR_DEFAULTSIZE
  484. );
  485. }
  486. if(bGetMini || SmallIcon) {
  487. //
  488. // Retrieve the small icon as well. If the resource doesn't
  489. // have a small icon then the big one will get smushed, but
  490. // it's better than getting the default icon.
  491. //
  492. hRetSmallIcon = LoadImage(MyDllModuleHandle,
  493. MAKEINTRESOURCE(ClassIconIndexNeg),
  494. IMAGE_ICON,
  495. GetSystemMetrics(SM_CXSMICON),
  496. GetSystemMetrics(SM_CYSMICON),
  497. 0
  498. );
  499. if(hRetSmallIcon && bGetMini) {
  500. *MiniIconIndex = NewMiniIcon(ClassGuid, hRetSmallIcon);
  501. }
  502. }
  503. } else if(bGetMini || LargeIcon || SmallIcon) {
  504. //
  505. // Look for the binary containing the icon(s) first in the
  506. // "Installer32" entry, and if not found, then in the
  507. // "EnumPropPages32" entry.
  508. //
  509. hr = StringCchCopy(FullPath,
  510. SIZECHARS(FullPath),
  511. SystemDirectory
  512. );
  513. if(FAILED(hr)) {
  514. goto LoadIconFinalize;
  515. }
  516. StringSize = sizeof(TempString);
  517. Err = RegQueryValueEx(hk,
  518. pszInstaller32,
  519. NULL,
  520. &RegDataType,
  521. (PBYTE)TempString,
  522. &StringSize
  523. );
  524. if((Err != ERROR_SUCCESS) || (RegDataType != REG_SZ) ||
  525. !TempString[0]) {
  526. StringSize = sizeof(TempString);
  527. Err = RegQueryValueEx(hk,
  528. pszEnumPropPages32,
  529. NULL,
  530. &RegDataType,
  531. (PBYTE)TempString,
  532. &StringSize
  533. );
  534. if((Err != ERROR_SUCCESS) || (RegDataType != REG_SZ) ||
  535. !TempString[0]) {
  536. goto LoadIconFinalize;
  537. }
  538. }
  539. //
  540. // Remove function name, if present, from installer name.
  541. //
  542. for(EndPtr = TempString + (lstrlen(TempString) - 1);
  543. EndPtr >= TempString;
  544. EndPtr--) {
  545. if(*EndPtr == TEXT(',')) {
  546. *EndPtr = TEXT('\0');
  547. break;
  548. }
  549. //
  550. // If we hit a double-quote mark, we terminate the search.
  551. //
  552. if(*EndPtr == TEXT('\"')) {
  553. goto LoadIconFinalize;
  554. }
  555. }
  556. if(!pSetupConcatenatePaths(FullPath,
  557. TempString,
  558. SIZECHARS(FullPath),
  559. NULL)) {
  560. goto LoadIconFinalize;
  561. }
  562. IconsExtracted = ExtractIconEx(FullPath,
  563. -ClassIconIndex,
  564. LargeIcon ? &hRetLargeIcon : NULL,
  565. (bGetMini || SmallIcon) ? &hRetSmallIcon : NULL,
  566. 1
  567. );
  568. if((IconsExtracted != (UINT)-1) && (IconsExtracted > 0)) {
  569. if(hRetSmallIcon && bGetMini) {
  570. *MiniIconIndex = NewMiniIcon(ClassGuid, hRetSmallIcon);
  571. }
  572. }
  573. }
  574. LoadIconFinalize:
  575. //
  576. // Assume success, unless we hit some really big problem below.
  577. //
  578. Err = NO_ERROR;
  579. if(LargeIcon && !hRetLargeIcon) {
  580. //
  581. // We didn't retrieve a large icon, so use a default.
  582. //
  583. Err = GLE_FN_CALL(NULL,
  584. hRetLargeIcon = LoadImage(
  585. MyDllModuleHandle,
  586. MAKEINTRESOURCE(ICON_DEFAULT),
  587. IMAGE_ICON,
  588. 0,
  589. 0,
  590. LR_DEFAULTSIZE)
  591. );
  592. if(Err != NO_ERROR) {
  593. leave;
  594. }
  595. }
  596. if(SmallIcon && !hRetSmallIcon) {
  597. //
  598. // We didn't retrieve a small icon, so use a default.
  599. //
  600. Err = GLE_FN_CALL(NULL,
  601. hRetSmallIcon = LoadImage(
  602. MyDllModuleHandle,
  603. MAKEINTRESOURCE(ICON_DEFAULT),
  604. IMAGE_ICON,
  605. GetSystemMetrics(SM_CXSMICON),
  606. GetSystemMetrics(SM_CYSMICON),
  607. 0)
  608. );
  609. if(Err != NO_ERROR) {
  610. leave;
  611. }
  612. }
  613. if(LargeIcon) {
  614. *LargeIcon = hRetLargeIcon;
  615. hRetLargeIcon = NULL; // so we won't try to destroy it later
  616. }
  617. if(SmallIcon) {
  618. *SmallIcon = hRetSmallIcon;
  619. hRetSmallIcon = NULL; // so we won't try to destroy it later
  620. }
  621. if(MiniIconIndex && (*MiniIconIndex == -1)) {
  622. SetupDiGetClassBitmapIndex(NULL, MiniIconIndex);
  623. }
  624. } except(pSetupExceptionFilter(GetExceptionCode())) {
  625. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  626. }
  627. UnlockMiniIconList(&GlobalMiniIconList);
  628. if(hk != INVALID_HANDLE_VALUE) {
  629. RegCloseKey(hk);
  630. }
  631. if(hRetLargeIcon) {
  632. DestroyIcon(hRetLargeIcon);
  633. }
  634. if(hRetSmallIcon) {
  635. DestroyIcon(hRetSmallIcon);
  636. }
  637. return Err;
  638. }
  639. BOOL
  640. WINAPI
  641. SetupDiLoadClassIcon(
  642. IN CONST GUID *ClassGuid,
  643. OUT HICON *LargeIcon, OPTIONAL
  644. OUT LPINT MiniIconIndex OPTIONAL
  645. )
  646. /*++
  647. Routine Description:
  648. This routine loads both the large and mini-icons for the specified class
  649. Arguments:
  650. ClassGuid - Supplies the GUID of the class for which the icon(s) should
  651. be loaded.
  652. LargeIcon - Optionally, supplies a pointer to a variable that will receive
  653. a handle to the loaded large icon for the specified class. If this
  654. parameter is not specified, the large icon will not be loaded.
  655. The caller must free this icon handle by calling DestroyIcon when they
  656. no longer need the icon.
  657. MiniIconIndex - Optionally, supplies a pointer to a variable that will
  658. receive the index of the mini-icon for the specified class. The
  659. mini-icon is stored in the device installer's mini-icon cache.
  660. Return Value:
  661. If the function succeeds, the return value is TRUE.
  662. If the function fails, the return value is FALSE. To get extended error
  663. information, call GetLastError.
  664. Remarks:
  665. The icons of the class are either pre-defined, and loaded from the device
  666. installer's internal cache, or they are loaded directly from the class
  667. installer's executable. This function will query the registry value ICON
  668. in the specified class's section. If this value is specified then it
  669. indicates what mini icon to load. If the icon value is negative the
  670. absolute value represents a predefined icon. See SetupDiDrawMiniIcon for a
  671. list of pre-defined mini icons. If the icon value is positive it
  672. represents an icon in the class installer's executable, and will be
  673. extracted (the number one is reserved). This function also uses the
  674. INSTALLER32 value first and ENUMPROPPAGES32 value second to determine what
  675. executable to extract the icon(s) from.
  676. --*/
  677. {
  678. DWORD Err;
  679. //
  680. // Wrap call in try/except to catch stack overflow
  681. //
  682. try {
  683. Err = pSetupDiLoadClassIcon(ClassGuid,
  684. LargeIcon,
  685. NULL,
  686. MiniIconIndex
  687. );
  688. } except(pSetupExceptionFilter(GetExceptionCode())) {
  689. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  690. }
  691. SetLastError(Err);
  692. return (Err == NO_ERROR);
  693. }
  694. BOOL
  695. WINAPI
  696. SetupDiGetClassBitmapIndex(
  697. IN CONST GUID *ClassGuid, OPTIONAL
  698. OUT PINT MiniIconIndex
  699. )
  700. /*++
  701. Routine Description:
  702. This routine retrieves the index of the mini-icon for the specified class.
  703. Arguments:
  704. ClassGuid - Optionally, supplies the GUID of the class to get the mini-icon
  705. index for. If this parameter is not specified, the index of the 'unknown'
  706. icon is returned.
  707. MiniIconIndex - Supplies a pointer to a variable that receives the index of
  708. the mini-icon for the specified class. This buffer is always filled in,
  709. and receives the index of the unknown mini-icon if there is no mini-icon
  710. for the specified class (i.e., the return value is FALSE).
  711. Return Value:
  712. If there was a mini-icon for the specified class, the return value is TRUE.
  713. If there was not a mini-icon for the specified class, or if no class was
  714. specified, the return value is FALSE (and GetLastError returns
  715. ERROR_NO_DEVICE_CLASS_ICON). In this case, MiniIconIndex will contain the
  716. index of the unknown mini-icon.
  717. --*/
  718. {
  719. BOOL bRet = FALSE; // assume not found
  720. int i;
  721. PCLASSICON pci;
  722. DWORD Err;
  723. BOOL MiniIconListLocked = FALSE;
  724. try {
  725. if(ClassGuid) {
  726. //
  727. // First check the built-in list.
  728. //
  729. for(i = 0; !bRet && (i < ARRAYSIZE(MiniIconXlate)); i++) {
  730. if(IsEqualGUID(MiniIconXlate[i].ClassGuid, ClassGuid)) {
  731. *MiniIconIndex = MiniIconXlate[i].MiniBitmapIndex;
  732. bRet = TRUE;
  733. }
  734. }
  735. //
  736. // Next check the "new stuff" list to see if it's there.
  737. //
  738. if(!bRet && LockMiniIconList(&GlobalMiniIconList)) {
  739. MiniIconListLocked = TRUE;
  740. for(pci = GlobalMiniIconList.ClassIconList;
  741. !bRet && pci;
  742. pci = pci->Next) {
  743. if(IsEqualGUID(pci->ClassGuid, ClassGuid)) {
  744. *MiniIconIndex = pci->MiniBitmapIndex;
  745. bRet = TRUE;
  746. }
  747. }
  748. }
  749. }
  750. //
  751. // If no match was found, snag the "unknown" class.
  752. //
  753. if(!bRet) {
  754. *MiniIconIndex = UnknownClassMiniIconIndex;
  755. Err = ERROR_NO_DEVICE_ICON;
  756. } else {
  757. Err = NO_ERROR;
  758. }
  759. } except(pSetupExceptionFilter(GetExceptionCode())) {
  760. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  761. }
  762. if(MiniIconListLocked) {
  763. UnlockMiniIconList(&GlobalMiniIconList);
  764. }
  765. SetLastError(Err);
  766. return bRet;
  767. }
  768. BOOL
  769. CreateMiniIcons(
  770. VOID
  771. )
  772. /*++
  773. Routine Description:
  774. This routine loads the default bitmap of mini-icons and turns it into
  775. the image/mask pair that will be the cornerstone of mini-icon management.
  776. THIS FUNCTION ASSUMES THE MINI-ICON LOCK HAS ALREADY BEEN ACQUIRED!
  777. Arguments:
  778. None.
  779. Return Value:
  780. If the function succeeds, the return value is TRUE, otherwise it is FALSE.
  781. --*/
  782. {
  783. HDC hdc = NULL;
  784. HDC hdcMem = NULL;
  785. HBITMAP hbmOld = NULL;
  786. BITMAP bm;
  787. BOOL bRet = FALSE; // assume failure
  788. if(GlobalMiniIconList.hdcMiniMem) {
  789. //
  790. // Then the mini-icon list has already been built, so
  791. // return success.
  792. //
  793. return TRUE;
  794. }
  795. try {
  796. hdc = GetDC(NULL);
  797. if(!hdc) {
  798. leave;
  799. }
  800. GlobalMiniIconList.hdcMiniMem = CreateCompatibleDC(hdc);
  801. if(!GlobalMiniIconList.hdcMiniMem) {
  802. leave;
  803. }
  804. hdcMem = CreateCompatibleDC(GlobalMiniIconList.hdcMiniMem);
  805. if(!hdcMem) {
  806. leave;
  807. }
  808. if(!(GlobalMiniIconList.hbmMiniImage = LoadBitmap(MyDllModuleHandle,
  809. MAKEINTRESOURCE(BMP_DRIVERTYPES)))) {
  810. leave;
  811. }
  812. GetObject(GlobalMiniIconList.hbmMiniImage, sizeof(bm), &bm);
  813. if(!(GlobalMiniIconList.hbmMiniMask = CreateBitmap(bm.bmWidth,
  814. bm.bmHeight,
  815. 1,
  816. 1,
  817. NULL))) {
  818. leave;
  819. }
  820. hbmOld = SelectObject(hdcMem, GlobalMiniIconList.hbmMiniImage);
  821. if(!hbmOld) {
  822. leave;
  823. }
  824. SelectObject(GlobalMiniIconList.hdcMiniMem,
  825. GlobalMiniIconList.hbmMiniMask
  826. );
  827. //
  828. // make the mask. white where transparent, black where opaque
  829. //
  830. SetBkColor(hdcMem, RGB_TRANSPARENT);
  831. BitBlt(GlobalMiniIconList.hdcMiniMem,
  832. 0,
  833. 0,
  834. bm.bmWidth,
  835. bm.bmHeight,
  836. hdcMem,
  837. 0,
  838. 0,
  839. SRCCOPY
  840. );
  841. //
  842. // black-out all of the transparent parts of the image, in preparation
  843. // for drawing.
  844. //
  845. SetBkColor(hdcMem, RGB_BLACK);
  846. SetTextColor(hdcMem, RGB_WHITE);
  847. BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, GlobalMiniIconList.hdcMiniMem, 0, 0, SRCAND);
  848. SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
  849. GlobalMiniIconList.NumClassImages = bm.bmWidth/MINIX;
  850. bRet = TRUE;
  851. } except(pSetupExceptionFilter(GetExceptionCode())) {
  852. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  853. bRet = FALSE;
  854. }
  855. if(hdc) {
  856. ReleaseDC(NULL, hdc);
  857. }
  858. if(hdcMem) {
  859. if(hbmOld) {
  860. SelectObject(hdcMem, hbmOld);
  861. }
  862. DeleteObject(hdcMem);
  863. }
  864. //
  865. // If failure, clean up anything we might have built
  866. //
  867. if(!bRet) {
  868. DestroyMiniIcons();
  869. }
  870. return bRet;
  871. }
  872. INT
  873. NewMiniIcon(
  874. IN CONST GUID *ClassGuid,
  875. IN HICON hIcon OPTIONAL
  876. )
  877. /*++
  878. Routine Description:
  879. It's a new class, and we have a mini-icon for it, so let's add it
  880. to the mini-icon database. First pull out the image and mask
  881. bitmaps. Then add these to the mini-icon bitmap. If this all
  882. works, add the new class to the list
  883. THIS FUNCTION ASSUMES THE MINI-ICON LOCK HAS ALREADY BEEN ACQUIRED!
  884. Arguments:
  885. ClassGuid - Supplies a pointer to the class GUID for this mini-icon.
  886. hIcon - Optionally, supplies a handle to the mini-icon to be added to
  887. the database. If this parameter is not specified, then the index
  888. for the "unknown class" icon will be returned.
  889. Return Value:
  890. Index for class (set to "unknown class" if error)
  891. --*/
  892. {
  893. INT iBitmap = -1;
  894. ICONINFO ii;
  895. PCLASSICON pci = NULL;
  896. if(hIcon && GetIconInfo(hIcon, &ii)) {
  897. try {
  898. if((iBitmap = pSetupAddMiniIconToList(ii.hbmColor, ii.hbmMask)) != -1) {
  899. //
  900. // Allocate an extra GUID's worth of memory, so we can store
  901. // the class GUID in the same chunk of memory as the CLASSICON
  902. // node.
  903. //
  904. if(pci = (PCLASSICON)MyMalloc(sizeof(CLASSICON) + sizeof(GUID))) {
  905. CopyMemory((PBYTE)pci + sizeof(CLASSICON),
  906. ClassGuid,
  907. sizeof(GUID)
  908. );
  909. pci->ClassGuid = (LPGUID)((PBYTE)pci + sizeof(CLASSICON));
  910. pci->MiniBitmapIndex = iBitmap;
  911. pci->Next = GlobalMiniIconList.ClassIconList;
  912. GlobalMiniIconList.ClassIconList = pci;
  913. }
  914. }
  915. } except(pSetupExceptionFilter(GetExceptionCode())) {
  916. pSetupExceptionHandler(GetExceptionCode(),
  917. ERROR_INVALID_PARAMETER,
  918. NULL
  919. );
  920. if(pci) {
  921. MyFree(pci);
  922. }
  923. iBitmap = -1;
  924. }
  925. DeleteObject(ii.hbmColor);
  926. DeleteObject(ii.hbmMask);
  927. }
  928. if(iBitmap == -1) {
  929. SetupDiGetClassBitmapIndex(NULL, &iBitmap);
  930. }
  931. return iBitmap;
  932. }
  933. INT
  934. pSetupAddMiniIconToList(
  935. IN HBITMAP hbmImage,
  936. IN HBITMAP hbmMask
  937. )
  938. /*++
  939. Routine Description:
  940. Given the image and mask bitmaps of a mini-icon, add these to the
  941. mini-icon bitmap.
  942. THIS FUNCTION ASSUMES THE MINI-ICON LOCK HAS ALREADY BEEN ACQUIRED!
  943. Arguments:
  944. hbmImage - Supplies the handle of the bitmap for the mini-icon.
  945. hbmMask - Supplies the handle of the bitmap for the mini-icon's mask.
  946. Return Value:
  947. If success, returns the index of the added mini-icon.
  948. If failure, returns -1.
  949. --*/
  950. {
  951. HBITMAP hbmNewImage = NULL, hbmNewMask = NULL;
  952. HBITMAP hbmOld;
  953. HDC hdcMem = NULL;
  954. BITMAP bm;
  955. BOOL bSelectOldBitmap = FALSE;
  956. INT iIcon = -1; // assume failure
  957. if(!CreateMiniIcons()) {
  958. return iIcon;
  959. }
  960. MYASSERT(GlobalMiniIconList.hdcMiniMem);
  961. try {
  962. hdcMem = CreateCompatibleDC(GlobalMiniIconList.hdcMiniMem);
  963. if(!hdcMem) {
  964. leave;
  965. }
  966. //
  967. // Create a New global Bitmap for the minis
  968. //
  969. hbmOld = SelectObject(GlobalMiniIconList.hdcMiniMem,
  970. GlobalMiniIconList.hbmMiniImage
  971. );
  972. bSelectOldBitmap = TRUE;
  973. if(!(hbmNewImage = CreateCompatibleBitmap(
  974. GlobalMiniIconList.hdcMiniMem,
  975. MINIX * (GlobalMiniIconList.NumClassImages + 1),
  976. MINIY))) {
  977. leave;
  978. }
  979. //
  980. // Copy the current Mini bitmap
  981. //
  982. SelectObject(hdcMem, hbmNewImage);
  983. BitBlt(hdcMem,
  984. 0,
  985. 0,
  986. MINIX * GlobalMiniIconList.NumClassImages,
  987. MINIY,
  988. GlobalMiniIconList.hdcMiniMem,
  989. 0,
  990. 0,
  991. SRCCOPY
  992. );
  993. //
  994. // Fit the New icon into ours. We need to stretch it to fit correctly.
  995. //
  996. SelectObject(GlobalMiniIconList.hdcMiniMem, hbmImage);
  997. GetObject(hbmImage, sizeof(bm), &bm);
  998. StretchBlt(hdcMem,
  999. MINIX * GlobalMiniIconList.NumClassImages,
  1000. 0,
  1001. MINIX,
  1002. MINIY,
  1003. GlobalMiniIconList.hdcMiniMem,
  1004. 0,
  1005. 0,
  1006. bm.bmWidth,
  1007. bm.bmHeight,
  1008. SRCCOPY
  1009. );
  1010. SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
  1011. bSelectOldBitmap = FALSE;
  1012. //
  1013. // Next, copy the mask.
  1014. //
  1015. hbmOld = SelectObject(GlobalMiniIconList.hdcMiniMem,
  1016. GlobalMiniIconList.hbmMiniMask
  1017. );
  1018. bSelectOldBitmap = TRUE;
  1019. if(!(hbmNewMask = CreateBitmap(MINIX * (GlobalMiniIconList.NumClassImages + 1),
  1020. MINIY,
  1021. 1,
  1022. 1,
  1023. NULL))) {
  1024. leave;
  1025. }
  1026. SelectObject(hdcMem, hbmNewMask);
  1027. BitBlt(hdcMem,
  1028. 0,
  1029. 0,
  1030. MINIX * GlobalMiniIconList.NumClassImages,
  1031. MINIY,
  1032. GlobalMiniIconList.hdcMiniMem,
  1033. 0,
  1034. 0,
  1035. SRCCOPY
  1036. );
  1037. SelectObject(GlobalMiniIconList.hdcMiniMem, hbmMask);
  1038. GetObject(hbmMask, sizeof(bm), &bm);
  1039. StretchBlt(hdcMem,
  1040. MINIX * GlobalMiniIconList.NumClassImages,
  1041. 0,
  1042. MINIX,
  1043. MINIY,
  1044. GlobalMiniIconList.hdcMiniMem,
  1045. 0,
  1046. 0,
  1047. bm.bmWidth,
  1048. bm.bmHeight,
  1049. SRCCOPY
  1050. );
  1051. SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
  1052. bSelectOldBitmap = FALSE;
  1053. //
  1054. // Now that we've successfully constructed new image and mask bitmaps,
  1055. // store those into our mini-icon list.
  1056. //
  1057. DeleteObject(GlobalMiniIconList.hbmMiniImage);
  1058. GlobalMiniIconList.hbmMiniImage = hbmNewImage;
  1059. hbmNewImage = NULL; // so we won't try to delete this later
  1060. DeleteObject(GlobalMiniIconList.hbmMiniMask);
  1061. GlobalMiniIconList.hbmMiniMask = hbmNewMask;
  1062. hbmNewMask = NULL; // so we won't try to delete this later
  1063. iIcon = GlobalMiniIconList.NumClassImages;
  1064. GlobalMiniIconList.NumClassImages++; // one more image in the list
  1065. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1066. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  1067. iIcon = -1;
  1068. }
  1069. if(bSelectOldBitmap) {
  1070. SelectObject(GlobalMiniIconList.hdcMiniMem, hbmOld);
  1071. }
  1072. if(hbmNewImage) {
  1073. DeleteObject(hbmNewImage);
  1074. }
  1075. if(hbmNewMask) {
  1076. DeleteObject(hbmNewMask);
  1077. }
  1078. if(hdcMem) {
  1079. DeleteDC(hdcMem);
  1080. }
  1081. return iIcon;
  1082. }
  1083. VOID
  1084. DestroyMiniIcons(
  1085. VOID
  1086. )
  1087. /*++
  1088. Routine Description:
  1089. This routine destroys the mini-icon bitmaps, if they exist.
  1090. THIS FUNCTION ASSUMES THE MINI-ICON LOCK HAS ALREADY BEEN ACQUIRED!
  1091. Arguments:
  1092. None.
  1093. Return Value:
  1094. None.
  1095. --*/
  1096. {
  1097. PCLASSICON pci;
  1098. if(GlobalMiniIconList.hdcMiniMem) {
  1099. DeleteDC(GlobalMiniIconList.hdcMiniMem);
  1100. GlobalMiniIconList.hdcMiniMem = NULL;
  1101. }
  1102. if(GlobalMiniIconList.hbmMiniImage) {
  1103. DeleteObject(GlobalMiniIconList.hbmMiniImage);
  1104. GlobalMiniIconList.hbmMiniImage = NULL;
  1105. }
  1106. if(GlobalMiniIconList.hbmMiniMask) {
  1107. DeleteObject(GlobalMiniIconList.hbmMiniMask);
  1108. GlobalMiniIconList.hbmMiniMask = NULL;
  1109. }
  1110. GlobalMiniIconList.NumClassImages = 0;
  1111. //
  1112. // Free up any additional class icon guys that were created
  1113. //
  1114. while(GlobalMiniIconList.ClassIconList) {
  1115. pci = GlobalMiniIconList.ClassIconList;
  1116. GlobalMiniIconList.ClassIconList = pci->Next;
  1117. MyFree(pci);
  1118. }
  1119. }
  1120. BOOL
  1121. WINAPI
  1122. SetupDiGetClassImageList(
  1123. OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
  1124. )
  1125. /*++
  1126. Routine Description:
  1127. See SetupDiGetClassImageListEx for details.
  1128. --*/
  1129. {
  1130. DWORD Err;
  1131. //
  1132. // Wrap call in try/except to catch stack overflow
  1133. //
  1134. try {
  1135. Err = GLE_FN_CALL(FALSE,
  1136. SetupDiGetClassImageListEx(ClassImageListData,
  1137. NULL,
  1138. NULL)
  1139. );
  1140. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1141. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  1142. }
  1143. SetLastError(Err);
  1144. return (Err == NO_ERROR);
  1145. }
  1146. //
  1147. // ANSI version
  1148. //
  1149. BOOL
  1150. WINAPI
  1151. SetupDiGetClassImageListExA(
  1152. OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
  1153. IN PCSTR MachineName, OPTIONAL
  1154. IN PVOID Reserved
  1155. )
  1156. {
  1157. PCWSTR UnicodeMachineName = NULL;
  1158. DWORD rc;
  1159. try {
  1160. if(MachineName) {
  1161. rc = pSetupCaptureAndConvertAnsiArg(MachineName,
  1162. &UnicodeMachineName
  1163. );
  1164. if(rc != NO_ERROR) {
  1165. leave;
  1166. }
  1167. }
  1168. rc = GLE_FN_CALL(FALSE,
  1169. SetupDiGetClassImageListExW(ClassImageListData,
  1170. UnicodeMachineName,
  1171. Reserved)
  1172. );
  1173. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1174. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &rc);
  1175. }
  1176. if(UnicodeMachineName) {
  1177. MyFree(UnicodeMachineName);
  1178. }
  1179. SetLastError(rc);
  1180. return (rc == NO_ERROR);
  1181. }
  1182. BOOL
  1183. WINAPI
  1184. SetupDiGetClassImageListEx(
  1185. OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
  1186. IN PCTSTR MachineName, OPTIONAL
  1187. IN PVOID Reserved
  1188. )
  1189. /*++
  1190. Routine Description:
  1191. This routine builds an image list containing bitmaps for every installed class,
  1192. and returns a data structure containing the list.
  1193. Arguments:
  1194. ClassImageListData - Supplies the address of a SP_CLASSIMAGELIST_DATA structure
  1195. that will receive information regarding the class list (including a handle
  1196. to the image list). The cbSize field of this structure must be initialized
  1197. with the size of the structure (in bytes) before calling this routine, or the
  1198. API will fail.
  1199. MachineName - Optionally, specifies the name of the remote machine whose installed
  1200. classes are to be used in building the class image list. If this parameter is
  1201. not specified, the local machine is used.
  1202. NOTE: Presently, class-specific icons can only be displayed if the class is
  1203. also present on the local machine. Thus, if the remote machine has
  1204. class x, but class x is not installed locally, then the generic (unknown)
  1205. icon will be returned.
  1206. Reserved - Reserved for future use--must be NULL.
  1207. Return Value:
  1208. If the function succeeds, the return value is TRUE.
  1209. If the function fails, the return value is FALSE. To get extended error
  1210. information, call GetLastError.
  1211. Remarks:
  1212. The image list contained in structure filled in by this API should NOT be
  1213. destroyed by calling ImageList_Destroy. Instead, SetupDiDestroyClassImageList
  1214. should be called, for proper clean-up to occur.
  1215. --*/
  1216. {
  1217. DWORD Err = NO_ERROR;
  1218. int cxMiniIcon, cyMiniIcon;
  1219. int MiniIconIndex = 0, DefaultIndex = 0;
  1220. int GuidCount, i;
  1221. int iIcon, iIndex;
  1222. HDC hDC = NULL, hMemImageDC = NULL;
  1223. HBITMAP hbmMiniImage = NULL, hbmMiniMask = NULL, hbmOldImage = NULL;
  1224. RECT rc;
  1225. CONST GUID *pClassGuid = NULL;
  1226. BOOL bUseBitmap, ComputerClassFound = FALSE;
  1227. HICON hiLargeIcon = NULL, hiSmallIcon = NULL;
  1228. HICON hIcon;
  1229. HBRUSH hOldBrush;
  1230. PCLASSICON pci = NULL;
  1231. PCLASS_IMAGE_LIST ImageData = NULL;
  1232. BOOL DestroyLock = FALSE;
  1233. HIMAGELIST ImageList = NULL;
  1234. DWORD dwLayout = 0;
  1235. UINT ImageListFlags = 0;
  1236. //
  1237. // Make sure the caller didn't pass us anything in the Reserved parameter.
  1238. //
  1239. if(Reserved) {
  1240. SetLastError(ERROR_INVALID_PARAMETER);
  1241. return FALSE;
  1242. }
  1243. try {
  1244. if(ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA)) {
  1245. Err = ERROR_INVALID_USER_BUFFER;
  1246. leave;
  1247. }
  1248. //
  1249. // Allocate and initialize the image list, including setting up the
  1250. // synchronization lock. Destroy it when done.
  1251. //
  1252. if(ImageData = MyMalloc(sizeof(CLASS_IMAGE_LIST))) {
  1253. ZeroMemory(ImageData, sizeof(CLASS_IMAGE_LIST));
  1254. } else {
  1255. Err = ERROR_NOT_ENOUGH_MEMORY;
  1256. leave;
  1257. }
  1258. if(InitializeSynchronizedAccess(&ImageData->Lock)) {
  1259. DestroyLock = TRUE;
  1260. }
  1261. //
  1262. // Build the class image list. Create an Image List with no mask,
  1263. // 1 image, and a growth factor of 1.
  1264. //
  1265. cxMiniIcon = GetSystemMetrics(SM_CXSMICON);
  1266. cyMiniIcon = GetSystemMetrics(SM_CYSMICON);
  1267. ImageListFlags = ILC_MASK;
  1268. //
  1269. // Check which color depth we are running in. Set the ILC_COLOR32
  1270. // imagelist create flag if we are running at greate than 8bit (256)
  1271. // color depth.
  1272. //
  1273. hDC = GetDC(NULL);
  1274. if (hDC) {
  1275. if (GetDeviceCaps(hDC, BITSPIXEL) > 8) {
  1276. ImageListFlags |= ILC_COLOR32;
  1277. }
  1278. ReleaseDC(NULL, hDC);
  1279. hDC = NULL;
  1280. }
  1281. //
  1282. // If we are running on an RTL build then we need to set the ILC_MIRROR
  1283. // flag when calling ImageList_Create to un-mirror the icons. By
  1284. // default the icons are mirrored.
  1285. //
  1286. if (GetProcessDefaultLayout(&dwLayout) &&
  1287. (dwLayout & LAYOUT_RTL)) {
  1288. ImageListFlags |= ILC_MIRROR;
  1289. }
  1290. if(!(ImageList = ImageList_Create(cxMiniIcon,
  1291. cyMiniIcon,
  1292. ImageListFlags,
  1293. 1,
  1294. 1)))
  1295. {
  1296. Err = ERROR_NOT_ENOUGH_MEMORY;
  1297. leave;
  1298. }
  1299. ImageList_SetBkColor(ImageList, GetSysColor(COLOR_WINDOW));
  1300. //
  1301. // Create a DC to draw the mini icons into. This is needed
  1302. // for the system defined Minis
  1303. //
  1304. if(!(hDC = GetDC(HWND_DESKTOP)) ||
  1305. !(hMemImageDC = CreateCompatibleDC(hDC)))
  1306. {
  1307. Err = ERROR_NOT_ENOUGH_MEMORY;
  1308. leave;
  1309. }
  1310. //
  1311. // Create a bitmap to draw the icons on. Defer checking for creation
  1312. // of bitmap until afer freeing DC, so it only has to be done once.
  1313. //
  1314. hbmMiniImage = CreateCompatibleBitmap(hDC, cxMiniIcon, cyMiniIcon);
  1315. hbmMiniMask = CreateCompatibleBitmap(hDC, cxMiniIcon, cyMiniIcon);
  1316. ReleaseDC(HWND_DESKTOP, hDC);
  1317. hDC = NULL;
  1318. //
  1319. // Did the bitmap get created?
  1320. //
  1321. if (!hbmMiniImage || ! hbmMiniMask) {
  1322. Err = ERROR_NOT_ENOUGH_MEMORY;
  1323. leave;
  1324. }
  1325. //
  1326. // Select our bitmap into the memory DC.
  1327. //
  1328. hbmOldImage = SelectObject(hMemImageDC, hbmMiniImage);
  1329. //
  1330. // Prepare to draw the mini icon onto the memory DC
  1331. //
  1332. rc.left = 0;
  1333. rc.top = 0;
  1334. rc.right = cxMiniIcon;
  1335. rc.bottom = cyMiniIcon;
  1336. //
  1337. // Get the Index of the Default mini icon.
  1338. //
  1339. SetupDiGetClassBitmapIndex(NULL, &DefaultIndex);
  1340. //
  1341. // Enumerate all classes, and for each class, draw its bitmap.
  1342. //
  1343. GuidCount = 32; // reasonable sized list to start out with.
  1344. ImageData->ClassGuidList = (LPGUID)MyMalloc(sizeof(GUID) * GuidCount);
  1345. Err = GLE_FN_CALL(FALSE,
  1346. SetupDiBuildClassInfoListEx(0,
  1347. ImageData->ClassGuidList,
  1348. GuidCount,
  1349. &GuidCount,
  1350. MachineName,
  1351. NULL)
  1352. );
  1353. if(Err == ERROR_INSUFFICIENT_BUFFER) {
  1354. //
  1355. // Realloc buffer and try again.
  1356. //
  1357. MyFree(ImageData->ClassGuidList);
  1358. if(!(ImageData->ClassGuidList = MyMalloc(sizeof(GUID) * GuidCount))) {
  1359. Err = ERROR_NOT_ENOUGH_MEMORY;
  1360. leave;
  1361. }
  1362. Err = GLE_FN_CALL(FALSE,
  1363. SetupDiBuildClassInfoListEx(
  1364. 0,
  1365. ImageData->ClassGuidList,
  1366. GuidCount,
  1367. &GuidCount,
  1368. MachineName,
  1369. NULL)
  1370. );
  1371. }
  1372. if(Err != NO_ERROR) {
  1373. leave;
  1374. }
  1375. //
  1376. // Retrieve the icon for each class in the class list.
  1377. //
  1378. for(pClassGuid = ImageData->ClassGuidList, i = 0;
  1379. i < GuidCount;
  1380. pClassGuid++, i++) {
  1381. Err = pSetupDiLoadClassIcon(pClassGuid,
  1382. &hiLargeIcon,
  1383. &hiSmallIcon,
  1384. &MiniIconIndex
  1385. );
  1386. if(Err != NO_ERROR) {
  1387. leave;
  1388. }
  1389. //
  1390. // If the returned Mini Icon index is not the Default one, then
  1391. // we use the MiniBitmap, since it is a pre-defined one in SETUPAPI.
  1392. // If the Mini is not pre-defined, and there is no Class Installer
  1393. // then we use the Mini, since it is a valid default. If there
  1394. // is no Mini, and there is a class installer, then we will use
  1395. // the Class installer's big Icon, and have the Image list crunch
  1396. // it for us.
  1397. //
  1398. bUseBitmap = FALSE;
  1399. if(DefaultIndex != MiniIconIndex) {
  1400. SetupDiDrawMiniIcon(hMemImageDC,
  1401. rc,
  1402. MiniIconIndex,
  1403. DMI_USERECT);
  1404. SelectObject(hMemImageDC, hbmMiniMask);
  1405. SetupDiDrawMiniIcon(hMemImageDC,
  1406. rc,
  1407. MiniIconIndex,
  1408. DMI_MASK | DMI_USERECT);
  1409. bUseBitmap = TRUE;
  1410. }
  1411. //
  1412. // Deselect the bitmap from our DC BEFORE calling ImageList
  1413. // functions.
  1414. //
  1415. SelectObject(hMemImageDC, hbmOldImage);
  1416. //
  1417. // Add the image. Allocate a new PCI.
  1418. //
  1419. if(!(pci = (PCLASSICON)MyMalloc(sizeof(CLASSICON)))) {
  1420. Err = ERROR_NOT_ENOUGH_MEMORY;
  1421. leave;
  1422. }
  1423. if(hiSmallIcon) {
  1424. pci->MiniBitmapIndex = (UINT)ImageList_AddIcon(ImageList, hiSmallIcon);
  1425. } else if(bUseBitmap) {
  1426. pci->MiniBitmapIndex = (UINT)ImageList_Add(ImageList, hbmMiniImage, hbmMiniMask);
  1427. } else {
  1428. pci->MiniBitmapIndex = (UINT)ImageList_AddIcon(ImageList, hiLargeIcon);
  1429. }
  1430. if(hiLargeIcon) {
  1431. DestroyIcon(hiLargeIcon);
  1432. hiLargeIcon = NULL;
  1433. }
  1434. if(hiSmallIcon) {
  1435. DestroyIcon(hiSmallIcon);
  1436. hiSmallIcon = NULL;
  1437. }
  1438. if(pci->MiniBitmapIndex == (UINT)-1) {
  1439. Err = ERROR_NOT_ENOUGH_MEMORY;
  1440. MyFree(pci);
  1441. pci = NULL;
  1442. leave;
  1443. }
  1444. pci->ClassGuid = pClassGuid;
  1445. //
  1446. // Link it in.
  1447. //
  1448. pci->Next = ImageData->ClassIconList;
  1449. ImageData->ClassIconList = pci;
  1450. //
  1451. // Reset pci to NULL so we won't try to free it later.
  1452. //
  1453. pci = NULL;
  1454. //
  1455. // Select our bitmap back for the next ICON.
  1456. //
  1457. SelectObject(hMemImageDC, hbmMiniImage);
  1458. if(IsEqualGUID(pClassGuid, &GUID_DEVCLASS_UNKNOWN)) {
  1459. ImageData->UnknownImageIndex = i;
  1460. }
  1461. //
  1462. // Check to see if we've encountered the computer class. This used
  1463. // to be a special pseudo-class used solely by DevMgr to retrieve
  1464. // the icon for the root of the device tree. Now, we use this class
  1465. // for specifying the 'drivers' for the computer itself (i.e., the
  1466. // HALs and the appropriate versions of files that are different for
  1467. // MP vs. UP.
  1468. //
  1469. // We should encounter this class GUID, but if we don't, then we
  1470. // want to maintain the old behavior of adding this in manually
  1471. // later on.
  1472. //
  1473. if(!ComputerClassFound && IsEqualGUID(pClassGuid, &GUID_DEVCLASS_COMPUTER)) {
  1474. ComputerClassFound = TRUE;
  1475. }
  1476. }
  1477. if(!ComputerClassFound) {
  1478. //
  1479. // Special Case for the Internal Class "Computer"
  1480. //
  1481. if(!(pci = (PCLASSICON)MyMalloc(sizeof(CLASSICON)))) {
  1482. Err = ERROR_NOT_ENOUGH_MEMORY;
  1483. leave;
  1484. }
  1485. pci->ClassGuid = &GUID_DEVCLASS_COMPUTER;
  1486. SelectObject(hMemImageDC, hbmMiniImage);
  1487. hOldBrush = SelectObject(hMemImageDC, GetSysColorBrush(COLOR_WINDOW));
  1488. PatBlt(hMemImageDC, 0, 0, cxMiniIcon, cyMiniIcon, PATCOPY);
  1489. SelectObject(hMemImageDC, hOldBrush);
  1490. SetupDiGetClassBitmapIndex((LPGUID)pci->ClassGuid, &MiniIconIndex);
  1491. SetupDiDrawMiniIcon(hMemImageDC,
  1492. rc,
  1493. MiniIconIndex,
  1494. DMI_USERECT);
  1495. SelectObject(hMemImageDC, hbmMiniMask);
  1496. SetupDiDrawMiniIcon(hMemImageDC,
  1497. rc,
  1498. MiniIconIndex,
  1499. DMI_MASK | DMI_USERECT);
  1500. //
  1501. // Deselect the bitmap from our DC BEFORE calling ImageList
  1502. // functions.
  1503. //
  1504. SelectObject(hMemImageDC, hbmOldImage);
  1505. pci->MiniBitmapIndex = ImageList_Add(ImageList, hbmMiniImage, hbmMiniMask);
  1506. if(pci->MiniBitmapIndex == (UINT)-1) {
  1507. Err = ERROR_NOT_ENOUGH_MEMORY;
  1508. MyFree(pci);
  1509. pci = NULL;
  1510. leave;
  1511. }
  1512. //
  1513. // Link it in.
  1514. //
  1515. pci->Next = ImageData->ClassIconList;
  1516. ImageData->ClassIconList = pci;
  1517. //
  1518. // Reset pci to NULL so we won't try to free it later.
  1519. //
  1520. pci = NULL;
  1521. }
  1522. //
  1523. // Add the Overlay ICONs.
  1524. //
  1525. for(iIcon = IDI_CLASSICON_OVERLAYFIRST;
  1526. iIcon <= IDI_CLASSICON_OVERLAYLAST;
  1527. iIcon++) {
  1528. Err = GLE_FN_CALL(NULL,
  1529. hIcon = LoadIcon(MyDllModuleHandle,
  1530. MAKEINTRESOURCE(iIcon))
  1531. );
  1532. if(Err != NO_ERROR) {
  1533. leave;
  1534. }
  1535. iIndex = ImageList_AddIcon(ImageList, hIcon);
  1536. if(iIndex == -1) {
  1537. Err = ERROR_NOT_ENOUGH_MEMORY;
  1538. leave;
  1539. }
  1540. if(!ImageList_SetOverlayImage(ImageList, iIndex, iIcon - IDI_CLASSICON_OVERLAYFIRST + 1)) {
  1541. Err = ERROR_INVALID_DATA;
  1542. leave;
  1543. }
  1544. }
  1545. //
  1546. // If we get to this point, then we've successfully constructed the entire
  1547. // image list, and associated CLASSICON nodes. Now, store this information
  1548. // in the caller's SP_CLASSIMAGELIST_DATA buffer.
  1549. //
  1550. ClassImageListData->Reserved = (ULONG_PTR)ImageData;
  1551. ClassImageListData->ImageList = ImageList;
  1552. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1553. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_USER_BUFFER, &Err);
  1554. }
  1555. if(hiLargeIcon) {
  1556. DestroyIcon(hiLargeIcon);
  1557. }
  1558. if(hiSmallIcon) {
  1559. DestroyIcon(hiSmallIcon);
  1560. }
  1561. if(pci) {
  1562. MyFree(pci);
  1563. }
  1564. if(hDC) {
  1565. ReleaseDC(HWND_DESKTOP, hDC);
  1566. }
  1567. if(hbmMiniImage) {
  1568. DeleteObject(hbmMiniImage);
  1569. }
  1570. if(hbmMiniMask) {
  1571. DeleteObject(hbmMiniMask);
  1572. }
  1573. if(hMemImageDC) {
  1574. DeleteDC(hMemImageDC);
  1575. }
  1576. if(Err != NO_ERROR) {
  1577. if(ImageData) {
  1578. if(DestroyLock) {
  1579. DestroySynchronizedAccess(&ImageData->Lock);
  1580. }
  1581. if(ImageData->ClassGuidList) {
  1582. MyFree(ImageData->ClassGuidList);
  1583. }
  1584. while(ImageData->ClassIconList) {
  1585. pci = ImageData->ClassIconList;
  1586. ImageData->ClassIconList = pci->Next;
  1587. MyFree(pci);
  1588. }
  1589. MyFree(ImageData);
  1590. }
  1591. if(ImageList) {
  1592. ImageList_Destroy(ImageList);
  1593. }
  1594. }
  1595. SetLastError(Err);
  1596. return (Err == NO_ERROR);
  1597. }
  1598. BOOL
  1599. WINAPI
  1600. SetupDiDestroyClassImageList(
  1601. IN PSP_CLASSIMAGELIST_DATA ClassImageListData
  1602. )
  1603. /*++
  1604. Routine Description:
  1605. This routine destroys a class image list built by a call to
  1606. SetupDiGetClassImageList.
  1607. Arguments:
  1608. ClassImageListData - Supplies the address of a SP_CLASSIMAGELIST_DATA
  1609. structure containing the class image list to be destroyed.
  1610. Return Value:
  1611. If the function succeeds, the return value is TRUE.
  1612. If the function fails, the return value is FALSE. To get extended error
  1613. information, call GetLastError.
  1614. --*/
  1615. {
  1616. DWORD Err = NO_ERROR;
  1617. PCLASS_IMAGE_LIST ImageData = NULL;
  1618. PCLASSICON pci;
  1619. try {
  1620. if(ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA)) {
  1621. Err = ERROR_INVALID_USER_BUFFER;
  1622. leave;
  1623. }
  1624. if (ClassImageListData->Reserved == 0x0) {
  1625. Err = ERROR_INVALID_USER_BUFFER;
  1626. leave;
  1627. }
  1628. ImageData = (PCLASS_IMAGE_LIST)ClassImageListData->Reserved;
  1629. if (!LockImageList(ImageData)) {
  1630. Err = ERROR_CANT_LOAD_CLASS_ICON;
  1631. leave;
  1632. }
  1633. if (ClassImageListData->ImageList) {
  1634. ImageList_Destroy(ClassImageListData->ImageList);
  1635. }
  1636. if (ImageData->ClassGuidList) {
  1637. MyFree(ImageData->ClassGuidList);
  1638. }
  1639. while(ImageData->ClassIconList) {
  1640. pci = ImageData->ClassIconList;
  1641. ImageData->ClassIconList = pci->Next;
  1642. MyFree(pci);
  1643. }
  1644. DestroySynchronizedAccess(&ImageData->Lock);
  1645. MyFree(ImageData);
  1646. ClassImageListData->Reserved = 0;
  1647. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1648. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_USER_BUFFER, &Err);
  1649. }
  1650. SetLastError(Err);
  1651. return (Err == NO_ERROR);
  1652. }
  1653. BOOL
  1654. WINAPI
  1655. SetupDiGetClassImageIndex(
  1656. IN PSP_CLASSIMAGELIST_DATA ClassImageListData,
  1657. IN CONST GUID *ClassGuid,
  1658. OUT PINT ImageIndex
  1659. )
  1660. /*++
  1661. Routine Description:
  1662. This routine retrieves the index within the class image list of a specified
  1663. class.
  1664. Arguments:
  1665. ClassImageListData - Supplies the address of a SP_CLASSIMAGELIST_DATA
  1666. structure containing the specified class's image.
  1667. ClassGuid - Supplies the address of the GUID for the class whose index is
  1668. to be retrieved.
  1669. ImageIndex - Supplies the address of a variable that receives the index of
  1670. the specified class's image within the class image list.
  1671. Return Value:
  1672. If the function succeeds, the return value is TRUE.
  1673. If the function fails, the return value is FALSE. To get extended error
  1674. information, call GetLastError.
  1675. --*/
  1676. {
  1677. DWORD Err = NO_ERROR;
  1678. BOOL bFound = FALSE, bLocked = FALSE;
  1679. PCLASS_IMAGE_LIST ImageData = NULL;
  1680. PCLASSICON pci;
  1681. try {
  1682. if(ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA)) {
  1683. Err = ERROR_INVALID_USER_BUFFER;
  1684. leave;
  1685. }
  1686. if(ClassImageListData->Reserved == 0x0) {
  1687. Err = ERROR_INVALID_USER_BUFFER;
  1688. leave;
  1689. }
  1690. ImageData = (PCLASS_IMAGE_LIST)ClassImageListData->Reserved;
  1691. if(!LockImageList(ImageData)) {
  1692. Err = ERROR_CANT_LOAD_CLASS_ICON;
  1693. leave;
  1694. }
  1695. bLocked = TRUE;
  1696. if(ClassGuid) {
  1697. //
  1698. // check the "new stuff" list to see if it's there
  1699. //
  1700. for(pci = ImageData->ClassIconList;
  1701. !bFound && pci;
  1702. pci = pci->Next) {
  1703. if(IsEqualGUID(pci->ClassGuid, ClassGuid)) {
  1704. *ImageIndex = pci->MiniBitmapIndex;
  1705. bFound = TRUE;
  1706. }
  1707. }
  1708. }
  1709. //
  1710. // if no match was found, snag the "unknown" class
  1711. //
  1712. if(!bFound) {
  1713. *ImageIndex = ImageData->UnknownImageIndex;
  1714. }
  1715. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1716. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_USER_BUFFER, &Err);
  1717. }
  1718. if(bLocked) {
  1719. UnlockImageList(ImageData);
  1720. }
  1721. SetLastError(Err);
  1722. return (Err == NO_ERROR);
  1723. }