Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5115 lines
150 KiB

  1. /* DRIVERS.C
  2. **
  3. ** Copyright (C) Microsoft, 1990, All Rights Reserved.
  4. **
  5. ** Multimedia Control Panel Applet for installing/configuring installable
  6. ** device drivers. See the ispec doc DRIVERS.DOC for more information.
  7. **
  8. ** History:
  9. **
  10. ** Tue Jul 31 1990 -by- MichaelE
  11. ** Created.
  12. **
  13. ** Thu Oct 25 1990 -by- MichaelE
  14. ** Added restart, horz. scroll, added SKIPDESC reading desc. strings.
  15. **
  16. ** Sat Oct 27 1990 -by- MichaelE
  17. ** Added FileCopy. Uses SULIB.LIB and LZCOPY.LIB. Finished stuff
  18. ** for case of installing a driver with more than one type.
  19. **
  20. ** May 1991 -by- JohnYG
  21. ** Added and replaced too many things to list. Better management
  22. ** of removed drivers, correct usage of DRV_INSTALL/DRV_REMOVE,
  23. ** installing VxD's, replaced "Unknown" dialog with an OEMSETUP.INF
  24. ** method, proper "Cancel" method, fixed many potential UAE's.
  25. */
  26. #include <nt.h>
  27. #include <ntrtl.h>
  28. #include <nturtl.h>
  29. #include <ntseapi.h>
  30. #include <windows.h>
  31. #include <mmsystem.h>
  32. #include <memory.h>
  33. #include <string.h>
  34. #include <stdlib.h>
  35. #include <cpl.h>
  36. #include <cphelp.h>
  37. #include <commctrl.h>
  38. #include <mmcpl.h>
  39. #include <mmddkp.h>
  40. #include <mmreg.h>
  41. #include <msacm.h>
  42. #include <msacmdrv.h>
  43. #include <regstr.h>
  44. #include "drivers.h"
  45. #include "sulib.h"
  46. #include "utils.h"
  47. #include "medhelp.h"
  48. #include "midi.h"
  49. #ifdef FIX_BUG_15451
  50. #include "trayvol.h"
  51. #endif // FIX_BUG_15451
  52. #ifndef cchLENGTH
  53. #define cchLENGTH(_sz) (sizeof(_sz) / sizeof((_sz)[0]))
  54. #endif
  55. #ifndef TreeView_GetGrandParent
  56. #define TreeView_GetGrandParent(_htree,_hti) \
  57. TreeView_GetParent(_htree,TreeView_GetParent(_htree,_hti))
  58. #endif
  59. /*
  60. * Enable the definition below to cause MCI devices to be listed by their
  61. * internal descriptions in the tree, rather than their descriptions as
  62. * read from Drivers.Desc.
  63. *
  64. */
  65. // #define GET_MCI_DEVICE_DESCRIPTIONS_FROM_THEIR_DEVICES
  66. typedef struct
  67. {
  68. int idIcon;
  69. int idName;
  70. int idInfo;
  71. BOOL bEnabled;
  72. DWORD dwContext;
  73. LPTSTR pszHelp;
  74. } APPLET_INFO;
  75. #define NUM_APPLETS 1
  76. #define OBJECT_SIZE 1024
  77. BOOL bBadOemSetup;
  78. BOOL bRestart = FALSE;
  79. int iRestartMessage = 0;
  80. BOOL bInstallBootLine = FALSE;
  81. BOOL bCopyVxD;
  82. BOOL bFindOEM = FALSE;
  83. BOOL bRelated = FALSE;
  84. BOOL bCopyEvenIfOlder = FALSE;
  85. BOOL bDriversAppInUse;
  86. BOOL bCopyingRelated;
  87. BOOL bDescFileValid;
  88. HANDLE myInstance;
  89. HWND hAdvDlgTree;
  90. UINT wHelpMessage;
  91. DWORD dwContext;
  92. PINF pinfOldDefault = NULL;
  93. TCHAR szDriversHlp[24];
  94. TCHAR szLastQuery[20];
  95. TCHAR szSetupInf[18];
  96. TCHAR szKnown[250];
  97. TCHAR szRestartDrv[80];
  98. TCHAR szUnlisted[150];
  99. TCHAR szRelatedDesc[30];
  100. TCHAR szAppName[26];
  101. TCHAR szDrivers[12];
  102. TCHAR szRemove[12];
  103. TCHAR szControlIni[20];
  104. TCHAR szSysIni[20];
  105. TCHAR szMCI[6];
  106. TCHAR szOutOfRemoveSpace[54];
  107. TCHAR szDriversDesc[38];
  108. TCHAR szUserDrivers[38];
  109. // Where the source of files to copy is - user updates
  110. TCHAR szDirOfSrc[MAX_PATH];
  111. TCHAR szAddDriver[36];
  112. TCHAR szNoDesc[36];
  113. TCHAR szError[20];
  114. TCHAR szRemoveOrNot[250];
  115. TCHAR szRemoveOrNotStrict[250];
  116. TCHAR szStringBuf[128];
  117. TCHAR szMDrivers[38];
  118. TCHAR szMDrivers32[38];
  119. TCHAR szFullPath[MAXFILESPECLEN];
  120. TCHAR szSystem[MAX_PATH];
  121. TCHAR szOemInf[MAX_PATH];
  122. TCHAR aszClose[16];
  123. TCHAR szFileError[50];
  124. #ifdef FIX_BUG_15451
  125. TCHAR szDriverWhichNeedsSettings[MAX_PATH]; // See MMCPL.C
  126. #endif // FIX_BUG_15451
  127. static HANDLE hIList;
  128. static HANDLE hWndMain;
  129. /*
  130. * Global flag telling us if we're allowed to write to ini files
  131. */
  132. BOOL IniFileReadAllowed;
  133. BOOL IniFileWriteAllowed;
  134. /*
  135. *** Stuff for keeping track of the TreeView window
  136. *
  137. */
  138. #define GetString(_psz,_id) LoadString(myInstance,(_id),(_psz),sizeof((_psz))/sizeof(TCHAR))
  139. static struct // aDriverKeyword
  140. {
  141. LPTSTR psz; // text found as alias for driver
  142. DriverClass dc; // DriverClass inferred from keyword
  143. }
  144. aDriverKeyword[] = // (used by GuessDriverClass())
  145. {
  146. { TEXT("waveaudio"), dcMCI }, // (sort in inverse alphabetical;
  147. { TEXT("wavemap"), dcWAVE }, // in particular, longer names first)
  148. { TEXT("wave"), dcWAVE },
  149. { TEXT("vids"), dcVCODEC },
  150. { TEXT("vidc"), dcVCODEC },
  151. { TEXT("sequencer"), dcMCI },
  152. { TEXT("msvideo"), dcVIDCAP },
  153. { TEXT("msacm"), dcACODEC },
  154. { TEXT("mpegvideo"), dcMCI },
  155. { TEXT("mixer"), dcMIXER },
  156. { TEXT("midimapper"), dcMIDI },
  157. { TEXT("midi"), dcMIDI },
  158. { TEXT("mci"), dcMCI },
  159. { TEXT("icm"), dcVCODEC },
  160. { TEXT("cdaudio"), dcMCI },
  161. { TEXT("avivideo"), dcMCI },
  162. { TEXT("aux"), dcAUX },
  163. { TEXT("acm"), dcACODEC },
  164. { TEXT("joy"), dcJOY }
  165. };
  166. #define nDriverKEYWORDS ((int)(sizeof(aDriverKeyword) / \
  167. sizeof(aDriverKeyword[0])))
  168. static struct // aKeywordDesc
  169. {
  170. DriverClass dc; // DriverClass
  171. LPTSTR psz; // alias which best describes class
  172. }
  173. aKeywordDesc[] = // (used by DriverClassToClassNode())
  174. {
  175. { dcWAVE, TEXT("wave") },
  176. { dcMIXER, TEXT("mixer") },
  177. { dcVIDCAP, TEXT("msvideo") },
  178. { dcVCODEC, TEXT("icm") },
  179. { dcAUX, TEXT("aux") },
  180. { dcACODEC, TEXT("acm") },
  181. { dcMIDI, TEXT("midi") },
  182. { dcJOY, TEXT("joystick") }
  183. };
  184. #define nKeywordDESCS ((int)(sizeof(aKeywordDesc) / \
  185. sizeof(aKeywordDesc[0])))
  186. static struct // aDriverRoot
  187. {
  188. DriverClass dc; // corresponding driver classification
  189. BOOL fAlwaysMake; // TRUE if should exist even w/o child
  190. int idIcon; // icon for items under this tree
  191. int idDesc; // description string for parent
  192. int idEnable; // string to describe enabling action
  193. int idDisable; // string to describe disabling action
  194. HTREEITEM hti; // item within tree
  195. DWORD dwBit; // bit mask representing this node
  196. }
  197. aDriverRoot[] = // (order will define order in display)
  198. {
  199. { dcINVALID, TRUE, IDI_MMICON, IDS_MM_HEADER,
  200. 0,
  201. 0 },
  202. { dcWAVE, TRUE, IDI_WAVE, IDS_WAVE_HEADER,
  203. IDS_ENABLEAUDIO,
  204. IDS_DISABLEAUDIO },
  205. { dcMIDI, TRUE, IDI_MIDI, IDS_MIDI_HEADER,
  206. IDS_ENABLEMIDI,
  207. IDS_DISABLEMIDI },
  208. { dcMIXER, TRUE, IDI_MIXER, IDS_MIXER_HEADER,
  209. IDS_ENABLEMIXER,
  210. IDS_DISABLEMIXER },
  211. { dcAUX, TRUE, IDI_AUX, IDS_AUX_HEADER,
  212. IDS_ENABLEAUX,
  213. IDS_DISABLEAUX },
  214. { dcMCI, TRUE, IDI_MCI, IDS_MCI_HEADER,
  215. IDS_ENABLEMCI,
  216. IDS_DISABLEMCI },
  217. { dcVCODEC, TRUE, IDI_ICM, IDS_ICM_HEADER,
  218. IDS_ENABLEICM,
  219. IDS_DISABLEICM },
  220. { dcACODEC, TRUE, IDI_ACM, IDS_ACM_HEADER,
  221. IDS_ENABLEACM,
  222. IDS_DISABLEACM },
  223. { dcVIDCAP, TRUE, IDI_VIDEO, IDS_VIDCAP_HEADER,
  224. IDS_ENABLECAP,
  225. IDS_DISABLECAP },
  226. { dcJOY, TRUE, IDI_JOYSTICK,IDS_JOYSTICK_HEADER,
  227. IDS_ENABLEJOY,
  228. IDS_DISABLEJOY },
  229. { dcOTHER, FALSE, IDI_MMICON, IDS_OTHER_HEADER,
  230. IDS_ENABLEJOY,
  231. IDS_DISABLEJOY },
  232. };
  233. #define nDriverROOTS ((int)(sizeof(aDriverRoot) / sizeof(aDriverRoot[0])))
  234. static LPCTSTR aDriversToSKIP[] =
  235. {
  236. TEXT( "MMDRV.DLL" ),
  237. TEXT( "MIDIMAP.DLL" ),
  238. TEXT( "MSACM32.DRV" )
  239. };
  240. static TCHAR cszMMDRVDLL[] = TEXT("MMDRV.DLL");
  241. static TCHAR cszAliasKERNEL[] = TEXT("KERNEL");
  242. static TCHAR cszRegValueLOADTYPE[] = TEXT("Load Type");
  243. #define nDriversToSKIP ((int)( sizeof(aDriversToSKIP) \
  244. / sizeof(aDriversToSKIP[0]) ))
  245. static HIMAGELIST hImageList = NULL; // image list for treeview in advdlg
  246. DriverClass g_dcFilterClass = dcINVALID;
  247. short DriverClassToRootIndex (DriverClass);
  248. DriverClass GuessDriverClass (PIDRIVER);
  249. #ifdef FIX_BUG_15451
  250. DriverClass GuessDriverClassFromAlias (LPTSTR);
  251. #endif // FIX_BUG_15451
  252. DriverClass GuessDriverClassFromTreeItem (HTREEITEM hti);
  253. BOOL EnsureRootIndexExists (HWND, short);
  254. HTREEITEM AdvDlgFindTopLevel (void);
  255. BOOL InitAdvDlgTree (HWND);
  256. void FreeAdvDlgTree (HWND);
  257. void TreeContextMenu (HWND, HWND);
  258. int lstrnicmp (LPTSTR, LPTSTR, size_t);
  259. LPTSTR lstrchr (LPTSTR, TCHAR);
  260. void lstrncpy (LPTSTR, LPTSTR, size_t);
  261. void ShowDeviceProperties (HWND, HTREEITEM);
  262. PIDRIVER FindIDriverByTreeItem (HTREEITEM);
  263. #ifdef FIX_BUG_15451
  264. HTREEITEM FindTreeItemByDriverName (LPTSTR);
  265. #endif // FIX_BUG_15451
  266. // We want to run "control joy.cpl" when the joystick devices
  267. // are highlight and the user clicks Add/Remove/Properties buttons.
  268. BOOL RunJoyControlPanel(void); //qzheng
  269. /*
  270. ***
  271. *
  272. */
  273. DWORD GetFileDateTime (LPTSTR);
  274. LPTSTR GetProfile (LPTSTR,LPTSTR, LPTSTR, LPTSTR, int);
  275. void AddIDrivers (HWND, LPTSTR, LPTSTR);
  276. HTREEITEM AddIDriver (HWND, PIDRIVER, DriverClass);
  277. BOOL AddIDriverByName (HWND, LPCWSTR, DriverClass);
  278. PIDRIVER GetSelectedIDriver (HWND);
  279. BOOL FillTreeFromWinMM (HWND);
  280. BOOL FillTreeFromMSACM (HWND);
  281. BOOL FillTreeFromMCI (HWND);
  282. BOOL FillTreeFromMIDI (HWND);
  283. BOOL FillTreeFromRemaining (HWND);
  284. void FillTreeFromRemainingBySection (HWND, long ii, LPCTSTR, DriverClass);
  285. BOOL CALLBACK FillTreeFromMSACMQueryCallback (HACMDRIVERID, DWORD_PTR, DWORD);
  286. int __cdecl FillTreeFromMSACMSortCallback (const void *p1, const void *p2);
  287. BOOL InitAvailable (HWND, int);
  288. void RemoveAvailable (HWND);
  289. BOOL UserInstalled (LPTSTR);
  290. INT_PTR RestartDlg (HWND, unsigned, WPARAM, LPARAM);
  291. INT_PTR AddUnlistedDlg (HWND, unsigned, WPARAM, LPARAM);
  292. INT_PTR AvailableDriversDlg (HWND, unsigned, WPARAM, LPARAM);
  293. INT_PTR AdvDlg (HWND, unsigned, WPARAM, LPARAM);
  294. void ReBoot (HWND);
  295. BOOL GetMappable (PIDRIVER);
  296. BOOL SetMappable (PIRESOURCE, BOOL);
  297. #define REGSTR_PATH_WAVEMAPPER TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Wave Mapper")
  298. #define REGSTR_VALUE_MAPPABLE TEXT("Mappable")
  299. #define REGSTR_PATH_MCI TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\MCI")
  300. #define REGSTR_PATH_MCI32 TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\MCI32")
  301. #define REGSTR_PATH_DRIVERS TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers")
  302. #define REGSTR_PATH_DRIVERS32 TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32")
  303. /*
  304. * REALLOC - Allows expansion of GlobalAlloc()'d block while retaining contents
  305. *
  306. * Newly-allocated portions of memory are initialized to zero, while
  307. * the contents of reallocated portions of memory are retained.
  308. *
  309. * Parameters:
  310. * LPVOID _pData....allocated array
  311. * mysize_t _cOld.....current count of elements in allocated array
  312. * mysize_t _cNew.....minimum number of elements requested
  313. * mysize_t _cDelta...granularity of increase
  314. *
  315. * Example:
  316. * {
  317. * mysize_t cElements = 0; // Number of elements allocated so far
  318. * DataType *aElements = NULL; // Allocated array of DataType
  319. *
  320. * // At this point, cElements == 0 (obviously)
  321. *
  322. * REALLOC (aElements, cElements, 10, 16)
  323. *
  324. * // The line above requested 10 elements, and indicated that elements
  325. * // should be allocated in increments of 16. So cElements is 16 at this
  326. * // point (thus, sizeof(aElements) == sizeof(DataType)*16).
  327. *
  328. * REALLOC (aElements, cElements, 12, 16)
  329. *
  330. * // The line above requested 12 elements. Since cElements is already 16,
  331. * // REALLOC knows that 12 elements are already available--and does nothing.
  332. *
  333. * REALLOC (aElements, cElements, 17, 16)
  334. *
  335. * // The line above requested 17 elements, in increments of 16. aElements
  336. * // has been reallocated to contain 32 elements, and cElements is
  337. * // therefore 32.
  338. *
  339. * GlobalFree ((HGLOBAL)aElements); // All done!
  340. * aElements = NULL;
  341. * cElements = 0;
  342. * }
  343. *
  344. *
  345. */
  346. typedef signed long mysize_t;
  347. #ifdef REALLOC
  348. #undef REALLOC
  349. #endif
  350. #define REALLOC(_pData,_cOld,_cNew,_cDelta) \
  351. ReallocFn (sizeof(*_pData), (void **)&_pData, &_cOld, _cNew, _cDelta)
  352. #ifdef DivRoundUp
  353. #undef DivRoundUp
  354. #endif
  355. #define DivRoundUp(_a,_b) ( (LONG)(((_a) + (_b) -1) / (_b)) )
  356. #ifdef RoundUp
  357. #undef RoundUp
  358. #endif
  359. #define RoundUp(_a,_b) ( DivRoundUp(_a,_b) * (LONG)_b )
  360. BOOL ReallocFn (mysize_t cbElement,
  361. LPVOID *ppOld, mysize_t *pcOld, mysize_t cNew, mysize_t cDelta)
  362. {
  363. LPVOID pNew;
  364. mysize_t cbOld, cbNew;
  365. // First check if we actually need to reallocate or not.
  366. // It's possible that {ppOld} was already allocated with
  367. // enough space.
  368. //
  369. if ( ((*ppOld) != NULL) && (cNew <= (*pcOld)) )
  370. return TRUE;
  371. // Oh well. Determine how much space we need, and how much
  372. // is allocated now.
  373. //
  374. cNew = RoundUp (cNew, cDelta);
  375. cbNew = cbElement * cNew;
  376. cbOld = (ppOld == NULL) ? 0 : (cbElement * (*pcOld));
  377. // Allocate the space and copy over the original contents.
  378. // Zero-fill the remaining space.
  379. //
  380. if ((pNew = (LPVOID)GlobalAlloc (GMEM_FIXED, cbNew)) == NULL)
  381. return FALSE;
  382. if (cbOld != 0)
  383. {
  384. memcpy (pNew, *ppOld, cbOld);
  385. GlobalFree ((HGLOBAL)(*ppOld));
  386. }
  387. memset (&((char*)pNew)[ cbOld ], 0x00, cbNew -cbOld);
  388. // Finally, update the passed-in pointers and we're done.
  389. //
  390. *pcOld = cNew;
  391. *ppOld = pNew;
  392. return TRUE;
  393. }
  394. /*
  395. * PIDRIVER ARRAY
  396. *
  397. * The AddIDrivers() routine LocalAlloc()'s a single IDRIVER structure
  398. * for each installed device driver. Pointers to these structures are
  399. * retained in the InstalledDriver array, and indices into this array
  400. * are stored as the LPARAM values for each tree item. Each element
  401. * in the array stores not only a pointer to the driver's IDRIVER structure,
  402. * but also a DWORD which, as a combination of aDriverRoot[].dwBit values,
  403. * reflects the tree root items under which the driver has tree items.
  404. *
  405. */
  406. typedef struct // InstalledDriver
  407. {
  408. PIDRIVER pIDriver; // Pointer to AddIDrivers()'s PIDRIVER structure
  409. DWORD dwBits; // Combination of aDriverRoot[].dwBit flags
  410. } InstalledDriver;
  411. InstalledDriver *aInstalledDrivers = NULL;
  412. mysize_t cInstalledDrivers = 0;
  413. #define NOPIDRIVER ((LPARAM)-1)
  414. /*
  415. * CheckSectionAccess()
  416. *
  417. * See if we can read/write to a given section
  418. */
  419. BOOL CheckSectionAccess(TCHAR *szIniFile, TCHAR *SectionName)
  420. {
  421. static TCHAR TestKey[] = TEXT("TestKey!!!");
  422. static TCHAR TestData[] = TEXT("TestData");
  423. static TCHAR ReturnData[50];
  424. /*
  425. * Check we can write, read back and delete our key
  426. */
  427. return WritePrivateProfileString(SectionName,
  428. TestKey,
  429. TestData,
  430. szIniFile) &&
  431. GetPrivateProfileString(SectionName,
  432. TestKey,
  433. TEXT(""),
  434. ReturnData,
  435. sizeof(ReturnData) / sizeof(TCHAR),
  436. szIniFile) == (DWORD)wcslen(TestData) &&
  437. WritePrivateProfileString(SectionName,
  438. TestKey,
  439. NULL,
  440. szIniFile);
  441. }
  442. /*
  443. * CheckIniAccess()
  444. *
  445. * Checks access to our 2 .ini file sections - DRIVERS_SECTION and
  446. * MCI_SECTION by just writing and reading some junk
  447. *
  448. * Basically if we don't have access to these sections we're not
  449. * going to allow Add and Remove. The individual MCI drivers must
  450. * take care not to put their data into non-writeable storage although
  451. * this completely messes up the default parameters thing so we're going
  452. * to put these into a well-known key in the win.ini file (ie per user).
  453. *
  454. */
  455. BOOL CheckIniAccess(void)
  456. {
  457. return CheckSectionAccess(szSysIni, szDrivers) &&
  458. CheckSectionAccess(szSysIni, szMCI) &&
  459. CheckSectionAccess(szControlIni, szUserDrivers) &&
  460. CheckSectionAccess(szControlIni, szDriversDesc) &&
  461. CheckSectionAccess(szControlIni, szRelatedDesc);
  462. }
  463. /*
  464. * QueryRemoveDrivers()
  465. *
  466. * Ask the user if they're sure. If the Driver is one required by the
  467. * system (ie not listed in [Userinstallable.drivers] in control.ini)
  468. * warn the user of that too.
  469. */
  470. BOOL QueryRemoveDrivers(HWND hDlg, LPTSTR szKey, LPTSTR szDesc)
  471. {
  472. TCHAR bufout[MAXSTR];
  473. if (UserInstalled(szKey))
  474. wsprintf(bufout, szRemoveOrNot, (LPTSTR)szDesc);
  475. else
  476. wsprintf(bufout, szRemoveOrNotStrict, (LPTSTR)szDesc);
  477. return (MessageBox(hDlg, bufout, szRemove,
  478. MB_ICONEXCLAMATION | MB_TASKMODAL | MB_YESNO) == IDYES );
  479. }
  480. /*
  481. * GetProfile()
  482. *
  483. * Get private profile strings.
  484. */
  485. LPTSTR GetProfile(LPTSTR pstrAppName, LPTSTR pstrKeyName, LPTSTR pstrIniFile,
  486. LPTSTR pstrRet, int cbSize)
  487. {
  488. TCHAR szNULL[2];
  489. szNULL[0] = TEXT('\0');
  490. GetPrivateProfileString(pstrAppName, (pstrKeyName==NULL) ? NULL :
  491. (LPTSTR)pstrKeyName, szNULL, pstrRet, cbSize/sizeof(TCHAR), pstrIniFile);
  492. return(pstrRet);
  493. }
  494. /*********************************************************************
  495. *
  496. * AddIDrivers()
  497. *
  498. * Add drivers in the passed key strings list to the InstalledDrivers array
  499. *
  500. *********************************************************************/
  501. void AddIDrivers(HWND hWnd, LPTSTR pstrKeys, LPTSTR pstrSection)
  502. {
  503. PIDRIVER pIDriver;
  504. LPTSTR pstrKey;
  505. LPTSTR pstrDesc;
  506. pstrKey = pstrKeys;
  507. pstrDesc = (LPTSTR)LocalAlloc(LPTR, MAXSTR);
  508. if (!pstrDesc) return;
  509. /*
  510. * parse key strings for profile, and make IDRIVER structs
  511. */
  512. while ( *pstrKey )
  513. {
  514. pIDriver = (PIDRIVER)LocalAlloc(LPTR, sizeof(IDRIVER));
  515. if ( pIDriver )
  516. {
  517. LPTSTR pstr;
  518. if (*GetProfile(pstrSection, pstrKey, szSysIni, pIDriver->szFile,
  519. sizeof(pIDriver->szFile)) == TEXT('\0'))
  520. {
  521. LocalFree((HANDLE)pIDriver);
  522. goto nextkey;
  523. }
  524. for ( pstr=pIDriver->szFile; *pstr && (*pstr!=COMMA) &&
  525. (*pstr!=SPACE); pstr++ )
  526. ;
  527. *pstr = TEXT('\0');
  528. #ifdef TRASHDRIVERDESC
  529. if (bDescFileValid)
  530. #endif
  531. /*
  532. * try to load the cached description
  533. */
  534. GetProfile(szDriversDesc,
  535. pIDriver->szFile,
  536. szControlIni,
  537. pIDriver->szDesc,
  538. sizeof(pIDriver->szDesc));
  539. /*
  540. * if we failed, then try to get the information from
  541. * mmdriver.inf or the exehdr
  542. */
  543. if (pIDriver->szDesc[0] == TEXT('\0'))
  544. {
  545. if (LoadDescFromFile(pIDriver, pstrKey, pstrDesc) != DESC_NOFILE)
  546. {
  547. if (!*pstrDesc)
  548. {
  549. /*
  550. * failed to load a description.
  551. * The file isn't in setup.inf
  552. * and doesn't have exehdr information
  553. */
  554. lstrcpy(pIDriver->szDesc, pIDriver->szFile);
  555. lstrcat(pIDriver->szDesc, szNoDesc);
  556. }
  557. else
  558. lstrcpy(pIDriver->szDesc, pstrDesc);
  559. WritePrivateProfileString(szDriversDesc, pIDriver->szFile,
  560. pIDriver->szDesc, szControlIni);
  561. } else {
  562. LocalFree((HANDLE)pIDriver);
  563. goto nextkey;
  564. }
  565. }
  566. wcsncpy(pIDriver->szAlias, pstrKey, sizeof(pIDriver->szAlias)/sizeof(TCHAR));
  567. pIDriver->szAlias[sizeof(pIDriver->szAlias)/sizeof(TCHAR) - 1] = TEXT('\0');
  568. wcscpy(pIDriver->wszAlias, pIDriver->szAlias);
  569. wcsncpy(pIDriver->szSection, pstrSection,sizeof(pIDriver->szSection)/sizeof(TCHAR));
  570. pIDriver->szSection[sizeof(pIDriver->szSection)/sizeof(TCHAR) - 1] = TEXT('\0');
  571. wcscpy(pIDriver->wszSection, pIDriver->szSection);
  572. pIDriver->KernelDriver = IsFileKernelDriver(pIDriver->szFile);
  573. pIDriver->fQueryable = pIDriver->KernelDriver ? 0 : -1;
  574. pIDriver->lp = 0L;
  575. if (!AddIDriverToArray (pIDriver))
  576. LocalFree((HANDLE)pIDriver);
  577. }
  578. else
  579. break; //ERROR Low Memory
  580. nextkey: while (*pstrKey++);
  581. }
  582. LocalFree((HANDLE)pstrDesc);
  583. }
  584. /*
  585. * AddIDriverToArray - Adds the given PIDRIVER to the InstalledDrivers array
  586. *
  587. */
  588. BOOL AddIDriverToArray (PIDRIVER pIDriver)
  589. {
  590. mysize_t ii;
  591. if (pIDriver == NULL)
  592. {
  593. return FALSE;
  594. }
  595. // Don't create duplicate entries in this array; one PIDRIVER
  596. // per driver-file is sufficient.
  597. //
  598. for (ii = 0; ii < cInstalledDrivers; ++ii)
  599. {
  600. if (aInstalledDrivers[ ii ].pIDriver != NULL)
  601. {
  602. if (!lstrcmpi (aInstalledDrivers[ ii ].pIDriver->szFile,
  603. pIDriver->szFile))
  604. {
  605. return FALSE;
  606. }
  607. }
  608. }
  609. // To reduce repetitive calls to GlobalAlloc(), we'll allocate
  610. // space for an additional 50 InstalledDriver entries within
  611. // the aInstalledDrivers array each time we run out of space.
  612. //
  613. #define nDriverEntriesToAllocAtONCE 50
  614. for (ii = 0; ii < cInstalledDrivers; ++ii)
  615. {
  616. if (aInstalledDrivers[ ii ].pIDriver == NULL)
  617. break;
  618. }
  619. if (ii >= cInstalledDrivers)
  620. {
  621. if (!REALLOC (aInstalledDrivers, // Array
  622. cInstalledDrivers, // Current size of array
  623. 1+ii, // Requested size of array
  624. nDriverEntriesToAllocAtONCE))
  625. {
  626. return FALSE;
  627. }
  628. }
  629. aInstalledDrivers[ ii ].pIDriver = pIDriver;
  630. aInstalledDrivers[ ii ].dwBits = 0L;
  631. return TRUE;
  632. }
  633. /*********************************************************************
  634. *
  635. * FindInstallableDriversSection()
  636. *
  637. *********************************************************************/
  638. PINF FindInstallableDriversSection(PINF pinf)
  639. {
  640. PINF pinfFound;
  641. pinfFound = infFindSection(pinf, szMDrivers32);
  642. if (pinfFound == NULL) {
  643. pinfFound = infFindSection(pinf, szMDrivers);
  644. }
  645. return pinfFound;
  646. }
  647. //NOTE: Returns nSize as a count of bytes, not characters (later calls expect this)
  648. int GetINISectionSize(LPCTSTR pstrSection, LPCTSTR pstrFile)
  649. {
  650. int ncbSize = 0;
  651. int ncbMaxSize = 0;
  652. while (ncbSize >= ncbMaxSize)
  653. {
  654. TCHAR szNULL[2];
  655. LPTSTR pStr = NULL;
  656. szNULL[0] = TEXT('\0');
  657. ncbMaxSize += SECTION; //allocate another 512 bytes
  658. pStr = (LPTSTR)LocalAlloc(LPTR, ncbMaxSize);
  659. if (!pStr)
  660. {
  661. //we're trying to allocate too much memory ...
  662. //drop out and use the last smaller size that worked
  663. break;
  664. }
  665. ncbSize = GetPrivateProfileString(pstrSection, NULL, szNULL, pStr, ncbMaxSize/sizeof(TCHAR), pstrFile);
  666. ncbSize = (ncbSize+2) * sizeof(TCHAR); //convert to byte count, adding two chars
  667. //to account for terminating null and API's truncation
  668. LocalFree(pStr);
  669. }
  670. return (ncbSize);
  671. }
  672. /*********************************************************************
  673. *
  674. * InitInstalled()
  675. *
  676. * Add the drivers installed in [DRIVERS] and [MCI] to the Installed
  677. * Drivers list box.
  678. *
  679. *********************************************************************/
  680. BOOL InitInstalled(HWND hWnd, LPTSTR pstrSection)
  681. {
  682. BOOL bSuccess=FALSE;
  683. LPTSTR pstr;
  684. int nSize = SECTION;
  685. #ifdef TRASHDRIVERDESC
  686. UINT wTime;
  687. BOOL fForce;
  688. TCHAR szOut[10];
  689. wTime = LOWORD(GetFileDateTime(szControlIni)) >> 1;
  690. if (fForce = (GetPrivateProfileInt((LPTSTR)szUserDrivers,
  691. (LPTSTR)szLastQuery, 0, (LPTSTR)szControlIni) != wTime))
  692. {
  693. wsprintf(szOut, TEXT("%d"), wTime);
  694. WritePrivateProfileString((LPTSTR)szUserDrivers, (LPTSTR)szLastQuery,
  695. szOut, (LPTSTR)szControlIni);
  696. WritePrivateProfileString((LPTSTR)szDriversDesc, NULL, NULL,
  697. (LPTSTR)szControlIni);
  698. bDescFileValid = FALSE;
  699. }
  700. else
  701. bDescFileValid = TRUE;
  702. #endif
  703. nSize = GetINISectionSize(pstrSection, szSysIni);
  704. pstr = (LPTSTR)LocalAlloc(LPTR, nSize);
  705. if ( pstr )
  706. {
  707. if (*GetProfile(pstrSection, NULL, szSysIni, pstr, nSize ))
  708. {
  709. AddIDrivers(hWnd,pstr,pstrSection);
  710. bSuccess = TRUE;
  711. }
  712. LocalFree((HANDLE)pstr);
  713. }
  714. return(bSuccess);
  715. }
  716. /*
  717. * RefreshAdvDlgTree - Clears the Devices tree, and fills it back in
  718. *
  719. */
  720. void RefreshAdvDlgTree (void)
  721. {
  722. if (hAdvDlgTree != NULL)
  723. {
  724. SendMessage (hAdvDlgTree, WM_SETREDRAW, FALSE, 0L);
  725. FreeAdvDlgTree (hAdvDlgTree);
  726. InitAdvDlgTree (hAdvDlgTree);
  727. InitInstalled (GetParent (hAdvDlgTree), szDrivers);
  728. InitInstalled (GetParent (hAdvDlgTree), szMCI);
  729. FillTreeInAdvDlg (hAdvDlgTree, NULL);
  730. SendMessage (hAdvDlgTree, WM_SETREDRAW, TRUE, 0L);
  731. }
  732. }
  733. /*
  734. * FillTreeInAdvDlg - Adds TreeItems for each entry in aInstalledDrivers
  735. *
  736. * If pIDriver is specified, the first treeitem to mention that driver
  737. * will be highlighted.
  738. *
  739. */
  740. BOOL FillTreeInAdvDlg (HWND hTree, PIDRIVER pIDriver)
  741. {
  742. if (!FillTreeFromWinMM (hTree))
  743. return FALSE;
  744. if (!FillTreeFromMSACM (hTree))
  745. return FALSE;
  746. if (!FillTreeFromMCI (hTree))
  747. return FALSE;
  748. if (!FillTreeFromMIDI (hTree))
  749. return FALSE;
  750. if (!FillTreeFromRemaining (hTree))
  751. return FALSE;
  752. if (pIDriver != NULL) // Do we have to highlight a pIDriver?
  753. {
  754. short idr;
  755. for (idr = 0; idr < nDriverROOTS; idr++)
  756. {
  757. HTREEITEM hti;
  758. if ((hti = aDriverRoot[ idr ].hti) == NULL)
  759. continue;
  760. for (hti = TreeView_GetChild (hTree, hti);
  761. hti != NULL;
  762. hti = TreeView_GetNextSibling (hTree, hti))
  763. {
  764. if (pIDriver == FindIDriverByTreeItem (hti))
  765. {
  766. TreeView_SelectItem (hTree, hti);
  767. break;
  768. }
  769. }
  770. if (hti != NULL) // Found and selected a TreeItem?
  771. break; // Then we're done!
  772. }
  773. }
  774. return TRUE;
  775. }
  776. /*
  777. * FillTreeFromWinMM - Adds tree items for all WinMM-controlled MM devices
  778. *
  779. * This routine adds tree items under the following DriverClasses:
  780. * dcWAVE - waveOut*
  781. * dcMIXER - mixer*
  782. * dcAUX - aux*
  783. *
  784. */
  785. BOOL FillTreeFromWinMM (HWND hTree)
  786. {
  787. UINT iDevice;
  788. UINT cDevices;
  789. WCHAR szDriver[ cchRESOURCE ];
  790. // Add entries for each waveOut device
  791. //
  792. cDevices = waveOutGetNumDevs ();
  793. for (iDevice = 0; iDevice < cDevices; ++iDevice)
  794. {
  795. if (waveOutMessage (HWAVEOUT_INDEX(iDevice),
  796. DRV_QUERYFILENAME,
  797. (DWORD_PTR)szDriver,
  798. (DWORD_PTR)cchRESOURCE) == MMSYSERR_NOERROR)
  799. {
  800. AddIDriverByName (hTree, szDriver, dcWAVE);
  801. }
  802. }
  803. // Add entries for each mixer device
  804. //
  805. cDevices = mixerGetNumDevs ();
  806. for (iDevice = 0; iDevice < cDevices; ++iDevice)
  807. {
  808. if (mixerMessage (HMIXER_INDEX(iDevice),
  809. DRV_QUERYFILENAME,
  810. (DWORD_PTR)szDriver,
  811. (DWORD_PTR)cchRESOURCE) == MMSYSERR_NOERROR)
  812. {
  813. AddIDriverByName (hTree, szDriver, dcMIXER);
  814. }
  815. }
  816. // Add entries for each aux device
  817. //
  818. cDevices = auxGetNumDevs ();
  819. for (iDevice = 0; iDevice < cDevices; ++iDevice)
  820. {
  821. if (auxOutMessage (iDevice,
  822. DRV_QUERYFILENAME,
  823. (DWORD_PTR)szDriver,
  824. (DWORD_PTR)cchRESOURCE) == MMSYSERR_NOERROR)
  825. {
  826. AddIDriverByName (hTree, szDriver, dcAUX);
  827. }
  828. }
  829. return TRUE;
  830. }
  831. /*
  832. * FillTreeFromMSACM - Adds tree items for all MSACM-controlled MM devices
  833. *
  834. * This routine adds tree items under the following DriverClasses:
  835. * dcACODEC - acmDriverEnum()
  836. *
  837. * Note that, since audio codecs are supposed to be sorted in the tree,
  838. * all audio codec treeitems are first deleted from the tree (if there
  839. * are any at this point) then all audio codecs are added in their
  840. * sorted order.
  841. *
  842. */
  843. typedef struct
  844. {
  845. DWORD dwPriority; // priority of this audio codec
  846. PIDRIVER pIDriver; // matching driver file (or NULL)
  847. WORD wMid; // manufacturer ID
  848. WORD wPid; // product ID
  849. TCHAR szDesc[ ACMDRIVERDETAILS_LONGNAME_CHARS ];
  850. } AudioCodec;
  851. AudioCodec *pCodecs;
  852. mysize_t cCodecs;
  853. extern BOOL gfLoadedACM; // From MSACMCPL.C
  854. BOOL FillTreeFromMSACM (HWND hTree)
  855. {
  856. MMRESULT mmr;
  857. short idr;
  858. mysize_t ii;
  859. if (!gfLoadedACM)
  860. {
  861. if (LoadACM())
  862. gfLoadedACM = TRUE;
  863. }
  864. if (!gfLoadedACM)
  865. return FALSE;
  866. // Step one: get rid of any audio codecs listed in the tree
  867. //
  868. if ((idr = DriverClassToRootIndex (dcACODEC)) != -1)
  869. {
  870. if (aDriverRoot[ idr ].hti != NULL)
  871. {
  872. HTREEITEM hti;
  873. while ((hti = TreeView_GetChild (hTree, aDriverRoot[ idr ].hti)) != 0)
  874. {
  875. TreeView_DeleteItem (hTree, hti);
  876. if (hti == TreeView_GetChild (hTree, aDriverRoot[ idr ].hti))
  877. break; // if it didn't delete, make sure we don't loop forever!
  878. }
  879. }
  880. for (ii = 0; ii < cInstalledDrivers; ++ii)
  881. {
  882. aInstalledDrivers[ ii ].dwBits &= ~aDriverRoot[ idr ].dwBit;
  883. }
  884. }
  885. // Step two: query ACM to obtain the list of codecs
  886. //
  887. pCodecs = NULL;
  888. cCodecs = 0;
  889. mmr = (MMRESULT)acmDriverEnum (FillTreeFromMSACMQueryCallback,
  890. 0,
  891. ACM_DRIVERENUMF_NOLOCAL | ACM_DRIVERENUMF_DISABLED);
  892. // Step three: sort the list of codecs and add each to the tree
  893. //
  894. if ((mmr == MMSYSERR_NOERROR) && (pCodecs != NULL))
  895. {
  896. mysize_t iiDr;
  897. qsort (pCodecs, (size_t)cCodecs, sizeof(AudioCodec),
  898. FillTreeFromMSACMSortCallback);
  899. // Assign lp=wMid+wPid for each audio codec we find
  900. //
  901. for (iiDr = 0; iiDr < cInstalledDrivers; ++iiDr)
  902. {
  903. if (aInstalledDrivers[ iiDr ].pIDriver == NULL)
  904. continue;
  905. if (aInstalledDrivers[ iiDr ].pIDriver->lp != 0L) // already did this
  906. continue;
  907. if (GuessDriverClass (aInstalledDrivers[ iiDr ].pIDriver) == dcACODEC)
  908. {
  909. HANDLE hDriver;
  910. hDriver = OpenDriver (aInstalledDrivers[iiDr].pIDriver->wszAlias,
  911. aInstalledDrivers[iiDr].pIDriver->wszSection,
  912. 0L);
  913. if (hDriver != NULL)
  914. {
  915. ACMDRIVERDETAILSW add;
  916. memset ((TCHAR *)&add, 0x00, sizeof(add));
  917. add.cbStruct = sizeof(add);
  918. SendDriverMessage (hDriver, ACMDM_DRIVER_DETAILS, (LONG_PTR)&add, 0);
  919. CloseDriver (hDriver, 0L, 0L);
  920. aInstalledDrivers[ iiDr ].pIDriver->lp = MAKELONG( add.wMid,
  921. add.wPid );
  922. }
  923. }
  924. }
  925. // Search for installed drivers with matching lp=wMid+wPid's
  926. //
  927. for (iiDr = 0; iiDr < cInstalledDrivers; ++iiDr)
  928. {
  929. if (aInstalledDrivers[ iiDr ].pIDriver == NULL)
  930. continue;
  931. if ((aInstalledDrivers[ iiDr ].pIDriver->szAlias[0] == TEXT('\0')) ||
  932. (GuessDriverClass (aInstalledDrivers[iiDr].pIDriver) == dcACODEC))
  933. {
  934. for (ii = 0; ii < cCodecs; ++ii)
  935. {
  936. if (pCodecs[ ii ].dwPriority == 0)
  937. continue;
  938. if ( (pCodecs[ ii ].wMid ==
  939. LOWORD( aInstalledDrivers[ iiDr ].pIDriver->lp )) &&
  940. (pCodecs[ ii ].wPid ==
  941. HIWORD( aInstalledDrivers[ iiDr ].pIDriver->lp )) )
  942. {
  943. pCodecs[ ii ].pIDriver = aInstalledDrivers[ iiDr ].pIDriver;
  944. break;
  945. }
  946. }
  947. }
  948. }
  949. // Add each in-use entry in pCodecs to the treeview
  950. //
  951. for (ii = 0; ii < cCodecs; ++ii)
  952. {
  953. if (pCodecs[ ii ].dwPriority == 0)
  954. continue;
  955. // The PCM converter, for instance, won't have a matching
  956. // PID. So create a bogus one--the lack of an szAlias
  957. // will let us know it's bogus--and insert it into the
  958. // aInstalledDrivers array.
  959. //
  960. if (pCodecs[ ii ].pIDriver == NULL)
  961. {
  962. PIDRIVER pid = (PIDRIVER)LocalAlloc(LPTR, sizeof(IDRIVER));
  963. if (pid != NULL)
  964. {
  965. memset (pid, 0x00, sizeof(IDRIVER));
  966. pid->lp = MAKELONG( pCodecs[ ii ].wMid, pCodecs[ ii ].wPid );
  967. lstrcpy (pid->szDesc, pCodecs[ ii ].szDesc);
  968. if (!AddIDriverToArray (pid))
  969. LocalFree ((HLOCAL)pid);
  970. else
  971. {
  972. pCodecs[ ii ].pIDriver = pid;
  973. }
  974. }
  975. }
  976. if (pCodecs[ ii ].pIDriver != NULL)
  977. {
  978. AddIDriver (hTree, pCodecs[ ii ].pIDriver, dcACODEC);
  979. }
  980. }
  981. }
  982. // Cleanup
  983. //
  984. if (pCodecs != NULL)
  985. {
  986. GlobalFree ((HGLOBAL)pCodecs);
  987. pCodecs = NULL;
  988. cCodecs = 0;
  989. }
  990. return (mmr == MMSYSERR_NOERROR) ? TRUE : FALSE;
  991. }
  992. /*
  993. * FillTreeFromMCI - Adds tree items for all MCI devices
  994. *
  995. * This routine adds tree items under the following DriverClasses:
  996. * dcMCI - mciSendCommand
  997. *
  998. */
  999. BOOL FillTreeFromMCI (HWND hTree)
  1000. {
  1001. MCI_SYSINFO_PARMS mciSysInfo;
  1002. TCHAR szAlias[ cchRESOURCE ];
  1003. // How many MCI devices does WinMM know about?
  1004. //
  1005. memset ((TCHAR *)&mciSysInfo, 0x00, sizeof(mciSysInfo));
  1006. mciSysInfo.lpstrReturn = szAlias;
  1007. mciSysInfo.dwRetSize = cchLENGTH(szAlias);
  1008. mciSysInfo.wDeviceType = MCI_ALL_DEVICE_ID;
  1009. if (mciSendCommand (MCI_ALL_DEVICE_ID,
  1010. MCI_SYSINFO,
  1011. MCI_SYSINFO_QUANTITY,
  1012. (DWORD_PTR)&mciSysInfo) == 0)
  1013. {
  1014. DWORD iDevice;
  1015. DWORD cDevices;
  1016. cDevices = *((DWORD *)(mciSysInfo.lpstrReturn));
  1017. // Get the name of each MCI device in turn.
  1018. //
  1019. for (iDevice = 0; iDevice < cDevices; ++iDevice)
  1020. {
  1021. mysize_t ii;
  1022. memset ((TCHAR *)&mciSysInfo, 0x00, sizeof(mciSysInfo));
  1023. mciSysInfo.lpstrReturn = szAlias;
  1024. mciSysInfo.dwRetSize = cchLENGTH(szAlias);
  1025. mciSysInfo.wDeviceType = MCI_ALL_DEVICE_ID;
  1026. mciSysInfo.dwNumber = 1+iDevice; // note: 1-based, not 0-based!
  1027. if (mciSendCommand (MCI_ALL_DEVICE_ID,
  1028. MCI_SYSINFO,
  1029. MCI_SYSINFO_NAME,
  1030. (DWORD_PTR)&mciSysInfo) != 0)
  1031. {
  1032. continue;
  1033. }
  1034. // Got an alias--search the InstalledDrivers array
  1035. // and try to find a matching PIDRIVER.
  1036. //
  1037. for (ii = 0; ii < cInstalledDrivers; ++ii)
  1038. {
  1039. if (aInstalledDrivers[ ii ].pIDriver == NULL)
  1040. continue;
  1041. if (!lstrcmpi (aInstalledDrivers[ ii ].pIDriver->szAlias, szAlias))
  1042. {
  1043. #ifdef GET_MCI_DEVICE_DESCRIPTIONS_FROM_THEIR_DEVICES
  1044. MCI_OPEN_PARMS mciOpen;
  1045. MCI_INFO_PARMS mciInfo;
  1046. MCIERROR rc;
  1047. // It's an installed, functioning, happy MCI device.
  1048. // Open it up and see what it calls itself; update the
  1049. // description in the PIDRIVER (what's in there was
  1050. // obtained from the registry, thus from MMDRIVER.INF,
  1051. // and we instead want what Media Player lists in its
  1052. // Device menu).
  1053. //
  1054. memset ((TCHAR *)&mciOpen, 0x00, sizeof(mciOpen));
  1055. mciOpen.lpstrDeviceType = szAlias;
  1056. rc = mciSendCommand (0,MCI_OPEN,MCI_OPEN_TYPE,(DWORD)&mciOpen);
  1057. if (rc == MCIERR_MUST_USE_SHAREABLE)
  1058. {
  1059. rc = mciSendCommand (0, MCI_OPEN,
  1060. MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE,
  1061. (DWORD)&mciOpen);
  1062. }
  1063. if (rc == 0)
  1064. {
  1065. TCHAR szDesc[ cchRESOURCE ];
  1066. szDesc[0] = 0;
  1067. mciInfo.lpstrReturn = szDesc;
  1068. mciInfo.dwRetSize = cchLENGTH(szDesc);
  1069. if (mciSendCommand (mciOpen.wDeviceID,
  1070. MCI_INFO,
  1071. MCI_INFO_PRODUCT,
  1072. (DWORD)&mciInfo) == 0)
  1073. {
  1074. lstrcpy (aInstalledDrivers[ ii ].pIDriver->szDesc, szDesc);
  1075. }
  1076. mciSendCommand (mciOpen.wDeviceID, MCI_CLOSE, 0L, 0);
  1077. }
  1078. #endif // GET_MCI_DEVICE_DESCRIPTIONS_FROM_THEIR_DEVICES
  1079. AddIDriver (hTree, aInstalledDrivers[ ii ].pIDriver, dcMCI);
  1080. break;
  1081. }
  1082. }
  1083. }
  1084. }
  1085. return TRUE;
  1086. }
  1087. /*
  1088. * FillTreeFromMIDI - Adds tree items for all MIDI devices and instruments
  1089. *
  1090. * This routine adds tree items under the following DriverClasses:
  1091. * dcMIDI - LoadInstruments() provides necessary data
  1092. *
  1093. */
  1094. BOOL FillTreeFromMIDI (HWND hTree)
  1095. {
  1096. MCMIDI mcm;
  1097. UINT iiRoot;
  1098. int idrMIDI;
  1099. if ((idrMIDI = DriverClassToRootIndex (dcMIDI)) == -1)
  1100. return FALSE;
  1101. // First load in all relevant information regarding MIDI
  1102. // instruments. Fortunately, all that work is encapsulated
  1103. // nicely within one routine.
  1104. //
  1105. memset (&mcm, 0x00, sizeof(mcm));
  1106. LoadInstruments (&mcm, FALSE);
  1107. // Each entry in mcm's api array is one of three things:
  1108. // - a parent (say, a sound card)
  1109. // - a child (say, an external instrument)
  1110. // - the "(none)" thing that we want to skip
  1111. //
  1112. // Add each parent to the tree, and when we find a parent,
  1113. // add all its children.
  1114. //
  1115. for (iiRoot = 0; iiRoot < mcm.nInstr; ++iiRoot)
  1116. {
  1117. TCHAR szName[ MAXSTR ];
  1118. LPTSTR pch;
  1119. PIDRIVER pid;
  1120. if (mcm.api[ iiRoot ] == NULL)
  1121. continue;
  1122. if (mcm.api[ iiRoot ]->piParent != NULL)
  1123. continue;
  1124. if (mcm.api[ iiRoot ]->szKey[0] == TEXT('\0'))
  1125. continue;
  1126. // Found a parent! If we can match it to an installed driver,
  1127. // add it to the tree. Note that mcm.api[]->szKey will
  1128. // be of the form "MMDRV.DLL<0000>"--we need to strip off
  1129. // the "<0000>" before we can match this thing to a PIDRIVER.
  1130. //
  1131. lstrcpy (szName, mcm.api[ iiRoot ]->szKey);
  1132. if ((pch = lstrchr (szName, TEXT('<'))) != NULL)
  1133. *pch = TEXT('\0');
  1134. if ((pid = FindIDriverByName (szName)) != NULL)
  1135. {
  1136. HTREEITEM hti;
  1137. UINT ii;
  1138. TV_ITEM tvi;
  1139. if ((hti = AddIDriver (hTree, pid, dcMIDI)) == NULL)
  1140. continue;
  1141. #if 0
  1142. tvi.mask = TVIF_TEXT;
  1143. tvi.hItem = hti;
  1144. tvi.pszText = mcm.api[ iiRoot ]->szFriendly;
  1145. TreeView_SetItem(hTree, &tvi);
  1146. #endif
  1147. // We've added this parent. See if it has any children,
  1148. // and if so, stick 'em in the tree.
  1149. //
  1150. for (ii = 0; ii < mcm.nInstr; ++ii)
  1151. {
  1152. PINSTRUM lp;
  1153. TV_INSERTSTRUCT ti;
  1154. if (mcm.api[ ii ] == NULL)
  1155. continue;
  1156. if (mcm.api[ ii ]->piParent != mcm.api[ iiRoot ])
  1157. continue;
  1158. // Yep--it's got a parent. Allocate a second copy
  1159. // of this PINSTRUM; that copy will be our LPARAM value.
  1160. //
  1161. if ((lp = (PINSTRUM)LocalAlloc(LPTR,sizeof (INSTRUM))) == NULL)
  1162. continue;
  1163. memcpy ((TCHAR *)lp, (TCHAR *)mcm.api[ ii ], sizeof (INSTRUM));
  1164. // Now add a treeitem for this instrument.
  1165. //
  1166. ti.hParent = hti;
  1167. ti.hInsertAfter = TVI_LAST;
  1168. ti.item.mask = TVIF_TEXT | TVIF_PARAM |
  1169. TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  1170. ti.item.iImage = (int)idrMIDI;
  1171. ti.item.iSelectedImage = (int)idrMIDI;
  1172. ti.item.pszText = mcm.api[ ii ]->szFriendly;
  1173. ti.item.lParam = (LPARAM)lp;
  1174. if (!TreeView_InsertItem (hTree, &ti))
  1175. break;
  1176. }
  1177. }
  1178. }
  1179. // Done--cleanup and we're out of here.
  1180. //
  1181. FreeInstruments (&mcm);
  1182. if (mcm.hkMidi)
  1183. RegCloseKey (mcm.hkMidi);
  1184. return TRUE;
  1185. }
  1186. // To reduce repetitive calls to GlobalAlloc(), we'll allocate
  1187. // space for an additional 10 AudioCodec entries within
  1188. // the pCodecs array each time we run out of space.
  1189. //
  1190. #define nAudioCodecEntriesToAllocAtONCE 10
  1191. BOOL CALLBACK FillTreeFromMSACMQueryCallback (HACMDRIVERID hadid,
  1192. DWORD_PTR dwUser,
  1193. DWORD fdwSupport)
  1194. {
  1195. short ii;
  1196. AudioCodec *pac;
  1197. ACMDRIVERDETAILS add;
  1198. // Find or create a place in which to store information
  1199. // about this codec
  1200. //
  1201. for (ii = 0; ii < cCodecs; ++ii)
  1202. {
  1203. if (pCodecs[ ii ].dwPriority == 0)
  1204. break;
  1205. }
  1206. if (ii >= cCodecs)
  1207. {
  1208. if (!REALLOC (pCodecs, cCodecs, 1+ii, nAudioCodecEntriesToAllocAtONCE))
  1209. return FALSE;
  1210. }
  1211. pac = &pCodecs[ ii ]; // for shorthand
  1212. // Find out about this codec
  1213. //
  1214. memset ((TCHAR *)&add, 0x00, sizeof(add));
  1215. add.cbStruct = sizeof(add);
  1216. if (acmDriverDetails (hadid, &add, 0) == MMSYSERR_NOERROR)
  1217. {
  1218. acmMetrics ((HACMOBJ)hadid,ACM_METRIC_DRIVER_PRIORITY,&pac->dwPriority);
  1219. lstrcpy (pac->szDesc, add.szLongName);
  1220. pac->wMid = add.wMid;
  1221. pac->wPid = add.wPid;
  1222. pac->pIDriver = NULL;
  1223. }
  1224. return TRUE; // keep counting
  1225. }
  1226. int __cdecl FillTreeFromMSACMSortCallback (const void *p1, const void *p2)
  1227. {
  1228. if (((AudioCodec *)p1)->dwPriority == 0)
  1229. return 1;
  1230. if (((AudioCodec *)p2)->dwPriority == 0)
  1231. return -1;
  1232. return ((AudioCodec *)p1)->dwPriority - ((AudioCodec *)p2)->dwPriority;
  1233. }
  1234. /*
  1235. * FillTreeFromRemaining - Adds tree items for all remaining MM devices
  1236. *
  1237. * This routine adds a single tree item for each entry in the aInstalledDrivers
  1238. * array which is not already represented somewhere in the tree. The
  1239. * classification is based on the driver's alias--if that fails, it is lumped
  1240. * under dcOTHER.
  1241. *
  1242. */
  1243. BOOL FillTreeFromRemaining (HWND hTree)
  1244. {
  1245. mysize_t ii;
  1246. for (ii = 0; ii < cInstalledDrivers; ++ii)
  1247. {
  1248. UINT iiSkipCheck;
  1249. if (aInstalledDrivers[ ii ].pIDriver == NULL)
  1250. continue;
  1251. if (aInstalledDrivers[ ii ].pIDriver->szAlias[0] == TEXT('\0'))
  1252. continue;
  1253. // (don't do this for any not-to-be-displayed drivers)
  1254. //
  1255. for (iiSkipCheck = 0; iiSkipCheck < nDriversToSKIP; iiSkipCheck++)
  1256. {
  1257. if (!FileNameCmp ((LPTSTR)aDriversToSKIP[ iiSkipCheck ],
  1258. (LPTSTR)aInstalledDrivers[ ii ].pIDriver->szFile))
  1259. break;
  1260. }
  1261. if (iiSkipCheck < nDriversToSKIP)
  1262. continue;
  1263. // Zip through the {drivers,drivers32,mci,mci32} sections, to
  1264. // try to classify this driver. If we find a classification
  1265. // for which we haven't already added an entry in the tree,
  1266. // add another.
  1267. //
  1268. FillTreeFromRemainingBySection (hTree,
  1269. ii,
  1270. REGSTR_PATH_DRIVERS,
  1271. dcINVALID);
  1272. FillTreeFromRemainingBySection (hTree,
  1273. ii,
  1274. REGSTR_PATH_DRIVERS32,
  1275. dcINVALID);
  1276. FillTreeFromRemainingBySection (hTree,
  1277. ii,
  1278. REGSTR_PATH_MCI,
  1279. dcMCI);
  1280. FillTreeFromRemainingBySection (hTree,
  1281. ii,
  1282. REGSTR_PATH_MCI32,
  1283. dcMCI);
  1284. // If the dwBits element is zero, then this driver hasn't
  1285. // already been assigned a treeitem elsewhere. In that event,
  1286. // call AddIDriver() with dcOTHER--to tell it to lump this
  1287. // driver under "Other Drivers".
  1288. //
  1289. if (aInstalledDrivers[ ii ].dwBits == 0)
  1290. {
  1291. AddIDriver (hTree, aInstalledDrivers[ ii ].pIDriver, dcOTHER);
  1292. }
  1293. }
  1294. return TRUE;
  1295. }
  1296. void FillTreeFromRemainingBySection (HWND hTree,
  1297. long iiDriver,
  1298. LPCTSTR pszSection,
  1299. DriverClass dcSection)
  1300. {
  1301. HKEY hk;
  1302. UINT ii;
  1303. if (RegOpenKey (HKEY_LOCAL_MACHINE, pszSection, &hk))
  1304. return;
  1305. for (ii = 0; ; ++ii)
  1306. {
  1307. TCHAR szLHS[ cchRESOURCE ];
  1308. TCHAR szRHS[ cchRESOURCE ];
  1309. DWORD dw1;
  1310. DWORD dw2;
  1311. DWORD dw3;
  1312. dw1 = cchRESOURCE;
  1313. dw3 = cchRESOURCE;
  1314. if (RegEnumValue (hk, ii, szLHS, &dw1,
  1315. 0, &dw2, (LPBYTE)szRHS, &dw3) != ERROR_SUCCESS)
  1316. {
  1317. break;
  1318. }
  1319. if (!FileNameCmp (szRHS, aInstalledDrivers[ iiDriver ].pIDriver->szFile))
  1320. {
  1321. DriverClass dc;
  1322. if ((dc = dcSection) == dcINVALID)
  1323. dc = GuessDriverClassFromAlias (szLHS);
  1324. if ((dc == dcINVALID) || (dc == dcOTHER))
  1325. continue;
  1326. (void)AddIDriver (hTree, aInstalledDrivers[ iiDriver ].pIDriver, dc);
  1327. }
  1328. }
  1329. RegCloseKey (hk);
  1330. }
  1331. #ifdef FIX_BUG_15451
  1332. HWND MakeThisCPLLookLikeTheOldCPL (HWND hWndCPL)
  1333. {
  1334. TCHAR szTitle[ cchRESOURCE ];
  1335. HWND hWndOldCPL = NULL;
  1336. GetWindowText (hWndCPL, szTitle, cchRESOURCE);
  1337. for (hWndOldCPL = GetWindow (hWndCPL, GW_HWNDFIRST);
  1338. hWndOldCPL != NULL;
  1339. hWndOldCPL = GetWindow (hWndOldCPL, GW_HWNDNEXT))
  1340. {
  1341. TCHAR szTitleTest[ cchRESOURCE ];
  1342. GetWindowText (hWndOldCPL, szTitleTest, cchRESOURCE);
  1343. if ( (!lstrcmpi (szTitle, szTitleTest)) && (hWndCPL != hWndOldCPL) )
  1344. {
  1345. RECT rOld;
  1346. GetWindowRect (hWndOldCPL, &rOld);
  1347. SetWindowPos (hWndCPL, hWndOldCPL, rOld.left, rOld.top,
  1348. 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
  1349. SetWindowPos (hWndOldCPL, hWndCPL, 0, 0, 0, 0,
  1350. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  1351. }
  1352. }
  1353. return hWndOldCPL;
  1354. }
  1355. HWND MakeThisDialogLookLikeTheOldDialog (HWND hDlg)
  1356. {
  1357. TCHAR szTitle[ cchRESOURCE ];
  1358. RECT rOld;
  1359. POINT pt;
  1360. HWND hWndOldDlg;
  1361. GetWindowText (hDlg, szTitle, cchRESOURCE);
  1362. for (hWndOldDlg = GetWindow (hDlg, GW_HWNDFIRST);
  1363. hWndOldDlg != NULL;
  1364. hWndOldDlg = GetWindow (hWndOldDlg, GW_HWNDNEXT))
  1365. {
  1366. TCHAR szTitleTest[ cchRESOURCE ];
  1367. GetWindowText (hWndOldDlg, szTitleTest, cchRESOURCE);
  1368. if ( (!lstrcmpi (szTitle, szTitleTest)) && (hDlg != hWndOldDlg) )
  1369. {
  1370. GetWindowRect (hWndOldDlg, &rOld);
  1371. SetWindowPos (hDlg, NULL, rOld.left, rOld.top, 0, 0,
  1372. SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  1373. return hWndOldDlg;
  1374. }
  1375. }
  1376. return NULL;
  1377. }
  1378. BOOL WaitForNewCPLWindow (HWND hWndMyDlg)
  1379. {
  1380. TCHAR szTitle[ cchRESOURCE ];
  1381. HWND hWnd;
  1382. DWORD tickStart;
  1383. #define msecMAXWAIT 5000
  1384. hWndMyDlg = GetParent (hWndMyDlg); // (hWndMyDlg was a property sheet)
  1385. GetWindowText (hWndMyDlg, szTitle, cchRESOURCE);
  1386. for (tickStart = GetTickCount();
  1387. GetTickCount() - tickStart < msecMAXWAIT;)
  1388. {
  1389. MSG msg;
  1390. for (hWnd = GetWindow (hWndMyDlg, GW_HWNDFIRST);
  1391. hWnd != NULL;
  1392. hWnd = GetWindow (hWnd, GW_HWNDNEXT))
  1393. {
  1394. TCHAR szTitleTest[ cchRESOURCE ];
  1395. if (!IsWindowVisible (hWnd))
  1396. continue;
  1397. GetWindowText (hWnd, szTitleTest, cchRESOURCE);
  1398. if ( (!lstrcmpi (szTitle, szTitleTest)) && (hWnd != hWndMyDlg) )
  1399. {
  1400. PropSheet_PressButton (hWndMyDlg, PSBTN_CANCEL);
  1401. hWnd = GetParent (GetParent (hAdvDlgTree));
  1402. PropSheet_PressButton (hWnd, PSBTN_CANCEL);
  1403. return TRUE;
  1404. }
  1405. }
  1406. if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
  1407. {
  1408. if (GetMessage (&msg, NULL, 0, 0))
  1409. {
  1410. TranslateMessage (&msg);
  1411. DispatchMessage (&msg);
  1412. }
  1413. }
  1414. }
  1415. return FALSE;
  1416. }
  1417. #endif // FIX_BUG_15451
  1418. // Prevent any more REMOVE button presses
  1419. // Otherwise one can get stacked up and cause trouble,
  1420. // particularly if it is assocated with a driver that
  1421. // is automatically removed. We have to use a static
  1422. // as any focus changes cause the button to change state.
  1423. //
  1424. static long fWorking = 0;
  1425. /********************************************************************
  1426. *
  1427. * AdvDlg ()
  1428. *
  1429. * Display list of installed installable drivers. Return TRUE/FALSE
  1430. * indicating if should restart windows.
  1431. *
  1432. ********************************************************************/
  1433. const static DWORD aAdvDlgHelpIds[] = { // Context Help IDs
  1434. IDC_ADV_TREE, IDH_GENERIC_DEVICES,
  1435. ID_ADV_PROP, IDH_ADV_PROPERTIES,
  1436. ID_ADV_REMOVE, IDH_MMCPL_DEVPROP_REMOVE,
  1437. 0, 0
  1438. };
  1439. void MapDriverClass(DWORD_PTR dwSetupClass)
  1440. {
  1441. g_dcFilterClass = dcINVALID;
  1442. switch (dwSetupClass)
  1443. {
  1444. case IS_MS_MMMCI :
  1445. {
  1446. g_dcFilterClass = dcMCI;
  1447. }
  1448. break;
  1449. case IS_MS_MMVID :
  1450. {
  1451. g_dcFilterClass = dcVCODEC;
  1452. }
  1453. break;
  1454. case IS_MS_MMACM :
  1455. {
  1456. g_dcFilterClass = dcACODEC;
  1457. }
  1458. break;
  1459. case IS_MS_MMVCD :
  1460. {
  1461. g_dcFilterClass = dcVIDCAP;
  1462. }
  1463. break;
  1464. case IS_MS_MMDRV :
  1465. {
  1466. g_dcFilterClass = dcLEGACY;
  1467. }
  1468. break;
  1469. }
  1470. }
  1471. INT_PTR AdvDlg (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1472. {
  1473. HANDLE hWndI, hWnd;
  1474. PIDRIVER pIDriver;
  1475. DWORD_PTR dwType = 0;
  1476. switch ( uMsg )
  1477. {
  1478. case WM_INITDIALOG:
  1479. #ifdef FIX_BUG_15451
  1480. if (szDriverWhichNeedsSettings[0] != TEXT('\0'))
  1481. {
  1482. MakeThisCPLLookLikeTheOldCPL (GetParent(hDlg));
  1483. }
  1484. #endif // FIX_BUG_15451
  1485. wsStartWait();
  1486. if (lParam)
  1487. {
  1488. dwType = ((LPPROPSHEETPAGE) lParam)->lParam;
  1489. }
  1490. MapDriverClass(dwType);
  1491. hWndI = GetDlgItem(hDlg, IDC_ADV_TREE);
  1492. SendMessage(hWndI,WM_SETREDRAW, FALSE, 0L);
  1493. InitAdvDlgTree (hWndI); // initialize the treeview display
  1494. /*
  1495. * Handle the fact that we may not be able to update our .ini
  1496. * sections
  1497. *
  1498. */
  1499. IniFileWriteAllowed = CheckIniAccess();
  1500. // Note nasty sneaky hack: using (A|B) instead of (A&&B)
  1501. // makes both functions evaluate in either success or
  1502. // failure cases.
  1503. //
  1504. IniFileReadAllowed = ( InitInstalled (hDlg, szDrivers) |
  1505. InitInstalled (hDlg, szMCI) );
  1506. FillTreeInAdvDlg (GetDlgItem (hDlg, IDC_ADV_TREE), NULL);
  1507. wsEndWait();
  1508. if ((!IniFileReadAllowed) || (!IniFileWriteAllowed))
  1509. {
  1510. TCHAR szCantAdd[120];
  1511. EnableWindow(GetDlgItem(hDlg, ID_ADV_ADD),FALSE);
  1512. EnableWindow(GetDlgItem(hDlg, ID_ADV_REMOVE),FALSE);
  1513. LoadString(myInstance,IDS_CANTADD,szCantAdd,sizeof(szCantAdd)/sizeof(TCHAR));
  1514. MessageBox(hDlg, szCantAdd, szError,
  1515. MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
  1516. }
  1517. SendMessage (hWndI, WM_SETREDRAW, TRUE, 0L);
  1518. break;
  1519. case WM_COMMAND:
  1520. hWndI = GetDlgItem(hDlg, IDC_ADV_TREE);
  1521. hWndMain = hDlg;
  1522. pIDriver = GetSelectedIDriver (hWndI);
  1523. switch ( LOWORD(wParam ))
  1524. {
  1525. case ID_ADV_PROP:
  1526. {
  1527. HTREEITEM htiCur = TreeView_GetSelection (hWndI);
  1528. DriverClass dc = GuessDriverClassFromTreeItem (htiCur);
  1529. if (fWorking)
  1530. break;
  1531. ++fWorking; // Just starting an operation
  1532. if( dc == dcJOY )
  1533. // We want to run "control joy.cpl" when the joystick devices
  1534. // are highlight and the user clicks Properties buttons.
  1535. RunJoyControlPanel();
  1536. else
  1537. ShowDeviceProperties (hDlg, TreeView_GetSelection(hWndI));
  1538. --fWorking; // Finished with this operation
  1539. }
  1540. break;
  1541. case ID_WHATSTHIS:
  1542. {
  1543. WinHelp((HWND)GetDlgItem (hDlg, IDC_ADV_TREE),
  1544. gszWindowsHlp, HELP_WM_HELP,
  1545. (UINT_PTR)(LPTSTR)aAdvDlgHelpIds);
  1546. }
  1547. break;
  1548. case ID_ADV_REMOVE:
  1549. {
  1550. HWND hTree = GetDlgItem (hDlg, IDC_ADV_TREE);
  1551. HTREEITEM htiCur = TreeView_GetSelection (hTree);
  1552. DriverClass dc = GuessDriverClassFromTreeItem (htiCur);
  1553. PIDRIVER pid;
  1554. LONG_PTR Status;
  1555. if ((!IniFileReadAllowed) || (!IniFileWriteAllowed))
  1556. break; // (button should be disabled)
  1557. if( dc == dcJOY ) {
  1558. RunJoyControlPanel();
  1559. break;
  1560. }
  1561. if (TreeView_GetParent (hAdvDlgTree, htiCur) &&
  1562. TreeView_GetGrandParent (hAdvDlgTree, htiCur) &&
  1563. (GuessDriverClassFromTreeItem (
  1564. TreeView_GetGrandParent (hAdvDlgTree, htiCur)
  1565. ) == dcMIDI))
  1566. {
  1567. TV_ITEM tvi;
  1568. PINSTRUM pin;
  1569. tvi.mask = TVIF_PARAM;
  1570. tvi.hItem = htiCur;
  1571. tvi.lParam = 0;
  1572. TreeView_GetItem(hAdvDlgTree, &tvi);
  1573. if ((pin = (PINSTRUM)tvi.lParam) != NULL)
  1574. {
  1575. RemoveInstrumentByKeyName (pin->szKey);
  1576. RefreshAdvDlgTree ();
  1577. KickMapper (hDlg);
  1578. }
  1579. break;
  1580. }
  1581. if ((pid = FindIDriverByTreeItem (htiCur)) == NULL)
  1582. break;
  1583. if (dc == dcLEGACY)
  1584. {
  1585. dc = GuessDriverClass(pid);
  1586. }
  1587. if (pid->szAlias[0] == TEXT('\0'))
  1588. {
  1589. TCHAR szCantRemove[ cchRESOURCE ];
  1590. GetString(szCantRemove, IDS_ACMREMOVEFAIL);
  1591. MessageBox(hDlg, szCantRemove, szError,
  1592. MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
  1593. break;
  1594. }
  1595. if (fWorking)
  1596. break;
  1597. ++fWorking; // Just starting an operation
  1598. if (QueryRemoveDrivers (hDlg, pid->szAlias, pid->szDesc))
  1599. {
  1600. if ((Status = PostRemove (pid, TRUE)) != DRVCNF_CANCEL)
  1601. {
  1602. switch (dc)
  1603. {
  1604. case dcMIDI:
  1605. break;
  1606. case dcACODEC:
  1607. acmDeleteCodec (LOWORD(pid->lp),
  1608. HIWORD(pid->lp));
  1609. break;
  1610. default:
  1611. break;
  1612. }
  1613. iRestartMessage = IDS_RESTART_REM;
  1614. if (Status == DRVCNF_RESTART)
  1615. {
  1616. DialogBox (myInstance,
  1617. MAKEINTRESOURCE(DLG_RESTART),
  1618. hDlg,
  1619. RestartDlg);
  1620. }
  1621. }
  1622. }
  1623. --fWorking; // Finished with this operation
  1624. }
  1625. break;
  1626. case ID_ADV_ADD:
  1627. {
  1628. HTREEITEM htiCur = TreeView_GetSelection (hWndI);
  1629. DriverClass dc = GuessDriverClassFromTreeItem (htiCur);
  1630. if ((!IniFileReadAllowed) || (!IniFileWriteAllowed))
  1631. break; // (button should be disabled)
  1632. if( dc == dcJOY ) {
  1633. RunJoyControlPanel();
  1634. break;
  1635. }
  1636. if (fWorking)
  1637. break;
  1638. ++fWorking; // Just starting an operation
  1639. bCopyEvenIfOlder = FALSE;
  1640. DialogBox(myInstance, MAKEINTRESOURCE(DLG_KNOWN), hDlg,
  1641. AvailableDriversDlg);
  1642. bCopyEvenIfOlder = FALSE;
  1643. --fWorking; // Finished with this operation
  1644. }
  1645. break;
  1646. case ID_ADV_TSHOOT:
  1647. {
  1648. TCHAR szCommand[ MAX_PATH ];
  1649. STARTUPINFO si;
  1650. PROCESS_INFORMATION pi;
  1651. LoadString(myInstance,IDS_TSHOOT, szCommand, sizeof(szCommand)/sizeof(TCHAR));
  1652. ZeroMemory(&si, sizeof(si));
  1653. si.cb = sizeof(si);
  1654. si.dwFlags = STARTF_USESHOWWINDOW;
  1655. si.wShowWindow = SW_NORMAL;
  1656. if (CreateProcess(NULL, szCommand, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi)) {
  1657. CloseHandle(pi.hThread);
  1658. CloseHandle(pi.hProcess);
  1659. }
  1660. }
  1661. break;
  1662. #ifdef FIX_BUG_15451
  1663. case ID_INIT:
  1664. if (szDriverWhichNeedsSettings[0] != TEXT('\0'))
  1665. {
  1666. HTREEITEM hti;
  1667. if ((hti = FindTreeItemByDriverName (
  1668. szDriverWhichNeedsSettings)) != 0)
  1669. {
  1670. TreeView_Expand (hAdvDlgTree,
  1671. TreeView_GetParent(hAdvDlgTree,hti),
  1672. TVE_EXPAND);
  1673. TreeView_SelectItem(hAdvDlgTree,hti);
  1674. FORWARD_WM_COMMAND(hDlg,ID_ADV_PROP,0,0,PostMessage);
  1675. }
  1676. else
  1677. {
  1678. szDriverWhichNeedsSettings[0] = 0;
  1679. }
  1680. }
  1681. break;
  1682. #endif // FIX_BUG_15451
  1683. default:
  1684. return(FALSE);
  1685. }
  1686. break;
  1687. case WM_NOTIFY:
  1688. {
  1689. NMHDR *lpnm = (NMHDR *)lParam;
  1690. LPNM_TREEVIEW lpnmtv = (LPNM_TREEVIEW)lParam;
  1691. switch (lpnm->code)
  1692. {
  1693. case PSN_KILLACTIVE:
  1694. FORWARD_WM_COMMAND (hDlg, IDOK, 0, 0, SendMessage);
  1695. break;
  1696. case PSN_APPLY:
  1697. FORWARD_WM_COMMAND (hDlg, ID_APPLY, 0, 0, SendMessage);
  1698. break;
  1699. case PSN_SETACTIVE:
  1700. FORWARD_WM_COMMAND (hDlg, ID_INIT, 0, 0, SendMessage);
  1701. break;
  1702. case PSN_RESET:
  1703. FORWARD_WM_COMMAND (hDlg, IDCANCEL, 0, 0, SendMessage);
  1704. break;
  1705. case NM_DBLCLK:
  1706. // show properties or expand/collapse tree node.
  1707. //
  1708. if (lpnm->idFrom == (UINT)IDC_ADV_TREE)
  1709. {
  1710. HWND hTree = GetDlgItem (hDlg, IDC_ADV_TREE);
  1711. HTREEITEM htiCur = TreeView_GetSelection (hTree);
  1712. TV_HITTESTINFO tvht;
  1713. if (!htiCur)
  1714. break;
  1715. GetCursorPos (&tvht.pt);
  1716. ScreenToClient (hTree, &tvht.pt);
  1717. TreeView_HitTest (hTree, &tvht);
  1718. if ( (tvht.flags & TVHT_ONITEM) &&
  1719. (TreeView_GetChild (hTree, htiCur) == NULL) &&
  1720. (IsWindowEnabled (GetDlgItem(hDlg,ID_ADV_PROP))) )
  1721. {
  1722. FORWARD_WM_COMMAND(hDlg,ID_ADV_PROP,0,0,PostMessage);
  1723. }
  1724. }
  1725. break;
  1726. case NM_RCLICK:
  1727. TreeContextMenu (hDlg, GetDlgItem (hDlg, IDC_ADV_TREE));
  1728. return TRUE;
  1729. break;
  1730. }
  1731. }
  1732. break;
  1733. // The TreeView has its own right-click handling, and presents a
  1734. // "What's This?" automatically--so don't handle WM_CONTEXTMENU
  1735. // for that control.
  1736. //
  1737. case WM_CONTEXTMENU:
  1738. if (wParam != (WPARAM)GetDlgItem (hDlg, IDC_ADV_TREE))
  1739. {
  1740. WinHelp((HWND)wParam, gszWindowsHlp, HELP_CONTEXTMENU,
  1741. (UINT_PTR)(LPTSTR)aAdvDlgHelpIds);
  1742. }
  1743. break;
  1744. case WM_HELP:
  1745. WinHelp(((LPHELPINFO)lParam)->hItemHandle, gszWindowsHlp,
  1746. HELP_WM_HELP, (UINT_PTR)(LPTSTR)aAdvDlgHelpIds);
  1747. break;
  1748. case WM_DESTROY:
  1749. FreeAdvDlgTree (GetDlgItem (hDlg, IDC_ADV_TREE));
  1750. return FALSE;
  1751. break;
  1752. default:
  1753. return FALSE;
  1754. break;
  1755. }
  1756. return(TRUE);
  1757. }
  1758. /*
  1759. *** TreeContextMenu
  1760. *
  1761. * This function displays the context menu that pops up when the
  1762. * user right clicks on any of the tree view items.
  1763. *
  1764. */
  1765. void TreeContextMenu (HWND hWnd, HWND hKeyTreeWnd)
  1766. {
  1767. DWORD MessagePos;
  1768. POINT MessagePoint;
  1769. TV_HITTESTINFO TVHitTestInfo;
  1770. HMENU hContextMenu;
  1771. HMENU hContextPopupMenu;
  1772. TV_ITEM TVItem;
  1773. int MenuCommand;
  1774. TCHAR szCollapse[32];
  1775. // dont bring up a menu unless click is on the item.
  1776. //
  1777. MessagePos = GetMessagePos();
  1778. MessagePoint.x = GET_X_LPARAM(MessagePos);
  1779. MessagePoint.y = GET_Y_LPARAM(MessagePos);
  1780. TVHitTestInfo.pt = MessagePoint;
  1781. ScreenToClient(hKeyTreeWnd, &TVHitTestInfo.pt);
  1782. TVItem.hItem = TreeView_HitTest(hKeyTreeWnd, &TVHitTestInfo);
  1783. if (TVItem.hItem == NULL)
  1784. return;
  1785. hContextMenu = LoadMenu(ghInstance, MAKEINTRESOURCE(POPUP_TREE_CONTEXT));
  1786. if (hContextMenu == NULL)
  1787. return;
  1788. hContextPopupMenu = GetSubMenu (hContextMenu, 0);
  1789. TVItem.mask = TVIF_STATE | TVIF_HANDLE | TVIF_CHILDREN | TVIF_PARAM;
  1790. TreeView_GetItem(hKeyTreeWnd, &TVItem);
  1791. // show collapse item because we are expanded?
  1792. //
  1793. if (TVItem.state & TVIS_EXPANDED)
  1794. {
  1795. LoadString(ghInstance, IDS_COLLAPSE, szCollapse, sizeof(szCollapse)/sizeof(TCHAR));
  1796. ModifyMenu(hContextPopupMenu, ID_TOGGLE, MF_BYCOMMAND | MF_STRING,
  1797. ID_TOGGLE, szCollapse);
  1798. }
  1799. SetMenuDefaultItem (hContextPopupMenu, ID_TOGGLE, MF_BYCOMMAND);
  1800. if (TVItem.cChildren == 0) //gray expand/collaps if no children
  1801. {
  1802. SetMenuDefaultItem(hContextPopupMenu, ID_ADV_PROP, MF_BYCOMMAND);
  1803. EnableMenuItem(hContextPopupMenu, ID_TOGGLE, MF_GRAYED |MF_BYCOMMAND);
  1804. }
  1805. TreeView_SelectItem (hKeyTreeWnd, TVItem.hItem);
  1806. MenuCommand = TrackPopupMenuEx (hContextPopupMenu,
  1807. TPM_RETURNCMD | TPM_RIGHTBUTTON |
  1808. TPM_LEFTALIGN | TPM_TOPALIGN,
  1809. MessagePoint.x, MessagePoint.y,
  1810. hWnd, NULL);
  1811. DestroyMenu (hContextMenu);
  1812. FORWARD_WM_COMMAND(hWnd, MenuCommand, 0, 0, SendMessage);
  1813. }
  1814. /*--------------------------------------------------------------------------*
  1815. * *
  1816. * *
  1817. * LB_AVAILABLE Dialog Routines *
  1818. * *
  1819. * *
  1820. *--------------------------------------------------------------------------*/
  1821. /*
  1822. * DLG: LB_AVAILABLE
  1823. *
  1824. * InitAvailable()
  1825. *
  1826. * Add the available drivers from mmdriver.inf to the passed list box.
  1827. * The format of [Installable.drivers] in setup.inf is:
  1828. * profile=disk#:driverfile,"type1,type2","Installable driver Description","vxd1.386,vxd2.386","opt1,2,3"
  1829. *
  1830. * for example:
  1831. *
  1832. * driver1=6:sndblst.drv,"midi,wave","SoundBlaster MIDI and Waveform drivers","vdmad.386,vadmad.386","3,260"
  1833. */
  1834. BOOL InitAvailable(HWND hWnd, int iLine)
  1835. {
  1836. PINF pinf;
  1837. BOOL bInitd=FALSE;
  1838. LPTSTR pstrKey;
  1839. int iIndex;
  1840. TCHAR szDesc[MAX_INF_LINE_LEN];
  1841. SendMessage(hWnd,WM_SETREDRAW, FALSE, 0L);
  1842. /*
  1843. * Parse the list of keywords and load their strings
  1844. */
  1845. for (pinf = FindInstallableDriversSection(NULL); pinf; pinf = infNextLine(pinf))
  1846. {
  1847. //
  1848. // found at least one keyname!
  1849. //
  1850. bInitd = TRUE;
  1851. if ( (pstrKey = (LPTSTR)LocalAlloc(LPTR, MAX_SYS_INF_LEN)) != NULL )
  1852. infParseField(pinf, 0, pstrKey);
  1853. else
  1854. break;
  1855. /*
  1856. * add the installable driver's description to listbox, and filename as data
  1857. */
  1858. infParseField(pinf, 3, szDesc);
  1859. if ( (iIndex = (int)SendMessage(hWnd, LB_ADDSTRING, 0, (LONG_PTR)(LPTSTR)szDesc)) != LB_ERR )
  1860. SendMessage(hWnd, LB_SETITEMDATA, iIndex, (LONG_PTR)pstrKey);
  1861. }
  1862. if (iLine == UNLIST_LINE)
  1863. {
  1864. //
  1865. // Add the "Install unlisted..." choice to the top of the list
  1866. // box.
  1867. LoadString(myInstance, IDS_UPDATED, szDesc, sizeof(szDesc)/sizeof(TCHAR));
  1868. if ((iIndex = (int)(LONG)SendMessage(hWnd, LB_INSERTSTRING, 0, (LPARAM)(LPTSTR)szDesc)) != LB_ERR)
  1869. SendMessage(hWnd, LB_SETITEMDATA, (WPARAM)iIndex, (LPARAM)0);
  1870. }
  1871. if (bInitd)
  1872. SendMessage(hWnd, LB_SETCURSEL, 0, 0L );
  1873. SendMessage(hWnd,WM_SETREDRAW, TRUE, 0L);
  1874. return(bInitd);
  1875. }
  1876. /*
  1877. * DLG: LB_AVAILABLE
  1878. *
  1879. * RemoveAvailable()
  1880. *
  1881. * Remove all drivers from the listbox and free all storage associated with
  1882. * the keyname
  1883. */
  1884. void RemoveAvailable(HWND hWnd)
  1885. {
  1886. int iIndex;
  1887. HWND hWndA;
  1888. LPTSTR pstrKey;
  1889. hWndA = GetDlgItem(hWnd, LB_AVAILABLE);
  1890. iIndex = (int)SendMessage(hWndA, LB_GETCOUNT, 0, 0L);
  1891. while ( iIndex-- > 0)
  1892. {
  1893. if (( (pstrKey = (LPTSTR)SendMessage(hWndA, LB_GETITEMDATA, iIndex,
  1894. 0L)) != (LPTSTR)LB_ERR ) && pstrKey)
  1895. LocalFree((HLOCAL)pstrKey);
  1896. }
  1897. }
  1898. /*
  1899. * DLG: LB_AVAILABLE
  1900. *
  1901. * AvailableDriversDlg()
  1902. *
  1903. * List the available installable drivers or return FALSE if there are none.
  1904. */
  1905. const static DWORD aAvailDlgHelpIds[] = { // Context Help IDs
  1906. LB_AVAILABLE, IDH_ADD_DRIVER_LIST,
  1907. ID_DRVSTRING, IDH_ADD_DRIVER_LIST,
  1908. 0, 0
  1909. };
  1910. INT_PTR AvailableDriversDlg(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1911. {
  1912. LPTSTR pstrKey; //-jyg- added
  1913. HWND hWndA;
  1914. int iIndex;
  1915. switch ( uMsg )
  1916. {
  1917. case WM_INITDIALOG:
  1918. ShowWindow(hWnd, TRUE);
  1919. wsStartWait();
  1920. if (pinfOldDefault)
  1921. {
  1922. infSetDefault(pinfOldDefault);
  1923. pinfOldDefault = NULL;
  1924. }
  1925. if ( !InitAvailable(hWndA = GetDlgItem(hWnd, LB_AVAILABLE), UNLIST_LINE))
  1926. {
  1927. /*
  1928. * We weren't able to find the [installable.drivers] section
  1929. * of the
  1930. * mmdriver.inf OR it was corrupt. Go ahead and query the
  1931. * user to find an oemsetup.inf to make our default. This
  1932. * is a bad state.
  1933. */
  1934. EndDialog(hWnd, FALSE);
  1935. bFindOEM = TRUE;
  1936. wcscpy(szDrv, szOemInf);
  1937. if (DialogBox(myInstance, MAKEINTRESOURCE(DLG_INSERTDISK),
  1938. hWnd, AddDriversDlg) == TRUE)
  1939. PostMessage(hWnd, WM_INITDIALOG, 0, 0L);
  1940. else
  1941. pinfOldDefault = infSetDefault(pinfOldDefault);
  1942. bFindOEM = FALSE;
  1943. }
  1944. wsEndWait();
  1945. break;
  1946. case WM_COMMAND:
  1947. switch ( LOWORD(wParam ))
  1948. {
  1949. case LB_AVAILABLE:
  1950. // Hm... We've picked it.
  1951. if ( HIWORD(wParam) == LBN_DBLCLK )
  1952. SendMessage(hWnd, WM_COMMAND, IDOK, 0L);
  1953. break;
  1954. case IDOK:
  1955. /*
  1956. * We've made our selection
  1957. */
  1958. hWndA = GetDlgItem(hWnd, LB_AVAILABLE);
  1959. if ( (iIndex = (int)SendMessage(hWndA, LB_GETCURSEL, 0, 0L)) != LB_ERR)
  1960. {
  1961. if (!iIndex)
  1962. {
  1963. /*
  1964. * The first entry is for OEMs
  1965. */
  1966. INT_PTR iFound;
  1967. bBadOemSetup = FALSE;
  1968. bCopyEvenIfOlder = TRUE;
  1969. bFindOEM = TRUE;
  1970. hMesgBoxParent = hWnd;
  1971. while ((iFound = DialogBox(myInstance,
  1972. MAKEINTRESOURCE(DLG_INSERTDISK), hWnd,
  1973. AddDriversDlg)) == 2);
  1974. if (iFound == 1)
  1975. {
  1976. RemoveAvailable(hWnd);
  1977. SendDlgItemMessage(hWnd, LB_AVAILABLE,
  1978. LB_RESETCONTENT, 0, 0L);
  1979. PostMessage(hWnd, WM_INITDIALOG, 0, 0L);
  1980. }
  1981. bFindOEM = FALSE;
  1982. }
  1983. else
  1984. {
  1985. /*
  1986. * The user selected an entry from our .inf
  1987. */
  1988. wsStartWait();
  1989. /*
  1990. * The data associated with the list item is
  1991. * the driver key name (field 0 in the inf file).
  1992. */
  1993. pstrKey = (LPTSTR)SendMessage(hWndA, LB_GETITEMDATA, iIndex, 0L);
  1994. bCopyingRelated = FALSE;
  1995. bQueryExist = TRUE;
  1996. if (InstallDrivers(hWndMain, hWnd, pstrKey))
  1997. {
  1998. RefreshAdvDlgTree ();
  1999. wsEndWait();
  2000. /*
  2001. * If bRestart is true then the system must
  2002. * be restarted to activate these changes
  2003. */
  2004. if (bRestart)
  2005. {
  2006. iRestartMessage= IDS_RESTART_ADD;
  2007. DialogBox(myInstance,
  2008. MAKEINTRESOURCE(DLG_RESTART), hWnd,
  2009. RestartDlg);
  2010. }
  2011. }
  2012. else
  2013. wsEndWait();
  2014. bRestart = FALSE;
  2015. bRelated = FALSE;
  2016. }
  2017. }
  2018. EndDialog(hWnd, FALSE);
  2019. break;
  2020. case IDCANCEL:
  2021. EndDialog(hWnd, FALSE);
  2022. break;
  2023. default:
  2024. return(FALSE);
  2025. }
  2026. break;
  2027. case WM_CONTEXTMENU:
  2028. WinHelp((HWND)wParam, gszWindowsHlp, HELP_CONTEXTMENU,
  2029. (UINT_PTR)(LPTSTR)aAvailDlgHelpIds);
  2030. break;
  2031. case WM_HELP:
  2032. WinHelp(((LPHELPINFO)lParam)->hItemHandle, gszWindowsHlp,
  2033. HELP_WM_HELP, (UINT_PTR)(LPTSTR)aAvailDlgHelpIds);
  2034. break;
  2035. case WM_DESTROY:
  2036. //
  2037. // free the strings added as DATAITEM to the avail list
  2038. RemoveAvailable(hWnd);
  2039. return(FALSE);
  2040. default:
  2041. return FALSE;
  2042. break;
  2043. }
  2044. return(TRUE);
  2045. }
  2046. BOOL DriversDllInitialize( IN PVOID hInstance
  2047. , IN DWORD ulReason
  2048. , IN PCONTEXT pctx OPTIONAL
  2049. )
  2050. {
  2051. if (ulReason != DLL_PROCESS_ATTACH)
  2052. return TRUE;
  2053. myInstance = hInstance;
  2054. LoadString(myInstance, IDS_CLOSE, aszClose, sizeof(aszClose)/sizeof(TCHAR));
  2055. LoadString(myInstance, IDS_DRIVERDESC, szDriversDesc, sizeof(szDriversDesc)/sizeof(TCHAR));
  2056. LoadString(myInstance, IDS_FILE_ERROR, szFileError, sizeof(szFileError)/sizeof(TCHAR));
  2057. LoadString(myInstance, IDS_INSTALLDRIVERS, szMDrivers, sizeof(szMDrivers)/sizeof(TCHAR));
  2058. LoadString(myInstance, IDS_INSTALLDRIVERS32, szMDrivers32, sizeof(szMDrivers)/sizeof(TCHAR));
  2059. LoadString(myInstance, IDS_RELATEDDESC, szRelatedDesc, sizeof(szRelatedDesc)/sizeof(TCHAR));
  2060. LoadString(myInstance, IDS_USERINSTALLDRIVERS, szUserDrivers, sizeof(szUserDrivers)/sizeof(TCHAR));
  2061. LoadString(myInstance, IDS_UNLISTED, (LPTSTR)szUnlisted, sizeof(szUnlisted)/sizeof(TCHAR));
  2062. LoadString(myInstance, IDS_KNOWN, szKnown, sizeof(szKnown)/sizeof(TCHAR));
  2063. LoadString(myInstance, IDS_OEMSETUP, szOemInf, sizeof(szOemInf)/sizeof(TCHAR));
  2064. LoadString(myInstance, IDS_SYSTEM, szSystem, sizeof(szSystem)/sizeof(TCHAR));
  2065. LoadString(myInstance, IDS_OUT_OF_REMOVE_SPACE, szOutOfRemoveSpace, sizeof(szOutOfRemoveSpace)/sizeof(TCHAR));
  2066. LoadString(myInstance, IDS_NO_DESCRIPTION, szNoDesc, sizeof(szNoDesc)/sizeof(TCHAR));
  2067. LoadString(myInstance, IDS_ERRORBOX, szError, sizeof(szError)/sizeof(TCHAR));
  2068. LoadString(myInstance, IDS_REMOVEORNOT, szRemoveOrNot, sizeof(szRemoveOrNot)/sizeof(TCHAR));
  2069. LoadString(myInstance, IDS_REMOVEORNOTSTRICT, szRemoveOrNotStrict, sizeof(szRemoveOrNotStrict)/sizeof(TCHAR));
  2070. LoadString(myInstance, IDS_SETUPINF, szSetupInf, sizeof(szSetupInf)/sizeof(TCHAR));
  2071. LoadString(myInstance, IDS_APPNAME, szAppName, sizeof(szAppName)/sizeof(TCHAR));
  2072. LoadString(myInstance, IDS_DRIVERS, szDrivers, sizeof(szDrivers)/sizeof(TCHAR));
  2073. LoadString(myInstance, IDS_REMOVE, szRemove, sizeof(szRemove)/sizeof(TCHAR));
  2074. LoadString(myInstance, IDS_CONTROLINI, szControlIni, sizeof(szControlIni)/sizeof(TCHAR));
  2075. LoadString(myInstance, IDS_SYSINI, szSysIni, sizeof(szSysIni)/sizeof(TCHAR));
  2076. LoadString(myInstance, IDS_MCI, szMCI, sizeof(szMCI)/sizeof(TCHAR));
  2077. LoadString(myInstance, IDS_DEFDRIVE, szDirOfSrc, sizeof(szDirOfSrc)/sizeof(TCHAR));
  2078. LoadString(myInstance, IDS_CONTROL_HLP_FILE, szDriversHlp, sizeof(szDriversHlp)/sizeof(TCHAR));
  2079. LoadString(myInstance, IDS_LASTQUERY, szLastQuery, sizeof(szLastQuery)/sizeof(TCHAR));
  2080. return TRUE;
  2081. }
  2082. void DeleteCPLCache(void)
  2083. {
  2084. HKEY hKeyCache;
  2085. if (ERROR_SUCCESS ==
  2086. RegOpenKey(HKEY_CURRENT_USER,
  2087. TEXT("Control Panel\\Cache\\multimed.cpl"),
  2088. &hKeyCache)) {
  2089. for ( ; ; ) {
  2090. TCHAR Name[50];
  2091. if (ERROR_SUCCESS ==
  2092. RegEnumKey(hKeyCache,
  2093. 0,
  2094. Name,
  2095. sizeof(Name)/sizeof(TCHAR))) {
  2096. HKEY hSubKey;
  2097. RegDeleteKey(hKeyCache, Name);
  2098. } else {
  2099. break; // leave loop
  2100. }
  2101. }
  2102. RegDeleteKey(hKeyCache, NULL);
  2103. RegCloseKey(hKeyCache);
  2104. }
  2105. }
  2106. /*
  2107. ** RestartDlg()
  2108. **
  2109. ** Offer user the choice to (not) restart windows.
  2110. */
  2111. INT_PTR RestartDlg(HWND hDlg, unsigned uiMessage, WPARAM wParam, LPARAM lParam)
  2112. {
  2113. switch (uiMessage)
  2114. {
  2115. case WM_COMMAND:
  2116. switch (LOWORD(wParam))
  2117. {
  2118. case IDCANCEL:
  2119. //
  2120. // don't restart windows
  2121. //
  2122. EndDialog(hDlg, FALSE);
  2123. break;
  2124. case IDOK:
  2125. //
  2126. // do restart windows, *dont* dismiss dialog incase
  2127. // the user canceled it.
  2128. //
  2129. ReBoot(hDlg);
  2130. SetActiveWindow(hDlg);
  2131. //EndDialog(hDlg, TRUE);
  2132. break;
  2133. default:
  2134. return FALSE;
  2135. }
  2136. return TRUE;
  2137. case WM_INITDIALOG:
  2138. /*
  2139. ** Delete the control panel's cache so it will get it
  2140. ** right!
  2141. */
  2142. DeleteCPLCache();
  2143. if (iRestartMessage)
  2144. {
  2145. TCHAR szMesg1[300];
  2146. TCHAR szMesg2[300];
  2147. LoadString(myInstance, iRestartMessage, szMesg1, sizeof(szMesg1)/sizeof(TCHAR));
  2148. wsprintf(szMesg2, szMesg1, (LPTSTR)szRestartDrv);
  2149. SetDlgItemText(hDlg, IDS_RESTARTTEXT, (LPTSTR)szMesg2);
  2150. if (iRestartMessage == IDS_RESTART_NOSOUND)
  2151. {
  2152. PostMessage (hDlg, WM_NEXTDLGCTL,
  2153. (WPARAM)GetDlgItem(hDlg,IDOK), (LPARAM)TRUE);
  2154. }
  2155. }
  2156. return TRUE;
  2157. case WM_KEYUP:
  2158. if (wParam == VK_F3)
  2159. //
  2160. // don't restart windows
  2161. //
  2162. EndDialog(hDlg, FALSE);
  2163. break;
  2164. default:
  2165. break;
  2166. }
  2167. return FALSE;
  2168. }
  2169. /*
  2170. * UserInstalled()
  2171. *
  2172. *
  2173. */
  2174. BOOL UserInstalled(LPTSTR szKey)
  2175. {
  2176. TCHAR buf[MAXSTR];
  2177. LPTSTR lpstr = NULL;
  2178. ZeroMemory (buf, sizeof (buf)); // make prefix happy.
  2179. lpstr = GetProfile (szUserDrivers, (LPTSTR)szKey, szControlIni, buf, sizeof(buf));
  2180. if (lpstr && *lpstr != TEXT('\0'))
  2181. return(TRUE);
  2182. else
  2183. return(FALSE);
  2184. }
  2185. /*
  2186. * AddUnlistedDlg()
  2187. *
  2188. * The following function processes requests by the user to install unlisted
  2189. * or updated drivers.
  2190. *
  2191. * PARAMETERS: The normal Dialog box parameters
  2192. * RETURN VALUE: The usual Dialog box return value
  2193. */
  2194. INT_PTR AddUnlistedDlg(HWND hDlg, unsigned nMsg, WPARAM wParam, LPARAM lParam)
  2195. {
  2196. switch (nMsg)
  2197. {
  2198. case WM_INITDIALOG:
  2199. {
  2200. HWND hListDrivers;
  2201. BOOL bFoundDrivers;
  2202. wsStartWait();
  2203. hListDrivers = GetDlgItem(hDlg, LB_UNLISTED);
  2204. /* Search for drivers */
  2205. bFoundDrivers = InitAvailable(hListDrivers, NO_UNLIST_LINE);
  2206. if (!bFoundDrivers)
  2207. {
  2208. //
  2209. // We weren't able to find the MMDRIVERS section of the
  2210. // setup.inf OR it was corrupt. Go ahead and query the
  2211. // user to find an oemsetup.inf to make our default. This
  2212. // is a bad state.
  2213. //
  2214. INT_PTR iFound;
  2215. bFindOEM = TRUE;
  2216. bBadOemSetup = TRUE;
  2217. while ((iFound = DialogBox(myInstance,
  2218. MAKEINTRESOURCE(DLG_INSERTDISK), hMesgBoxParent,
  2219. AddDriversDlg)) == 2);
  2220. bFindOEM = FALSE;
  2221. if (iFound == 1)
  2222. {
  2223. SendDlgItemMessage(hDlg, LB_AVAILABLE,
  2224. LB_RESETCONTENT, 0, 0L);
  2225. PostMessage(hDlg, WM_INITDIALOG, 0, 0L);
  2226. }
  2227. EndDialog(hDlg, FALSE);
  2228. }
  2229. SendMessage(hListDrivers, LB_SETCURSEL, 0, 0L);
  2230. wsEndWait();
  2231. break;
  2232. }
  2233. case WM_COMMAND:
  2234. switch (LOWORD(wParam))
  2235. {
  2236. case IDH_DLG_ADD_UNKNOWN:
  2237. goto DoHelp;
  2238. case LB_UNLISTED:
  2239. if (HIWORD(wParam) != LBN_DBLCLK)
  2240. break;
  2241. // else Fall through here
  2242. case IDOK:
  2243. {
  2244. HWND hWndA;
  2245. int iIndex;
  2246. LPTSTR pstrKey;
  2247. hWndA = GetDlgItem(hDlg, LB_UNLISTED);
  2248. if ( (iIndex = (int)SendMessage(hWndA, LB_GETCURSEL, 0, 0L))
  2249. != LB_ERR)
  2250. {
  2251. wsStartWait();
  2252. pstrKey = (LPTSTR)SendMessage(hWndA, LB_GETITEMDATA, iIndex, 0L);
  2253. bCopyingRelated = FALSE;
  2254. bQueryExist = TRUE;
  2255. if (InstallDrivers(hWndMain, hDlg, pstrKey))
  2256. {
  2257. RefreshAdvDlgTree ();
  2258. wsEndWait();
  2259. if (bRestart)
  2260. {
  2261. iRestartMessage= IDS_RESTART_ADD;
  2262. DialogBox(myInstance, MAKEINTRESOURCE(DLG_RESTART),
  2263. hDlg, RestartDlg);
  2264. }
  2265. }
  2266. else
  2267. wsEndWait();
  2268. bRelated = FALSE;
  2269. bRestart = FALSE;
  2270. }
  2271. EndDialog(hDlg, FALSE);
  2272. }
  2273. break;
  2274. case IDCANCEL:
  2275. EndDialog(hDlg, wParam);
  2276. break;
  2277. default:
  2278. return FALSE;
  2279. }
  2280. break;
  2281. case WM_HELP:
  2282. DoHelp:
  2283. WinHelp (hDlg, gszWindowsHlp, HELP_CONTEXT, IDH_MMCPL_DEVPROP_ENABLE);
  2284. break;
  2285. default:
  2286. return FALSE;
  2287. }
  2288. return TRUE;
  2289. }
  2290. /*
  2291. * ReBoot()
  2292. *
  2293. * Restart the system. If this fails we put up a message box
  2294. */
  2295. void ReBoot(HWND hDlg)
  2296. {
  2297. DWORD Error;
  2298. BOOLEAN WasEnabled;
  2299. /*
  2300. * We must adjust our privilege level to be allowed to restart the
  2301. * system
  2302. */
  2303. RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE,
  2304. TRUE,
  2305. FALSE,
  2306. &WasEnabled
  2307. );
  2308. /*
  2309. * Try to reboot the system
  2310. */
  2311. if (!ExitWindowsEx(EWX_REBOOT, 0xFFFFFFFF)) {
  2312. Error = GetLastError();
  2313. /*
  2314. * Put up a message box if we failed
  2315. */
  2316. if (Error != NO_ERROR) {
  2317. TCHAR szCantRestart[80];
  2318. LoadString(myInstance,
  2319. Error == ERROR_PRIVILEGE_NOT_HELD ||
  2320. Error == ERROR_NOT_ALL_ASSIGNED ||
  2321. Error == ERROR_ACCESS_DENIED ?
  2322. IDS_CANNOT_RESTART_PRIVILEGE :
  2323. IDS_CANNOT_RESTART_UNKNOWN,
  2324. szCantRestart,
  2325. sizeof(szCantRestart)/sizeof(TCHAR));
  2326. MessageBox(hDlg, szCantRestart, szError,
  2327. MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
  2328. }
  2329. }
  2330. }
  2331. void OpenDriverError(HWND hDlg, LPTSTR szDriver, LPTSTR szFile)
  2332. {
  2333. TCHAR szMesg[MAXSTR];
  2334. TCHAR szMesg2[MAXSTR];
  2335. LoadString(myInstance, IDS_INSTALLING_DRIVERS, szMesg, sizeof(szMesg)/sizeof(TCHAR));
  2336. wsprintf(szMesg2, szMesg, szDriver, szFile);
  2337. MessageBox(hDlg, szMesg2, szError, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
  2338. }
  2339. /*
  2340. *** AddIDriver - Adds a treeitem referencing the given PIDRIVER
  2341. *
  2342. * Note that the listed PIDRIVER should already have been added to the
  2343. * aInstalledDrivers array (via AddIDriverToArray()) before calling this
  2344. * routine.
  2345. *
  2346. */
  2347. HTREEITEM AddIDriver (HWND hTree, PIDRIVER pIDriver, DriverClass dc)
  2348. {
  2349. short idr;
  2350. TV_INSERTSTRUCT ti;
  2351. HTREEITEM hti;
  2352. short ii;
  2353. TCHAR szFile[ _MAX_FNAME +1 +_MAX_EXT +1 ];
  2354. TCHAR szExt[ _MAX_EXT +1 ];
  2355. TCHAR szDesc[ cchRESOURCE ];
  2356. // don't add an entry for one of the to-be-skipped drivers
  2357. //
  2358. lsplitpath (pIDriver->szFile, NULL, NULL, szFile, szExt);
  2359. if (szExt[0] != TEXT('\0'))
  2360. lstrcat (szFile, szExt);
  2361. //check to see if we're trying to put a PNP driver into the legacy tree
  2362. if (g_dcFilterClass == dcLEGACY)
  2363. {
  2364. if ((dc == dcWAVE) ||
  2365. (dc == dcMIDI) ||
  2366. (dc == dcMIXER) ||
  2367. (dc == dcAUX))
  2368. {
  2369. if (IsPnPDriver(szFile))
  2370. {
  2371. return FALSE;
  2372. }
  2373. }
  2374. }
  2375. if (dc != dcMIDI)
  2376. {
  2377. for (ii = 0; ii < nDriversToSKIP; ii++)
  2378. {
  2379. if (!lstrcmpi (szFile, aDriversToSKIP[ ii ]))
  2380. return FALSE;
  2381. }
  2382. }
  2383. // If we were given a DriverClass, then the caller has
  2384. // specified where we should create an entry--add the "Audio for"
  2385. // (etc) tag before the description, and add it.
  2386. //
  2387. // Otherwise, determine where this driver belongs in the tree
  2388. //
  2389. if (dc != dcINVALID)
  2390. {
  2391. TCHAR szTag[ cchRESOURCE ];
  2392. switch (dc)
  2393. {
  2394. case dcWAVE: GetString (szTag, IDS_AUDIOFOR);
  2395. break;
  2396. case dcMIDI: GetString (szTag, IDS_MIDIFOR);
  2397. break;
  2398. case dcMIXER: GetString (szTag, IDS_MIXERFOR);
  2399. break;
  2400. case dcAUX: GetString (szTag, IDS_AUXFOR);
  2401. break;
  2402. default: lstrcpy (szTag, TEXT("%s"));
  2403. break;
  2404. }
  2405. wsprintf (szDesc, szTag, pIDriver->szDesc);
  2406. }
  2407. else
  2408. {
  2409. if ((dc = GuessDriverClass (pIDriver)) == dcINVALID)
  2410. return FALSE;
  2411. lstrcpy (szDesc, pIDriver->szDesc);
  2412. }
  2413. // map that classification into an index within the
  2414. // root entries of the tree (aDriverRoot[])
  2415. //
  2416. if ((idr = DriverClassToRootIndex (dc)) == -1)
  2417. return FALSE;
  2418. // if this driver already has an entry under this DriverClass,
  2419. // then don't add another.
  2420. //
  2421. for (ii =0; ii < cInstalledDrivers; ++ii)
  2422. {
  2423. if (aInstalledDrivers[ ii ].pIDriver == pIDriver)
  2424. break;
  2425. }
  2426. if (ii >= cInstalledDrivers)
  2427. {
  2428. ii = (short)NOPIDRIVER;
  2429. }
  2430. else if (aInstalledDrivers[ ii ].dwBits & aDriverRoot[ idr ].dwBit)
  2431. {
  2432. return FALSE; // Already have an entry here!
  2433. }
  2434. // since not all roots need exist all the time, make sure
  2435. // this classification HAS a root in the tree
  2436. //
  2437. if (!EnsureRootIndexExists (hTree, idr))
  2438. return FALSE;
  2439. // finally, insert an item into the tree for this driver
  2440. // note that for audio codecs to be sorted properly, they must
  2441. // be added via this routine in their appropriate order--ie,
  2442. // call this routine for the highest-priority codec first.
  2443. //
  2444. ti.hParent = aDriverRoot[ idr ].hti;
  2445. ti.hInsertAfter = (dc == dcACODEC) ? TVI_LAST : TVI_SORT;
  2446. ti.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  2447. ti.item.iImage = (int)idr;
  2448. ti.item.iSelectedImage = (int)idr;
  2449. ti.item.pszText = szDesc;
  2450. ti.item.lParam = ii;
  2451. if ((hti = TreeView_InsertItem (hTree, &ti)) == NULL)
  2452. return FALSE;
  2453. if (ii != NOPIDRIVER)
  2454. aInstalledDrivers[ ii ].dwBits |= aDriverRoot[ idr ].dwBit;
  2455. return hti;
  2456. }
  2457. BOOL AddIDriverByName (HWND hTree, LPCWSTR wszFile, DriverClass dc)
  2458. {
  2459. LPTSTR pch;
  2460. TCHAR tszFile[ max(cchRESOURCE, MAX_PATH) ];
  2461. PIDRIVER pid;
  2462. #ifdef UNICODE
  2463. lstrcpy (tszFile, wszFile);
  2464. #else
  2465. wcstombs (tszFile, wszFile, cchRESOURCE);
  2466. #endif
  2467. // Strip off any trailing whitespace
  2468. //
  2469. if (tszFile[0] == TEXT('\0'))
  2470. return FALSE;
  2471. for (pch = &tszFile[ lstrlen(tszFile)-1 ];
  2472. pch >= tszFile && (*pch == TEXT('\t') || *pch == TEXT(' '));
  2473. --pch)
  2474. ;
  2475. *(1+pch) = TEXT('\0');
  2476. // If this is MMDRV.DLL, then it's possibly providing the
  2477. // user-mode component for kernel-mode drivers. Since it's
  2478. // apparently impossible to determine the name of the .SYS
  2479. // file which is providing a "\\.\WaveIn0" device (etc),
  2480. // we'll use a hack: Check around for anyone registered
  2481. // under the alias "Kernel", and use that.
  2482. //
  2483. if (!lstrcmpi (tszFile, cszMMDRVDLL))
  2484. {
  2485. mysize_t ii;
  2486. for (ii = 0; ii < cInstalledDrivers; ++ii)
  2487. {
  2488. if (aInstalledDrivers[ ii ].pIDriver == NULL)
  2489. continue;
  2490. if (!lstrnicmp (aInstalledDrivers[ ii ].pIDriver->szAlias,
  2491. cszAliasKERNEL,
  2492. lstrlen(cszAliasKERNEL)))
  2493. {
  2494. lstrcpy (tszFile, aInstalledDrivers[ ii ].pIDriver->szFile);
  2495. break;
  2496. }
  2497. }
  2498. if (ii >= cInstalledDrivers)
  2499. return FALSE;
  2500. }
  2501. // Find the driver in the aInstalledDriver array, and add
  2502. // an entry for it in the tree.
  2503. //
  2504. if ((pid = FindIDriverByName (tszFile)) == NULL)
  2505. return FALSE;
  2506. if (AddIDriver (hTree, pid, dc) == NULL)
  2507. return FALSE;
  2508. return TRUE;
  2509. }
  2510. /*
  2511. *** RemoveIDriver - Removes (and optionally frees) an IDRIVER from hAdvDlgTree
  2512. *
  2513. */
  2514. void RemoveIDriver (HWND hTree, PIDRIVER pIDriver, BOOL fFreeToo)
  2515. {
  2516. mysize_t ii;
  2517. short idr;
  2518. HTREEITEM hti;
  2519. // Find each TreeItem which references this entry.
  2520. //
  2521. for (idr = 0; idr < nDriverROOTS; idr++)
  2522. {
  2523. if ((hti = aDriverRoot[ idr ].hti) == NULL)
  2524. continue;
  2525. hti = TreeView_GetChild (hTree, hti);
  2526. while (hti != NULL)
  2527. {
  2528. if (pIDriver != FindIDriverByTreeItem (hti))
  2529. {
  2530. hti = TreeView_GetNextSibling (hTree, hti);
  2531. continue;
  2532. }
  2533. // We found a tree item which uses this driver, so delete the
  2534. // item. Also note that this may cause the driver's parent
  2535. // node to no longer be necessary.
  2536. //
  2537. TreeView_DeleteItem (hTree, hti);
  2538. hti = TreeView_GetChild (hTree, aDriverRoot[ idr ].hti);
  2539. if (!aDriverRoot[ idr ].fAlwaysMake) // may no longer need parent?
  2540. {
  2541. if (hti == NULL) // parent now has no children?
  2542. {
  2543. TreeView_DeleteItem (hTree, aDriverRoot[ idr ].hti);
  2544. aDriverRoot[ idr ].hti = NULL;
  2545. }
  2546. }
  2547. }
  2548. }
  2549. // See if we can find the given pIDriver within the
  2550. // aInstalledDriver array.
  2551. //
  2552. for (ii = 0; ii < cInstalledDrivers; ++ii)
  2553. {
  2554. if (aInstalledDrivers[ ii ].pIDriver == pIDriver)
  2555. {
  2556. aInstalledDrivers[ ii ].dwBits = 0L; // no longer in tree at all
  2557. if (fFreeToo)
  2558. {
  2559. LocalFree ((HANDLE)aInstalledDrivers[ ii ].pIDriver);
  2560. aInstalledDrivers[ ii ].pIDriver = NULL;
  2561. }
  2562. break; // There's only one entry in this array for each pIDriver
  2563. }
  2564. }
  2565. }
  2566. #ifdef FIX_BUG_15451
  2567. HTREEITEM FindTreeItemByDriverName (LPTSTR pszName)
  2568. {
  2569. PIDRIVER pid;
  2570. short idr;
  2571. HTREEITEM hti;
  2572. if ((pid = FindIDriverByName (pszName)) == NULL)
  2573. return (HTREEITEM)0;
  2574. for (idr = 0; idr < nDriverROOTS; idr++)
  2575. {
  2576. if ((hti = aDriverRoot[ idr ].hti) == NULL)
  2577. continue;
  2578. for (hti = TreeView_GetChild (hAdvDlgTree, hti);
  2579. hti != NULL;
  2580. hti = TreeView_GetNextSibling (hAdvDlgTree, hti))
  2581. {
  2582. if (pid == FindIDriverByTreeItem (hti))
  2583. {
  2584. return hti;
  2585. }
  2586. }
  2587. }
  2588. return (HTREEITEM)0;
  2589. }
  2590. #endif // FIX_BUG_15451
  2591. PIDRIVER FindIDriverByTreeItem (HTREEITEM hti)
  2592. {
  2593. TV_ITEM tvi;
  2594. tvi.mask = TVIF_PARAM;
  2595. tvi.hItem = hti;
  2596. TreeView_GetItem (hAdvDlgTree, &tvi);
  2597. if ( (tvi.lParam < 0) ||
  2598. (tvi.lParam >= cInstalledDrivers) )
  2599. {
  2600. return NULL;
  2601. }
  2602. return aInstalledDrivers[ tvi.lParam ].pIDriver;
  2603. }
  2604. /*
  2605. *** FindIDriverByName - Returns the first found IDRIVER structure with a name
  2606. *
  2607. */
  2608. PIDRIVER FindIDriverByName (LPTSTR szFile)
  2609. {
  2610. mysize_t ii;
  2611. for (ii = 0; ii < cInstalledDrivers; ++ii)
  2612. {
  2613. if (aInstalledDrivers[ ii ].pIDriver == NULL)
  2614. continue;
  2615. if (aInstalledDrivers[ ii ].pIDriver->szAlias[0] == TEXT('\0'))
  2616. continue;
  2617. if (!FileNameCmp (aInstalledDrivers[ ii ].pIDriver->szFile, szFile))
  2618. return aInstalledDrivers[ ii ].pIDriver;
  2619. }
  2620. return NULL;
  2621. }
  2622. PIDRIVER FindIDriverByResource (PIRESOURCE pir)
  2623. {
  2624. return FindIDriverByName (FileName( pir->szFile ));
  2625. }
  2626. /*
  2627. *** GetSelectedIDriver - Returns the IDRIVER structure the user has selected
  2628. *
  2629. */
  2630. PIDRIVER GetSelectedIDriver (HWND hTree)
  2631. {
  2632. HTREEITEM htiCur = TreeView_GetSelection (hTree);
  2633. if (htiCur == NULL)
  2634. return NULL;
  2635. return FindIDriverByTreeItem (htiCur);
  2636. }
  2637. /*
  2638. *** DriverClassToRootIndex - obtain idr for which {aDriverRoot[idr].dc == dc}
  2639. *
  2640. * The array index for aDriverRoot[] is NOT a DriverClass--that is,
  2641. * aDriverRoot[ PickAnyDC ].dc is not necessarily equal to PickAnyDC.
  2642. * Given a DC, this routine finds the index into aDriverRoot which references
  2643. * that DC.
  2644. *
  2645. */
  2646. short DriverClassToRootIndex (DriverClass dc)
  2647. {
  2648. short idr;
  2649. for (idr = 0; idr < nDriverROOTS; idr++)
  2650. {
  2651. if (aDriverRoot[ idr ].dc == dc)
  2652. return idr;
  2653. }
  2654. return -1;
  2655. }
  2656. /*
  2657. *** GetDriverClass - guess a DriverClass based on an IDRIVER structure
  2658. *
  2659. * The registry has several different aliases which it uses in the LHS
  2660. * of HKLM\software\microsoft\windowsnt\drivers,drivers32,etc to indicate
  2661. * the classification of a particular driver. These include:
  2662. *
  2663. * AUX, MIDI, MIDIMAPPER, MIXER, MSACM.*, VIDC.* WAVE, WAVEMAPPER
  2664. *
  2665. * as well as others--the full array of known entries is tracked within
  2666. * aDriverKeywords[]. In addition, any of these may be followed by a
  2667. * string of digits by which they are distinguished. This routine parses
  2668. * these keywords and returns a corresponding DriverClass enum.
  2669. *
  2670. */
  2671. DriverClass GuessDriverClass (PIDRIVER pid)
  2672. {
  2673. #ifdef FIX_BUG_15451
  2674. return GuessDriverClassFromAlias (pid->szAlias);
  2675. }
  2676. DriverClass GuessDriverClassFromAlias (LPTSTR pszAlias)
  2677. {
  2678. #endif // FIX_BUG_15451
  2679. TCHAR szAlias[ cchRESOURCE ];
  2680. TCHAR *pch;
  2681. short ii;
  2682. #ifdef FIX_BUG_15451
  2683. lstrcpy (szAlias, pszAlias); // Make a local copy so we can munge it
  2684. #else // FIX_BUG_15451
  2685. lstrcpy (szAlias, pid->szAlias); // Make a local copy so we can munge it
  2686. #endif // FIX_BUG_15451
  2687. if ((pch = lstrchr (szAlias, TEXT('.'))) != NULL)
  2688. *pch = TEXT('0');
  2689. for (ii = 0; ii < nDriverKEYWORDS; ii++)
  2690. {
  2691. if (!lstrnicmp (szAlias,
  2692. aDriverKeyword[ii].psz,
  2693. lstrlen (aDriverKeyword[ii].psz)))
  2694. {
  2695. return aDriverKeyword[ii].dc;
  2696. }
  2697. }
  2698. return dcOTHER;
  2699. }
  2700. DriverClass GuessDriverClassFromTreeItem (HTREEITEM hti)
  2701. {
  2702. short idr;
  2703. for (idr = 0; idr < nDriverROOTS; idr++)
  2704. {
  2705. if (hti == aDriverRoot[idr].hti)
  2706. return aDriverRoot[idr].dc;
  2707. }
  2708. return (g_dcFilterClass);
  2709. }
  2710. /*
  2711. *** EnsureRootIndexExists - makes sure a given parent exists in hAdvDlgTree
  2712. *
  2713. */
  2714. BOOL EnsureRootIndexExists (HWND hTree, short idr)
  2715. {
  2716. TV_INSERTSTRUCT ti;
  2717. TCHAR szDesc[ cchRESOURCE ];
  2718. HWND hwndParent = NULL;
  2719. HWND hwndName = NULL;
  2720. // If we already HAVE a root in the tree, we're done.
  2721. //
  2722. if (aDriverRoot[ idr ].hti != NULL)
  2723. return TRUE;
  2724. if (g_dcFilterClass != dcINVALID)
  2725. {
  2726. if (g_dcFilterClass == dcLEGACY)
  2727. {
  2728. if ((aDriverRoot[ idr ].dc != dcWAVE) &&
  2729. (aDriverRoot[ idr ].dc != dcMIDI) &&
  2730. (aDriverRoot[ idr ].dc != dcMIXER) &&
  2731. (aDriverRoot[ idr ].dc != dcAUX))
  2732. {
  2733. return FALSE;
  2734. }
  2735. }
  2736. else if (aDriverRoot[ idr ].dc != g_dcFilterClass)
  2737. {
  2738. return FALSE;
  2739. }
  2740. }
  2741. aDriverRoot[idr].hti = TVI_ROOT;
  2742. LoadString (myInstance, aDriverRoot[idr].idDesc, szDesc, cchRESOURCE);
  2743. if ((g_dcFilterClass == dcINVALID) || (g_dcFilterClass == dcLEGACY))
  2744. {
  2745. ti.hInsertAfter = TVI_LAST;
  2746. ti.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  2747. ti.item.iImage = idr;
  2748. ti.item.iSelectedImage = idr;
  2749. ti.item.pszText = szDesc;
  2750. ti.item.lParam = NOPIDRIVER;
  2751. if (aDriverRoot[idr].dc == dcINVALID)
  2752. ti.hParent = TVI_ROOT;
  2753. else
  2754. ti.hParent = AdvDlgFindTopLevel ();
  2755. if ((aDriverRoot[idr].hti = TreeView_InsertItem (hTree, &ti)) == NULL)
  2756. return FALSE;
  2757. }
  2758. if (g_dcFilterClass != dcINVALID)
  2759. {
  2760. hwndParent = GetParent(hTree);
  2761. if (hwndParent)
  2762. {
  2763. hwndName = GetDlgItem(hwndParent,IDC_DEVICECLASS);
  2764. if (hwndName)
  2765. {
  2766. if (g_dcFilterClass == dcLEGACY)
  2767. {
  2768. LoadString (myInstance, IDS_WAVE_HEADER, szDesc, cchRESOURCE);
  2769. }
  2770. SetWindowText(hwndName,szDesc);
  2771. }
  2772. }
  2773. }
  2774. return TRUE;
  2775. }
  2776. /*
  2777. **** AdvDlgFindTopLevel - Finds the HTREEITEM associated with the tree root
  2778. *
  2779. * If there's a "Multimedia Devices" tree item under which the other roots
  2780. * are collected, this will return that item. Otherwise, it returns TVI_ROOT.
  2781. *
  2782. */
  2783. HTREEITEM AdvDlgFindTopLevel (void)
  2784. {
  2785. short idr;
  2786. for (idr = 0; idr < nDriverROOTS; idr++)
  2787. {
  2788. if (aDriverRoot[idr].dc == dcINVALID)
  2789. return aDriverRoot[idr].hti;
  2790. }
  2791. return TVI_ROOT;
  2792. }
  2793. /*
  2794. **** InitAdvDlgTree - Prepares the AdvDlg's treeview to display devices
  2795. *
  2796. */
  2797. BOOL InitAdvDlgTree (HWND hTree)
  2798. {
  2799. int cxIcon, cyIcon;
  2800. short idr;
  2801. UINT uFlags;
  2802. DWORD dwLayout;
  2803. #ifdef UNICODE
  2804. TreeView_SetUnicodeFormat(hTree,TRUE);
  2805. #endif
  2806. // Make sure we start with a clean slate
  2807. //
  2808. hAdvDlgTree = hTree;
  2809. SendMessage (hTree, WM_SETREDRAW, FALSE, 0L);
  2810. for (idr = 0; idr < nDriverROOTS; idr++)
  2811. {
  2812. aDriverRoot[ idr ].hti = NULL;
  2813. aDriverRoot[ idr ].dwBit = ((DWORD)1) << idr;
  2814. }
  2815. // Create an imagelist for the icons in the treeview
  2816. //
  2817. cxIcon = (int)GetSystemMetrics (SM_CXSMICON);
  2818. cyIcon = (int)GetSystemMetrics (SM_CYSMICON);
  2819. uFlags = ILC_MASK | ILC_COLOR32;
  2820. if (GetProcessDefaultLayout(&dwLayout) &&
  2821. (dwLayout & LAYOUT_RTL))
  2822. {
  2823. uFlags |= ILC_MIRROR;
  2824. }
  2825. if ((hImageList = ImageList_Create (cxIcon, cyIcon,
  2826. uFlags, nDriverROOTS, 1)) == NULL)
  2827. return FALSE;
  2828. for (idr = 0; idr < nDriverROOTS; idr++)
  2829. {
  2830. HICON hi = LoadImage (myInstance,
  2831. MAKEINTRESOURCE( aDriverRoot[idr].idIcon ),
  2832. IMAGE_ICON, cxIcon, cyIcon, LR_DEFAULTCOLOR);
  2833. ImageList_AddIcon (hImageList, hi);
  2834. }
  2835. TreeView_SetImageList (hTree, hImageList, TVSIL_NORMAL);
  2836. if (g_dcFilterClass == dcINVALID)
  2837. {
  2838. // Create the root nodes that are supposed to exist
  2839. // even without children (note that not all are)
  2840. //
  2841. for (idr = 0; idr < nDriverROOTS; idr++)
  2842. {
  2843. if (aDriverRoot[ idr ].dc == dcINVALID)
  2844. {
  2845. if (!EnsureRootIndexExists (hTree, idr))
  2846. return FALSE;
  2847. }
  2848. }
  2849. for (idr = 0; idr < nDriverROOTS; idr++)
  2850. {
  2851. if (aDriverRoot[ idr ].dc != dcINVALID && aDriverRoot[ idr ].fAlwaysMake)
  2852. {
  2853. if (!EnsureRootIndexExists (hTree, idr))
  2854. return FALSE;
  2855. }
  2856. }
  2857. }
  2858. // Expand the tree somewhat, so the user doesn't get
  2859. // greeted by a blank page
  2860. //
  2861. TreeView_Expand (hTree, AdvDlgFindTopLevel(), TVE_EXPAND);
  2862. SendMessage (hTree, WM_SETREDRAW, TRUE, 0L);
  2863. return TRUE;
  2864. }
  2865. /*
  2866. **** FreeAdvDlgTree - Removes and frees all items within the AdvDlg treeview
  2867. *
  2868. */
  2869. void FreeAdvDlgTree (HWND hTree)
  2870. {
  2871. short idr;
  2872. // Delete all leaf nodes
  2873. //
  2874. for (idr = 0; idr < nDriverROOTS; idr++)
  2875. {
  2876. HTREEITEM hti;
  2877. if (aDriverRoot[idr].dc == dcINVALID)
  2878. continue;
  2879. if (aDriverRoot[idr].hti == NULL)
  2880. continue;
  2881. while ((hti = TreeView_GetChild (hTree, aDriverRoot[idr].hti)) != NULL)
  2882. {
  2883. if (aDriverRoot[ idr ].dc == dcMIDI)
  2884. {
  2885. HTREEITEM htiInstrument;
  2886. while ((htiInstrument = TreeView_GetChild (hTree, hti)) != NULL)
  2887. {
  2888. TV_ITEM tvi;
  2889. tvi.mask = TVIF_PARAM;
  2890. tvi.hItem = htiInstrument;
  2891. tvi.lParam = 0;
  2892. TreeView_GetItem(hTree, &tvi);
  2893. if (tvi.lParam != 0)
  2894. LocalFree ((HANDLE)tvi.lParam);
  2895. TreeView_DeleteItem (hTree, htiInstrument);
  2896. }
  2897. }
  2898. TreeView_DeleteItem (hTree, hti);
  2899. }
  2900. }
  2901. // Delete everything else
  2902. //
  2903. TreeView_DeleteAllItems (hTree);
  2904. // Delete the tree's image list
  2905. //
  2906. if (hImageList)
  2907. {
  2908. TreeView_SetImageList (hTree, NULL, TVSIL_NORMAL);
  2909. ImageList_Destroy (hImageList);
  2910. hImageList = NULL;
  2911. }
  2912. // Delete the InstalledDrivers array
  2913. //
  2914. if (aInstalledDrivers != NULL)
  2915. {
  2916. mysize_t ii;
  2917. for (ii = 0; ii < cInstalledDrivers; ++ii)
  2918. {
  2919. if (aInstalledDrivers[ ii ].pIDriver != NULL)
  2920. {
  2921. LocalFree ((HANDLE)aInstalledDrivers[ ii ].pIDriver);
  2922. aInstalledDrivers[ ii ].pIDriver = NULL;
  2923. }
  2924. }
  2925. GlobalFree ((HGLOBAL)aInstalledDrivers);
  2926. aInstalledDrivers = NULL;
  2927. cInstalledDrivers = 0;
  2928. }
  2929. }
  2930. int lstrnicmp (LPTSTR pszA, LPTSTR pszB, size_t cch)
  2931. {
  2932. #ifdef UNICODE
  2933. size_t cchA, cchB;
  2934. TCHAR *pch;
  2935. for (cchA = 1, pch = pszA; cchA < cch; cchA++, pch++)
  2936. {
  2937. if (*pch == TEXT('\0'))
  2938. break;
  2939. }
  2940. for (cchB = 1, pch = pszB; cchB < cch; cchB++, pch++)
  2941. {
  2942. if (*pch == TEXT('\0'))
  2943. break;
  2944. }
  2945. return (CompareStringW (GetThreadLocale(), NORM_IGNORECASE,
  2946. pszA, cchA, pszB, cchB)
  2947. )-2; // CompareStringW returns {1,2,3} instead of {-1,0,1}.
  2948. #else
  2949. return _strnicmp (pszA, pszB, cch);
  2950. #endif
  2951. }
  2952. LPTSTR lstrchr (LPTSTR pszTarget, TCHAR ch)
  2953. {
  2954. size_t ich;
  2955. if (pszTarget == NULL)
  2956. return NULL;
  2957. for (ich = 0; pszTarget[ich] != TEXT('\0'); ich++)
  2958. {
  2959. if (pszTarget[ich] == ch)
  2960. return &pszTarget[ ich ];
  2961. }
  2962. return NULL;
  2963. }
  2964. void lsplitpath (LPTSTR pszSource,
  2965. LPTSTR pszDrive, LPTSTR pszPath, LPTSTR pszName, LPTSTR pszExt)
  2966. {
  2967. LPTSTR pszLastSlash = NULL;
  2968. LPTSTR pszLastDot = NULL;
  2969. LPTSTR pch;
  2970. size_t cchCopy;
  2971. /*
  2972. * NOTE: This routine was snitched out of USERPRI.LIB 'cause the
  2973. * one in there doesn't split the extension off the name properly.
  2974. *
  2975. * We assume that the path argument has the following form, where any
  2976. * or all of the components may be missing.
  2977. *
  2978. * <drive><dir><fname><ext>
  2979. *
  2980. * and each of the components has the following expected form(s)
  2981. *
  2982. * drive:
  2983. * 0 to _MAX_DRIVE-1 characters, the last of which, if any, is a
  2984. * ':'
  2985. * dir:
  2986. * 0 to _MAX_DIR-1 characters in the form of an absolute path
  2987. * (leading '/' or '\') or relative path, the last of which, if
  2988. * any, must be a '/' or '\'. E.g -
  2989. * absolute path:
  2990. * \top\next\last\ ; or
  2991. * /top/next/last/
  2992. * relative path:
  2993. * top\next\last\ ; or
  2994. * top/next/last/
  2995. * Mixed use of '/' and '\' within a path is also tolerated
  2996. * fname:
  2997. * 0 to _MAX_FNAME-1 characters not including the '.' character
  2998. * ext:
  2999. * 0 to _MAX_EXT-1 characters where, if any, the first must be a
  3000. * '.'
  3001. *
  3002. */
  3003. // extract drive letter and :, if any
  3004. //
  3005. if (*(pszSource + _MAX_DRIVE - 2) == TEXT(':'))
  3006. {
  3007. if (pszDrive)
  3008. {
  3009. lstrncpy (pszDrive, pszSource, _MAX_DRIVE-1);
  3010. pszDrive[ _MAX_DRIVE-1 ] = TEXT('\0');
  3011. }
  3012. pszSource += _MAX_DRIVE-1;
  3013. }
  3014. else if (pszDrive)
  3015. {
  3016. *pszDrive = TEXT('\0');
  3017. }
  3018. // extract path string, if any. pszSource now points to the first
  3019. // character of the path, if any, or the filename or extension, if
  3020. // no path was specified. Scan ahead for the last occurence, if
  3021. // any, of a '/' or '\' path separator character. If none is found,
  3022. // there is no path. We will also note the last '.' character found,
  3023. // if any, to aid in handling the extension.
  3024. //
  3025. for (pch = pszSource; *pch != TEXT('\0'); pch++)
  3026. {
  3027. if (*pch == TEXT('/') || *pch == TEXT('\\'))
  3028. pszLastSlash = pch;
  3029. else if (*pch == TEXT('.'))
  3030. pszLastDot = pch;
  3031. }
  3032. // if we found a '\\' or '/', fill in pszPath
  3033. //
  3034. if (pszLastSlash)
  3035. {
  3036. if (pszPath)
  3037. {
  3038. cchCopy = (size_t)min((UINT)_MAX_DIR-1, (pszLastSlash-pszSource) + 1);
  3039. lstrncpy (pszPath, pszSource, cchCopy);
  3040. pszPath[ cchCopy ] = 0;
  3041. }
  3042. pszSource = pszLastSlash +1;
  3043. }
  3044. else if (pszPath)
  3045. {
  3046. *pszPath = TEXT('\0');
  3047. }
  3048. // extract file name and extension, if any. Path now points to
  3049. // the first character of the file name, if any, or the extension
  3050. // if no file name was given. Dot points to the '.' beginning the
  3051. // extension, if any.
  3052. //
  3053. if (pszLastDot && (pszLastDot >= pszSource))
  3054. {
  3055. // found the marker for an extension -
  3056. // copy the file name up to the '.'.
  3057. //
  3058. if (pszName)
  3059. {
  3060. cchCopy = (size_t)min( (UINT)_MAX_DIR-1, (pszLastDot-pszSource) );
  3061. lstrncpy (pszName, pszSource, cchCopy);
  3062. pszName[ cchCopy ] = 0;
  3063. }
  3064. // now we can get the extension
  3065. //
  3066. if (pszExt)
  3067. {
  3068. lstrncpy (pszExt, pszLastDot, _MAX_EXT -1);
  3069. pszExt[ _MAX_EXT-1 ] = TEXT('\0');
  3070. }
  3071. }
  3072. else
  3073. {
  3074. // found no extension, give empty extension and copy rest of
  3075. // string into fname.
  3076. //
  3077. if (pszName)
  3078. {
  3079. lstrncpy (pszName, pszSource, _MAX_FNAME -1);
  3080. pszName[ _MAX_FNAME -1 ] = TEXT('\0');
  3081. }
  3082. if (pszExt)
  3083. {
  3084. *pszExt = TEXT('\0');
  3085. }
  3086. }
  3087. }
  3088. void lstrncpy (LPTSTR pszTarget, LPTSTR pszSource, size_t cch)
  3089. {
  3090. size_t ich;
  3091. for (ich = 0; ich < cch; ich++)
  3092. {
  3093. if ((pszTarget[ich] = pszSource[ich]) == TEXT('\0'))
  3094. break;
  3095. }
  3096. }
  3097. /*
  3098. * DEVICE PROPERTY SHEETS _____________________________________________________
  3099. *
  3100. */
  3101. // General flag macros
  3102. //
  3103. #define SetFlag(obj, f) do {obj |= (f);} while (0)
  3104. #define ToggleFlag(obj, f) do {obj ^= (f);} while (0)
  3105. #define ClearFlag(obj, f) do {obj &= ~(f);} while (0)
  3106. #define IsFlagSet(obj, f) (BOOL)(((obj) & (f)) == (f))
  3107. #define IsFlagClear(obj, f) (BOOL)(((obj) & (f)) != (f))
  3108. BOOL InstrumentToResource (PIRESOURCE, HTREEITEM);
  3109. BOOL DriverToResource (HWND,PIRESOURCE,PIDRIVER,DriverClass);
  3110. DriverClass OldClassIDToDriverClass (int);
  3111. void FreeClassNode (PCLASSNODE);
  3112. PIDRIVER FindIDriverByResource (PIRESOURCE);
  3113. void EnableDriverService (PIRESOURCE, BOOL);
  3114. BOOL PASCAL DoDevPropCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify);
  3115. STATIC void SetDevStatus(int iStatus, HWND hDlg);
  3116. INT_PTR CALLBACK ACMDlg(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
  3117. /*
  3118. *** DriverToResource - create a PIRESOURCE structure from a PIDRIVER structure
  3119. *
  3120. * The Win95 code uses PIRESOURCEs (among other structures) to keep track of
  3121. * the item in the Advanced tab's treeview; the old WinNT code used PIDRIVER
  3122. * structures to keep track of the items in its listbox. The tree now uses
  3123. * PIDRIVER structures, but we create PIRESOURCE structures out of 'em before
  3124. * passing control off to the Win95 properties dialogs, which came through
  3125. * largely unmodified.
  3126. *
  3127. * BTW, I retained the PIDRIVER structures as the main treeview structure
  3128. * because it prevented difficulty in porting over the Install/Remove Driver
  3129. * code from the old NT code.
  3130. *
  3131. */
  3132. BOOL DriverToResource (HWND hPar, PIRESOURCE pir, PIDRIVER pid, DriverClass dc)
  3133. {
  3134. if (dc == dcINVALID)
  3135. {
  3136. if ((dc = GuessDriverClass (pid)) == dcINVALID)
  3137. return FALSE;
  3138. }
  3139. if ((pir->pcn = (PCLASSNODE)LocalAlloc (LPTR, sizeof(CLASSNODE))) == NULL)
  3140. return FALSE;
  3141. if (!DriverClassToClassNode (pir->pcn, dc))
  3142. {
  3143. LocalFree ((HANDLE)pir->pcn);
  3144. return FALSE;
  3145. }
  3146. if (dc == dcACODEC)
  3147. pir->iNode = 3; // 1=class, 2=device, 3=acm, 4=instmt
  3148. // else if (dc == dcINSTRUMENT)
  3149. // pir->iNode = 4; // 1=class, 2=device, 3=acm, 4=instmt
  3150. else
  3151. pir->iNode = 2; // 1=class, 2=device, 3=acm, 4=instmt
  3152. lstrcpy (pir->szFriendlyName, pid->szDesc);
  3153. lstrcpy (pir->szDesc, pid->szDesc);
  3154. lstrcpy (pir->szFile, pid->szFile);
  3155. lstrcpy (pir->szDrvEntry, pid->szAlias);
  3156. lstrcpy (pir->szClass, pir->pcn->szClass);
  3157. pid->fQueryable = IsConfigurable (pid, hPar);
  3158. pir->fQueryable = (short)pid->fQueryable;
  3159. pir->iClassID = (short)DriverClassToOldClassID (dc);
  3160. pir->szParam[0] = 0;
  3161. pir->dnDevNode = 0;
  3162. pir->hDriver = NULL;
  3163. // Find fStatus, which despite its name is really a series of
  3164. // flags--in Win95 it's composed of DEV_* flags (from the old
  3165. // mmcpl.h), but those are tied with PNP. Here, we use the
  3166. // dwStatus* flags:
  3167. //
  3168. pir->fStatus = (int)GetDriverStatus (pid);
  3169. return TRUE;
  3170. }
  3171. BOOL InstrumentToResource (PIRESOURCE pir, HTREEITEM hti)
  3172. {
  3173. TV_ITEM tvi;
  3174. PINSTRUM pin;
  3175. tvi.mask = TVIF_PARAM;
  3176. tvi.hItem = hti;
  3177. tvi.lParam = 0;
  3178. TreeView_GetItem(hAdvDlgTree, &tvi);
  3179. if ((pin = (PINSTRUM)tvi.lParam) == NULL)
  3180. return FALSE;
  3181. if ((pir->pcn = (PCLASSNODE)LocalAlloc (LPTR, sizeof(CLASSNODE))) == NULL)
  3182. return FALSE;
  3183. if (!DriverClassToClassNode (pir->pcn, dcMIDI))
  3184. {
  3185. LocalFree ((HANDLE)pir->pcn);
  3186. return FALSE;
  3187. }
  3188. pir->iNode = 4; // 1=class, 2=device, 3=acm, 4=instmt
  3189. lstrcpy (pir->szFriendlyName, pin->szFriendly);
  3190. lstrcpy (pir->szDesc, pin->szKey);
  3191. // lstrcpy (pir->szFile, TEXT("unused"));
  3192. // lstrcpy (pir->szDrvEntry, TEXT("unused"));
  3193. lstrcpy (pir->szClass, pir->pcn->szClass);
  3194. pir->fQueryable = FALSE;
  3195. pir->iClassID = MIDI_ID;
  3196. pir->szParam[0] = 0;
  3197. pir->dnDevNode = 0;
  3198. pir->hDriver = NULL;
  3199. pir->fStatus = 0;
  3200. return TRUE;
  3201. }
  3202. BOOL DriverClassToClassNode (PCLASSNODE pcn, DriverClass dc)
  3203. {
  3204. short idr;
  3205. short ii;
  3206. int cxIcon, cyIcon;
  3207. if ((idr = DriverClassToRootIndex (dc)) == -1)
  3208. return FALSE;
  3209. pcn->iNode = 1; // 1=class, 2=device, 3=acm, 4=instmt
  3210. GetString (pcn->szClassName, aDriverRoot[idr].idDesc);
  3211. pcn->szClass[0] = TEXT('\0');
  3212. for (ii = 0; ii < nKeywordDESCS; ii++)
  3213. {
  3214. if (aKeywordDesc[ii].dc == dc)
  3215. {
  3216. lstrcpy (pcn->szClass, aKeywordDesc[ii].psz);
  3217. break;
  3218. }
  3219. }
  3220. cxIcon = (int)GetSystemMetrics (SM_CXICON);
  3221. cyIcon = (int)GetSystemMetrics (SM_CYICON);
  3222. pcn->hIcon = LoadImage (myInstance,
  3223. MAKEINTRESOURCE( aDriverRoot[ idr ].idIcon ),
  3224. IMAGE_ICON, cxIcon, cyIcon, LR_DEFAULTCOLOR);
  3225. return TRUE;
  3226. }
  3227. int DriverClassToOldClassID (DriverClass dc)
  3228. {
  3229. switch (dc)
  3230. {
  3231. case dcWAVE: return WAVE_ID; break;
  3232. case dcMIDI: return MIDI_ID; break;
  3233. case dcMIXER: return MIXER_ID; break;
  3234. case dcAUX: return AUX_ID; break;
  3235. case dcMCI: return MCI_ID; break;
  3236. case dcACODEC: return ACM_ID; break;
  3237. case dcVCODEC: return ICM_ID; break;
  3238. case dcVIDCAP: return VIDCAP_ID; break;
  3239. case dcJOY: return JOYSTICK_ID; break;
  3240. default: return JOYSTICK_ID; break;
  3241. }
  3242. }
  3243. DriverClass OldClassIDToDriverClass (int ii)
  3244. {
  3245. switch (ii)
  3246. {
  3247. case WAVE_ID: return dcWAVE; break;
  3248. case MIDI_ID: return dcMIDI; break;
  3249. case MIXER_ID: return dcMIXER; break;
  3250. case AUX_ID: return dcAUX; break;
  3251. case MCI_ID: return dcMCI; break;
  3252. case ACM_ID: return dcACODEC; break;
  3253. case ICM_ID: return dcVCODEC; break;
  3254. case VIDCAP_ID: return dcVIDCAP; break;
  3255. case JOYSTICK_ID: return dcJOY; break;
  3256. default: return dcOTHER;
  3257. }
  3258. }
  3259. void FreeIResource (PIRESOURCE pir)
  3260. {
  3261. if (pir->pcn != NULL)
  3262. {
  3263. FreeClassNode (pir->pcn);
  3264. LocalFree ((HANDLE)pir->pcn);
  3265. pir->pcn = NULL;
  3266. }
  3267. }
  3268. void FreeClassNode (PCLASSNODE pcn)
  3269. {
  3270. if (pcn->hIcon != NULL)
  3271. {
  3272. DestroyIcon (pcn->hIcon);
  3273. pcn->hIcon = NULL;
  3274. }
  3275. }
  3276. DWORD GetDriverStatus (PIDRIVER pid)
  3277. {
  3278. DWORD dwStatus;
  3279. SC_HANDLE scManager;
  3280. SC_HANDLE scDriver;
  3281. TCHAR szName[ cchRESOURCE ];
  3282. dwStatus = 0;
  3283. lsplitpath (pid->szFile, NULL, NULL, szName, NULL);
  3284. // First step: determine if the driver has a service
  3285. //
  3286. if ((scManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
  3287. {
  3288. if ((scDriver = OpenService (scManager, szName, GENERIC_READ)) != NULL)
  3289. {
  3290. QUERY_SERVICE_CONFIG qsc;
  3291. SERVICE_STATUS ss;
  3292. DWORD cbReq;
  3293. void *pqsc;
  3294. SetFlag (dwStatus, dwStatusHASSERVICE);
  3295. // Great! It has a service. Find out if the service
  3296. // is actively running, and whether it is disabled.
  3297. //
  3298. if (QueryServiceConfig (scDriver, &qsc, sizeof(qsc), &cbReq))
  3299. {
  3300. if (qsc.dwStartType != SERVICE_DISABLED)
  3301. {
  3302. SetFlag (dwStatus, dwStatusSvcENABLED);
  3303. }
  3304. }
  3305. else if ((pqsc = (void *)LocalAlloc (LPTR, cbReq)) != NULL)
  3306. {
  3307. if (QueryServiceConfig (scDriver,
  3308. (QUERY_SERVICE_CONFIG *)pqsc,
  3309. cbReq, &cbReq))
  3310. {
  3311. if ( ((QUERY_SERVICE_CONFIG *)pqsc)->dwStartType
  3312. != SERVICE_DISABLED)
  3313. {
  3314. SetFlag (dwStatus, dwStatusSvcENABLED);
  3315. }
  3316. }
  3317. LocalFree ((HANDLE)pqsc);
  3318. }
  3319. if (QueryServiceStatus (scDriver, &ss))
  3320. {
  3321. if ((ss.dwCurrentState != SERVICE_STOPPED) &&
  3322. (ss.dwCurrentState != SERVICE_STOP_PENDING))
  3323. {
  3324. SetFlag (dwStatus, dwStatusSvcSTARTED);
  3325. }
  3326. }
  3327. CloseServiceHandle (scDriver);
  3328. }
  3329. CloseServiceHandle (scManager);
  3330. }
  3331. // If no service, see if we can talk to the driver itself
  3332. //
  3333. if (!IsFlagSet (dwStatus, dwStatusHASSERVICE))
  3334. {
  3335. HANDLE hDriver;
  3336. if ((hDriver = OpenDriver (pid->wszAlias, pid->wszSection, 0L)) != NULL)
  3337. {
  3338. SetFlag (dwStatus, dwStatusDRIVEROK);
  3339. CloseDriver (hDriver, 0L, 0L);
  3340. }
  3341. }
  3342. // If it's a wave device, can we map through it?
  3343. //
  3344. if (GetMappable (pid))
  3345. {
  3346. SetFlag (dwStatus, dwStatusMAPPABLE);
  3347. }
  3348. return dwStatus;
  3349. }
  3350. void GetTreeItemNodeDesc (LPTSTR pszTarget, PIRESOURCE pir)
  3351. {
  3352. lstrcpy (pszTarget, pir->szFriendlyName);
  3353. }
  3354. void GetTreeItemNodeID (LPTSTR pszTarget, PIRESOURCE pir)
  3355. {
  3356. DriverClass dc;
  3357. CLASSNODE cn;
  3358. *pszTarget = 0; // In case we fail later
  3359. dc = OldClassIDToDriverClass (pir->iClassID);
  3360. if (!DriverClassToClassNode (&cn, dc))
  3361. return;
  3362. switch (pir->iNode) // 1=class, 2=device, 3=acm, 4=instmt
  3363. {
  3364. case 1: // class
  3365. lstrcpy (pszTarget, cn.szClass);
  3366. break;
  3367. case 2: // instrument
  3368. wsprintf (pszTarget, TEXT("%s\\%s"), cn.szClass, pir->szDrvEntry);
  3369. break;
  3370. case 4: // instrument
  3371. lstrcpy (pszTarget, pir->szDesc);
  3372. break;
  3373. default:
  3374. lstrcpy (pszTarget, pir->szDesc);
  3375. break;
  3376. }
  3377. FreeClassNode (&cn);
  3378. }
  3379. void ShowDeviceProperties (HWND hPar, HTREEITEM hti)
  3380. {
  3381. IRESOURCE ir;
  3382. CLASSNODE cn;
  3383. DEVTREENODE dtn;
  3384. short idr;
  3385. TCHAR szTitle[ cchRESOURCE ];
  3386. TCHAR szTab[ cchRESOURCE ];
  3387. DriverClass dc;
  3388. PIDRIVER pid;
  3389. if (hti == NULL)
  3390. return;
  3391. if (TreeView_GetParent (hAdvDlgTree, hti) &&
  3392. TreeView_GetGrandParent (hAdvDlgTree, hti) &&
  3393. (GuessDriverClassFromTreeItem (
  3394. TreeView_GetGrandParent (hAdvDlgTree, hti)
  3395. ) == dcMIDI))
  3396. {
  3397. if (InstrumentToResource (&ir, hti))
  3398. {
  3399. ShowMidiPropSheet (NULL,
  3400. ir.szFriendlyName,
  3401. hPar,
  3402. MIDI_INSTRUMENT_PROP,
  3403. ir.szFriendlyName,
  3404. hti,
  3405. (LPARAM)&ir,
  3406. (LPARAM)hAdvDlgTree);
  3407. FreeIResource (&ir);
  3408. }
  3409. return;
  3410. }
  3411. else if ((pid = FindIDriverByTreeItem (hti)) != NULL)
  3412. {
  3413. dc = GuessDriverClassFromTreeItem (TreeView_GetParent(hAdvDlgTree,hti));
  3414. if (dc == dcINVALID)
  3415. {
  3416. if ((dc = GuessDriverClass (pid)) == dcINVALID)
  3417. return;
  3418. }
  3419. }
  3420. else
  3421. {
  3422. if ((dc = GuessDriverClassFromTreeItem (hti)) == dcINVALID)
  3423. return;
  3424. }
  3425. if (g_dcFilterClass != dcINVALID)
  3426. {
  3427. if ((dc == dcOTHER) || (dc == dcINVALID))
  3428. {
  3429. dc = g_dcFilterClass;
  3430. }
  3431. }
  3432. if ((idr = DriverClassToRootIndex (dc)) == -1)
  3433. return;
  3434. if (pid == NULL) // Just want class properties?
  3435. {
  3436. if (!DriverClassToClassNode (&cn, dc))
  3437. return;
  3438. if (dc == dcMIDI) // MIDI class properties?
  3439. {
  3440. GetString (szTitle, aDriverRoot[idr].idDesc);
  3441. ShowMidiPropSheet (NULL,
  3442. szTitle,
  3443. hPar,
  3444. MIDI_CLASS_PROP,
  3445. szTitle,
  3446. hti,
  3447. (LPARAM)&cn,
  3448. (LPARAM)hAdvDlgTree);
  3449. }
  3450. else // Generic class properties? (nothing to do, really)
  3451. {
  3452. GetString (szTab, IDS_GENERAL);
  3453. GetString (szTitle, aDriverRoot[idr].idDesc);
  3454. dtn.lParam = (LPARAM)&cn;
  3455. dtn.hwndTree = hAdvDlgTree;
  3456. ShowPropSheet (szTab,
  3457. DevPropDlg,
  3458. DLG_DEV_PROP,
  3459. hPar,
  3460. szTitle,
  3461. (LPARAM)&dtn);
  3462. }
  3463. FreeClassNode (&cn);
  3464. }
  3465. else
  3466. {
  3467. switch (dc)
  3468. {
  3469. case dcACODEC:
  3470. GetString (szTab, IDS_GENERAL);
  3471. ShowPropSheet (szTab,
  3472. ACMDlg,
  3473. DLG_ACMDEV_PROP,
  3474. hPar,
  3475. pid->szDesc,
  3476. pid->lp);
  3477. // Re-sort the Audio Codec entries, in case their priorities
  3478. // have changed. Then find treeview item for this codec,
  3479. // and select it.
  3480. //
  3481. {
  3482. HTREEITEM hti;
  3483. short idr;
  3484. SendMessage (hAdvDlgTree, WM_SETREDRAW, FALSE, 0L);
  3485. FillTreeFromMSACM (hAdvDlgTree);
  3486. SendMessage (hAdvDlgTree, WM_SETREDRAW, TRUE, 0L);
  3487. if ((idr = DriverClassToRootIndex (dcACODEC)) != -1)
  3488. {
  3489. if ((hti = aDriverRoot[ idr ].hti) != NULL)
  3490. {
  3491. for (hti = TreeView_GetChild (hAdvDlgTree, hti);
  3492. hti != NULL;
  3493. hti = TreeView_GetNextSibling (hAdvDlgTree, hti))
  3494. {
  3495. if (pid == FindIDriverByTreeItem (hti))
  3496. {
  3497. TreeView_SelectItem (hAdvDlgTree, hti);
  3498. break;
  3499. }
  3500. }
  3501. }
  3502. }
  3503. }
  3504. break;
  3505. case dcMIDI:
  3506. if (!DriverToResource (hPar, &ir, pid, dc))
  3507. break;
  3508. GetString (szTab, IDS_GENERAL);
  3509. dtn.lParam = (LPARAM)&ir;
  3510. dtn.hwndTree = hAdvDlgTree;
  3511. ShowWithMidiDevPropSheet (szTab,
  3512. DevPropDlg,
  3513. DLG_DEV_PROP,
  3514. hPar,
  3515. pid->szDesc,
  3516. hti,
  3517. (LPARAM)&dtn,
  3518. (LPARAM)&ir,
  3519. (LPARAM)hAdvDlgTree);
  3520. FreeIResource (&ir);
  3521. break;
  3522. case dcWAVE:
  3523. if (!DriverToResource (hPar, &ir, pid, dc))
  3524. break;
  3525. GetString (szTab, IDS_GENERAL);
  3526. dtn.lParam = (LPARAM)&ir;
  3527. dtn.hwndTree = hAdvDlgTree;
  3528. ShowPropSheet (szTab,
  3529. DevPropDlg,
  3530. DLG_WAVDEV_PROP,
  3531. hPar,
  3532. pid->szDesc,
  3533. (LPARAM)&dtn);
  3534. FreeIResource (&ir);
  3535. break;
  3536. default:
  3537. if (!DriverToResource (hPar, &ir, pid, dc))
  3538. break;
  3539. GetString (szTab, IDS_GENERAL);
  3540. dtn.lParam = (LPARAM)&ir;
  3541. dtn.hwndTree = hAdvDlgTree;
  3542. ShowPropSheet (szTab,
  3543. DevPropDlg,
  3544. DLG_DEV_PROP,
  3545. hPar,
  3546. pid->szDesc,
  3547. (LPARAM)&dtn);
  3548. FreeIResource (&ir);
  3549. break;
  3550. }
  3551. }
  3552. }
  3553. #include "medhelp.h"
  3554. const static DWORD aDevPropHelpIds[] = { // Context Help IDs
  3555. ID_DEV_SETTINGS, IDH_MMCPL_DEVPROP_SETTINGS,
  3556. IDC_DEV_ICON, NO_HELP,
  3557. IDC_DEV_DESC, NO_HELP,
  3558. IDC_DEV_STATUS, NO_HELP,
  3559. IDC_ENABLE, IDH_MMCPL_DEVPROP_ENABLE,
  3560. IDC_DISABLE, IDH_MMCPL_DEVPROP_DISABLE,
  3561. IDC_DONOTMAP, IDH_MMCPL_DEVPROP_DONT_MAP,
  3562. 0, 0
  3563. };
  3564. /*
  3565. ***************************************************************
  3566. * DlgProc for device Property sheet.
  3567. ***************************************************************
  3568. */
  3569. INT_PTR CALLBACK DevPropDlg (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  3570. {
  3571. NMHDR FAR *lpnm;
  3572. switch (uMsg)
  3573. {
  3574. case WM_NOTIFY:
  3575. lpnm = (NMHDR FAR *)lParam;
  3576. switch(lpnm->code)
  3577. {
  3578. case PSN_KILLACTIVE:
  3579. FORWARD_WM_COMMAND(hDlg, IDOK, 0, 0, SendMessage);
  3580. break;
  3581. case PSN_APPLY:
  3582. FORWARD_WM_COMMAND(hDlg, ID_APPLY, 0, 0, SendMessage);
  3583. break;
  3584. case PSN_SETACTIVE:
  3585. FORWARD_WM_COMMAND(hDlg, ID_INIT, 0, 0, SendMessage);
  3586. break;
  3587. case PSN_RESET:
  3588. FORWARD_WM_COMMAND(hDlg, IDCANCEL, 0, 0, SendMessage);
  3589. break;
  3590. }
  3591. break;
  3592. case WM_INITDIALOG:
  3593. {
  3594. PIRESOURCE pIResource;
  3595. PCLASSNODE pcn;
  3596. PDEVTREENODE pdtn = (PDEVTREENODE)(((LPPROPSHEETPAGE)lParam)->lParam);
  3597. SetWindowLongPtr(hDlg, DWLP_USER, ((LPPROPSHEETPAGE)lParam)->lParam);
  3598. if (*((short *)(pdtn->lParam)) == 1)
  3599. {
  3600. HWND hwndTree = pdtn->hwndTree;
  3601. HTREEITEM htiCur = TreeView_GetSelection(hwndTree);
  3602. TCHAR sz[cchRESOURCE];
  3603. TV_ITEM tvi;
  3604. tvi.mask = TVIF_CHILDREN;
  3605. tvi.hItem = htiCur;
  3606. TreeView_GetItem(hwndTree, &tvi);
  3607. pcn = (PCLASSNODE)(pdtn->lParam);
  3608. //set class icon.
  3609. SendDlgItemMessage(hDlg, IDC_DEV_ICON, STM_SETICON, (WPARAM)pcn->hIcon , 0L);
  3610. SetWindowText(GetDlgItem(hDlg, IDC_DEV_DESC), pcn->szClassName);
  3611. DestroyWindow(GetDlgItem(hDlg, IDC_ENABLE));
  3612. DestroyWindow(GetDlgItem(hDlg, IDC_DISABLE));
  3613. DestroyWindow(GetDlgItem(hDlg, ID_DEV_SETTINGS));
  3614. GetString (sz, (tvi.cChildren) ? IDS_NOPROP : IDS_NODEVS);
  3615. SetWindowText(GetDlgItem(hDlg, IDC_DEV_STATUS), sz);
  3616. }
  3617. else
  3618. {
  3619. pIResource = (PIRESOURCE)(pdtn->lParam);
  3620. SendDlgItemMessage(hDlg, IDC_DEV_ICON, STM_SETICON, (WPARAM)pIResource->pcn->hIcon , 0L);
  3621. SetWindowText(GetDlgItem(hDlg, IDC_DEV_DESC), pIResource->szDesc);
  3622. if (!IsFlagSet(pIResource->fStatus, dwStatusHASSERVICE) &&
  3623. !IsFlagSet(pIResource->fStatus, dwStatusDRIVEROK))
  3624. {
  3625. SetDevStatus(pIResource->fStatus, hDlg);
  3626. }
  3627. else
  3628. {
  3629. if (pIResource->iClassID == WAVE_ID)
  3630. {
  3631. CheckDlgButton (hDlg,
  3632. IDC_DONOTMAP,
  3633. IsFlagClear(pIResource->fStatus,
  3634. dwStatusMAPPABLE));
  3635. }
  3636. if (!pIResource->fQueryable || pIResource->fQueryable == -1)
  3637. EnableWindow(GetDlgItem(hDlg, ID_DEV_SETTINGS), FALSE);
  3638. if (!IsFlagSet (pIResource->fStatus, dwStatusHASSERVICE))
  3639. {
  3640. DestroyWindow(GetDlgItem(hDlg, IDC_ENABLE));
  3641. DestroyWindow(GetDlgItem(hDlg, IDC_DISABLE));
  3642. }
  3643. else
  3644. {
  3645. TCHAR szStatusStr[MAXSTR];
  3646. DriverClass dc;
  3647. short idr;
  3648. dc = OldClassIDToDriverClass (pIResource->iClassID);
  3649. idr = DriverClassToRootIndex (dc);
  3650. if (idr == -1)
  3651. {
  3652. DestroyWindow (GetDlgItem(hDlg, IDC_ENABLE));
  3653. DestroyWindow (GetDlgItem(hDlg, IDC_DISABLE));
  3654. }
  3655. else
  3656. {
  3657. GetString (szStatusStr, aDriverRoot[idr].idEnable);
  3658. SetDlgItemText(hDlg, IDC_ENABLE, szStatusStr);
  3659. GetString (szStatusStr, aDriverRoot[idr].idDisable);
  3660. SetDlgItemText(hDlg, IDC_DISABLE, szStatusStr);
  3661. }
  3662. }
  3663. }
  3664. SetDevStatus(pIResource->fStatus, hDlg);
  3665. }
  3666. #ifdef FIX_BUG_15451
  3667. if (szDriverWhichNeedsSettings[0] != TEXT('\0'))
  3668. {
  3669. MakeThisDialogLookLikeTheOldDialog (GetParent(hDlg));
  3670. }
  3671. #endif // FIX_BUG_15451
  3672. break;
  3673. }
  3674. case WM_DESTROY:
  3675. break;
  3676. case WM_DROPFILES:
  3677. break;
  3678. case WM_CONTEXTMENU:
  3679. WinHelp ((HWND) wParam, NULL, HELP_CONTEXTMENU,
  3680. (UINT_PTR) (LPTSTR) aDevPropHelpIds);
  3681. return TRUE;
  3682. case WM_HELP:
  3683. {
  3684. LPHELPINFO lphi = (LPVOID) lParam;
  3685. WinHelp (lphi->hItemHandle, NULL, HELP_WM_HELP,
  3686. (UINT_PTR) (LPTSTR) aDevPropHelpIds);
  3687. return TRUE;
  3688. }
  3689. case WM_COMMAND:
  3690. HANDLE_WM_COMMAND(hDlg, wParam, lParam, DoDevPropCommand);
  3691. break;
  3692. }
  3693. return FALSE;
  3694. }
  3695. /*
  3696. ***************************************************************
  3697. *
  3698. ***************************************************************
  3699. */
  3700. BOOL PASCAL DoDevPropCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify)
  3701. {
  3702. PDEVTREENODE pdtn = (PDEVTREENODE)GetWindowLongPtr(hDlg, DWLP_USER);
  3703. PIRESOURCE pIResource;
  3704. static int fDevStatus;
  3705. if (!pdtn)
  3706. return FALSE;
  3707. pIResource = (PIRESOURCE)(pdtn->lParam);
  3708. switch (id)
  3709. {
  3710. case ID_APPLY:
  3711. if ((pIResource->iNode == 2) && (fDevStatus != pIResource->fStatus))
  3712. {
  3713. if ( (IsFlagSet (fDevStatus, dwStatusMAPPABLE)) !=
  3714. (IsFlagSet (pIResource->fStatus, dwStatusMAPPABLE)) )
  3715. {
  3716. SetMappable (pIResource,
  3717. (BOOL)IsFlagSet (fDevStatus, dwStatusMAPPABLE));
  3718. }
  3719. if ( (IsFlagSet (fDevStatus, dwStatusHASSERVICE)) &&
  3720. (IsFlagSet (fDevStatus, dwStatusSvcENABLED) !=
  3721. IsFlagSet (pIResource->fStatus, dwStatusSvcENABLED)) )
  3722. {
  3723. #if 0 // TODO: Multiportmidi
  3724. if ( (pIResource->iClassID == MIDI_ID) &&
  3725. (IsFlagSet(fDevStatus, DEV_MULTIPORTMIDI)) )
  3726. {
  3727. EnableMultiPortMIDI (pIResource,
  3728. IsFlagSet (fDevStatus,
  3729. dwStatusSvcENABLED));
  3730. }
  3731. else
  3732. #endif
  3733. {
  3734. EnableDriverService (pIResource,
  3735. IsFlagSet (fDevStatus,
  3736. dwStatusSvcENABLED));
  3737. }
  3738. }
  3739. DisplayMessage(hDlg, IDS_CHANGESAVED, IDS_RESTART, MB_OK);
  3740. }
  3741. return TRUE;
  3742. case IDOK:
  3743. return TRUE;
  3744. case IDCANCEL:
  3745. break;
  3746. case ID_INIT:
  3747. if (pIResource->iNode == 2)
  3748. fDevStatus = pIResource->fStatus;
  3749. #ifdef FIX_BUG_15451
  3750. if (szDriverWhichNeedsSettings[0] != TEXT('\0'))
  3751. {
  3752. FORWARD_WM_COMMAND(hDlg,ID_DEV_SETTINGS,0,0,PostMessage);
  3753. }
  3754. #endif // FIX_BUG_15451
  3755. break;
  3756. case IDC_DONOTMAP:
  3757. if(Button_GetCheck(GetDlgItem(hDlg, IDC_DONOTMAP)))
  3758. ClearFlag(fDevStatus, dwStatusMAPPABLE);
  3759. else
  3760. SetFlag(fDevStatus, dwStatusMAPPABLE);
  3761. PropSheet_Changed(GetParent(hDlg),hDlg);
  3762. break;
  3763. case IDC_ENABLE:
  3764. if (IsFlagSet (fDevStatus, dwStatusHASSERVICE))
  3765. {
  3766. SetFlag(fDevStatus, dwStatusSvcENABLED);
  3767. SetDevStatus(fDevStatus, hDlg);
  3768. PropSheet_Changed(GetParent(hDlg),hDlg);
  3769. #if 0 // TODO: Multiportmidi
  3770. if (IsFlagSet(fDevStatus, DEV_MULTIPORTMIDI))
  3771. {
  3772. DisplayMessage(hDlg, IDS_ENABLE, IDS_ENABLEMULTIPORTMIDI, MB_OK);
  3773. }
  3774. #endif
  3775. }
  3776. break;
  3777. case IDC_DISABLE:
  3778. if (IsFlagSet (fDevStatus, dwStatusHASSERVICE))
  3779. {
  3780. ClearFlag(fDevStatus, dwStatusSvcENABLED);
  3781. SetDevStatus(fDevStatus, hDlg);
  3782. PropSheet_Changed(GetParent(hDlg),hDlg);
  3783. #if 0 // TODO: Multiportmidi
  3784. if (IsFlagSet(fDevStatus, DEV_MULTIPORTMIDI))
  3785. {
  3786. DisplayMessage(hDlg, IDS_DISABLE, IDS_DISABLEMULTIPORTMIDI, MB_OK);
  3787. }
  3788. #endif
  3789. }
  3790. break;
  3791. case ID_DEV_SETTINGS:
  3792. #ifdef FIX_BUG_15451
  3793. if (szDriverWhichNeedsSettings[0] != TEXT('\0'))
  3794. {
  3795. ConfigureDriver (hDlg, szDriverWhichNeedsSettings);
  3796. szDriverWhichNeedsSettings[0] = 0;
  3797. }
  3798. else
  3799. {
  3800. PIDRIVER pid;
  3801. if ((pid = FindIDriverByResource (pIResource)) == NULL)
  3802. break;
  3803. ShowDriverSettings (hDlg, pid->szFile);
  3804. }
  3805. #else // FIX_BUG_15451
  3806. {
  3807. PIDRIVER pid;
  3808. HANDLE hDriver;
  3809. if ((pid = FindIDriverByResource (pIResource)) == NULL)
  3810. break;
  3811. if ((hDriver = OpenDriver (pid->wszAlias, pid->wszSection, 0L)) == 0)
  3812. {
  3813. OpenDriverError(hDlg, pid->szDesc, pid->szFile);
  3814. }
  3815. else
  3816. {
  3817. DRVCONFIGINFO DrvConfigInfo;
  3818. InitDrvConfigInfo(&DrvConfigInfo, pid);
  3819. if ((SendDriverMessage(
  3820. hDriver,
  3821. DRV_CONFIGURE,
  3822. (LONG)hDlg,
  3823. (LONG)(LPDRVCONFIGINFO)&DrvConfigInfo) ==
  3824. DRVCNF_RESTART))
  3825. {
  3826. iRestartMessage= 0;
  3827. DialogBox(myInstance,
  3828. MAKEINTRESOURCE(DLG_RESTART), hDlg, RestartDlg);
  3829. }
  3830. CloseDriver(hDriver, 0L, 0L);
  3831. }
  3832. }
  3833. #endif // FIX_BUG_15451
  3834. break;
  3835. }
  3836. return FALSE;
  3837. }
  3838. /*
  3839. ***************************************************************
  3840. * Check the status flag for the device and display the appropriate text the
  3841. * the device properties prop sheet.
  3842. ***************************************************************
  3843. */
  3844. STATIC void SetDevStatus(int iStatus, HWND hDlg)
  3845. {
  3846. HWND hwndS = GetDlgItem(hDlg, IDC_DEV_STATUS);
  3847. TCHAR szStatus[cchRESOURCE];
  3848. if (IsFlagSet (iStatus, dwStatusHASSERVICE))
  3849. {
  3850. if (IsFlagSet (iStatus, dwStatusSvcENABLED))
  3851. {
  3852. if (IsFlagSet (iStatus, dwStatusSvcSTARTED))
  3853. GetString (szStatus, IDS_DEVENABLEDOK);
  3854. else
  3855. GetString (szStatus, IDS_DEVENABLEDNOTOK);
  3856. CheckRadioButton (hDlg, IDC_ENABLE, IDC_DISABLE, IDC_ENABLE);
  3857. }
  3858. else // service has been disabled
  3859. {
  3860. if (IsFlagSet (iStatus, dwStatusSvcSTARTED))
  3861. GetString (szStatus, IDS_DEVDISABLEDOK);
  3862. else
  3863. GetString (szStatus, IDS_DEVDISABLED);
  3864. CheckRadioButton(hDlg, IDC_ENABLE, IDC_DISABLE, IDC_DISABLE);
  3865. }
  3866. SetWindowText(hwndS, szStatus);
  3867. }
  3868. else // driver does not have a service, and thus can't be disabled
  3869. {
  3870. if (IsFlagSet (iStatus, dwStatusDRIVEROK))
  3871. GetString (szStatus, IDS_DEVENABLEDOK);
  3872. else
  3873. GetString (szStatus, IDS_DEVENABLEDNODRIVER);
  3874. CheckRadioButton(hDlg, IDC_ENABLE, IDC_DISABLE, IDC_ENABLE);
  3875. SetWindowText(hwndS, szStatus);
  3876. }
  3877. }
  3878. /*
  3879. *** EnableDriverService - enable or disable a service-based driver
  3880. *
  3881. * If Enable, the service will be set to start==system_start.
  3882. * If !Enable, the service will be set to start==disabled.
  3883. *
  3884. */
  3885. void EnableDriverService (PIRESOURCE pir, BOOL fEnable)
  3886. {
  3887. SC_HANDLE scManager;
  3888. SC_HANDLE scDriver;
  3889. TCHAR szName[ cchRESOURCE ];
  3890. lsplitpath (pir->szFile, NULL, NULL, szName, NULL);
  3891. // First step: determine if the driver has a service
  3892. //
  3893. if ((scManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS)) != NULL)
  3894. {
  3895. if ((scDriver = OpenService (scManager, szName, SERVICE_ALL_ACCESS)) != 0)
  3896. {
  3897. QUERY_SERVICE_CONFIG qsc;
  3898. SERVICE_STATUS ss;
  3899. DWORD cbReq;
  3900. void *pqsc;
  3901. ChangeServiceConfig (scDriver,
  3902. SERVICE_NO_CHANGE,
  3903. (fEnable) ? SERVICE_SYSTEM_START
  3904. : SERVICE_DISABLED,
  3905. SERVICE_NO_CHANGE,
  3906. NULL,
  3907. NULL,
  3908. NULL,
  3909. NULL,
  3910. NULL,
  3911. NULL,
  3912. NULL);
  3913. CloseServiceHandle (scDriver);
  3914. }
  3915. CloseServiceHandle (scManager);
  3916. }
  3917. }
  3918. /*
  3919. ***************************************************************
  3920. * SetMappable
  3921. *
  3922. * Sets the "Mappable" value for wave devices in the registry.
  3923. * The registry key is created if necessary
  3924. *
  3925. ***************************************************************
  3926. */
  3927. BOOL SetMappable (PIRESOURCE pIResource, BOOL fMappable)
  3928. {
  3929. TCHAR szFile[ _MAX_FNAME +1 +_MAX_EXT +1 ];
  3930. TCHAR szExt[ _MAX_EXT +1 ];
  3931. TCHAR szRegKey[MAX_PATH+1];
  3932. DWORD dwMappable;
  3933. HKEY hKey;
  3934. dwMappable = (fMappable) ? 1 : 0;
  3935. lsplitpath (pIResource->szFile, NULL, NULL, szFile, szExt);
  3936. if (szExt[0] != TEXT('\0'))
  3937. lstrcat (szFile, szExt);
  3938. wsprintf (szRegKey, TEXT("%s\\%s"), REGSTR_PATH_WAVEMAPPER, szFile);
  3939. if (RegCreateKey (HKEY_LOCAL_MACHINE, szRegKey, &hKey) != ERROR_SUCCESS)
  3940. {
  3941. return FALSE;
  3942. }
  3943. if (RegSetValueEx (hKey,
  3944. REGSTR_VALUE_MAPPABLE,
  3945. (DWORD)0,
  3946. REG_DWORD,
  3947. (void *)&dwMappable,
  3948. sizeof(dwMappable)) != ERROR_SUCCESS)
  3949. {
  3950. RegCloseKey (hKey);
  3951. return FALSE;
  3952. }
  3953. RegCloseKey (hKey);
  3954. if (fMappable)
  3955. {
  3956. SetFlag(pIResource->fStatus, dwStatusMAPPABLE);
  3957. }
  3958. else
  3959. {
  3960. ClearFlag(pIResource->fStatus, dwStatusMAPPABLE);
  3961. }
  3962. return TRUE;
  3963. }
  3964. BOOL GetMappable (PIDRIVER pIDriver)
  3965. {
  3966. TCHAR szFile[ _MAX_FNAME +1 +_MAX_EXT +1 ];
  3967. TCHAR szExt[ _MAX_EXT +1 ];
  3968. TCHAR szRegKey[MAX_PATH+1];
  3969. DWORD dwMappable;
  3970. DWORD dwSize;
  3971. DWORD dwType;
  3972. HKEY hKey;
  3973. lsplitpath (pIDriver->szFile, NULL, NULL, szFile, szExt);
  3974. if (szExt[0] != TEXT('\0'))
  3975. lstrcat (szFile, szExt);
  3976. wsprintf (szRegKey, TEXT("%s\\%s"), REGSTR_PATH_WAVEMAPPER, szFile);
  3977. if (RegOpenKey (HKEY_LOCAL_MACHINE, szRegKey, &hKey) != ERROR_SUCCESS)
  3978. {
  3979. return TRUE;
  3980. }
  3981. dwSize = sizeof(dwMappable);
  3982. if (RegQueryValueEx (hKey,
  3983. REGSTR_VALUE_MAPPABLE,
  3984. NULL,
  3985. &dwType,
  3986. (void *)&dwMappable,
  3987. &dwSize) != ERROR_SUCCESS)
  3988. {
  3989. RegCloseKey (hKey);
  3990. return TRUE;
  3991. }
  3992. RegCloseKey (hKey);
  3993. return (dwMappable) ? TRUE : FALSE;
  3994. }
  3995. #ifdef FIX_BUG_15451
  3996. // FixDriverService - work around known problems with sound drivers
  3997. //
  3998. // If there was a functioning kernel-mode service in place before the
  3999. // config dialog was presented, then there should still be one
  4000. // afterwards. However, there are two known problems with the
  4001. // currently-release drivers:
  4002. //
  4003. // 1) The service may not have shut down properly, and is stuck
  4004. // in a STOP_PENDING state(*). If this is the case, we need to
  4005. // ensure that the service is set to load on SYSTEM_START, and
  4006. // tell the user that the machine has to be rebooted before sound
  4007. // will work again.
  4008. //
  4009. // 2) The service may have failed to restart properly, and is
  4010. // stopped(**). If this is the case, and LoadType!=0, try setting
  4011. // LoadType=1 and starting the service.
  4012. //
  4013. // (*) -- bug #15451 in NT/SUR, where pending IRPs and open mixer
  4014. // handles prevent the service from shutting down
  4015. //
  4016. // (**) -- bug #XXXXX in NT/SUR, where some RISC machines stop the
  4017. // service, set LoadType=1, and fail to restart the service
  4018. // after you cancel their config dialog
  4019. //
  4020. BOOL FixDriverService (PIDRIVER pid)
  4021. {
  4022. SC_HANDLE scManager;
  4023. SC_HANDLE scDriver;
  4024. SERVICE_STATUS ss;
  4025. BOOL rc = FALSE;
  4026. TCHAR szName[ cchRESOURCE ];
  4027. lsplitpath (pid->szFile, NULL, NULL, szName, NULL);
  4028. // First step: open the service...even if it's hosed, we should
  4029. // still be able to do this.
  4030. //
  4031. if ((scManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS)) == 0)
  4032. {
  4033. return FALSE;
  4034. }
  4035. if ((scDriver = OpenService (scManager, szName, SERVICE_ALL_ACCESS)) == 0)
  4036. {
  4037. CloseServiceHandle (scManager);
  4038. return FALSE;
  4039. }
  4040. // Now check its status. Look for STOP_PENDING and STOPPED states.
  4041. //
  4042. if (QueryServiceStatus (scDriver, &ss))
  4043. {
  4044. if (ss.dwCurrentState == SERVICE_STOP_PENDING)
  4045. {
  4046. // The service didn't stop properly--we'll have to reboot.
  4047. // Make sure the service is configured such that it will start
  4048. // properly when we restart.
  4049. //
  4050. ChangeServiceConfig (scDriver,
  4051. SERVICE_NO_CHANGE,
  4052. SERVICE_SYSTEM_START, // Enable this puppy!
  4053. SERVICE_NO_CHANGE,
  4054. NULL,
  4055. NULL,
  4056. NULL,
  4057. NULL,
  4058. NULL,
  4059. NULL,
  4060. NULL);
  4061. // Tell the caller that a reboot is mandatory
  4062. rc = TRUE;
  4063. }
  4064. else if (ss.dwCurrentState == SERVICE_STOPPED)
  4065. {
  4066. TCHAR szKey[ cchRESOURCE ];
  4067. HKEY hkParams;
  4068. // The service stopped, but didn't restart properly--it could
  4069. // just be the LoadType problem. To fix this, we'll need
  4070. // to enumerate all the keys underneath the key
  4071. // HKLM\System\CurrentControlSet\Services\(thisdriver)\Parameters,
  4072. // and look for ...\Parameters\*\LoadType==(DWORD)1.
  4073. //
  4074. // First step is to open HKLM\System\CCS\Services\(driver)\Parms.
  4075. //
  4076. wsprintf (szKey, TEXT("%s\\%s\\Parameters"),
  4077. REGSTR_PATH_SERVICES,
  4078. szName);
  4079. if (RegOpenKey (HKEY_LOCAL_MACHINE, szKey, &hkParams) == 0)
  4080. {
  4081. DWORD cSubKeys;
  4082. DWORD iSubKey;
  4083. BOOL fFixedLoadType = FALSE;
  4084. // Find out how many subkeys there are under here--the
  4085. // keys we want are named "Device0" through "Device(n-1)"
  4086. //
  4087. RegQueryInfoKey (hkParams,
  4088. NULL, // lpClass
  4089. NULL, // lpcbClass
  4090. NULL, // lpReserved
  4091. &cSubKeys, // Whoops! We want this.
  4092. NULL, // lpcbMaxSubKeyLen
  4093. NULL, // lpcbMaxClassLen
  4094. NULL, // lpcValues
  4095. NULL, // lpcbMaxValueNameLen
  4096. NULL, // lpcbMaxValueLen
  4097. NULL, // lpcbSecurityDescriptor
  4098. NULL); // lpftLastWriteTime
  4099. // Open each subkey in turn, and look for a LoadType=
  4100. // which is bogus.
  4101. //
  4102. for (iSubKey = 0; iSubKey < cSubKeys; ++iSubKey)
  4103. {
  4104. HKEY hk;
  4105. TCHAR szSubKey[ cchRESOURCE ];
  4106. wsprintf (szSubKey, TEXT("Device%lu"), (LONG)iSubKey);
  4107. if (RegOpenKey (hkParams, szSubKey, &hk) == ERROR_SUCCESS)
  4108. {
  4109. DWORD dwLoadType;
  4110. DWORD dwType;
  4111. DWORD dwSize = sizeof(dwType);
  4112. if (RegQueryValueEx (hk,
  4113. cszRegValueLOADTYPE,
  4114. NULL,
  4115. &dwType,
  4116. (void *)&dwLoadType,
  4117. &dwSize) == 0)
  4118. {
  4119. if (dwLoadType == 1)
  4120. {
  4121. dwLoadType = 0;
  4122. fFixedLoadType = TRUE;
  4123. RegSetValueEx (hk,
  4124. cszRegValueLOADTYPE,
  4125. 0,
  4126. REG_DWORD,
  4127. (void *)&dwLoadType,
  4128. sizeof(dwLoadType));
  4129. }
  4130. }
  4131. RegCloseKey (hk);
  4132. }
  4133. }
  4134. // If we fixed a LoadType value, try to restart the service.
  4135. //
  4136. if (fFixedLoadType)
  4137. {
  4138. if (StartService (scDriver, 0, NULL))
  4139. {
  4140. ChangeServiceConfig (scDriver,
  4141. SERVICE_NO_CHANGE,
  4142. SERVICE_SYSTEM_START,
  4143. SERVICE_NO_CHANGE,
  4144. NULL,
  4145. NULL,
  4146. NULL,
  4147. NULL,
  4148. NULL,
  4149. NULL,
  4150. NULL);
  4151. }
  4152. }
  4153. }
  4154. }
  4155. }
  4156. // Clean up. We'll return TRUE if a reboot is necessary, and FALSE
  4157. // otherwise.
  4158. //
  4159. CloseServiceHandle (scDriver);
  4160. CloseServiceHandle (scManager);
  4161. return rc;
  4162. }
  4163. void ConfigureDriver (HWND hDlg, LPTSTR pszName)
  4164. {
  4165. PIDRIVER pid;
  4166. HANDLE hDriver;
  4167. BOOL fShowTrayVol;
  4168. BOOL fRestartDialog = FALSE;
  4169. if ((pid = FindIDriverByName (pszName)) == NULL)
  4170. return;
  4171. fShowTrayVol = GetTrayVolumeEnabled();
  4172. if (fShowTrayVol)
  4173. SetTrayVolumeEnabled(FALSE);
  4174. if ((hDriver = OpenDriver (pid->wszAlias, pid->wszSection, 0L)) == 0)
  4175. {
  4176. OpenDriverError(hDlg, pid->szDesc, pid->szFile);
  4177. }
  4178. else
  4179. {
  4180. DWORD dwStatus = GetDriverStatus (pid);
  4181. BOOL fHadService = IsFlagSet (dwStatus, dwStatusSvcSTARTED) &&
  4182. IsFlagSet (dwStatus, dwStatusHASSERVICE);
  4183. DRVCONFIGINFO DrvConfigInfo;
  4184. InitDrvConfigInfo(&DrvConfigInfo, pid);
  4185. if ((SendDriverMessage(
  4186. hDriver,
  4187. DRV_CONFIGURE,
  4188. (LONG_PTR)hDlg,
  4189. (LONG_PTR)(LPDRVCONFIGINFO)&DrvConfigInfo) ==
  4190. DRVCNF_RESTART))
  4191. {
  4192. iRestartMessage = 0;
  4193. fRestartDialog = TRUE;
  4194. }
  4195. CloseDriver(hDriver, 0L, 0L);
  4196. // If there was a functioning kernel-mode service in place before the
  4197. // config dialog was presented, then we should verify that there is
  4198. // still one in place now. See FixDriverService() for details.
  4199. //
  4200. if (fHadService)
  4201. {
  4202. dwStatus = GetDriverStatus (pid);
  4203. if (!IsFlagSet (dwStatus, dwStatusSvcSTARTED) ||
  4204. !IsFlagSet (dwStatus, dwStatusHASSERVICE))
  4205. {
  4206. if (FixDriverService (pid))
  4207. {
  4208. iRestartMessage = IDS_RESTART_NOSOUND;
  4209. fRestartDialog = TRUE;
  4210. }
  4211. }
  4212. }
  4213. }
  4214. if (fShowTrayVol)
  4215. SetTrayVolumeEnabled(TRUE);
  4216. if (fRestartDialog)
  4217. {
  4218. DialogBox(myInstance,MAKEINTRESOURCE(DLG_RESTART),hDlg,RestartDlg);
  4219. }
  4220. }
  4221. BOOL fDeviceHasMixers (LPTSTR pszName)
  4222. {
  4223. HKEY hk;
  4224. UINT ii;
  4225. BOOL rc = FALSE;
  4226. if (RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_DRIVERS32, &hk))
  4227. {
  4228. return FALSE;
  4229. }
  4230. for (ii = 0; ; ++ii)
  4231. {
  4232. TCHAR szLHS[ cchRESOURCE ];
  4233. TCHAR szRHS[ cchRESOURCE ];
  4234. DWORD dw1;
  4235. DWORD dw2;
  4236. DWORD dw3;
  4237. dw1 = cchRESOURCE;
  4238. dw3 = cchRESOURCE;
  4239. if (RegEnumValue (hk, ii, szLHS, &dw1,
  4240. 0, &dw2, (LPBYTE)szRHS, &dw3) != ERROR_SUCCESS)
  4241. {
  4242. break;
  4243. }
  4244. if ( (GuessDriverClassFromAlias (szLHS) == dcMIXER) &&
  4245. (!FileNameCmp (pszName, szRHS)) )
  4246. {
  4247. rc = TRUE;
  4248. break;
  4249. }
  4250. }
  4251. RegCloseKey (hk);
  4252. return rc;
  4253. }
  4254. #endif // FIX_BUG_15451
  4255. TCHAR c_tszControlExeS[] = TEXT("control.exe %s");
  4256. BOOL RunJoyControlPanel(void)
  4257. {
  4258. STARTUPINFO si;
  4259. PROCESS_INFORMATION pi;
  4260. TCHAR tsz[MAX_PATH];
  4261. BOOL fRtn;
  4262. memset(&si, 0, sizeof(si));
  4263. si.cb = sizeof(si);
  4264. wsprintf(tsz, c_tszControlExeS, TEXT("joy.cpl"));
  4265. if (CreateProcess(0, tsz, 0, 0, 0, 0, 0, 0, &si, &pi)) {
  4266. CloseHandle(pi.hProcess);
  4267. CloseHandle(pi.hThread);
  4268. fRtn = TRUE;
  4269. } else {
  4270. fRtn = FALSE;
  4271. }
  4272. return fRtn;
  4273. }