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

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