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.

1333 lines
44 KiB

  1. #pragma warning( disable: 4103)
  2. #include "mmcpl.h"
  3. #include <cpl.h>
  4. #define NOSTATUSBAR
  5. #include <commctrl.h>
  6. #include <prsht.h>
  7. #include <regstr.h>
  8. #include <infstr.h>
  9. #include <devguid.h>
  10. #include "draw.h"
  11. #include "utils.h"
  12. #include "drivers.h"
  13. #include "sulib.h"
  14. #include "medhelp.h"
  15. #include <tchar.h>
  16. #define GetString(_psz,_id) LoadString(myInstance,(_id),(_psz),sizeof((_psz))/sizeof(TCHAR))
  17. // Global info struct. One instance for the whole dialog
  18. typedef struct _OUR_PROP_PARAMS
  19. {
  20. HDEVINFO DeviceInfoSet;
  21. PSP_DEVINFO_DATA DeviceInfoData;
  22. HKEY hkDrv; // Key to classguid\0000
  23. HKEY hkDrivers; // Key to classguid\0000\Drivers
  24. BOOL bClosing; // Set to TRUE while dialog is closing
  25. TCHAR szSubClasses[256]; // Subclasses to process
  26. } OUR_PROP_PARAMS, *POUR_PROP_PARAMS;
  27. typedef enum
  28. {
  29. NodeTypeRoot,
  30. NodeTypeClass,
  31. NodeTypeDriver
  32. } NODETYPE;
  33. // Tree node. One per node on tree.
  34. typedef struct _DMTREE_NODE;
  35. typedef BOOL (*PFNCONFIG) (HWND ParentHwnd, struct _DMTREE_NODE *pTreeNode);
  36. typedef BOOL (*PFNQUERYCONFIG)(HWND ParentHwnd, struct _DMTREE_NODE *pTreeNode);
  37. typedef struct _DMTREE_NODE
  38. {
  39. NODETYPE NodeType; // Type of node
  40. PFNCONFIG pfnConfig; // Ptr to config function
  41. PFNQUERYCONFIG pfnQueryConfig; // Ptr to query config function
  42. int QueryConfigInfo; // Data for config function
  43. TCHAR szDescription[MAXSTR]; // Node description
  44. TCHAR szDriver[MAXSTR]; // Driver name of this node
  45. WCHAR wszDriver[MAXSTR]; // Wide char driver name
  46. TCHAR szAlias[MAXSTR]; // Alias
  47. WCHAR wszAlias[MAXSTR]; // Wide char alias
  48. DriverClass dc; // Legacy-style driver class, if available
  49. HTREEITEM hti; // For use with MIDI prop sheet callback
  50. } DMTREE_NODE, *PDMTREE_NODE;
  51. INT_PTR APIENTRY DmAdvPropPageDlgProc(IN HWND hDlg,
  52. IN UINT uMessage,
  53. IN WPARAM wParam,
  54. IN LPARAM lParam
  55. );
  56. UINT CALLBACK DmAdvPropPageDlgCallback(HWND hwnd,
  57. UINT uMsg,
  58. LPPROPSHEETPAGE ppsp
  59. );
  60. BOOL DmAdvPropPage_OnCommand(
  61. HWND ParentHwnd,
  62. int ControlId,
  63. HWND ControlHwnd,
  64. UINT NotifyCode
  65. );
  66. BOOL DmAdvPropPage_OnContextMenu(
  67. HWND HwndControl,
  68. WORD Xpos,
  69. WORD Ypos
  70. );
  71. BOOL DmAdvPropPage_OnHelp(
  72. HWND ParentHwnd,
  73. LPHELPINFO HelpInfo
  74. );
  75. BOOL DmAdvPropPage_OnInitDialog(
  76. HWND ParentHwnd,
  77. HWND FocusHwnd,
  78. LPARAM Lparam
  79. );
  80. BOOL DmAdvPropPage_OnNotify(
  81. HWND ParentHwnd,
  82. LPNMHDR NmHdr
  83. );
  84. void DmAdvPropPage_OnPropertiesClicked(
  85. HWND ParentHwnd,
  86. POUR_PROP_PARAMS Params
  87. );
  88. BOOL DmOverrideResourcesPage(LPVOID Info,
  89. LPFNADDPROPSHEETPAGE AddFunc,
  90. LPARAM Lparam,
  91. POUR_PROP_PARAMS Params
  92. );
  93. BOOL AddCDROMPropertyPage( HDEVINFO hDeviceInfoSet,
  94. PSP_DEVINFO_DATA pDeviceInfoData,
  95. LPFNADDPROPSHEETPAGE AddFunc,
  96. LPARAM Lparam
  97. );
  98. BOOL AddSpecialPropertyPage( DWORD SpecialDriverType,
  99. LPFNADDPROPSHEETPAGE AddFunc,
  100. LPARAM Lparam
  101. );
  102. BOOL DmInitDeviceTree(HWND hwndTree, POUR_PROP_PARAMS Params);
  103. BOOL DmAdvPropPage_OnDestroy(
  104. HWND ParentHwnd,
  105. LPNMHDR NmHdr
  106. );
  107. void DoProperties(HWND ParentHwnd, HWND hWndI, HTREEITEM htiCur);
  108. BOOL QueryConfigDriver(HWND ParentHwnd, PDMTREE_NODE pTreeNode)
  109. {
  110. HANDLE hDriver;
  111. if (pTreeNode->NodeType!=NodeTypeDriver)
  112. {
  113. return FALSE;
  114. }
  115. if (pTreeNode->QueryConfigInfo==0) // if 0, the we haven't checked yet
  116. {
  117. INT_PTR IsConfigurable;
  118. // open the driver
  119. hDriver = OpenDriver(pTreeNode->wszDriver, NULL, 0L);
  120. if (!hDriver)
  121. {
  122. return FALSE;
  123. }
  124. // Send the DRV_CONFIGURE message to the driver
  125. IsConfigurable = SendDriverMessage(hDriver,
  126. DRV_QUERYCONFIGURE,
  127. 0L,
  128. 0L);
  129. CloseDriver(hDriver, 0L, 0L);
  130. // 1->Is configurable, -1->Not configurable
  131. pTreeNode->QueryConfigInfo = IsConfigurable ? 1 : -1;
  132. }
  133. return (pTreeNode->QueryConfigInfo>0);
  134. }
  135. BOOL PNPDriverToIResource(PDMTREE_NODE pTreeNode, IRESOURCE* pir)
  136. {
  137. IDRIVER tempIDriver;
  138. if ((pir->pcn = (PCLASSNODE)LocalAlloc (LPTR, sizeof(CLASSNODE))) == NULL)
  139. {
  140. return FALSE;
  141. }
  142. if (!DriverClassToClassNode(pir->pcn, pTreeNode->dc))
  143. {
  144. LocalFree ((HANDLE)pir->pcn);
  145. return FALSE;
  146. }
  147. pir->iNode = 2; // 1=class, 2=device, 3=acm, 4=instmt
  148. lstrcpy (pir->szFriendlyName, pTreeNode->szDescription);
  149. lstrcpy (pir->szDesc, pTreeNode->szDescription);
  150. lstrcpy (pir->szFile, pTreeNode->szDriver);
  151. lstrcpy (pir->szDrvEntry, pTreeNode->szAlias);
  152. lstrcpy (pir->szClass, pir->pcn->szClass);
  153. pir->fQueryable = (short)QueryConfigDriver(NULL, pTreeNode);
  154. pir->iClassID = (short)DriverClassToOldClassID(pTreeNode->dc);
  155. pir->szParam[0] = 0;
  156. pir->dnDevNode = 0;
  157. pir->hDriver = NULL;
  158. // Find fStatus, which despite its name is really a series of
  159. // flags--in Win95 it's composed of DEV_* flags (from the old
  160. // mmcpl.h), but those are tied with PNP. Here, we use the
  161. // dwStatus* flags:
  162. //
  163. ZeroMemory(&tempIDriver,sizeof(IDRIVER));
  164. lstrcpy(tempIDriver.wszAlias,pTreeNode->wszAlias);
  165. lstrcpy(tempIDriver.szAlias,pTreeNode->szAlias);
  166. lstrcpy(tempIDriver.wszFile,pTreeNode->wszDriver);
  167. lstrcpy(tempIDriver.szFile,pTreeNode->szDriver);
  168. lstrcpy(tempIDriver.szDesc,pTreeNode->szDescription);
  169. lstrcpy(tempIDriver.szSection,wcsstr(pTreeNode->szDescription, TEXT("MCI")) ? szMCI : szDrivers);
  170. lstrcpy(tempIDriver.wszSection,wcsstr(pTreeNode->szDescription, TEXT("MCI")) ? szMCI : szDrivers);
  171. pir->fStatus = (int)GetDriverStatus (&tempIDriver);
  172. return TRUE;
  173. }
  174. BOOL ConfigDriver(HWND ParentHwnd, PDMTREE_NODE pTreeNode)
  175. {
  176. //need to pop up the legacy properties dialog
  177. IRESOURCE ir;
  178. DEVTREENODE dtn;
  179. TCHAR szTab[ cchRESOURCE ];
  180. if ((pTreeNode->NodeType == NodeTypeDriver) && (pTreeNode->dc != dcINVALID))
  181. {
  182. if (PNPDriverToIResource(pTreeNode, &ir))
  183. {
  184. GetString (szTab, IDS_GENERAL);
  185. dtn.lParam = (LPARAM)&ir;
  186. dtn.hwndTree = ParentHwnd;
  187. //must call this function twice to fill in the array of PIDRIVERs in drivers.c
  188. //otherwise, many of the "settings" calls won't work
  189. InitInstalled (GetParent (ParentHwnd), szDrivers);
  190. InitInstalled (GetParent (ParentHwnd), szMCI);
  191. switch (pTreeNode->dc)
  192. {
  193. case dcMIDI :
  194. ShowWithMidiDevPropSheet (szTab,
  195. DevPropDlg,
  196. DLG_DEV_PROP,
  197. ParentHwnd,
  198. pTreeNode->szDescription,
  199. pTreeNode->hti,
  200. (LPARAM)&dtn,
  201. (LPARAM)&ir,
  202. (LPARAM)ParentHwnd);
  203. break;
  204. case dcWAVE :
  205. ShowPropSheet (szTab,
  206. DevPropDlg,
  207. DLG_WAVDEV_PROP,
  208. ParentHwnd,
  209. pTreeNode->szDescription,
  210. (LPARAM)&dtn);
  211. break;
  212. default:
  213. ShowPropSheet (szTab,
  214. DevPropDlg,
  215. DLG_DEV_PROP,
  216. ParentHwnd,
  217. pTreeNode->szDescription,
  218. (LPARAM)&dtn);
  219. break;
  220. } //end switch
  221. FreeIResource (&ir);
  222. }
  223. }
  224. return (FALSE);
  225. }
  226. const static DWORD aDMPropHelpIds[] = { // Context Help IDs
  227. IDC_ADV_TREE, IDH_GENERIC_DEVICES,
  228. ID_ADV_PROP, IDH_ADV_PROPERTIES,
  229. 0, 0
  230. };
  231. //******************************************************************************
  232. //* Subtype code
  233. //******************************************************************************
  234. //
  235. // Subtype info. Array of one per device class subtype
  236. typedef struct _SUBTYPE_INFO
  237. {
  238. TCHAR *szClass;
  239. DWORD DescId;
  240. DWORD IconId;
  241. PFNCONFIG pfnConfig;
  242. PFNQUERYCONFIG pfnQueryConfig;
  243. DriverClass dc;
  244. TCHAR szDescription[64];
  245. DWORD IconIndex;
  246. } SUBTYPE_INFO;
  247. static SUBTYPE_INFO SubtypeInfo[] =
  248. {
  249. { TEXT(""), IDS_MM_HEADER, IDI_MMICON, ConfigDriver, QueryConfigDriver, dcOTHER},
  250. { TEXT("waveaudio"), IDS_MCI_HEADER, IDI_MCI, ConfigDriver, QueryConfigDriver, dcMCI},
  251. { TEXT("wavemap"), IDS_WAVE_HEADER, IDI_WAVE, ConfigDriver, QueryConfigDriver, dcWAVE},
  252. { TEXT("wave"), IDS_WAVE_HEADER, IDI_WAVE, ConfigDriver, QueryConfigDriver, dcWAVE},
  253. { TEXT("vids"), IDS_ICM_HEADER, IDI_ICM, ConfigDriver, QueryConfigDriver, dcVCODEC},
  254. { TEXT("vidc"), IDS_ICM_HEADER, IDI_ICM, ConfigDriver, QueryConfigDriver, dcVCODEC},
  255. { TEXT("sequencer"), IDS_MCI_HEADER, IDI_MCI, ConfigDriver, QueryConfigDriver, dcMCI},
  256. { TEXT("msvideo"), IDS_VIDCAP_HEADER, IDI_VIDEO, ConfigDriver, QueryConfigDriver, dcVIDCAP},
  257. { TEXT("msacm"), IDS_ACM_HEADER, IDI_ACM, ConfigDriver, QueryConfigDriver, dcACODEC},
  258. { TEXT("mpegvideo"), IDS_MCI_HEADER, IDI_MCI, ConfigDriver, QueryConfigDriver, dcMCI},
  259. { TEXT("mixer"), IDS_MIXER_HEADER, IDI_MIXER, ConfigDriver, QueryConfigDriver, dcMIXER},
  260. { TEXT("midimapper"), IDS_MIDI_HEADER, IDI_MIDI, ConfigDriver, QueryConfigDriver, dcMIDI},
  261. { TEXT("midi"), IDS_MIDI_HEADER, IDI_MIDI, ConfigDriver, QueryConfigDriver, dcMIDI},
  262. { TEXT("mci"), IDS_MCI_HEADER, IDI_MCI, ConfigDriver, QueryConfigDriver, dcMCI},
  263. { TEXT("icm"), IDS_ICM_HEADER, IDI_ICM, ConfigDriver, QueryConfigDriver, dcVCODEC},
  264. { TEXT("cdaudio"), IDS_MCI_HEADER, IDI_MCI, ConfigDriver, QueryConfigDriver, dcMCI},
  265. { TEXT("avivideo"), IDS_MCI_HEADER, IDI_MCI, ConfigDriver, QueryConfigDriver, dcMCI},
  266. { TEXT("aux"), IDS_AUX_HEADER, IDI_AUX, ConfigDriver, QueryConfigDriver, dcAUX},
  267. { TEXT("acm"), IDS_ACM_HEADER, IDI_ACM, ConfigDriver, QueryConfigDriver, dcACODEC},
  268. { TEXT("joy"), IDS_JOYSTICK_HEADER, IDI_JOYSTICK, ConfigDriver, QueryConfigDriver, dcJOY}
  269. };
  270. #define SUBTYPE_INFO_SIZE (sizeof(SubtypeInfo)/sizeof(SUBTYPE_INFO))
  271. BOOL LoadSubtypeInfo(HWND hwndTree)
  272. {
  273. UINT i;
  274. UINT uFlags;
  275. int cxMiniIcon;
  276. int cyMiniIcon;
  277. DWORD dwLayout;
  278. HIMAGELIST hImagelist;
  279. // Create the image list
  280. cxMiniIcon = (int)GetSystemMetrics(SM_CXSMICON);
  281. cyMiniIcon = (int)GetSystemMetrics(SM_CYSMICON);
  282. uFlags = ILC_MASK | ILC_COLOR32;
  283. if (GetProcessDefaultLayout(&dwLayout) &&
  284. (dwLayout & LAYOUT_RTL))
  285. {
  286. uFlags |= ILC_MIRROR;
  287. }
  288. hImagelist = ImageList_Create(cxMiniIcon, cyMiniIcon, uFlags, SUBTYPE_INFO_SIZE, 4);
  289. if (!hImagelist)
  290. return FALSE;
  291. for (i=0;i<SUBTYPE_INFO_SIZE;i++)
  292. {
  293. HICON hIcon;
  294. // Load the description
  295. LoadString(ghInstance, SubtypeInfo[i].DescId, SubtypeInfo[i].szDescription, 64);
  296. // Load the image into the image list
  297. hIcon = LoadImage (ghInstance,
  298. MAKEINTRESOURCE( SubtypeInfo[i].IconId ),
  299. IMAGE_ICON,
  300. cxMiniIcon,
  301. cyMiniIcon,
  302. LR_DEFAULTCOLOR);
  303. if (hIcon) // PREFIX 160723
  304. {
  305. SubtypeInfo[i].IconIndex = ImageList_AddIcon(hImagelist, hIcon);
  306. DestroyIcon(hIcon);
  307. }
  308. else
  309. {
  310. SubtypeInfo[i].IconIndex = -1;
  311. }
  312. }
  313. // Clean out and initialize tree control
  314. TreeView_SetImageList(hwndTree, hImagelist, TVSIL_NORMAL);
  315. return TRUE;
  316. }
  317. SUBTYPE_INFO *GetSubtypeInfo(TCHAR *pszClass)
  318. {
  319. UINT iClass;
  320. if (pszClass)
  321. {
  322. for (iClass=0;iClass<SUBTYPE_INFO_SIZE;iClass++)
  323. {
  324. if (!lstrcmpi(pszClass,SubtypeInfo[iClass].szClass))
  325. return &SubtypeInfo[iClass];
  326. }
  327. }
  328. return &SubtypeInfo[0];
  329. }
  330. //******************************************************************************
  331. /*
  332. Routine Description: MediaPropPageProvider
  333. Entry-point for adding additional device manager property
  334. sheet pages. Registry specifies this routine under
  335. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E96C-E325-11CE-BFC1-08002BE10318}
  336. EnumPropPage32="mmsys.cpl,thisproc"
  337. This entry-point gets called only when the DeviceManager asks for additional property pages.
  338. Arguments:
  339. Info - points to PROPSHEETPAGE_REQUEST, see setupapi.h
  340. AddFunc - function ptr to call to add sheet.
  341. Lparam - add sheet functions private data handle.
  342. Return Value:
  343. BOOL: FALSE if pages could not be added, TRUE on success
  344. */
  345. BOOL APIENTRY MediaPropPageProvider(LPVOID Info,
  346. LPFNADDPROPSHEETPAGE AddFunc,
  347. LPARAM Lparam
  348. )
  349. {
  350. PSP_PROPSHEETPAGE_REQUEST pprPropPageRequest;
  351. PROPSHEETPAGE psp;
  352. HPROPSHEETPAGE hpsp;
  353. POUR_PROP_PARAMS Params;
  354. HDEVINFO DeviceInfoSet;
  355. PSP_DEVINFO_DATA DeviceInfoData;
  356. DWORD SpecialDriverType;
  357. HKEY hkDrv;
  358. HKEY hkDrivers;
  359. DWORD cbLen;
  360. pprPropPageRequest = (PSP_PROPSHEETPAGE_REQUEST) Info;
  361. if (pprPropPageRequest->PageRequested != SPPSR_ENUM_ADV_DEVICE_PROPERTIES)
  362. {
  363. return TRUE;
  364. }
  365. DeviceInfoSet = pprPropPageRequest->DeviceInfoSet;
  366. DeviceInfoData = pprPropPageRequest->DeviceInfoData;
  367. // This API is called for both devices and the class as a whole
  368. // (when someone right-clicks on the class and chooses properties).
  369. // In the class case the DeviceInfoData field of the propPageRequest structure is NULL.
  370. // We don't do anything in that case, so just return.
  371. if (!DeviceInfoData)
  372. {
  373. return TRUE;
  374. }
  375. SpecialDriverType = IsSpecialDriver(DeviceInfoSet, DeviceInfoData);
  376. if (SpecialDriverType)
  377. {
  378. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  379. DeviceInstallParams.cbSize = sizeof(DeviceInstallParams);
  380. SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams);
  381. DeviceInstallParams.Flags |= DI_RESOURCEPAGE_ADDED | DI_DRIVERPAGE_ADDED; // | DI_GENERALPAGE_ADDED;
  382. SetupDiSetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams);
  383. AddSpecialPropertyPage(SpecialDriverType, AddFunc, Lparam);
  384. return TRUE;
  385. }
  386. if (AddCDROMPropertyPage(DeviceInfoSet,DeviceInfoData, AddFunc, Lparam))
  387. {
  388. return TRUE;
  389. }
  390. // Open device reg key to see if this is a WDM driver
  391. hkDrv = SetupDiOpenDevRegKey(DeviceInfoSet,
  392. DeviceInfoData,
  393. DICS_FLAG_GLOBAL,
  394. 0,
  395. DIREG_DRV,
  396. KEY_ALL_ACCESS);
  397. if (!hkDrv)
  398. return FALSE;
  399. // Allocate and zero out memory for the struct that will contain page specific data
  400. Params = (POUR_PROP_PARAMS)LocalAlloc(LPTR, sizeof(OUR_PROP_PARAMS));
  401. if (!Params)
  402. {
  403. RegCloseKey(hkDrv);
  404. return FALSE;
  405. }
  406. // Initialize Params structure
  407. Params->DeviceInfoSet = DeviceInfoSet;
  408. Params->DeviceInfoData = DeviceInfoData;
  409. Params->hkDrv = hkDrv;
  410. // Override Resource page if this is not a WDM (PNP) driver
  411. DmOverrideResourcesPage(Info, AddFunc, Lparam, Params);
  412. // Try a couple of things to see if there are actually any drivers under this key
  413. // and cache the results
  414. // Try to open up the Drivers subkey
  415. if (RegOpenKey(Params->hkDrv, TEXT("Drivers"), &hkDrivers))
  416. {
  417. RegCloseKey(hkDrv);
  418. LocalFree(Params);
  419. return TRUE;
  420. }
  421. // Try to read the SubClasses key to determine which subclasses to process
  422. cbLen=sizeof(Params->szSubClasses);
  423. if (RegQueryValueEx(hkDrivers, TEXT("Subclasses"), NULL, NULL, (LPBYTE)Params->szSubClasses, &cbLen))
  424. {
  425. RegCloseKey(hkDrv);
  426. RegCloseKey(hkDrivers);
  427. LocalFree(Params);
  428. return TRUE;
  429. }
  430. Params->hkDrivers = hkDrivers;
  431. // Initialize the property sheet page
  432. psp.dwSize = sizeof(PROPSHEETPAGE);
  433. psp.dwFlags = PSP_USECALLBACK; // | PSP_HASHELP;
  434. psp.hInstance = ghInstance;
  435. psp.pszTemplate = MAKEINTRESOURCE(DLG_DM_ADVDLG);
  436. psp.pfnDlgProc = DmAdvPropPageDlgProc; // dlg window proc
  437. psp.lParam = (LPARAM) Params;
  438. psp.pfnCallback = DmAdvPropPageDlgCallback; // control callback of the dlg window proc
  439. // Create the page & get back a handle
  440. hpsp = CreatePropertySheetPage(&psp);
  441. if (!hpsp)
  442. {
  443. RegCloseKey(hkDrv);
  444. LocalFree(Params);
  445. return FALSE;
  446. }
  447. // Add the property page
  448. if (!(*AddFunc)(hpsp, Lparam))
  449. {
  450. DestroyPropertySheetPage(hpsp);
  451. return FALSE;
  452. }
  453. return TRUE;
  454. } /* DmAdvPropPageProvider */
  455. UINT CALLBACK DmAdvPropPageDlgCallback(HWND hwnd,
  456. UINT uMsg,
  457. LPPROPSHEETPAGE ppsp)
  458. {
  459. POUR_PROP_PARAMS Params;
  460. switch (uMsg)
  461. {
  462. case PSPCB_CREATE: // This gets called when the page is created
  463. return TRUE; // return TRUE to continue with creation of page
  464. case PSPCB_RELEASE: // This gets called when the page is destroyed
  465. Params = (POUR_PROP_PARAMS) ppsp->lParam;
  466. RegCloseKey(Params->hkDrv);
  467. RegCloseKey(Params->hkDrivers);
  468. LocalFree(Params); // Free our local params
  469. return 0; // return value ignored
  470. default:
  471. break;
  472. }
  473. return TRUE;
  474. }
  475. /*++
  476. Routine Description: DmAdvPropPageDlgProc
  477. The windows control function for the Port Settings properties window
  478. Arguments:
  479. hDlg, uMessage, wParam, lParam: standard windows DlgProc parameters
  480. Return Value:
  481. BOOL: FALSE if function fails, TRUE if function passes
  482. --*/
  483. INT_PTR APIENTRY DmAdvPropPageDlgProc(IN HWND hDlg,
  484. IN UINT uMessage,
  485. IN WPARAM wParam,
  486. IN LPARAM lParam)
  487. {
  488. switch (uMessage)
  489. {
  490. case WM_COMMAND:
  491. return DmAdvPropPage_OnCommand(hDlg, (int) LOWORD(wParam), (HWND)lParam, (UINT)HIWORD(wParam));
  492. case WM_CONTEXTMENU:
  493. return DmAdvPropPage_OnContextMenu((HWND)wParam, LOWORD(lParam), HIWORD(lParam));
  494. case WM_HELP:
  495. return DmAdvPropPage_OnHelp(hDlg, (LPHELPINFO) lParam);
  496. case WM_INITDIALOG:
  497. return DmAdvPropPage_OnInitDialog(hDlg, (HWND)wParam, lParam);
  498. case WM_NOTIFY:
  499. return DmAdvPropPage_OnNotify(hDlg, (NMHDR *)lParam);
  500. case WM_DESTROY:
  501. return DmAdvPropPage_OnDestroy(hDlg, (NMHDR *)lParam);
  502. }
  503. return FALSE;
  504. } /* DmAdvPropPageDlgProc */
  505. BOOL DmAdvPropPage_OnCommand(
  506. HWND ParentHwnd,
  507. int ControlId,
  508. HWND ControlHwnd,
  509. UINT NotifyCode
  510. )
  511. {
  512. POUR_PROP_PARAMS params =
  513. (POUR_PROP_PARAMS) GetWindowLongPtr(ParentHwnd, DWLP_USER);
  514. switch (ControlId)
  515. {
  516. case ID_ADV_PROP:
  517. DmAdvPropPage_OnPropertiesClicked(ParentHwnd, params);
  518. break;
  519. }
  520. return FALSE;
  521. }
  522. BOOL DmAdvPropPage_OnContextMenu(
  523. HWND HwndControl,
  524. WORD Xpos,
  525. WORD Ypos
  526. )
  527. {
  528. WinHelp(HwndControl,
  529. gszWindowsHlp,
  530. HELP_CONTEXTMENU,
  531. (ULONG_PTR) aDMPropHelpIds);
  532. return FALSE;
  533. }
  534. BOOL DmAdvPropPage_OnHelp(
  535. HWND ParentHwnd,
  536. LPHELPINFO HelpInfo
  537. )
  538. {
  539. if (HelpInfo->iContextType == HELPINFO_WINDOW)
  540. {
  541. WinHelp((HWND) HelpInfo->hItemHandle,
  542. gszWindowsHlp,
  543. HELP_WM_HELP,
  544. (ULONG_PTR) aDMPropHelpIds);
  545. }
  546. return FALSE;
  547. }
  548. BOOL DmAdvPropPage_OnInitDialog(
  549. HWND ParentHwnd,
  550. HWND FocusHwnd,
  551. LPARAM Lparam
  552. )
  553. {
  554. HWND hwndTree;
  555. POUR_PROP_PARAMS Params;
  556. HCURSOR hCursor;
  557. BOOL bSuccess;
  558. // on WM_INITDIALOG call, lParam points to the property sheet page.
  559. //
  560. // The lParam field in the property sheet page struct is set by the
  561. // caller. When I created the property sheet, I passed in a pointer
  562. // to a struct containing information about the device. Save this in
  563. // the user window long so I can access it on later messages.
  564. Params = (POUR_PROP_PARAMS) ((LPPROPSHEETPAGE)Lparam)->lParam;
  565. SetWindowLongPtr(ParentHwnd, DWLP_USER, (ULONG_PTR) Params);
  566. // Put up the wait cursor
  567. hCursor = SetCursor(LoadCursor(NULL,IDC_WAIT));
  568. //create the device tree.
  569. hwndTree = GetDlgItem(ParentHwnd, IDC_ADV_TREE);
  570. // Initialize the tree
  571. bSuccess = DmInitDeviceTree(hwndTree, Params);
  572. // Enable the adv properties button
  573. EnableWindow(GetDlgItem(ParentHwnd, ID_ADV_PROP), TRUE);
  574. // Tear down the wait cursor
  575. SetCursor(hCursor);
  576. return bSuccess;
  577. }
  578. BOOL DmAdvPropPage_OnNotify(
  579. HWND ParentHwnd,
  580. LPNMHDR NmHdr
  581. )
  582. {
  583. POUR_PROP_PARAMS Params = (POUR_PROP_PARAMS) GetWindowLongPtr(ParentHwnd, DWLP_USER);
  584. switch (NmHdr->code)
  585. {
  586. case PSN_APPLY: // Sent when the user clicks on Apply OR OK !!
  587. SetWindowLongPtr(ParentHwnd, DWLP_MSGRESULT, (LONG_PTR)PSNRET_NOERROR);
  588. return TRUE;
  589. case TVN_SELCHANGED:
  590. //Don't bother if we are closing. This helps avoid irritating
  591. //redraw problems as destroy causes several of these messages to be sent.
  592. if (!Params->bClosing)
  593. {
  594. LPNM_TREEVIEW lpnmtv;
  595. TV_ITEM tvi;
  596. PDMTREE_NODE pTreeNode;
  597. BOOL fEnablePropButton;
  598. HWND hwndProp;
  599. lpnmtv = (LPNM_TREEVIEW)NmHdr;
  600. tvi = lpnmtv->itemNew;
  601. pTreeNode = (PDMTREE_NODE)tvi.lParam;
  602. fEnablePropButton = pTreeNode->pfnQueryConfig(ParentHwnd, pTreeNode);
  603. //override the enabling for driver entries
  604. if ((pTreeNode->NodeType == NodeTypeDriver) && (pTreeNode->dc != dcINVALID))
  605. {
  606. fEnablePropButton = TRUE;
  607. }
  608. // Enable or disable the Properties button depending upon
  609. // whether this driver can be configured
  610. hwndProp = GetDlgItem(ParentHwnd, ID_ADV_PROP);
  611. EnableWindow(hwndProp, fEnablePropButton);
  612. }
  613. break;
  614. case NM_DBLCLK:
  615. //show properties on a double-click
  616. if (NmHdr->idFrom == (DWORD)IDC_ADV_TREE)
  617. {
  618. HWND hwndTree;
  619. TV_HITTESTINFO tvht;
  620. hwndTree = GetDlgItem(ParentHwnd, IDC_ADV_TREE);
  621. // Find out which tree item the cursor is on and call properties on it
  622. GetCursorPos(&tvht.pt);
  623. ScreenToClient(hwndTree, &tvht.pt);
  624. TreeView_HitTest(hwndTree, &tvht);
  625. if (tvht.flags & TVHT_ONITEM)
  626. {
  627. DoProperties(ParentHwnd, hwndTree, tvht.hItem);
  628. }
  629. }
  630. break;
  631. #if 0 // stolen from Win98, not integrated yet
  632. case PSN_KILLACTIVE:
  633. FORWARD_WM_COMMAND(hDlg, IDOK, 0, 0, SendMessage);
  634. break;
  635. case PSN_APPLY:
  636. FORWARD_WM_COMMAND(hDlg, ID_APPLY, 0, 0, SendMessage);
  637. break;
  638. case PSN_SETACTIVE:
  639. FORWARD_WM_COMMAND(hDlg, ID_INIT, 0, 0, SendMessage);
  640. break;
  641. case PSN_RESET:
  642. FORWARD_WM_COMMAND(hDlg, IDCANCEL, 0, 0, SendMessage);
  643. break;
  644. case TVN_ITEMEXPANDING:
  645. {
  646. TV_ITEM tvi;
  647. HWND hwndTree = GetDlgItem(hDlg,IDC_ADV_TREE);
  648. tvi = lpnmtv->itemNew;
  649. tvi.mask = TVIF_PARAM;
  650. if (!TreeView_GetItem(hwndTree, &tvi))
  651. break;
  652. if (!tvi.lParam || IsBadReadPtr((LPVOID)tvi.lParam, 2))
  653. {
  654. DPF("****TVN_ITEMEXPANDING: lParam = 0 || BadReadPtr***\r\n");
  655. break;
  656. }
  657. if (*((short *)(tvi.lParam)) == 1)
  658. {
  659. //re-enum ACM codecs on expand because their states could have been programmatically changed.
  660. PCLASSNODE pcn = (PCLASSNODE)(tvi.lParam);
  661. if (lpnmtv->action == TVE_EXPAND && !lstrcmpi(pcn->szClass, ACM))
  662. {
  663. if (gfLoadedACM)
  664. ACMNodeChange(hDlg);
  665. }
  666. }
  667. else if (!tvi.lParam && lpnmtv->action == TVE_COLLAPSE)
  668. {
  669. //dont let the root collapse.
  670. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LPARAM)(LRESULT)TRUE);
  671. return TRUE;
  672. }
  673. break;
  674. }
  675. case TVN_BEGINLABELEDIT:
  676. //we don't want to allow editing of label unless the user explicitly wants it by
  677. //clicking context menu item
  678. if (!gfEditLabel)
  679. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LPARAM)(LRESULT)TRUE);
  680. return TRUE;
  681. case TVN_ENDLABELEDIT:
  682. {
  683. HWND hwndTree;
  684. LPSTR pszFriendlyName = ((TV_DISPINFO *) lpnm)->item.pszText;
  685. TV_ITEM item;
  686. HTREEITEM hti;
  687. PIRESOURCE pIResource;
  688. char szWarn[128];
  689. char ach[MAXSTR];
  690. //user has chosen a new friendly name. COnfirm with the user and put it in the
  691. //registry. ALso unhook KB hook which was used to track Esc and Return
  692. if (gfnKBHook)
  693. {
  694. UnhookWindowsHookEx(gfnKBHook);
  695. gfnKBHook = NULL;
  696. }
  697. if (!pszFriendlyName)
  698. return FALSE;
  699. hwndTree = GetDlgItem(hDlg, IDC_ADV_TREE);
  700. hti = TreeView_GetSelection(hwndTree);
  701. item.hItem = hti;
  702. item.mask = TVIF_PARAM;
  703. TreeView_GetItem(hwndTree, &item);
  704. LoadString(ghInstance, IDS_FRIENDLYWARNING, szWarn, sizeof(szWarn));
  705. wsprintf(ach, szWarn, pszFriendlyName);
  706. LoadString(ghInstance, IDS_FRIENDLYNAME, szWarn, sizeof(szWarn));
  707. if (mmse_MessageBox(hDlg, ach, szWarn, MMSE_YESNO) == MMSE_NO)
  708. {
  709. SetFocus(hwndTree);
  710. return FALSE;
  711. }
  712. if (*((short *)(item.lParam)) == 2)
  713. {
  714. pIResource = (PIRESOURCE)item.lParam;
  715. lstrcpy(pIResource->szFriendlyName, pszFriendlyName);
  716. SaveDevFriendlyName(pIResource);
  717. }
  718. else
  719. {
  720. PINSTRUMENT pInstr = (PINSTRUMENT)item.lParam;
  721. lstrcpy(pInstr->szFriendlyName, pszFriendlyName);
  722. SaveInstrFriendlyName(pInstr);
  723. }
  724. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LPARAM)(LRESULT)TRUE);
  725. return TRUE;
  726. }
  727. case NM_RCLICK:
  728. //popup context menu.
  729. TreeContextMenu(hDlg, GetDlgItem(hDlg, IDC_ADV_TREE));
  730. return TRUE;
  731. #endif
  732. default:
  733. return FALSE;
  734. }
  735. return FALSE;
  736. }
  737. void DoProperties(HWND ParentHwnd, HWND hWndI, HTREEITEM htiCur)
  738. {
  739. TV_ITEM tvi;
  740. PDMTREE_NODE pTreeNode;
  741. BOOL bRestart;
  742. // Get item struct attached to selected node
  743. tvi.mask = TVIF_PARAM;
  744. tvi.hItem = htiCur;
  745. if (TreeView_GetItem (hWndI, &tvi))
  746. {
  747. // Get my private data structure from item struct
  748. pTreeNode = (PDMTREE_NODE)tvi.lParam;
  749. if (pTreeNode->NodeType != NodeTypeDriver)
  750. {
  751. if (!pTreeNode->pfnQueryConfig(ParentHwnd, pTreeNode))
  752. {
  753. return;
  754. }
  755. }
  756. // Call config and get back whether restart needed
  757. pTreeNode->hti = htiCur; //this allows us to work with the legacy MIDI setup code
  758. bRestart = pTreeNode->pfnConfig(ParentHwnd, pTreeNode);
  759. if (bRestart)
  760. {
  761. PropSheet_Changed(GetParent(ParentHwnd), ParentHwnd);
  762. }
  763. }
  764. return;
  765. }
  766. void DmAdvPropPage_OnPropertiesClicked(
  767. HWND ParentHwnd,
  768. POUR_PROP_PARAMS Params
  769. )
  770. {
  771. HWND hWndI;
  772. HTREEITEM htiCur;
  773. // Get handle to treeview control
  774. hWndI = GetDlgItem(ParentHwnd, IDC_ADV_TREE);
  775. // Get handle to currently selected node
  776. htiCur = TreeView_GetSelection (hWndI);
  777. if (htiCur != NULL)
  778. {
  779. DoProperties(ParentHwnd, hWndI, htiCur);
  780. }
  781. return;
  782. }
  783. INT_PTR APIENTRY DmResourcesPageDlgProc(IN HWND hDlg,
  784. IN UINT uMessage,
  785. IN WPARAM wParam,
  786. IN LPARAM lParam)
  787. {
  788. return FALSE;
  789. } /* DmAdvPropPageDlgProc */
  790. INT_PTR CALLBACK CDDlg(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  791. BOOL AddCDROMPropertyPage( HDEVINFO hDeviceInfoSet,
  792. PSP_DEVINFO_DATA pDeviceInfoData,
  793. LPFNADDPROPSHEETPAGE AddFunc,
  794. LPARAM Lparam
  795. )
  796. {
  797. BOOL fHandled = FALSE;
  798. if (IsEqualGUID(&pDeviceInfoData->ClassGuid,&GUID_DEVCLASS_CDROM))
  799. {
  800. PROPSHEETPAGE psp;
  801. HPROPSHEETPAGE hpsp;
  802. PALLDEVINFO padi;
  803. padi = GlobalAllocPtr(GHND, sizeof(ALLDEVINFO));
  804. if (!padi) return FALSE;
  805. padi->hDevInfo = hDeviceInfoSet;
  806. padi->pDevInfoData = pDeviceInfoData;
  807. // Add our own page for DLG_DM_LEGACY_RESOURCES
  808. // Initialize the property sheet page
  809. psp.dwSize = sizeof(PROPSHEETPAGE);
  810. psp.dwFlags = 0;
  811. psp.hInstance = ghInstance;
  812. psp.pszTemplate = MAKEINTRESOURCE(DM_CDDLG);
  813. psp.pfnDlgProc = CDDlg; // dlg window proc
  814. psp.lParam = (LPARAM) padi;
  815. psp.pfnCallback = 0; // control callback of the dlg window proc
  816. // Create the page & get back a handle
  817. hpsp = CreatePropertySheetPage(&psp);
  818. if (!hpsp)
  819. {
  820. fHandled = TRUE;
  821. }
  822. else if (!(*AddFunc)(hpsp, Lparam))
  823. {
  824. GlobalFreePtr(padi);
  825. DestroyPropertySheetPage(hpsp);
  826. fHandled = FALSE;
  827. }
  828. }
  829. return(fHandled);
  830. }
  831. INT_PTR CALLBACK AdvDlg(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  832. BOOL AddSpecialPropertyPage( DWORD SpecialDriverType,
  833. LPFNADDPROPSHEETPAGE AddFunc,
  834. LPARAM Lparam
  835. )
  836. {
  837. PROPSHEETPAGE psp;
  838. HPROPSHEETPAGE hpsp;
  839. // Add our own page for DLG_DM_LEGACY_RESOURCES
  840. // Initialize the property sheet page
  841. psp.dwSize = sizeof(PROPSHEETPAGE);
  842. psp.dwFlags = 0;
  843. psp.hInstance = ghInstance;
  844. psp.pszTemplate = MAKEINTRESOURCE(DM_ADVDLG);
  845. psp.pfnDlgProc = AdvDlg; // dlg window proc
  846. psp.lParam = (LPARAM)SpecialDriverType;
  847. psp.pfnCallback = 0; // control callback of the dlg window proc
  848. // Create the page & get back a handle
  849. hpsp = CreatePropertySheetPage(&psp);
  850. if (!hpsp)
  851. {
  852. return FALSE;
  853. }
  854. // Add the property page
  855. if (!(*AddFunc)(hpsp, Lparam))
  856. {
  857. DestroyPropertySheetPage(hpsp);
  858. return FALSE;
  859. }
  860. return TRUE;
  861. }
  862. BOOL DmOverrideResourcesPage(LPVOID Info,
  863. LPFNADDPROPSHEETPAGE AddFunc,
  864. LPARAM Lparam,
  865. POUR_PROP_PARAMS Params
  866. )
  867. {
  868. HKEY hkDrv;
  869. HDEVINFO DeviceInfoSet;
  870. PSP_DEVINFO_DATA DeviceInfoData;
  871. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  872. PROPSHEETPAGE psp;
  873. HPROPSHEETPAGE hpsp;
  874. TCHAR szDriverType[16];
  875. DWORD cbLen;
  876. hkDrv = Params->hkDrv;
  877. DeviceInfoSet = Params->DeviceInfoSet;
  878. DeviceInfoData = Params->DeviceInfoData;
  879. // Query value of DriverType field to decide if this is a WDM driver
  880. cbLen = sizeof(szDriverType);
  881. if (!RegQueryValueEx(hkDrv, TEXT("DriverType"), NULL, NULL, (LPBYTE)szDriverType, &cbLen))
  882. {
  883. if ( lstrcmpi(szDriverType,TEXT("Legacy")) || lstrcmpi(szDriverType,TEXT("PNPISA")) )
  884. {
  885. // This is a PNPISA or Legacy device. Override resource page.
  886. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  887. SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams);
  888. DeviceInstallParams.Flags |= DI_RESOURCEPAGE_ADDED;
  889. SetupDiSetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams);
  890. // Add our own page for DLG_DM_LEGACY_RESOURCES
  891. // Initialize the property sheet page
  892. psp.dwSize = sizeof(PROPSHEETPAGE);
  893. psp.dwFlags = 0;
  894. psp.hInstance = ghInstance;
  895. psp.pszTemplate = MAKEINTRESOURCE(DLG_DM_LEGACY_RESOURCES);
  896. psp.pfnDlgProc = DmResourcesPageDlgProc; // dlg window proc
  897. psp.lParam = (LPARAM)0;
  898. psp.pfnCallback = 0; // control callback of the dlg window proc
  899. // Create the page & get back a handle
  900. hpsp = CreatePropertySheetPage(&psp);
  901. if (!hpsp)
  902. {
  903. return FALSE;
  904. }
  905. // Add the property page
  906. if (!(*AddFunc)(hpsp, Lparam))
  907. {
  908. DestroyPropertySheetPage(hpsp);
  909. return FALSE;
  910. }
  911. }
  912. }
  913. return TRUE;
  914. }
  915. /*
  916. ***************************************************************
  917. * BOOL DmInitDeviceTree
  918. *
  919. * This function calls commctrl to create the image list and tree and
  920. * the opens the registry, reads each class and loads all devices under
  921. * the class by calling ReadNodes. For ACM however it uses ACM
  922. * APIs (this enumeration code is in msacmcpl.c)
  923. ***************************************************************
  924. */
  925. BOOL DmInitDeviceTree(HWND hwndTree, POUR_PROP_PARAMS Params)
  926. {
  927. TV_INSERTSTRUCT ti;
  928. HDEVINFO DeviceInfoSet;
  929. PSP_DEVINFO_DATA DeviceInfoData;
  930. TCHAR *strtok_State; // strtok state
  931. TCHAR *pszClass; // Information about e.g. classguid\0000\Drivers\wave
  932. HKEY hkClass;
  933. DWORD idxR3DriverName; // Information about e.g. classguid\0000\Drivers\wave\foo.drv
  934. HKEY hkR3DriverName;
  935. TCHAR szR3DriverName[64];
  936. DWORD cbLen;
  937. PDMTREE_NODE pTreeNode;
  938. SUBTYPE_INFO *pSubtypeInfo;
  939. HTREEITEM htiRoot;
  940. HTREEITEM htiClass;
  941. HTREEITEM htiDriver;
  942. // Load up all the class descriptions and icons
  943. LoadSubtypeInfo(hwndTree);
  944. // Clear out the tree
  945. SendMessage(hwndTree, WM_SETREDRAW, FALSE, 0L);
  946. // Allocate my private data structure for this class
  947. pTreeNode = (PDMTREE_NODE)LocalAlloc(LPTR, sizeof(DMTREE_NODE));
  948. if (!pTreeNode)
  949. {
  950. return FALSE;
  951. }
  952. pSubtypeInfo = GetSubtypeInfo(NULL);
  953. pTreeNode->NodeType = NodeTypeRoot;
  954. pTreeNode->pfnConfig = pSubtypeInfo->pfnConfig;
  955. pTreeNode->pfnQueryConfig = pSubtypeInfo->pfnQueryConfig;
  956. // Insert root entry
  957. ti.hParent = TVI_ROOT;
  958. ti.hInsertAfter = TVI_LAST;
  959. ti.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  960. ti.item.iImage = ti.item.iSelectedImage = pSubtypeInfo->IconIndex;
  961. ti.item.pszText = pSubtypeInfo->szDescription;
  962. ti.item.lParam = (LPARAM)pTreeNode;
  963. htiRoot = NULL; //TreeView_InsertItem(hwndTree, &ti);
  964. // Enumerate all the subclasses
  965. for (
  966. pszClass = mystrtok(Params->szSubClasses,NULL,&strtok_State);
  967. pszClass;
  968. pszClass = mystrtok(NULL,NULL,&strtok_State)
  969. )
  970. {
  971. // Get an ID for this class
  972. pSubtypeInfo = GetSubtypeInfo(pszClass);
  973. // Open up each subclass
  974. if (RegOpenKey(Params->hkDrivers, pszClass, &hkClass))
  975. {
  976. continue;
  977. }
  978. // Allocate my private data structure for this class
  979. pTreeNode = (PDMTREE_NODE)LocalAlloc(LPTR, sizeof(DMTREE_NODE));
  980. if (!pTreeNode)
  981. {
  982. RegCloseKey(hkClass);
  983. continue;
  984. }
  985. pTreeNode->NodeType = NodeTypeClass;
  986. pTreeNode->pfnConfig = pSubtypeInfo->pfnConfig;
  987. pTreeNode->pfnQueryConfig = pSubtypeInfo->pfnQueryConfig;
  988. // Initialize tree insert struct
  989. ti.hParent = htiRoot;
  990. ti.hInsertAfter = TVI_LAST;
  991. ti.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  992. ti.item.iImage = ti.item.iSelectedImage = pSubtypeInfo->IconIndex;
  993. ti.item.pszText = pSubtypeInfo->szDescription;
  994. ti.item.lParam = (LPARAM)pTreeNode;
  995. // Insert Class entry into tree
  996. htiClass = TreeView_InsertItem(hwndTree, &ti);
  997. // Under each class is a set of driver name subkeys.
  998. // For each driver (e.g. foo1.drv, foo2.drv, etc.)
  999. for (idxR3DriverName = 0;
  1000. !RegEnumKey(hkClass, idxR3DriverName, szR3DriverName, sizeof(szR3DriverName)/sizeof(TCHAR));
  1001. idxR3DriverName++)
  1002. {
  1003. // Open the key to the driver name
  1004. if (RegOpenKey(hkClass, szR3DriverName, &hkR3DriverName))
  1005. {
  1006. continue;
  1007. }
  1008. // Create the branch for this subclass
  1009. pTreeNode = (PDMTREE_NODE)LocalAlloc(LPTR, sizeof(DMTREE_NODE));
  1010. pTreeNode->NodeType = NodeTypeDriver;
  1011. pTreeNode->pfnConfig = pSubtypeInfo->pfnConfig;
  1012. pTreeNode->pfnQueryConfig = pSubtypeInfo->pfnQueryConfig;
  1013. pTreeNode->dc = pSubtypeInfo->dc;
  1014. // Get driver name
  1015. cbLen = sizeof(pTreeNode->szDriver);
  1016. RegQueryValueEx(hkR3DriverName, TEXT("Driver"), NULL, NULL, (LPBYTE)pTreeNode->szDriver, &cbLen);
  1017. wcscpy(pTreeNode->wszDriver, pTreeNode->szDriver);
  1018. // Get driver description
  1019. cbLen = sizeof(pTreeNode->szDescription);
  1020. RegQueryValueEx(hkR3DriverName, TEXT("Description"), NULL, NULL, (LPBYTE)pTreeNode->szDescription, &cbLen);
  1021. // Get driver alias
  1022. cbLen = sizeof(pTreeNode->szAlias);
  1023. RegQueryValueEx(hkR3DriverName, TEXT("Alias"), NULL, NULL, (LPBYTE)pTreeNode->szAlias, &cbLen);
  1024. wcscpy(pTreeNode->wszAlias, pTreeNode->szAlias);
  1025. // Insert Class entry
  1026. ti.hParent = htiClass;
  1027. ti.hInsertAfter = TVI_LAST;
  1028. ti.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  1029. ti.item.iImage = ti.item.iSelectedImage = pSubtypeInfo->IconIndex;
  1030. ti.item.pszText = pTreeNode->szDescription;
  1031. ti.item.lParam = (LPARAM)pTreeNode;
  1032. htiDriver = TreeView_InsertItem(hwndTree, &ti);
  1033. // Close the Driver Name key
  1034. RegCloseKey(hkR3DriverName);
  1035. }
  1036. // Close the class key
  1037. RegCloseKey(hkClass);
  1038. }
  1039. // Open up the tree and display
  1040. TreeView_Expand(hwndTree, htiRoot, TVE_EXPAND);
  1041. SendMessage(hwndTree, WM_SETREDRAW, TRUE, 0L);
  1042. return TRUE;
  1043. }
  1044. // Free up the tree
  1045. void DmFreeAdvDlgTree (HWND hTree, HTREEITEM hti)
  1046. {
  1047. HTREEITEM htiChild;
  1048. TV_ITEM tvi;
  1049. // Delete all children by calling myself recursively
  1050. while ((htiChild = TreeView_GetChild(hTree, hti)) != NULL)
  1051. {
  1052. DmFreeAdvDlgTree(hTree, htiChild);
  1053. }
  1054. if (hti!=TVI_ROOT)
  1055. {
  1056. // Delete my attached data structures
  1057. tvi.mask = TVIF_PARAM;
  1058. tvi.hItem = hti;
  1059. tvi.lParam = 0;
  1060. TreeView_GetItem(hTree, &tvi);
  1061. if (tvi.lParam != 0)
  1062. LocalFree ((HANDLE)tvi.lParam);
  1063. // Delete myself
  1064. TreeView_DeleteItem (hTree, hti);
  1065. }
  1066. return;
  1067. }
  1068. BOOL DmAdvPropPage_OnDestroy(
  1069. HWND ParentHwnd,
  1070. LPNMHDR NmHdr
  1071. )
  1072. {
  1073. HWND hTree;
  1074. HIMAGELIST hImageList;
  1075. POUR_PROP_PARAMS Params = (POUR_PROP_PARAMS) GetWindowLongPtr(ParentHwnd, DWLP_USER);
  1076. if (Params)
  1077. {
  1078. Params->bClosing = TRUE; // Remember that we're now closing
  1079. }
  1080. // Get handle to treeview control
  1081. hTree = GetDlgItem(ParentHwnd, IDC_ADV_TREE);
  1082. // Free all the entries on the control
  1083. DmFreeAdvDlgTree(hTree,TVI_ROOT);
  1084. // Free up the image list attached to the control
  1085. hImageList = TreeView_GetImageList(hTree, TVSIL_NORMAL);
  1086. if (hImageList)
  1087. {
  1088. TreeView_SetImageList(hTree, NULL, TVSIL_NORMAL);
  1089. ImageList_Destroy (hImageList);
  1090. }
  1091. return FALSE;
  1092. }