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.

3636 lines
88 KiB

  1. /*==========================================================================*/
  2. //
  3. // midi.c
  4. //
  5. // Copyright (C) 1993-1994 Microsoft Corporation. All Rights Reserved.
  6. /*==========================================================================*/
  7. #include "mmcpl.h"
  8. #include <windowsx.h>
  9. #include <mmsystem.h>
  10. #include <mmddkp.h>
  11. #include <mmreg.h>
  12. #include <cpl.h>
  13. #define NOSTATUSBAR
  14. #include <commctrl.h>
  15. #include <prsht.h>
  16. #include <string.h>
  17. #include <memory.h>
  18. #include <regstr.h>
  19. #include "draw.h"
  20. #include "utils.h"
  21. #include "roland.h"
  22. #include "midi.h"
  23. #include "tchar.h"
  24. //#include "newexe.h"
  25. #include <winnt.h>
  26. #if defined DEBUG || defined DEBUG_RETAIL
  27. extern TCHAR szNestLevel[];
  28. TCHAR szNestLevel[] = TEXT ("0MidiProp:");
  29. #define MODULE_DEBUG_PREFIX szNestLevel
  30. #endif
  31. #define _INC_MMDEBUG_CODE_ TRUE
  32. #include "mmdebug.h"
  33. #include "medhelp.h"
  34. #ifndef TVIS_ALL
  35. #define TVIS_ALL 0xFF7F // internal
  36. #endif
  37. #ifndef MIDI_IO_CONTROL
  38. #define MIDI_IO_CONTROL 0x00000008L // internal
  39. #endif
  40. #ifndef DRV_F_ADD // FEATURE: These should be in MMDDK.H
  41. #define DRV_F_ADD 0x00000000
  42. #define DRV_F_REMOVE 0x00000001
  43. #define DRV_F_CHANGE 0x00000002
  44. #define DRV_F_PROP_INSTR 0x00000004
  45. #define DRV_F_NEWDEFAULTS 0x00000008
  46. #define DRV_F_PARAM_IS_DEVNODE 0x10000000
  47. #endif
  48. /*==========================================================================*/
  49. // containing struct for what would otherwise be global variables
  50. //
  51. struct _globalstate gs;
  52. // this is the registry key that has midi instrument aliases
  53. // as subkeys
  54. //
  55. SZCODE cszSchemeRoot[] = REGSTR_PATH_PRIVATEPROPERTIES TEXT ("\\MIDI\\Schemes");
  56. SZCODE cszMidiMapRoot[] = REGSTR_PATH_MULTIMEDIA TEXT ("\\MIDIMap");
  57. // this is the registry key that has midi driver/port names
  58. //
  59. SZCODE cszDriversRoot[] = REGSTR_PATH_MEDIARESOURCES TEXT ("\\MIDI");
  60. // this is the list of known hindered midi drivers (or rather,
  61. // known drivers that require special idf's)
  62. //
  63. SZCODE cszHinderedMidiList[] = REGSTR_PATH_MEDIARESOURCES TEXT ("\\NonGeneralMIDIDriverList");
  64. SZCODE cszFriendlyName[] = TEXT ("FriendlyName");
  65. SZCODE cszDescription[] = TEXT ("Description");
  66. SZCODE cszSlashInstruments[] = TEXT ("\\Instruments");
  67. SZCODE cszExternal[] = TEXT ("External");
  68. SZCODE cszActive[] = TEXT ("Active");
  69. SZCODE cszDefinition[] = TEXT ("Definition");
  70. SZCODE cszPort[] = TEXT ("Port");
  71. SZCODE cszMidiSlash[] = TEXT ("midi\\");
  72. SZCODE csz02d[] = TEXT ("%02d");
  73. SZCODE cszEmpty[] = TEXT ("");
  74. static SZCODE cszChannels[] = TEXT ("Channels");
  75. static SZCODE cszCurrentScheme[] = TEXT ("CurrentScheme");
  76. static SZCODE cszCurrentInstrument[] = TEXT ("CurrentInstrument");
  77. static SZCODE cszUseScheme[] = TEXT ("UseScheme");
  78. static SZCODE cszAutoScheme[] = TEXT ("AutoScheme");
  79. static SZCODE cszRunOnceCount[] = TEXT ("ConfigureCount");
  80. static SZCODE cszDriverList[] = TEXT ("DriverList");
  81. static SZCODE cszDriverVal[] = TEXT ("Driver");
  82. //
  83. // structures used to hold data for the control panel dialogs.
  84. //
  85. //
  86. typedef struct _midi_scheme {
  87. PMCMIDI pmcm;
  88. HKEY hkSchemes;
  89. TCHAR szNone[MAX_ALIAS];
  90. DWORD dwChanMask;
  91. TCHAR szName[MAX_ALIAS];
  92. UINT nChildren;
  93. BOOL bDirty;
  94. struct {
  95. PINSTRUM pi;
  96. DWORD dwMask;
  97. } a[NUM_CHANNEL*4 +1];
  98. } MSCHEME, * PMSCHEME;
  99. typedef struct _midi_cpl {
  100. LPPROPSHEETPAGE ppsp;
  101. MSCHEME ms;
  102. TCHAR szScheme[MAX_ALIAS];
  103. TCHAR szDefault[MAX_ALIAS];
  104. PINSTRUM piSingle;
  105. BOOL bUseScheme;
  106. BOOL bAutoScheme; // TRUE if scheme was auto created
  107. DWORD dwRunCount; // counts the number of times runonce
  108. LPTSTR pszReason; // reason for choosing external port
  109. BOOL bDlgType2;
  110. BOOL bPastInit;
  111. BOOL bIgnoreSelChange;
  112. MCMIDI mcm;
  113. } MCLOCAL, * PMCLOCAL;
  114. BOOL WINAPI ShowDetails (
  115. HWND hWnd,
  116. PMCLOCAL pmcl);
  117. LONG SHRegDeleteKey(HKEY hKey, LPCTSTR lpSubKey);
  118. static UINT
  119. DeviceIDFromDriverName(
  120. PTSTR pstrDriverName);
  121. extern BOOL AccessServiceController(void);
  122. /*+ SimulateNotify
  123. *
  124. *-=================================================================*/
  125. STATICFN LRESULT SimulateNotify (
  126. HWND hWnd,
  127. WORD uId,
  128. WORD wNotify)
  129. {
  130. #ifdef _WIN32
  131. return SendMessage (hWnd, WM_COMMAND,
  132. MAKELONG(uId, wNotify),
  133. (LPARAM)GetDlgItem (hWnd, uId));
  134. #else
  135. #error this code is not designed for 16 bits
  136. #endif
  137. }
  138. /*+ Confirm
  139. *
  140. *-=================================================================*/
  141. STATICFN UINT Confirm (
  142. HWND hWnd,
  143. UINT idQuery,
  144. LPTSTR pszArg)
  145. {
  146. TCHAR szQuery[255];
  147. TCHAR sz[255];
  148. LoadString (ghInstance, idQuery, sz, NUMELMS(sz));
  149. wsprintf (szQuery, sz, pszArg);
  150. LoadString (ghInstance, IDS_DEF_CAPTION, sz, NUMELMS(sz));
  151. return MessageBox (hWnd, szQuery, sz, MB_YESNO | MB_ICONQUESTION);
  152. }
  153. /*+ TellUser
  154. *
  155. *-=================================================================*/
  156. STATICFN UINT TellUser (
  157. HWND hWnd,
  158. UINT idQuery,
  159. LPTSTR pszArg)
  160. {
  161. TCHAR szQuery[255];
  162. TCHAR sz[255];
  163. LoadString (ghInstance, idQuery, sz, NUMELMS(sz));
  164. wsprintf (szQuery, sz, pszArg);
  165. LoadString (ghInstance, IDS_DEF_CAPTION, sz, NUMELMS(sz));
  166. return MessageBox (hWnd, szQuery, sz, MB_OK | MB_ICONINFORMATION);
  167. }
  168. /*+ ForwardBillNotify
  169. *
  170. *-=================================================================*/
  171. STATICFN void ForwardBillNotify (
  172. HWND hWnd,
  173. NMHDR FAR * lpnm)
  174. {
  175. static struct {
  176. UINT code;
  177. UINT uId;
  178. } amap[] = {PSN_KILLACTIVE, IDOK,
  179. PSN_APPLY, ID_APPLY,
  180. PSN_SETACTIVE, ID_INIT,
  181. PSN_RESET, IDCANCEL,
  182. };
  183. UINT ii;
  184. #ifdef DEBUG
  185. AuxDebugEx (4, DEBUGLINE TEXT ("ForwardBillNotify() code = %X\r\n"), lpnm->code);
  186. #endif
  187. for (ii = 0; ii < NUMELMS(amap); ++ii)
  188. if (lpnm->code == amap[ii].code)
  189. {
  190. FORWARD_WM_COMMAND (hWnd, amap[ii].uId, 0, 0, SendMessage);
  191. break;
  192. }
  193. return;
  194. }
  195. /*+
  196. *
  197. *-=================================================================*/
  198. STATICFN void EnumChildrenIntoCombo (
  199. HWND hWndT,
  200. LPTSTR pszSelect,
  201. HKEY hKey)
  202. {
  203. TCHAR sz[MAX_ALIAS];
  204. DWORD cch = sizeof(sz)/sizeof(TCHAR);
  205. UINT ii = 0;
  206. //SetWindowRedraw (hWndT, FALSE);
  207. ComboBox_ResetContent (hWndT);
  208. if (!hKey)
  209. return;
  210. while (RegEnumKey (hKey, ii, sz, cch) == ERROR_SUCCESS)
  211. {
  212. int ix = ComboBox_AddString (hWndT, sz);
  213. //ComboBox_SetItemData (hWndT, ix, ii);
  214. ++ii;
  215. }
  216. ii = 0;
  217. if (pszSelect)
  218. ii = ComboBox_FindString (hWndT, -1, pszSelect);
  219. ComboBox_SetCurSel (hWndT, ii);
  220. }
  221. STDAPI_(BOOL) QueryGSSynth(LPTSTR pszDriver)
  222. {
  223. MIDIOUTCAPS moc;
  224. MMRESULT mmr;
  225. UINT mid;
  226. BOOL fGSSynth = FALSE;
  227. if (pszDriver)
  228. {
  229. mid = DeviceIDFromDriverName(pszDriver);
  230. if (mid!=(UINT)-1)
  231. {
  232. mmr = midiOutGetDevCaps(mid, &moc, sizeof(moc));
  233. if (MMSYSERR_NOERROR == mmr)
  234. {
  235. if ((moc.wMid == MM_MICROSOFT) && (moc.wPid == MM_MSFT_WDMAUDIO_MIDIOUT) && (moc.wTechnology == MOD_SWSYNTH))
  236. {
  237. fGSSynth = TRUE;
  238. } //end if synth
  239. } //end if no mm error
  240. } //end if mid is valid
  241. } //end if driver is valid string
  242. return(fGSSynth);
  243. }
  244. /*+
  245. *
  246. *-=================================================================*/
  247. LONG WINAPI GetAlias (
  248. HKEY hKey,
  249. LPTSTR szSub,
  250. LPTSTR pszAlias,
  251. DWORD cchAlias,
  252. BOOL * pbExtern,
  253. BOOL * pbActive)
  254. {
  255. LONG lRet;
  256. DWORD cbSize;
  257. HKEY hkSub;
  258. DWORD dw;
  259. #ifdef DEBUG
  260. AuxDebugEx (8, DEBUGLINE TEXT ("GetAlias(%08x,'%s',%08x,%d,%08x)\r\n"),
  261. hKey, szSub, pszAlias, cchAlias, pbExtern);
  262. #endif
  263. if (!(lRet = RegOpenKeyEx (hKey, szSub, 0, KEY_QUERY_VALUE, &hkSub)))
  264. {
  265. cbSize = cchAlias * sizeof (TCHAR);
  266. if ((lRet = RegQueryValueEx (hkSub, cszFriendlyName, NULL, &dw, (LPBYTE)pszAlias, &cbSize)) || cbSize <= 2)
  267. {
  268. cbSize = cchAlias * sizeof (TCHAR);
  269. if ((lRet = RegQueryValueEx (hkSub, cszDescription, NULL, &dw, (LPBYTE)pszAlias, &cbSize)) || cbSize <= 2)
  270. {
  271. TCHAR szDriver[MAXSTR];
  272. cbSize = sizeof(szDriver);
  273. if (!RegQueryValueEx(hkSub, cszDriverVal, NULL, &dw, (LPBYTE)szDriver, &cbSize))
  274. {
  275. LoadVERSION();
  276. if (!LoadDesc(szDriver, pszAlias))
  277. lstrcpy(pszAlias, szDriver);
  278. FreeVERSION();
  279. cbSize = (lstrlen(pszAlias)+1) * sizeof(TCHAR);
  280. RegSetValueEx(hkSub, cszFriendlyName, (DWORD)0, REG_SZ, (LPBYTE)pszAlias, cbSize);
  281. RegSetValueEx(hkSub, cszDescription, (DWORD)0, REG_SZ, (LPBYTE)pszAlias, cbSize);
  282. }
  283. else
  284. pszAlias[0] = 0;
  285. }
  286. }
  287. if (pbExtern)
  288. {
  289. *pbExtern = 0;
  290. cbSize = sizeof(*pbExtern);
  291. if (!(lRet = RegQueryValueEx (hkSub, cszExternal, NULL, &dw, (LPBYTE)pbExtern, &cbSize)))
  292. {
  293. if (REG_SZ == dw)
  294. *pbExtern = (*(LPTSTR)pbExtern == TEXT('0')) ? FALSE : TRUE;
  295. }
  296. }
  297. if (pbActive)
  298. {
  299. *pbActive = 0;
  300. cbSize = sizeof(*pbActive);
  301. if (!(lRet = RegQueryValueEx (hkSub, cszActive, NULL, &dw, (LPBYTE)pbActive, &cbSize)))
  302. {
  303. if (REG_SZ == dw)
  304. *pbActive = (*(LPTSTR)pbActive == TEXT('1')) ? TRUE : FALSE;
  305. }
  306. }
  307. RegCloseKey (hkSub);
  308. }
  309. #ifdef DEBUG
  310. if (lRet)
  311. {
  312. TCHAR szErr[MAX_PATH];
  313. FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lRet, 0,
  314. szErr, NUMELMS(szErr), NULL);
  315. #ifdef DEBUG
  316. AuxDebugEx (1, DEBUGLINE TEXT ("GetAlias failed: %d %s\r\n"), lRet, szErr);
  317. #endif
  318. }
  319. #endif
  320. return lRet;
  321. }
  322. /*+
  323. *
  324. *-=================================================================*/
  325. LONG WINAPI GetDriverFilename (
  326. HKEY hKey,
  327. LPTSTR szSub,
  328. LPTSTR pszDriver,
  329. DWORD cchDriver)
  330. {
  331. HKEY hkSub;
  332. LONG lRet;
  333. if (!(lRet = RegOpenKeyEx (hKey, szSub, 0, KEY_QUERY_VALUE, &hkSub)))
  334. {
  335. DWORD dwType;
  336. TCHAR sz[MAX_PATH];
  337. UINT cb = sizeof(sz);
  338. // get the contents of the 'driver' value of the given key.
  339. // then copy the filename part
  340. //
  341. lRet = RegQueryValueEx(hkSub, cszDriverVal, NULL, &dwType, (LPBYTE)sz, &cb);
  342. if (lRet || dwType != REG_SZ)
  343. *pszDriver = 0;
  344. else
  345. {
  346. LPTSTR psz = sz;
  347. UINT ii;
  348. // scan forward till we get to the file part of the pathname
  349. // then copy that part into the supplied buffer
  350. //
  351. for (ii = 0; psz[ii]; )
  352. {
  353. if (psz[ii] == TEXT('\\') || psz[ii] == TEXT(':'))
  354. {
  355. psz += ii+1;
  356. ii = 0;
  357. }
  358. else
  359. ++ii;
  360. }
  361. lstrcpyn (pszDriver, psz, cchDriver);
  362. }
  363. RegCloseKey (hkSub);
  364. }
  365. return lRet;
  366. }
  367. /*+ LoadInstruments
  368. *
  369. * load interesting data for all instruments, if bDriverAsAlias
  370. * is true, then put driver filename in szFriendly field of each
  371. * instrument. (scheme init uses this for hindered driver detection)
  372. * if !bDriverAsAlias, put friendly name in friendly name slot
  373. *
  374. *
  375. *-=================================================================*/
  376. void WINAPI LoadInstruments (
  377. PMCMIDI pmcm,
  378. BOOL bDriverAsAlias)
  379. {
  380. HKEY hkMidi;
  381. TCHAR sz[MAX_ALIAS];
  382. DWORD cch = sizeof(sz)/sizeof(TCHAR);
  383. UINT ii;
  384. UINT nInstr;
  385. PINSTRUM pi;
  386. UINT idxPort = 0;
  387. pmcm->nInstr = 0;
  388. pmcm->bHasExternal = FALSE;
  389. if (!(hkMidi = pmcm->hkMidi))
  390. {
  391. if (RegCreateKey (HKEY_LOCAL_MACHINE, cszDriversRoot, &hkMidi))
  392. return;
  393. pmcm->hkMidi = hkMidi;
  394. }
  395. if (!(pi = pmcm->api[0]))
  396. {
  397. pmcm->api[0] = pi = (LPVOID)LocalAlloc (LPTR, sizeof(*pi));
  398. if (!pi)
  399. return;
  400. }
  401. for (cch = sizeof(pi->szKey)/sizeof(TCHAR), nInstr = 0, ii = 0;
  402. ! RegEnumKey (hkMidi, ii, pi->szKey, cch);
  403. ++ii)
  404. {
  405. UINT jj;
  406. HKEY hkInst;
  407. PINSTRUM piParent;
  408. BOOL bActive = FALSE;
  409. // get driver alias, external, and active flags. This has the side
  410. // effect of initializing the friendly name key for legacy drivers
  411. // that have neither friendly name, nor description
  412. //
  413. GetAlias (hkMidi, pi->szKey, pi->szFriendly,
  414. NUMELMS(pi->szFriendly), &pi->bExternal, &bActive);
  415. // if requested, stomp friendly name with driver filename
  416. //
  417. if (bDriverAsAlias)
  418. GetDriverFilename (hkMidi, pi->szKey,
  419. pi->szFriendly, NUMELMS(pi->szFriendly));
  420. pi->fGSSynth = QueryGSSynth(pi->szKey);
  421. pi->uID = idxPort;
  422. if (pi->bExternal)
  423. pmcm->bHasExternal = TRUE;
  424. pi->piParent = 0;
  425. pi->bActive = bActive;
  426. piParent = pi;
  427. ++nInstr;
  428. if (nInstr >= NUMELMS(pmcm->api))
  429. {
  430. assert2 (0, TEXT ("Tell JohnKn to make midi instrument table bigger"));
  431. break;
  432. }
  433. if (!(pi = pmcm->api[nInstr]))
  434. {
  435. pmcm->api[nInstr] = pi = (LPVOID)LocalAlloc (LPTR, sizeof(*pi));
  436. if (!pi)
  437. break;
  438. }
  439. // open the parent's instruments subkey
  440. //
  441. lstrcpy (sz, piParent->szKey);
  442. lstrcat (sz, cszSlashInstruments);
  443. if (RegCreateKey (hkMidi, sz, &hkInst))
  444. continue;
  445. // enum the instruments and add them to the list
  446. //
  447. for (jj = 0; ! RegEnumKey (hkInst, jj, sz, cch); ++jj)
  448. {
  449. lstrcpy (pi->szKey, piParent->szKey);
  450. lstrcat (pi->szKey, cszSlashInstruments);
  451. lstrcat (pi->szKey, cszSlash);
  452. lstrcat (pi->szKey, sz);
  453. GetAlias (hkInst, sz, pi->szFriendly,
  454. NUMELMS(pi->szFriendly), NULL, NULL);
  455. pi->piParent = piParent;
  456. pi->bExternal = FALSE;
  457. pi->bActive = bActive;
  458. ++nInstr;
  459. if (nInstr >= NUMELMS(pmcm->api))
  460. {
  461. assert2 (0, TEXT ("Tell JohnKn to make midi instrument table bigger"));
  462. break;
  463. }
  464. if (!(pi = pmcm->api[nInstr]))
  465. {
  466. pmcm->api[nInstr] = pi = (LPVOID)LocalAlloc (LPTR, sizeof(*pi));
  467. if (!pi)
  468. break;
  469. }
  470. }
  471. RegCloseKey (hkInst);
  472. }
  473. // create a 'none' entry at the end
  474. //
  475. if (pi)
  476. {
  477. pi->piParent = 0;
  478. pi->bExternal = FALSE;
  479. pi->bActive = TRUE;
  480. pi->szKey[0] = 0;
  481. LoadString (ghInstance, IDS_NONE, pi->szFriendly, NUMELMS(pi->szFriendly));
  482. ++nInstr;
  483. }
  484. pmcm->nInstr = nInstr;
  485. }
  486. /*+
  487. *
  488. *-=================================================================*/
  489. void WINAPI FreeInstruments (
  490. PMCMIDI pmcm)
  491. {
  492. UINT ii;
  493. for (ii = 0; ii < NUMELMS (pmcm->api); ++ii)
  494. if (pmcm->api[ii])
  495. LocalFree ((HLOCAL)(PVOID)pmcm->api[ii]), pmcm->api[ii] = NULL;
  496. pmcm->nInstr = 0;
  497. }
  498. #ifdef DEBUG
  499. /*+ CleanStringCopy
  500. *
  501. * Replaces unprintable characters with '.'
  502. *
  503. *-=================================================================*/
  504. STATICFN LPTSTR CleanStringCopy (
  505. LPTSTR pszOut,
  506. LPTSTR pszIn,
  507. UINT cbOut)
  508. {
  509. LPTSTR psz = pszOut;
  510. while (cbOut && *pszIn)
  511. {
  512. *psz = (*pszIn >= 32 && *pszIn < 127) ? *pszIn : TEXT('.');
  513. ++psz;
  514. ++pszIn;
  515. }
  516. *psz = 0;
  517. return pszOut;
  518. }
  519. /*+ DumpInstruments
  520. *
  521. *-=================================================================*/
  522. STATICFN void DumpInstruments (
  523. PMCMIDI pmcm)
  524. {
  525. UINT ii;
  526. PINSTRUM pi;
  527. #ifdef DEBUG
  528. AuxDebugEx (3, DEBUGLINE TEXT ("DumpInstruments(%08x) nInstr=%d\r\n"),
  529. pmcm, pmcm->nInstr);
  530. #endif
  531. for (ii = 0; ii < pmcm->nInstr; ++ii)
  532. {
  533. TCHAR szKey[MAX_ALIAS];
  534. TCHAR szFriendly[MAX_ALIAS];
  535. pi = pmcm->api[ii];
  536. if (!pi)
  537. {
  538. #ifdef DEBUG
  539. AuxDebugEx (2, TEXT ("\tapi[%d] NULL\r\n"), ii);
  540. #endif
  541. continue;
  542. }
  543. CleanStringCopy (szKey, pi->szKey, NUMELMS(szKey));
  544. CleanStringCopy (szFriendly, pi->szFriendly, NUMELMS(szFriendly));
  545. #ifdef DEBUG
  546. AuxDebugEx (3, TEXT ("\tapi[%d]%08X p:%08x x:%d a:%d '%s' '%s'\r\n"),
  547. ii, pi, pi->piParent,
  548. pi->bExternal, pi->bActive,
  549. szKey, szFriendly);
  550. #endif
  551. }
  552. }
  553. #endif
  554. /*+
  555. *
  556. *-=================================================================*/
  557. STATICFN PINSTRUM WINAPI FindInstrumPath (
  558. PMCMIDI pmcm,
  559. LPTSTR pszPath)
  560. {
  561. UINT ii;
  562. for (ii = 0; ii < pmcm->nInstr; ++ii)
  563. {
  564. assert (pmcm->api[ii]);
  565. if (IsSzEqual(pszPath, pmcm->api[ii]->szKey))
  566. return pmcm->api[ii];
  567. }
  568. return NULL;
  569. }
  570. /*+
  571. *
  572. *-=================================================================*/
  573. PINSTRUM WINAPI FindInstrumentFromKey (
  574. PMCMIDI pmcm,
  575. LPTSTR pszKey)
  576. {
  577. UINT ii;
  578. if (!pszKey || !pszKey[0])
  579. return NULL;
  580. for (ii = 0; ii < pmcm->nInstr; ++ii)
  581. {
  582. assert (pmcm->api[ii]);
  583. if (IsSzEqual(pszKey, pmcm->api[ii]->szKey))
  584. return pmcm->api[ii];
  585. }
  586. return NULL;
  587. }
  588. /*+
  589. *
  590. *-=================================================================*/
  591. STATICFN void LoadInstrumentsIntoCombo (
  592. HWND hWnd,
  593. UINT uId,
  594. PINSTRUM piSelect,
  595. PMCMIDI pmcm)
  596. {
  597. HWND hWndT = GetDlgItem (hWnd, uId);
  598. UINT ii;
  599. int ix;
  600. #ifdef DEBUG
  601. AuxDebugEx (4, DEBUGLINE TEXT ("LoadInstrumentsIntoCombo(%08X,%d,%08x,%08x)\r\n"),
  602. hWnd, uId, piSelect, pmcm);
  603. #endif
  604. assert (hWndT);
  605. if (!hWndT)
  606. return;
  607. if (pmcm->nInstr > 0)
  608. SetWindowRedraw (hWndT, FALSE);
  609. ComboBox_ResetContent(hWndT);
  610. for (ii = 0; ii < pmcm->nInstr; ++ii)
  611. {
  612. if (ii == pmcm->nInstr-1)
  613. SetWindowRedraw (hWndT, TRUE);
  614. if (pmcm->api[ii]->bActive
  615. #ifdef EXCLUDE_EXTERNAL
  616. && !pmcm->api[ii]->bExternal
  617. #endif
  618. )
  619. {
  620. #ifdef DEBUG
  621. AuxDebugEx (7, DEBUGLINE TEXT ("Instrument[%d] = '%s'\r\n"),
  622. ii, pmcm->api[ii]->szFriendly);
  623. #endif
  624. ix = ComboBox_AddString (hWndT, pmcm->api[ii]->szFriendly);
  625. ComboBox_SetItemData (hWndT, ix, (LPARAM)pmcm->api[ii]);
  626. if (piSelect && pmcm->api[ii] == piSelect)
  627. ComboBox_SetCurSel (hWndT, ix);
  628. }
  629. }
  630. }
  631. /*+
  632. *
  633. *-=================================================================*/
  634. STATICFN void LoadInstrumentsIntoTree (
  635. HWND hWnd,
  636. UINT uId,
  637. UINT uIdSingle,
  638. PINSTRUM piSelect,
  639. PMCLOCAL pmcl)
  640. {
  641. PMCMIDI pmcm = &pmcl->mcm;
  642. HWND hWndT = GetDlgItem (hWnd, uId);
  643. UINT ii;
  644. HTREEITEM htiSelect = NULL;
  645. HTREEITEM htiParent = TVI_ROOT;
  646. assert (hWndT);
  647. if (!hWndT)
  648. return;
  649. #ifdef UNICODE
  650. TreeView_SetUnicodeFormat(hWndT,TRUE);
  651. #endif
  652. //if (pmcm->nInstr > 0)
  653. // SetWindowRedraw (hWndT, FALSE);
  654. pmcl->bIgnoreSelChange = TRUE;
  655. #ifdef DEBUG
  656. AuxDebugEx (6, DEBUGLINE TEXT ("tv_DeleteAllItems(%08X)\r\n"), hWndT);
  657. #endif
  658. TreeView_DeleteAllItems(hWndT);
  659. #ifdef DEBUG
  660. AuxDebugEx (6, DEBUGLINE TEXT ("tv_DeleteAllItems(%08X) ends\r\n"), hWndT);
  661. #endif
  662. pmcl->bIgnoreSelChange = FALSE;
  663. for (ii = 0; ii < pmcm->nInstr; ++ii)
  664. {
  665. PINSTRUM pi = pmcm->api[ii];
  666. TV_INSERTSTRUCT ti;
  667. HTREEITEM hti;
  668. //if (ii == pmcm->nInstr-1)
  669. // SetWindowRedraw (hWndT, TRUE);
  670. if (!pi->szKey[0] || !pi->bActive)
  671. continue;
  672. ZeroMemory (&ti, sizeof(ti));
  673. ti.hParent = TVI_ROOT;
  674. if (pi->piParent)
  675. ti.hParent = htiParent;
  676. ti.hInsertAfter = TVI_SORT;
  677. ti.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
  678. // TV_ITEM may not be ported to UNICODE ?!?
  679. ti.item.pszText = pi->szFriendly;
  680. ti.item.state = TVIS_EXPANDED;
  681. ti.item.stateMask = TVIS_ALL;
  682. ti.item.lParam = (LPARAM)pi;
  683. hti = TreeView_InsertItem (hWndT, &ti);
  684. if (piSelect && (piSelect == pi))
  685. htiSelect = hti;
  686. if ( ! pi->piParent)
  687. htiParent = hti;
  688. }
  689. // if a 'single' control id has been specified, propagate
  690. // selected item text into this control
  691. //
  692. if (uIdSingle)
  693. {
  694. if (htiSelect)
  695. {
  696. assert (piSelect);
  697. TreeView_SelectItem (hWndT, htiSelect);
  698. SetDlgItemText (hWnd, uIdSingle, piSelect->szFriendly);
  699. EnableWindow(GetDlgItem(hWnd, IDC_ABOUTSYNTH), piSelect->fGSSynth);
  700. }
  701. else
  702. SetDlgItemText (hWnd, uIdSingle, cszEmpty);
  703. }
  704. }
  705. /*+
  706. *
  707. *-=================================================================*/
  708. STATICFN void LoadSchemesIntoCombo (
  709. HWND hWnd,
  710. UINT uId,
  711. LPTSTR pszSelect,
  712. PMSCHEME pms)
  713. {
  714. HWND hWndT = GetDlgItem (hWnd, uId);
  715. HKEY hKey;
  716. assert (hWndT);
  717. if (!hWndT)
  718. return;
  719. hKey = pms->hkSchemes;
  720. if (!hKey &&
  721. !RegCreateKey (HKEY_LOCAL_MACHINE, cszSchemeRoot, &hKey))
  722. pms->hkSchemes = hKey;
  723. EnumChildrenIntoCombo (hWndT, pszSelect, hKey);
  724. }
  725. /*+ ChildKeyExists
  726. *
  727. * given an open registry key, and the name of a child of that
  728. * registry key, returns true if a child key with the given
  729. * name exists.
  730. *
  731. *-=================================================================*/
  732. STATICFN BOOL ChildKeyExists (
  733. HKEY hKey,
  734. LPTSTR pszChild)
  735. {
  736. TCHAR sz[MAX_ALIAS];
  737. UINT ii;
  738. if (!hKey)
  739. return FALSE;
  740. for (ii = 0; ! RegEnumKey (hKey, ii, sz, sizeof(sz)/sizeof(TCHAR)); ++ii)
  741. {
  742. if (IsSzEqual (pszChild, sz))
  743. return TRUE;
  744. }
  745. return FALSE;
  746. }
  747. /*+ LoadSchemeFromReg
  748. *
  749. *-=================================================================*/
  750. STATICFN void LoadSchemeFromReg (
  751. PMCMIDI pmcm,
  752. PMSCHEME pms,
  753. LPTSTR pszName)
  754. {
  755. HKEY hKey;
  756. DWORD dwAccum;
  757. UINT count;
  758. // try to open the indicated scheme key in the registry
  759. // and read channel map from it. Failure here is permissible.
  760. // it indicates that we are createing a new scheme.
  761. //
  762. count = 0;
  763. if (RegOpenKey (pms->hkSchemes, pszName, &hKey) == ERROR_SUCCESS)
  764. {
  765. DWORD cb;
  766. TCHAR sz[MAX_ALIAS];
  767. while (RegEnumKey (hKey, count, sz, sizeof(sz)/sizeof(TCHAR)) == ERROR_SUCCESS)
  768. {
  769. HKEY hKeyA;
  770. DWORD dwType;
  771. if (RegOpenKey (hKey, sz, &hKeyA) != ERROR_SUCCESS)
  772. break;
  773. pms->a[count].pi = NULL;
  774. cb = sizeof(sz);
  775. if ( ! RegQueryValue (hKeyA, NULL, sz, &cb))
  776. pms->a[count].pi = FindInstrumPath (pmcm, sz);
  777. pms->a[count].dwMask = 0;
  778. cb = sizeof(pms->a[count].dwMask);
  779. RegQueryValueEx (hKeyA, cszChannels, NULL,
  780. &dwType, (LPBYTE)&pms->a[count].dwMask, &cb);
  781. assert (dwType == REG_DWORD);
  782. RegCloseKey (hKeyA);
  783. // Don't allow empty entries
  784. //assert (pms->a[ii].dwMask);
  785. if (0 == pms->a[count].dwMask)
  786. {
  787. pms->a[count].pi = NULL;
  788. }
  789. ++count;
  790. #ifdef DEBUG
  791. AuxDebugEx (4, DEBUGLINE TEXT ("[%d]Chan %08X Alias '%s'\r\n"),
  792. count, pms->a[count].dwMask, pms->a[count].pi
  793. ? pms->a[count].pi->szFriendly
  794. : TEXT ("(null)"));
  795. #endif
  796. if (count == NUMELMS(pms->a) -1)
  797. break;
  798. }
  799. RegCloseKey (hKey);
  800. }
  801. pms->nChildren = count;
  802. lstrcpyn (pms->szName, pszName, NUMELMS(pms->szName));
  803. // slam a dummy (none) alias that matches all channels
  804. // at the end of our channel/alias list
  805. //
  806. assert (count < NUMELMS(pms->a));
  807. pms->a[count].dwMask = (DWORD)~0;
  808. pms->a[count].pi = NULL;
  809. #ifdef DEBUG
  810. AuxDebugEx (4, DEBUGLINE TEXT ("[%d]Chan %08X Alias '%s'\r\n"),
  811. count, pms->a[count].dwMask, "null");
  812. #endif
  813. // make sure scheme channel masks are in a valid state
  814. //
  815. for (dwAccum = 0, count = 0; count < NUMELMS(pms->a); ++count)
  816. {
  817. pms->a[count].dwMask &= ~dwAccum;
  818. dwAccum |= pms->a[count].dwMask;
  819. }
  820. return;
  821. }
  822. /*+ KickMapper
  823. *
  824. *-=================================================================*/
  825. void WINAPI KickMapper (
  826. HWND hWnd)
  827. {
  828. HMIDIOUT hmo;
  829. if (! midiOutOpen(&hmo, MIDI_MAPPER, 0, 0, MIDI_IO_CONTROL))
  830. {
  831. BOOL bDone;
  832. #ifdef DEBUG
  833. AuxDebugEx (2, DEBUGLINE TEXT ("Kicking Midi Mapper\r\n"));
  834. #endif
  835. bDone = midiOutMessage(hmo, DRVM_MAPPER_RECONFIGURE, 0, DRV_F_PROP_INSTR);
  836. midiOutClose(hmo);
  837. /*
  838. //no longer necessary due to winmm change allowing configure during play
  839. if (!bDone && hWnd)
  840. TellUser (hWnd, IDS_MAPPER_BUSY, NULL);
  841. */
  842. }
  843. #ifdef DEBUG
  844. AuxDebugEx (2, DEBUGLINE TEXT ("Done Kicking Midi Mapper\r\n"));
  845. #endif
  846. }
  847. /*+ SaveSchemeToReg
  848. *
  849. *-=================================================================*/
  850. STATICFN void SaveSchemeToReg (
  851. PMCMIDI pmcm,
  852. PMSCHEME pms,
  853. LPTSTR pszName,
  854. HWND hWnd)
  855. {
  856. TCHAR sz[MAX_ALIAS];
  857. HKEY hKey;
  858. DWORD dwAccum;
  859. UINT ii;
  860. UINT kk;
  861. UINT cb;
  862. #ifdef DEBUG
  863. AuxDebugEx (4, DEBUGLINE TEXT ("Saving Scheme '%s' children=%d\r\n"),
  864. pszName, pms->nChildren);
  865. for (ii = 0; ii < NUMELMS(pms->a); ++ii)
  866. {
  867. AuxDebugEx (4, TEXT ("\t%08X '%s'\r\n"),
  868. pms->a[ii].dwMask,
  869. pms->a[ii].pi ? pms->a[ii].pi->szKey : TEXT ("(null)"));
  870. }
  871. #endif
  872. // make sure scheme channel masks are in a valid state,
  873. // that is, prevent a channel bit from being set in more
  874. // than one member of a scheme
  875. //
  876. for (dwAccum = 0, ii = 0; ii < NUMELMS(pms->a); ++ii)
  877. {
  878. pms->a[ii].dwMask &= ~dwAccum;
  879. dwAccum |= pms->a[ii].dwMask;
  880. }
  881. // try to open/create the indicated scheme key in the registry
  882. // and write/update channel map to it.
  883. //
  884. if (!RegCreateKey (pms->hkSchemes, pszName, &hKey))
  885. {
  886. HKEY hKeyA;
  887. BOOL bKill;
  888. // salvage all of the existing keys that we can. delete
  889. // the rest.
  890. //
  891. for (dwAccum = 0, ii = 0; !RegEnumKey (hKey, ii, sz, sizeof(sz)/sizeof(TCHAR)); ++ii)
  892. {
  893. if (ii >= NUMELMS(pms->a))
  894. break;
  895. // we reuse the first N keys in this scheme
  896. // and delete the rest.
  897. //
  898. bKill = TRUE;
  899. if (((dwAccum & 0xFFFF) != 0xFFFF) &&
  900. pms->a[ii].pi &&
  901. (!ii || (pms->a[ii].pi->szKey[0] && pms->a[ii].dwMask)))
  902. bKill = FALSE;
  903. dwAccum |= pms->a[ii].dwMask;
  904. // if we have an obsolete alias key, remove it now
  905. // otherwise create/open the alias key and set it's
  906. // channel property to the correct value.
  907. //
  908. if (bKill)
  909. {
  910. #ifdef DEBUG
  911. AuxDebugEx (3, DEBUGLINE TEXT ("Deleting key[%d] '%s'\r\n"), ii, sz);
  912. #endif
  913. RegDeleteKey (hKey, sz);
  914. }
  915. else
  916. {
  917. #ifdef DEBUG
  918. AuxDebugEx (3, DEBUGLINE TEXT ("Reusing key[%d] '%s'\r\n"), ii, pms->a[ii].pi->szKey);
  919. #endif
  920. if (RegOpenKeyEx (hKey, sz, 0, KEY_ALL_ACCESS, &hKeyA))
  921. break;
  922. cb = (lstrlen(pms->a[ii].pi->szKey) + 1) * sizeof(TCHAR);
  923. RegSetValueEx (hKeyA, NULL, 0, REG_SZ,
  924. (LPBYTE)(pms->a[ii].pi->szKey), cb);
  925. RegSetValueEx (hKeyA, cszChannels, 0,
  926. REG_DWORD,
  927. (LPBYTE)&pms->a[ii].dwMask,
  928. sizeof(DWORD));
  929. RegCloseKey (hKeyA);
  930. }
  931. }
  932. // if we have channels that have not yet been written.
  933. // do that now
  934. //
  935. for (kk = 0; ii < NUMELMS(pms->a); ++ii)
  936. {
  937. // if this alias has any assigned channels, create
  938. // a key and give it a channels value
  939. //
  940. if (pms->a[ii].pi &&
  941. (!ii || (pms->a[ii].pi->szKey[0] && pms->a[ii].dwMask)))
  942. {
  943. #ifdef DEBUG
  944. AuxDebugEx (3, DEBUGLINE TEXT ("Creating key[%d] '%s'\r\n"), ii, pms->a[ii].pi->szKey);
  945. #endif
  946. // find an unused keyname;
  947. //
  948. for ( ; kk < NUMELMS(pms->a); ++kk)
  949. {
  950. wsprintf (sz, csz02d, kk);
  951. if (RegOpenKey (hKey, sz, &hKeyA))
  952. break;
  953. RegCloseKey (hKeyA);
  954. }
  955. // create a key with that name
  956. //
  957. if (RegCreateKey (hKey, sz, &hKeyA))
  958. break;
  959. cb = (lstrlen(pms->a[ii].pi->szKey) + 1) * sizeof(TCHAR);
  960. RegSetValueEx (hKeyA, NULL, 0, REG_SZ,
  961. (LPBYTE)(pms->a[ii].pi->szKey),cb);
  962. #ifdef DEBUG
  963. AuxDebugEx (3, DEBUGLINE TEXT ("Setting Channel Value %08X\r\n"), pms->a[ii].dwMask);
  964. #endif
  965. RegSetValueEx (hKeyA, cszChannels, 0,
  966. REG_DWORD,
  967. (LPBYTE)&pms->a[ii].dwMask,
  968. sizeof(DWORD));
  969. RegCloseKey (hKeyA);
  970. }
  971. }
  972. RegCloseKey (hKey);
  973. }
  974. // if no HWND supplied, we are in the runonce, so we dont
  975. // want to kick mapper just because a scheme has changed
  976. //
  977. if (hWnd)
  978. KickMapper (hWnd);
  979. return;
  980. }
  981. /*+ DeleteSchemeFromReg
  982. *
  983. *-=================================================================*/
  984. STATICFN void DeleteSchemeFromReg (
  985. HKEY hkSchemes,
  986. LPTSTR pszName)
  987. {
  988. TCHAR sz[MAX_ALIAS];
  989. HKEY hKey;
  990. UINT ii;
  991. #ifdef DEBUG
  992. AuxDebugEx (4, DEBUGLINE TEXT ("DeletingSchemeFromReg(%08X,'%s')\r\n"),
  993. hkSchemes,pszName);
  994. #endif
  995. SHRegDeleteKey(hkSchemes, pszName);
  996. /*
  997. // if we cannot open this key as a child of the 'schemes' key
  998. // we are done.
  999. //
  1000. if (RegOpenKey (hkSchemes, pszName, &hKey))
  1001. return;
  1002. // Before we can delete a key, we must delete its children
  1003. //
  1004. for (ii = 0; !RegEnumKey (hKey, ii, sz, sizeof(sz)/sizeof(TCHAR)); ++ii)
  1005. {
  1006. // if we have an obsolete alias key, remove it now
  1007. // otherwise create/open the alias key and set it's
  1008. // channel property to the correct value.
  1009. //
  1010. AuxDebugEx (3, DEBUGLINE TEXT ("Deleting key[%d] '%s'\r\n"), ii, sz);
  1011. RegDeleteKey (hKey, sz);
  1012. }
  1013. RegCloseKey (hKey);
  1014. // now delete this key
  1015. //
  1016. RegDeleteKey (hkSchemes, pszName);
  1017. return;
  1018. */
  1019. }
  1020. /*+
  1021. *
  1022. *-=================================================================*/
  1023. STATICFN void LoadChannelsIntoList (
  1024. HWND hWnd,
  1025. UINT uId,
  1026. UINT uIdLabel,
  1027. PMSCHEME pms)
  1028. {
  1029. HWND hWndT = GetDlgItem (hWnd, uId);
  1030. RECT rc;
  1031. UINT ii;
  1032. UINT nChan;
  1033. int nTabs;
  1034. assert (pms);
  1035. // empty the list
  1036. //
  1037. SetWindowRedraw (hWndT, FALSE);
  1038. ListBox_ResetContent (hWndT);
  1039. // calculate the width of the tabstop
  1040. // so that the second column lines up under the indicated
  1041. // label
  1042. //
  1043. GetWindowRect (GetDlgItem(hWnd, uIdLabel), &rc);
  1044. nTabs = rc.left;
  1045. GetWindowRect (hWnd, &rc);
  1046. nTabs = MulDiv(nTabs - rc.left, 4, LOWORD(GetDialogBaseUnits()));
  1047. ListBox_SetTabStops (hWndT, 1, &nTabs);
  1048. // fill the list with channel data
  1049. //
  1050. for (nChan = 0; nChan < NUM_CHANNEL; ++nChan)
  1051. {
  1052. static CONST TCHAR cszDtabS[] = TEXT ("%d\t%s");
  1053. TCHAR sz[MAX_ALIAS + 10];
  1054. for (ii = 0; ii < NUMELMS(pms->a); ++ii)
  1055. if (pms->a[ii].dwMask & (1 << nChan))
  1056. break;
  1057. assert (ii < NUMELMS(pms->a));
  1058. wsprintf (sz, cszDtabS, nChan+1,
  1059. pms->a[ii].pi ? pms->a[ii].pi->szFriendly
  1060. : pms->szNone);
  1061. if (nChan == (UINT)NUM_CHANNEL-1)
  1062. SetWindowRedraw (hWndT, TRUE);
  1063. ListBox_InsertString (hWndT, nChan, sz);
  1064. if (pms->dwChanMask & (1 << nChan))
  1065. ListBox_SetSel (hWndT, TRUE, nChan);
  1066. }
  1067. }
  1068. /*+
  1069. *
  1070. *-=================================================================*/
  1071. /*+ ChannelMaskToEdit
  1072. *
  1073. * convert a bit mask to a string containing list of set bits
  1074. * and bit ranges. Then SetWindowText the result into the given
  1075. * edit control.
  1076. *
  1077. * This function loads prefix text from resource strings.
  1078. *
  1079. * For Example: ChannelMaskToEdit(....0x0000F0F) would set the text
  1080. * 'Channels 1-4,9-12'.
  1081. *
  1082. *-=================================================================*/
  1083. STATICFN void ChannelMaskToEdit (
  1084. HWND hWnd,
  1085. UINT uId,
  1086. DWORD dwMask)
  1087. {
  1088. HWND hWndT = GetDlgItem (hWnd, uId);
  1089. TCHAR sz[NUM_CHANNEL * 4 + MAX_ALIAS];
  1090. if (!dwMask)
  1091. LoadString (ghInstance, IDS_NOCHAN, sz, NUMELMS(sz));
  1092. else
  1093. {
  1094. LPTSTR psz;
  1095. LPTSTR pszT;
  1096. int ii;
  1097. int iSpan;
  1098. DWORD dwLast;
  1099. DWORD dwBit;
  1100. LoadString (ghInstance,
  1101. (dwMask & (dwMask-1)) ? IDS_CHANPLURAL : IDS_CHANSINGULAR,
  1102. sz, NUMELMS(sz));
  1103. pszT = psz = sz + lstrlen(sz);
  1104. for (ii = 0, dwBit = 1, dwLast = 0, iSpan = 0;
  1105. ii <= 32;
  1106. dwLast = dwMask & dwBit, ++ii, dwBit += dwBit)
  1107. {
  1108. if ((dwMask & dwBit) ^ (dwLast + dwLast))
  1109. {
  1110. static CONST TCHAR cszCommaD[] = TEXT (",%d");
  1111. static CONST TCHAR cszDashD[] = TEXT ("-%d");
  1112. if ( ! dwLast)
  1113. psz += wsprintf (psz, cszCommaD, ii+1);
  1114. else if (iSpan)
  1115. psz += wsprintf (psz, cszDashD, ii);
  1116. iSpan = 0;
  1117. }
  1118. else
  1119. ++iSpan;
  1120. }
  1121. *pszT = TEXT (' ');
  1122. }
  1123. SetWindowText (hWndT, sz);
  1124. }
  1125. /*+ MidiChangeCommands
  1126. *
  1127. *-=================================================================*/
  1128. BOOL WINAPI MidiChangeCommands (
  1129. HWND hWnd,
  1130. UINT wId,
  1131. HWND hWndCtl,
  1132. UINT wNotify)
  1133. {
  1134. PMCLOCAL pmcl = GetDlgData(hWnd);
  1135. PMSCHEME pms = &pmcl->ms;
  1136. #ifdef DEBUG
  1137. AuxDebugEx (5, DEBUGLINE TEXT ("MidiChangeCommands(%08X,%d,%08X,%d)\r\n"),
  1138. hWnd, wId, hWndCtl, wNotify);
  1139. #endif
  1140. switch (wId)
  1141. {
  1142. case ID_APPLY:
  1143. return TRUE;
  1144. case IDOK:
  1145. {
  1146. int ix;
  1147. HWND hWndT = GetDlgItem (hWnd, IDC_INSTRUMENTS);
  1148. ix = ComboBox_GetCurSel (hWndT);
  1149. if (ix >= 0)
  1150. {
  1151. BOOL bFound = FALSE;
  1152. PINSTRUM piSel;
  1153. BOOL bFoundFirst = FALSE;
  1154. piSel = (LPVOID)ComboBox_GetItemData (hWndT, ix);
  1155. assert (!IsBadWritePtr(piSel, sizeof(*piSel)));
  1156. // has the <none> item been selected? in this
  1157. // case, set stuff up so that we will not try
  1158. // to add none to the scheme, but we will clear
  1159. // all bits from other channels that are set
  1160. // to none.
  1161. //
  1162. if ( ! piSel || ! piSel->szKey[0])
  1163. piSel = NULL, bFound = TRUE;
  1164. // turn channels on for this instrument and off for
  1165. // other instruments in this scheme.
  1166. //
  1167. for (ix = 0; ix < (int)NUMELMS(pms->a); ++ix)
  1168. {
  1169. if (pms->a[ix].pi != piSel)
  1170. pms->a[ix].dwMask &= ~pms->dwChanMask;
  1171. else if (! pms->a[ix].pi)
  1172. {
  1173. if (! bFoundFirst)
  1174. {
  1175. pms->a[ix].dwMask |= pms->dwChanMask;
  1176. bFound = TRUE;
  1177. bFoundFirst = TRUE;
  1178. }
  1179. }
  1180. else
  1181. {
  1182. pms->a[ix].dwMask |= pms->dwChanMask;
  1183. bFound = TRUE;
  1184. }
  1185. }
  1186. // if this instrument was not already in the scheme,
  1187. // find an empty slot and add it to the scheme.
  1188. //
  1189. if (!bFound)
  1190. {
  1191. for (ix = 0; ix < (int)NUMELMS(pms->a); ++ix)
  1192. {
  1193. if ( ! pms->a[ix].dwMask)
  1194. {
  1195. pms->a[ix].dwMask = pms->dwChanMask;
  1196. pms->a[ix].pi = piSel;
  1197. bFound = TRUE;
  1198. break;
  1199. }
  1200. }
  1201. }
  1202. assert2 (bFound, TEXT ("no room to add instrument to scheme"));
  1203. }
  1204. EndDialog (hWnd, IDOK);
  1205. break;
  1206. }
  1207. case IDCANCEL:
  1208. EndDialog (hWnd, IDCANCEL);
  1209. break;
  1210. //
  1211. //case ID_INIT:
  1212. // break;
  1213. }
  1214. return FALSE;
  1215. }
  1216. /*+ SaveAsDlgProc
  1217. *
  1218. *-=================================================================*/
  1219. const static DWORD aSaveAsHelpIds[] = { // Context Help IDs
  1220. IDE_SCHEMENAME, IDH_MIDI_SAVEDLG_SCHEMENAME,
  1221. 0, 0
  1222. };
  1223. INT_PTR CALLBACK SaveAsDlgProc (
  1224. HWND hWnd,
  1225. UINT uMsg,
  1226. WPARAM wParam,
  1227. LPARAM lParam)
  1228. {
  1229. switch (uMsg)
  1230. {
  1231. case WM_COMMAND:
  1232. switch (GET_WM_COMMAND_ID(wParam, lParam))
  1233. {
  1234. case IDOK:
  1235. {
  1236. LPTSTR pszName = GetDlgData (hWnd);
  1237. assert (pszName);
  1238. GetDlgItemText (hWnd, IDE_SCHEMENAME, pszName, MAX_ALIAS);
  1239. }
  1240. // fall through
  1241. case IDCANCEL:
  1242. EndDialog (hWnd, GET_WM_COMMAND_ID(wParam, lParam));
  1243. break;
  1244. }
  1245. break;
  1246. case WM_CLOSE:
  1247. SendMessage (hWnd, WM_COMMAND, IDCANCEL, 0);
  1248. break;
  1249. case WM_INITDIALOG:
  1250. {
  1251. LPTSTR pszName = (LPVOID) lParam;
  1252. assert (pszName);
  1253. SetDlgData (hWnd, pszName);
  1254. SetDlgItemText (hWnd, IDE_SCHEMENAME, pszName);
  1255. break;
  1256. }
  1257. case WM_CONTEXTMENU:
  1258. WinHelp ((HWND) wParam, NULL, HELP_CONTEXTMENU,
  1259. (UINT_PTR) (LPTSTR) aSaveAsHelpIds);
  1260. return TRUE;
  1261. case WM_HELP:
  1262. {
  1263. LPHELPINFO lphi = (LPVOID) lParam;
  1264. WinHelp (lphi->hItemHandle, NULL, HELP_WM_HELP,
  1265. (UINT_PTR) (LPTSTR) aSaveAsHelpIds);
  1266. return TRUE;
  1267. }
  1268. }
  1269. return FALSE;
  1270. }
  1271. /*+ GetNewSchemeName
  1272. *
  1273. *-=================================================================*/
  1274. STATICFN BOOL WINAPI GetNewSchemeName (
  1275. HWND hWnd,
  1276. HKEY hkSchemes,
  1277. LPTSTR pszName)
  1278. {
  1279. TCHAR szNew[MAX_ALIAS];
  1280. UINT_PTR uBtn;
  1281. lstrcpyn (szNew, pszName, ARRAYSIZE(szNew));
  1282. uBtn = DialogBoxParam (ghInstance,
  1283. MAKEINTRESOURCE(IDD_SAVENAME),
  1284. hWnd,
  1285. SaveAsDlgProc,
  1286. (LPARAM)szNew);
  1287. if (IDOK == uBtn)
  1288. {
  1289. if (ChildKeyExists (hkSchemes, szNew))
  1290. uBtn = Confirm (hWnd, IDS_QUERY_OVERSCHEME, szNew);
  1291. else
  1292. lstrcpy (pszName, szNew);
  1293. }
  1294. return (IDOK == uBtn || IDYES == uBtn);
  1295. }
  1296. /*+ MidiChangeDlgProc
  1297. *
  1298. *-=================================================================*/
  1299. const static DWORD aChngInstrHelpIds[] = { // Context Help IDs
  1300. IDC_INSTRUMENTS, IDH_ADDMIDI_INSTRUMENT,
  1301. IDC_TEXT_1, IDH_ADDMIDI_CHANNEL,
  1302. IDE_SHOW_CHANNELS, IDH_ADDMIDI_CHANNEL,
  1303. 0, 0
  1304. };
  1305. INT_PTR CALLBACK MidiChangeDlgProc (
  1306. HWND hWnd,
  1307. UINT uMsg,
  1308. WPARAM wParam,
  1309. LPARAM lParam)
  1310. {
  1311. switch (uMsg)
  1312. {
  1313. case WM_COMMAND:
  1314. HANDLE_WM_COMMAND (hWnd, wParam, lParam, MidiChangeCommands);
  1315. break;
  1316. case WM_NOTIFY:
  1317. ForwardBillNotify(hWnd, (NMHDR FAR *)lParam);
  1318. break;
  1319. case WM_CLOSE:
  1320. SendMessage (hWnd, WM_COMMAND, IDCANCEL, 0);
  1321. break;
  1322. case WM_INITDIALOG:
  1323. {
  1324. PMCLOCAL pmcl = (LPVOID) lParam;
  1325. PMSCHEME pms = &pmcl->ms;
  1326. SetDlgData (hWnd, pmcl);
  1327. LoadInstrumentsIntoCombo (hWnd, IDC_INSTRUMENTS, NULL, &pmcl->mcm);
  1328. ChannelMaskToEdit (hWnd, IDE_SHOW_CHANNELS, pms->dwChanMask);
  1329. break;
  1330. }
  1331. //case WM_DESTROY:
  1332. // break;
  1333. case WM_CONTEXTMENU:
  1334. WinHelp ((HWND) wParam, NULL, HELP_CONTEXTMENU,
  1335. (UINT_PTR) (LPTSTR) aChngInstrHelpIds);
  1336. return TRUE;
  1337. case WM_HELP:
  1338. {
  1339. LPHELPINFO lphi = (LPVOID) lParam;
  1340. WinHelp (lphi->hItemHandle, NULL, HELP_WM_HELP,
  1341. (UINT_PTR) (LPTSTR) aChngInstrHelpIds);
  1342. return TRUE;
  1343. }
  1344. }
  1345. return FALSE;
  1346. }
  1347. /*+ MidiConfigCommands
  1348. *
  1349. *-=================================================================*/
  1350. BOOL WINAPI MidiConfigCommands (
  1351. HWND hWnd,
  1352. UINT wId,
  1353. HWND hWndCtl,
  1354. UINT wNotify)
  1355. {
  1356. PMCLOCAL pmcl = GetDlgData(hWnd);
  1357. PMSCHEME pms = &pmcl->ms;
  1358. #ifdef DEBUG
  1359. AuxDebugEx (5, DEBUGLINE TEXT ("MidiConfigCommands(%08X,%d,%08X,%d)\r\n"),
  1360. hWnd, wId, hWndCtl, wNotify);
  1361. #endif
  1362. switch (wId)
  1363. {
  1364. case IDB_CHANGE:
  1365. {
  1366. UINT_PTR uRet;
  1367. int ii;
  1368. HWND hWndList = GetDlgItem (hWnd, IDL_CHANNELS);
  1369. #ifdef DEBUG
  1370. AuxDebugEx (2, DEBUGLINE TEXT ("Launching Change Dialog\r\n"));
  1371. #endif
  1372. pms->dwChanMask = 0;
  1373. for (ii = 0; ii < NUM_CHANNEL; ++ii)
  1374. if (ListBox_GetSel (hWndList, ii))
  1375. pms->dwChanMask |= (1 << ii);
  1376. uRet = DialogBoxParam (ghInstance,
  1377. MAKEINTRESOURCE(IDD_MIDICHANGE),
  1378. hWnd,
  1379. MidiChangeDlgProc,
  1380. (LPARAM)pmcl);
  1381. if (uRet == IDOK)
  1382. {
  1383. LoadChannelsIntoList (hWnd, IDL_CHANNELS, IDC_TEXT_1, pms);
  1384. pms->bDirty = TRUE;
  1385. }
  1386. break;
  1387. }
  1388. case IDB_DELETE:
  1389. if (IsSzEqual(pmcl->szScheme, pmcl->szDefault))
  1390. {
  1391. break;
  1392. }
  1393. if (Confirm (hWnd, IDS_QUERY_DELETESCHEME, pmcl->szScheme) == IDYES)
  1394. {
  1395. HWND hWndCtl = GetDlgItem (hWnd, IDC_SCHEMES);
  1396. int ix = ComboBox_FindStringExact (hWndCtl, -1, pmcl->szScheme);
  1397. assert (ix >= 0);
  1398. DeleteSchemeFromReg (pms->hkSchemes, pmcl->szScheme);
  1399. ComboBox_DeleteString (hWndCtl, ix);
  1400. ComboBox_SetCurSel (hWndCtl, 0);
  1401. SimulateNotify (hWnd, IDC_SCHEMES, CBN_SELCHANGE);
  1402. }
  1403. break;
  1404. case IDB_SAVE_AS:
  1405. if (GetNewSchemeName (hWnd, pms->hkSchemes, pmcl->szScheme))
  1406. {
  1407. SaveSchemeToReg (&pmcl->mcm, pms, pmcl->szScheme, hWnd);
  1408. LoadSchemesIntoCombo (hWnd, IDC_SCHEMES,
  1409. pmcl->szScheme, pms);
  1410. }
  1411. SimulateNotify (hWnd, IDC_SCHEMES, CBN_SELCHANGE);
  1412. break;
  1413. case IDC_SCHEMES:
  1414. if (wNotify == CBN_SELCHANGE)
  1415. {
  1416. int ix;
  1417. ix = ComboBox_GetCurSel (hWndCtl);
  1418. if (ix >= 0)
  1419. ComboBox_GetLBText (hWndCtl, ix, pmcl->szScheme);
  1420. LoadSchemeFromReg (&pmcl->mcm, pms, pmcl->szScheme);
  1421. pms->dwChanMask = 0;
  1422. LoadChannelsIntoList (hWnd, IDL_CHANNELS, IDC_TEXT_1, pms);
  1423. EnableWindow (GetDlgItem (hWnd, IDB_DELETE),
  1424. !IsSzEqual(pmcl->szDefault, pmcl->szScheme));
  1425. }
  1426. break;
  1427. case IDL_CHANNELS:
  1428. if (wNotify == LBN_SELCHANGE)
  1429. {
  1430. int ix;
  1431. ix = ListBox_GetSelCount (hWndCtl);
  1432. EnableWindow (GetDlgItem (hWnd, IDB_CHANGE), (ix > 0));
  1433. }
  1434. break;
  1435. case IDOK:
  1436. {
  1437. SaveSchemeToReg (&pmcl->mcm, pms, pmcl->szScheme, hWnd);
  1438. EndDialog (hWnd, IDOK);
  1439. break;
  1440. }
  1441. case IDCANCEL:
  1442. EndDialog (hWnd, IDCANCEL);
  1443. break;
  1444. }
  1445. return FALSE;
  1446. }
  1447. /*+ MidiConfigDlgProc
  1448. *
  1449. *-=================================================================*/
  1450. const static DWORD aMidiConfigHelpIds[] = { // Context Help IDs
  1451. IDC_GROUPBOX, IDH_COMM_GROUPBOX,
  1452. IDC_SCHEMES, IDH_MIDI_CFGDLG_SCHEME,
  1453. IDB_SAVE_AS, IDH_MIDI_CFGDLG_SAVEAS,
  1454. IDB_DELETE, IDH_MIDI_CFGDLG_DELETE,
  1455. IDC_GROUPBOX_2, IDH_COMM_GROUPBOX,
  1456. IDL_CHANNELS, IDH_MIDI_INSTRUMENTS,
  1457. IDB_CHANGE, IDH_MIDI_CFGDLG_CHANGE,
  1458. IDC_TEXT_1, IDH_MIDI_INSTRUMENTS,
  1459. IDC_TEXT_2, IDH_MIDI_INSTRUMENTS,
  1460. IDC_TEXT_3, NO_HELP,
  1461. 0, 0
  1462. };
  1463. INT_PTR CALLBACK MidiConfigDlgProc (
  1464. HWND hWnd,
  1465. UINT uMsg,
  1466. WPARAM wParam,
  1467. LPARAM lParam)
  1468. {
  1469. switch (uMsg)
  1470. {
  1471. case WM_COMMAND:
  1472. HANDLE_WM_COMMAND (hWnd, wParam, lParam, MidiConfigCommands);
  1473. break;
  1474. case WM_NOTIFY:
  1475. ForwardBillNotify(hWnd, (NMHDR FAR *)lParam);
  1476. break;
  1477. case WM_CLOSE:
  1478. SendMessage (hWnd, WM_COMMAND, IDCANCEL, 0);
  1479. break;
  1480. case WM_INITDIALOG:
  1481. {
  1482. PMCLOCAL pmcl = (LPVOID) lParam;
  1483. assert (pmcl);
  1484. SetDlgData (hWnd, pmcl);
  1485. LoadString (ghInstance, IDS_NONE, pmcl->ms.szNone, NUMELMS(pmcl->ms.szNone));
  1486. LoadSchemesIntoCombo (hWnd, IDC_SCHEMES, pmcl->szScheme, &pmcl->ms);
  1487. SimulateNotify (hWnd, IDC_SCHEMES, CBN_SELCHANGE);
  1488. EnableWindow (GetDlgItem(hWnd, IDB_CHANGE), FALSE);
  1489. break;
  1490. }
  1491. case WM_CONTEXTMENU:
  1492. WinHelp ((HWND) wParam, NULL, HELP_CONTEXTMENU,
  1493. (UINT_PTR) (LPTSTR) aMidiConfigHelpIds);
  1494. return TRUE;
  1495. case WM_HELP:
  1496. {
  1497. LPHELPINFO lphi = (LPVOID) lParam;
  1498. WinHelp (lphi->hItemHandle, NULL, HELP_WM_HELP,
  1499. (UINT_PTR) (LPTSTR) aMidiConfigHelpIds);
  1500. return TRUE;
  1501. }
  1502. }
  1503. return FALSE;
  1504. }
  1505. STATICFN void WINAPI PickMidiInstrument(
  1506. LPTSTR pszKey)
  1507. {
  1508. HKEY hKeyMR, hKeyDriver;
  1509. UINT cDevs;
  1510. UINT ii, jj;
  1511. DWORD cbSize, dwType;
  1512. LPMIDIOUTCAPS pmoc;
  1513. MMRESULT mmr;
  1514. PWSTR pszDevIntDev, pszDevIntKey;
  1515. UINT aTech[] = { MOD_SWSYNTH,
  1516. MOD_WAVETABLE,
  1517. MOD_SYNTH,
  1518. MOD_FMSYNTH,
  1519. MOD_SQSYNTH,
  1520. MOD_MIDIPORT};
  1521. UINT cTech = sizeof(aTech)/sizeof(aTech[0]);
  1522. TCHAR szKey[MAX_ALIAS];
  1523. TCHAR szPname[MAXPNAMELEN];
  1524. TCHAR szPnameTarget[MAXPNAMELEN];
  1525. LONG lr;
  1526. szPname[0] = 0;
  1527. cDevs = midiOutGetNumDevs();
  1528. if (0 == cDevs)
  1529. {
  1530. return;
  1531. }
  1532. pmoc = (LPMIDIOUTCAPS)LocalAlloc (LPTR, cDevs * sizeof(MIDIOUTCAPS));
  1533. if (NULL == pmoc)
  1534. {
  1535. return;
  1536. }
  1537. for (ii = cDevs; ii; ii--)
  1538. {
  1539. mmr = midiOutGetDevCaps(ii - 1, &(pmoc[ii - 1]), sizeof(MIDIOUTCAPS));
  1540. if (MMSYSERR_NOERROR != mmr)
  1541. {
  1542. LocalFree ((HLOCAL)pmoc);
  1543. return;
  1544. }
  1545. }
  1546. for (ii = 0; ii < cTech; ii++)
  1547. {
  1548. for (jj = cDevs; jj; jj--)
  1549. {
  1550. if (pmoc[jj - 1].wTechnology == aTech[ii])
  1551. {
  1552. lstrcpy(szPname, pmoc[jj - 1].szPname);
  1553. break;
  1554. }
  1555. }
  1556. if (jj)
  1557. {
  1558. // Broke out of inner loop, found match
  1559. break;
  1560. }
  1561. }
  1562. LocalFree ((HLOCAL)pmoc);
  1563. if (0 == jj)
  1564. {
  1565. // This should never happen...
  1566. return;
  1567. }
  1568. jj--;
  1569. mmr = midiOutMessage (HMIDIOUT_INDEX(jj), DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)(PULONG)&cbSize, 0L);
  1570. if (MMSYSERR_NOERROR != mmr)
  1571. {
  1572. return;
  1573. }
  1574. pszDevIntDev = (PWSTR)LocalAlloc (LPTR, cbSize);
  1575. if (NULL == pszDevIntDev)
  1576. {
  1577. return;
  1578. }
  1579. mmr = midiOutMessage (HMIDIOUT_INDEX(jj), DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)pszDevIntDev, (DWORD)cbSize);
  1580. if (MMSYSERR_NOERROR != mmr)
  1581. {
  1582. LocalFree ((HLOCAL)pszDevIntDev);
  1583. return;
  1584. }
  1585. lr = RegOpenKey(HKEY_LOCAL_MACHINE, cszDriversRoot, &hKeyMR);
  1586. if (ERROR_SUCCESS != lr)
  1587. {
  1588. LocalFree ((HLOCAL)pszDevIntDev);
  1589. return;
  1590. }
  1591. for (ii = 0; ; )
  1592. {
  1593. lr = RegEnumKey(hKeyMR, ii++, szKey, sizeof(szKey)/sizeof(szKey[0]));
  1594. if (ERROR_SUCCESS != lr)
  1595. {
  1596. RegCloseKey(hKeyMR);
  1597. LocalFree ((HLOCAL)pszDevIntDev);
  1598. return;
  1599. }
  1600. lr = RegOpenKey(hKeyMR, szKey, &hKeyDriver);
  1601. if (ERROR_SUCCESS != lr)
  1602. {
  1603. RegCloseKey(hKeyMR);
  1604. LocalFree ((HLOCAL)pszDevIntDev);
  1605. return;
  1606. }
  1607. cbSize = sizeof(szPnameTarget);
  1608. lr = RegQueryValueEx(
  1609. hKeyDriver,
  1610. cszActive,
  1611. NULL,
  1612. &dwType,
  1613. (LPSTR)szPnameTarget,
  1614. &cbSize);
  1615. if (ERROR_SUCCESS != lr)
  1616. {
  1617. RegCloseKey(hKeyDriver);
  1618. RegCloseKey(hKeyMR);
  1619. LocalFree ((HLOCAL)pszDevIntDev);
  1620. return;
  1621. }
  1622. if (TEXT('1') != szPnameTarget[0])
  1623. {
  1624. RegCloseKey(hKeyDriver);
  1625. continue;
  1626. }
  1627. cbSize = sizeof(szPnameTarget);
  1628. lr = RegQueryValueEx(
  1629. hKeyDriver,
  1630. cszDescription,
  1631. NULL,
  1632. &dwType,
  1633. (LPSTR)szPnameTarget,
  1634. &cbSize);
  1635. if (ERROR_SUCCESS != lr)
  1636. {
  1637. RegCloseKey(hKeyDriver);
  1638. RegCloseKey(hKeyMR);
  1639. LocalFree ((HLOCAL)pszDevIntDev);
  1640. return;
  1641. }
  1642. if (0 != lstrcmp(szPnameTarget, szPname))
  1643. {
  1644. RegCloseKey(hKeyDriver);
  1645. continue;
  1646. }
  1647. cbSize = 0;
  1648. lr = RegQueryValueExW (
  1649. hKeyDriver,
  1650. L"DeviceInterface",
  1651. NULL,
  1652. &dwType,
  1653. (LPSTR)NULL,
  1654. &cbSize);
  1655. if (ERROR_SUCCESS != lr)
  1656. {
  1657. RegCloseKey(hKeyDriver);
  1658. RegCloseKey(hKeyMR);
  1659. LocalFree ((HLOCAL)pszDevIntDev);
  1660. return;
  1661. }
  1662. pszDevIntKey = (PWSTR) LocalAlloc (LPTR, cbSize);
  1663. if (NULL == pszDevIntKey)
  1664. {
  1665. RegCloseKey(hKeyDriver);
  1666. RegCloseKey(hKeyMR);
  1667. LocalFree ((HLOCAL)pszDevIntDev);
  1668. return;
  1669. }
  1670. lr = RegQueryValueExW (
  1671. hKeyDriver,
  1672. L"DeviceInterface",
  1673. NULL,
  1674. &dwType,
  1675. (LPSTR)pszDevIntKey,
  1676. &cbSize);
  1677. RegCloseKey(hKeyDriver);
  1678. if (ERROR_SUCCESS != lr)
  1679. {
  1680. LocalFree ((HLOCAL)pszDevIntKey);
  1681. RegCloseKey(hKeyMR);
  1682. LocalFree ((HLOCAL)pszDevIntDev);
  1683. return;
  1684. }
  1685. if (0 == lstrcmpiW(pszDevIntKey, pszDevIntDev))
  1686. {
  1687. LocalFree ((HLOCAL)pszDevIntKey);
  1688. RegCloseKey(hKeyMR);
  1689. LocalFree ((HLOCAL)pszDevIntDev);
  1690. lstrcpy(pszKey, szKey);
  1691. return;
  1692. }
  1693. LocalFree ((HLOCAL)pszDevIntKey);
  1694. }
  1695. }
  1696. /*+ SaveLocal
  1697. *
  1698. *-=================================================================*/
  1699. STATICFN void WINAPI SaveLocal (
  1700. PMCLOCAL pmcl,
  1701. BOOL bUserSetting,
  1702. HWND hWnd) // optional window to report errors: NULL - no reports
  1703. {
  1704. HKEY hKey = NULL;
  1705. UINT cb;
  1706. #ifdef DEBUG
  1707. AuxDebugEx (2, DEBUGLINE TEXT ("SaveLocal(%08X,%X) %s\r\n"),
  1708. pmcl, hWnd, pmcl->pszReason ? pmcl->pszReason : TEXT (""));
  1709. #endif
  1710. if ((RegCreateKey (HKEY_CURRENT_USER, cszMidiMapRoot, &hKey) == ERROR_SUCCESS) && hKey)
  1711. {
  1712. cb = (lstrlen(pmcl->szScheme) + 1) * sizeof(TCHAR);
  1713. RegSetValueEx (hKey, cszCurrentScheme, 0, REG_SZ,
  1714. (LPBYTE)pmcl->szScheme, cb);
  1715. //assert (pmcl->piSingle);
  1716. if ((pmcl->piSingle) && (pmcl->piSingle->bActive))
  1717. {
  1718. #ifdef DEBUG
  1719. AuxDebugEx (2, DEBUGLINE TEXT ("Setting CurrentInstrument Key to %08X '%s'\r\n"),
  1720. pmcl->piSingle, pmcl->piSingle->szKey);
  1721. #endif
  1722. cb = (lstrlen(pmcl->piSingle->szKey) + 1) * sizeof(TCHAR);
  1723. RegSetValueEx (hKey, cszCurrentInstrument, 0, REG_SZ,
  1724. (LPBYTE)(pmcl->piSingle->szKey),
  1725. cb);
  1726. }
  1727. else
  1728. {
  1729. // Assume No Match
  1730. TCHAR szKey[MAX_ALIAS];
  1731. LONG lr;
  1732. szKey[0] = 0;
  1733. RegSetValueEx (hKey, cszCurrentInstrument, 0, REG_SZ, (LPBYTE)cszEmpty, 0);
  1734. PickMidiInstrument(szKey);
  1735. cb = (lstrlen(szKey) + 1) * sizeof(TCHAR);
  1736. lr = RegSetValueEx (hKey, cszCurrentInstrument, 0, REG_SZ,
  1737. (LPBYTE)(szKey), cb);
  1738. }
  1739. RegSetValueEx (hKey, cszUseScheme, 0, REG_DWORD,
  1740. (LPBYTE)&pmcl->bUseScheme, sizeof(pmcl->bUseScheme));
  1741. if (bUserSetting)
  1742. pmcl->bAutoScheme = FALSE;
  1743. RegSetValueEx (hKey, cszAutoScheme, 0, REG_DWORD,
  1744. (LPBYTE)&pmcl->bAutoScheme, sizeof(pmcl->bAutoScheme));
  1745. RegSetValueEx (hKey, cszRunOnceCount, 0, REG_DWORD,
  1746. (LPBYTE)&pmcl->dwRunCount, sizeof(pmcl->dwRunCount));
  1747. if (pmcl->pszReason)
  1748. {
  1749. cb = (lstrlen(pmcl->pszReason) + 1) * sizeof(TCHAR);
  1750. RegSetValueEx (hKey, cszDriverList, 0, REG_SZ,
  1751. (LPBYTE)pmcl->pszReason, cb);
  1752. }
  1753. else
  1754. RegSetValueEx (hKey, cszDriverList, 0, REG_SZ, (LPBYTE)cszEmpty, 0);
  1755. RegCloseKey (hKey);
  1756. // Don't Kick mapper unless we have a window
  1757. if (hWnd)
  1758. KickMapper (hWnd);
  1759. }
  1760. }
  1761. /*+ InitLocal
  1762. *
  1763. *-=================================================================*/
  1764. STATICFN void WINAPI InitLocal (
  1765. PMCLOCAL pmcl,
  1766. LPARAM lParam,
  1767. BOOL bDriverAsAlias) // driver as alias mode used only for scheme init
  1768. {
  1769. HKEY hKey;
  1770. LoadString (ghInstance, IDS_DEFAULT_SCHEME_NAME,
  1771. pmcl->szDefault, NUMELMS(pmcl->szDefault));
  1772. // NOTE : Comment below regarding RunOnceSchemeInit is in reference
  1773. // to an obsolete RunOnce initialization.
  1774. //
  1775. // we allow driver as alias (szFriendly) only for InitLocal when called
  1776. // from RunOnceSchemeInit. this works because in this case we have
  1777. // no UI so we dont need the friendly names for anything.
  1778. //
  1779. assert (!bDriverAsAlias || lParam == 0);
  1780. LoadInstruments (&pmcl->mcm, bDriverAsAlias);
  1781. #ifdef DEBUG
  1782. if (mmdebug_OutputLevel >= 3)
  1783. DumpInstruments (&pmcl->mcm);
  1784. #endif
  1785. if (RegCreateKey (HKEY_CURRENT_USER, cszMidiMapRoot, &hKey) == ERROR_SUCCESS)
  1786. {
  1787. DWORD cb;
  1788. DWORD dwType;
  1789. TCHAR szSingle[MAX_ALIAS];
  1790. cb = sizeof(pmcl->szScheme);
  1791. if (RegQueryValueEx (hKey, cszCurrentScheme, NULL, &dwType, (LPBYTE)pmcl->szScheme, &cb))
  1792. pmcl->szScheme[0] = 0;
  1793. pmcl->piSingle = NULL;
  1794. cb = sizeof(szSingle);
  1795. if (!RegQueryValueEx (hKey, cszCurrentInstrument, NULL, &dwType, (LPBYTE)szSingle, &cb))
  1796. pmcl->piSingle = FindInstrumentFromKey (&pmcl->mcm, szSingle);
  1797. cb = sizeof(pmcl->bUseScheme);
  1798. if (RegQueryValueEx (hKey, cszUseScheme, NULL, &dwType, (LPBYTE)&pmcl->bUseScheme, &cb))
  1799. pmcl->bUseScheme = 0;
  1800. cb = sizeof(pmcl->bAutoScheme);
  1801. if (RegQueryValueEx (hKey, cszAutoScheme, NULL, &dwType, (LPBYTE)&pmcl->bAutoScheme, &cb))
  1802. pmcl->bAutoScheme = TRUE;
  1803. cb = sizeof(pmcl->dwRunCount);
  1804. if (RegQueryValueEx (hKey, cszRunOnceCount, NULL, &dwType, (LPBYTE)&pmcl->dwRunCount, &cb))
  1805. pmcl->dwRunCount = 0;
  1806. pmcl->pszReason = NULL;
  1807. RegCloseKey (hKey);
  1808. }
  1809. pmcl->ppsp = (LPVOID)lParam;
  1810. }
  1811. /*+ FixupHinderedIDFs
  1812. *
  1813. *-=================================================================*/
  1814. VOID WINAPI FixupHinderedIDFs (
  1815. PMCLOCAL pmcl,
  1816. LPTSTR pszTemp, // ptr to temp memory
  1817. UINT cchTemp) // size of temp memory
  1818. {
  1819. HKEY hkHind; // hinderedMidiList root
  1820. LPTSTR pszDriver = pszTemp; // max size is short filename
  1821. UINT cch;
  1822. LPTSTR pszIDF = (LPVOID)(pszTemp + MAX_PATH);
  1823. UINT cbSize;
  1824. DWORD iEnum;
  1825. DWORD dwType;
  1826. #ifdef DEBUG
  1827. AuxDebugEx (3, DEBUGLINE TEXT ("FixupHinderedIDFs(%08x)\r\n"), pmcl);
  1828. #endif
  1829. assert (pszTemp);
  1830. assert (cchTemp > MAX_PATH + MAX_PATH + 64);
  1831. // the midi key should have already been opened.
  1832. //
  1833. assert (pmcl->mcm.hkMidi);
  1834. if (RegCreateKey (HKEY_LOCAL_MACHINE, cszHinderedMidiList, &hkHind))
  1835. return;
  1836. // enumerate the known hindered driver list looking for
  1837. // drivers that need to have their IDF's set
  1838. //
  1839. for (iEnum = 0, cch = MAX_PATH, cbSize = (MAX_PATH + 64) * sizeof(TCHAR);
  1840. ! RegEnumValue (hkHind, iEnum, pszDriver, &cch, NULL, &dwType, (LPBYTE)pszIDF, &cbSize);
  1841. ++iEnum, cch = MAX_PATH, cbSize = (MAX_PATH + 64) * sizeof(TCHAR))
  1842. {
  1843. UINT ii;
  1844. #ifdef DEBUG
  1845. AuxDebugEx (3, DEBUGLINE TEXT ("enum[%d] pszDriver='%s' pszIDF='%s'\r\n"), iEnum, pszDriver, pszIDF);
  1846. #endif
  1847. // just to be careful. ignore any registry entry that
  1848. // does not have string data
  1849. //
  1850. assert (dwType == REG_SZ);
  1851. if (dwType != REG_SZ)
  1852. continue;
  1853. // scan through the list of drivers looking for one that is
  1854. // internal, and has the same driver name as one of our known
  1855. // list of hindered drivers. if we find one, force its
  1856. // IDF to be the given IDF
  1857. //
  1858. for (ii = 0; ii < pmcl->mcm.nInstr; ++ii)
  1859. {
  1860. PINSTRUM pi = pmcl->mcm.api[ii];
  1861. HKEY hkSub;
  1862. if (!pi || !pi->szKey[0] || pi->bExternal ||
  1863. !IsSzEqual (pi->szFriendly, pszDriver))
  1864. continue;
  1865. #ifdef DEBUG
  1866. AuxDebugEx (2, DEBUGLINE TEXT ("forcing driver '%s' to use IDF '%s'\r\n"), pi->szKey, pszIDF);
  1867. #endif
  1868. if ( ! RegOpenKeyEx (pmcl->mcm.hkMidi, pi->szKey, 0, KEY_ALL_ACCESS, &hkSub))
  1869. {
  1870. RegSetValueEx (hkSub, cszDefinition, 0, REG_SZ, (LPBYTE)pszIDF, cbSize);
  1871. RegCloseKey (hkSub);
  1872. }
  1873. }
  1874. }
  1875. RegCloseKey (hkHind);
  1876. return;
  1877. }
  1878. STDAPI_(void) HandleSynthAboutBox(HWND hWnd)
  1879. {
  1880. HWND hTree = GetDlgItem(hWnd, IDL_INSTRUMENTS);
  1881. HTREEITEM hItem = TreeView_GetSelection(hTree);
  1882. TV_ITEM ti;
  1883. PINSTRUM pi;
  1884. memset(&ti, 0, sizeof(ti));
  1885. ti.mask = TVIF_PARAM;
  1886. ti.hItem = hItem;
  1887. TreeView_GetItem (hTree, &ti);
  1888. pi = (LPVOID)ti.lParam;
  1889. if (pi)
  1890. {
  1891. UINT uWaveID;
  1892. if (GetWaveID(&uWaveID) != (MMRESULT)MMSYSERR_ERROR)
  1893. {
  1894. WAVEOUTCAPS woc;
  1895. if (waveOutGetDevCaps(uWaveID, &woc, sizeof(woc)) == MMSYSERR_NOERROR)
  1896. {
  1897. RolandProp(hWnd, ghInstance, woc.szPname);
  1898. }
  1899. }
  1900. }
  1901. }
  1902. /*+ MidiCplCommands
  1903. *
  1904. *-=================================================================*/
  1905. BOOL WINAPI MidiCplCommands (
  1906. HWND hWnd,
  1907. UINT wId,
  1908. HWND hWndCtl,
  1909. UINT wNotify)
  1910. {
  1911. PMCLOCAL pmcl = GetDlgData(hWnd);
  1912. #ifdef DEBUG
  1913. AuxDebugEx (3, DEBUGLINE TEXT ("MidiCplCommands(%08X,%X,%08X,%d)\r\n"),
  1914. hWnd, wId, hWndCtl, wNotify);
  1915. #endif
  1916. assert (pmcl);
  1917. if (!pmcl)
  1918. return FALSE;
  1919. switch (wId)
  1920. {
  1921. case IDB_CONFIGURE:
  1922. {
  1923. UINT_PTR uRet;
  1924. TCHAR szOld[MAX_ALIAS];
  1925. #ifdef DEBUG
  1926. AuxDebugEx (2, DEBUGLINE TEXT ("Launching Config Dialog\r\n"));
  1927. #endif
  1928. lstrcpy (szOld, pmcl->szScheme);
  1929. uRet = DialogBoxParam (ghInstance,
  1930. MAKEINTRESOURCE(IDD_MIDICONFIG),
  1931. hWnd,
  1932. MidiConfigDlgProc,
  1933. (LPARAM)pmcl);
  1934. if (uRet != IDOK)
  1935. lstrcpy (pmcl->szScheme, szOld);
  1936. else
  1937. PropSheet_Changed(GetParent(hWnd), hWnd);
  1938. LoadSchemesIntoCombo (hWnd, IDC_SCHEMES, pmcl->szScheme, &pmcl->ms);
  1939. }
  1940. break;
  1941. case IDC_ABOUTSYNTH:
  1942. {
  1943. HandleSynthAboutBox(hWnd);
  1944. }
  1945. break;
  1946. case IDB_ADDWIZ:
  1947. #ifdef DEBUG
  1948. AuxDebugEx (2, DEBUGLINE TEXT ("Launching Midi Wizard\r\n"));
  1949. #endif
  1950. MidiInstrumentsWizard (hWnd, &pmcl->mcm, NULL);
  1951. LoadInstruments (&pmcl->mcm, FALSE);
  1952. #ifdef DEBUG
  1953. if (mmdebug_OutputLevel >= 3)
  1954. DumpInstruments (&pmcl->mcm);
  1955. #endif
  1956. if (pmcl->bDlgType2)
  1957. {
  1958. LoadInstrumentsIntoTree (hWnd, IDL_INSTRUMENTS, IDC_INSTRUMENTS,
  1959. pmcl->piSingle, pmcl);
  1960. }
  1961. else
  1962. {
  1963. LoadInstrumentsIntoCombo (hWnd, IDC_INSTRUMENTS,
  1964. pmcl->piSingle, &pmcl->mcm);
  1965. }
  1966. MMExtPropSheetCallback(MM_EPS_BLIND_TREECHANGE, 0,0,0);
  1967. break;
  1968. case IDC_SCHEMES:
  1969. if (wNotify == CBN_SELCHANGE)
  1970. {
  1971. int ix;
  1972. ix = ComboBox_GetCurSel (hWndCtl);
  1973. if (ix >= 0)
  1974. ComboBox_GetLBText (hWndCtl, ix, pmcl->szScheme);
  1975. PropSheet_Changed(GetParent(hWnd), hWnd);
  1976. }
  1977. break;
  1978. case IDC_INSTRUMENTS:
  1979. if (wNotify == CBN_SELCHANGE)
  1980. {
  1981. int ix;
  1982. assert (!pmcl->bDlgType2);
  1983. ix = ComboBox_GetCurSel (hWndCtl);
  1984. if (ix >= 0)
  1985. {
  1986. pmcl->piSingle = (LPVOID)ComboBox_GetItemData (hWndCtl, ix);
  1987. }
  1988. PropSheet_Changed(GetParent(hWnd), hWnd);
  1989. }
  1990. break;
  1991. case IDC_RADIO_CUSTOM:
  1992. case IDC_RADIO_SINGLE:
  1993. {
  1994. BOOL bUseScheme = pmcl->bUseScheme;
  1995. pmcl->bUseScheme = IsDlgButtonChecked (hWnd, IDC_RADIO_CUSTOM);
  1996. if (bUseScheme != pmcl->bUseScheme)
  1997. PropSheet_Changed(GetParent(hWnd), hWnd);
  1998. if (pmcl->bDlgType2)
  1999. {
  2000. HWND hWndCtl;
  2001. EnableWindow(GetDlgItem (hWnd, IDL_INSTRUMENTS), !pmcl->bUseScheme);
  2002. if (hWndCtl = GetDlgItem (hWnd, IDB_DETAILS))
  2003. EnableWindow(hWndCtl, !pmcl->bUseScheme);
  2004. }
  2005. EnableWindow(GetDlgItem (hWnd, IDC_INSTRUMENTS), !pmcl->bUseScheme);
  2006. EnableWindow(GetDlgItem (hWnd, IDC_SCHEMES), pmcl->bUseScheme);
  2007. EnableWindow(GetDlgItem (hWnd, IDC_SCHEMESLABEL), pmcl->bUseScheme);
  2008. EnableWindow(GetDlgItem (hWnd, IDB_CONFIGURE), pmcl->bUseScheme);
  2009. }
  2010. break;
  2011. #if 1 //def DETAILS_FROM_MAIN_CPL
  2012. case IDB_DETAILS:
  2013. assert (pmcl->bDlgType2);
  2014. if (pmcl->bDlgType2)
  2015. {
  2016. TCHAR szSingle[MAX_PATH];
  2017. int ix;
  2018. ix = ComboBox_GetCurSel (hWndCtl);
  2019. if (ix >= 0)
  2020. pmcl->piSingle = (LPVOID)ComboBox_GetItemData (hWndCtl, ix);
  2021. szSingle[0] = 0;
  2022. if (pmcl->piSingle)
  2023. lstrcpy (szSingle, pmcl->piSingle->szKey);
  2024. if (ShowDetails (hWnd, pmcl))
  2025. {
  2026. LoadInstruments (&pmcl->mcm, FALSE);
  2027. pmcl->piSingle = FindInstrumentFromKey (&pmcl->mcm, szSingle);
  2028. LoadInstrumentsIntoTree (hWnd, IDL_INSTRUMENTS,
  2029. IDC_INSTRUMENTS, pmcl->piSingle,
  2030. pmcl);
  2031. }
  2032. }
  2033. break;
  2034. #endif
  2035. case ID_INIT:
  2036. LoadInstruments (&pmcl->mcm, FALSE);
  2037. #ifdef DEBUG
  2038. if (mmdebug_OutputLevel >= 3)
  2039. DumpInstruments (&pmcl->mcm);
  2040. #endif
  2041. if (pmcl->bDlgType2)
  2042. {
  2043. LoadInstrumentsIntoTree (hWnd, IDL_INSTRUMENTS, IDC_INSTRUMENTS,
  2044. pmcl->piSingle, pmcl);
  2045. }
  2046. else
  2047. {
  2048. LoadInstrumentsIntoCombo (hWnd, IDC_INSTRUMENTS,
  2049. pmcl->piSingle, &pmcl->mcm);
  2050. }
  2051. break;
  2052. case ID_APPLY:
  2053. pmcl->bUseScheme = IsDlgButtonChecked (hWnd, IDC_RADIO_CUSTOM);
  2054. SaveLocal (pmcl, TRUE, hWnd);
  2055. break;
  2056. case IDOK:
  2057. pmcl->bUseScheme = IsDlgButtonChecked (hWnd, IDC_RADIO_CUSTOM);
  2058. break;
  2059. case IDCANCEL:
  2060. break;
  2061. //
  2062. //case ID_INIT:
  2063. // break;
  2064. }
  2065. return FALSE;
  2066. }
  2067. /*+ HandleInstrumentsSelChange
  2068. *
  2069. *-=================================================================*/
  2070. STATICFN BOOL WINAPI HandleInstrumentsSelChange (
  2071. HWND hWnd,
  2072. LPNMHDR lpnm)
  2073. {
  2074. PMCLOCAL pmcl = GetDlgData(hWnd);
  2075. LPNM_TREEVIEW pntv = (LPVOID)lpnm;
  2076. LPTV_ITEM pti = &pntv->itemNew;
  2077. TV_ITEM ti;
  2078. PINSTRUM pi;
  2079. TCHAR szSingle[MAX_ALIAS];
  2080. BOOL bChange = FALSE;
  2081. if (!pmcl || pmcl->bIgnoreSelChange)
  2082. return FALSE;
  2083. // setup ti to get text & # of children
  2084. // from the IDF filename entry.
  2085. //
  2086. ti.mask = TVIF_TEXT | TVIF_PARAM;
  2087. ti.pszText = szSingle;
  2088. ti.cchTextMax = NUMELMS(szSingle);
  2089. ti.hItem = pti->hItem;
  2090. TreeView_GetItem (lpnm->hwndFrom, &ti);
  2091. pi = (LPVOID)ti.lParam; // FindInstrument (&pmcl->mcm, szSingle);
  2092. #ifdef DEBUG
  2093. AuxDebugEx (2, DEBUGLINE TEXT ("HandInstSelChg(%X,...) %X %X Init=%d\r\n"),
  2094. hWnd, pmcl->piSingle, pi, !pmcl->bPastInit);
  2095. #endif
  2096. SetDlgItemText (hWnd, IDC_INSTRUMENTS, szSingle);
  2097. if (pmcl->piSingle != pi)
  2098. {
  2099. EnableWindow(GetDlgItem(hWnd,IDC_ABOUTSYNTH),pi->fGSSynth);
  2100. bChange = TRUE;
  2101. pmcl->piSingle = pi;
  2102. }
  2103. return (bChange && pmcl->bPastInit);
  2104. }
  2105. /*+ MidiCplDlgProc
  2106. *
  2107. *-=================================================================*/
  2108. const static DWORD aKeyWordIds[] = { // Context Help IDs
  2109. IDC_GROUPBOX, IDH_COMM_GROUPBOX,
  2110. IDC_RADIO_SINGLE, IDH_MIDI_SINGLE_INST_BUTTON,
  2111. IDC_INSTRUMENTS, IDH_MIDI_SINGLE_INST,
  2112. IDL_INSTRUMENTS, IDH_MIDI_SINGLE_INST_LIST,
  2113. IDC_RADIO_CUSTOM, IDH_MIDI_CUST_CONFIG,
  2114. IDC_SCHEMESLABEL, IDH_MIDI_SCHEME,
  2115. IDC_SCHEMES, IDH_MIDI_SCHEME,
  2116. IDC_ABOUTSYNTH, IDH_ABOUT,
  2117. //IDB_DETAILS, IDH_MIDI_SINGLE_INST_PROP,
  2118. IDB_CONFIGURE, IDH_MIDI_CONFIG_SCHEME,
  2119. IDB_ADDWIZ, IDH_MIDI_ADD_NEW,
  2120. 0, 0
  2121. };
  2122. INT_PTR CALLBACK MidiCplDlgProc (
  2123. HWND hWnd,
  2124. UINT uMsg,
  2125. WPARAM wParam,
  2126. LPARAM lParam)
  2127. {
  2128. #ifdef DEBUG
  2129. AuxDebugEx (5, DEBUGLINE TEXT ("MidiCplDlgProc(%08X,%X,%08X,%08X)\r\n"),
  2130. hWnd, uMsg, wParam, lParam);
  2131. #endif
  2132. switch (uMsg)
  2133. {
  2134. case WM_COMMAND:
  2135. HANDLE_WM_COMMAND (hWnd, wParam, lParam, MidiCplCommands);
  2136. break;
  2137. case WM_NOTIFY:
  2138. {
  2139. LPNMHDR lpnm = (LPVOID)lParam;
  2140. if (lpnm->idFrom == (UINT)IDL_INSTRUMENTS &&
  2141. lpnm->code == TVN_SELCHANGED)
  2142. {
  2143. if (HandleInstrumentsSelChange (hWnd, lpnm))
  2144. PropSheet_Changed(GetParent(hWnd), hWnd);
  2145. }
  2146. else
  2147. ForwardBillNotify(hWnd, (NMHDR FAR *)lParam);
  2148. }
  2149. break;
  2150. case WM_INITDIALOG:
  2151. {
  2152. PMCLOCAL pmcl;
  2153. pmcl = (LPVOID)LocalAlloc(LPTR, sizeof(*pmcl));
  2154. SetDlgData (hWnd, pmcl);
  2155. if (!pmcl)
  2156. {
  2157. break;
  2158. }
  2159. pmcl->bPastInit = FALSE;
  2160. InitLocal (pmcl, lParam, FALSE);
  2161. EnableWindow (GetDlgItem (hWnd, IDB_ADDWIZ), pmcl->mcm.bHasExternal & AccessServiceController());
  2162. EnableWindow(GetDlgItem(hWnd, IDC_ABOUTSYNTH), FALSE);
  2163. if (GetDlgItem(hWnd, IDL_INSTRUMENTS))
  2164. {
  2165. pmcl->bDlgType2 = TRUE;
  2166. LoadInstrumentsIntoTree (hWnd, IDL_INSTRUMENTS,
  2167. IDC_INSTRUMENTS, pmcl->piSingle,
  2168. pmcl);
  2169. }
  2170. else
  2171. {
  2172. pmcl->bDlgType2 = FALSE;
  2173. LoadInstrumentsIntoCombo (hWnd, IDC_INSTRUMENTS,
  2174. pmcl->piSingle, &pmcl->mcm);
  2175. }
  2176. CheckRadioButton (hWnd,
  2177. IDC_RADIO_SINGLE,
  2178. IDC_RADIO_CUSTOM,
  2179. pmcl->bUseScheme ? IDC_RADIO_CUSTOM
  2180. : IDC_RADIO_SINGLE);
  2181. LoadSchemesIntoCombo (hWnd, IDC_SCHEMES,
  2182. pmcl->szScheme, &pmcl->ms);
  2183. if (pmcl->mcm.nInstr > 1)
  2184. {
  2185. if (pmcl->bDlgType2)
  2186. {
  2187. HWND hWndCtl;
  2188. EnableWindow(GetDlgItem (hWnd, IDL_INSTRUMENTS), !pmcl->bUseScheme);
  2189. if (hWndCtl = GetDlgItem (hWnd, IDB_DETAILS))
  2190. EnableWindow (hWndCtl, !pmcl->bUseScheme);
  2191. }
  2192. EnableWindow(GetDlgItem (hWnd, IDC_INSTRUMENTS), !pmcl->bUseScheme);
  2193. EnableWindow(GetDlgItem (hWnd, IDC_SCHEMES), pmcl->bUseScheme);
  2194. EnableWindow(GetDlgItem (hWnd, IDC_SCHEMESLABEL), pmcl->bUseScheme);
  2195. EnableWindow(GetDlgItem (hWnd, IDB_CONFIGURE), pmcl->bUseScheme);
  2196. }
  2197. else
  2198. {
  2199. UINT aid[] = { IDL_INSTRUMENTS, IDC_INSTRUMENTS, IDC_SCHEMES,
  2200. IDC_RADIO_SINGLE, IDC_RADIO_CUSTOM,
  2201. IDB_CONFIGURE, IDB_DETAILS, IDB_ADDWIZ };
  2202. UINT ii;
  2203. for (ii = 0; ii < NUMELMS(aid); ++ii)
  2204. {
  2205. HWND hWndCtl = GetDlgItem (hWnd, aid[ii]);
  2206. if (hWndCtl)
  2207. EnableWindow (hWndCtl, FALSE);
  2208. }
  2209. }
  2210. pmcl->bPastInit = TRUE;
  2211. break;
  2212. }
  2213. case WM_DESTROY:
  2214. {
  2215. PMCLOCAL pmcl = GetDlgData(hWnd);
  2216. #ifdef DEBUG
  2217. AuxDebugEx (5, DEBUGLINE TEXT ("MidiCPL - begin WM_DESTROY\r\n"));
  2218. #endif
  2219. if (pmcl)
  2220. {
  2221. if (pmcl->mcm.hkMidi)
  2222. RegCloseKey (pmcl->mcm.hkMidi);
  2223. if (pmcl->ms.hkSchemes)
  2224. RegCloseKey (pmcl->ms.hkSchemes);
  2225. FreeInstruments (&pmcl->mcm);
  2226. SetDlgData (hWnd, 0);
  2227. LocalFree ((HLOCAL)(UINT_PTR)(DWORD_PTR)pmcl);
  2228. }
  2229. #ifdef DEBUG
  2230. AuxDebugEx (5, DEBUGLINE TEXT ("MidiCPL - done with WM_DESTROY\r\n"));
  2231. #endif
  2232. break;
  2233. }
  2234. //case WM_DROPFILES:
  2235. // break;
  2236. case WM_CONTEXTMENU:
  2237. WinHelp ((HWND) wParam, NULL, HELP_CONTEXTMENU,
  2238. (UINT_PTR) (LPTSTR) aKeyWordIds);
  2239. return TRUE;
  2240. case WM_HELP:
  2241. {
  2242. LPHELPINFO lphi = (LPVOID) lParam;
  2243. WinHelp (lphi->hItemHandle, NULL, HELP_WM_HELP,
  2244. (UINT_PTR) (LPTSTR) aKeyWordIds);
  2245. return TRUE;
  2246. }
  2247. #if 0
  2248. default:
  2249. if (uMsg == wHelpMessage)
  2250. {
  2251. WinHelp (hWnd, gszWindowsHlp, HELP_CONTEXT, ID_SND_HELP);
  2252. return TRUE;
  2253. }
  2254. break;
  2255. #endif
  2256. }
  2257. return FALSE;
  2258. }
  2259. /*+ MidiClassCommands
  2260. *
  2261. *-=================================================================*/
  2262. BOOL WINAPI MidiClassCommands (
  2263. HWND hWnd,
  2264. UINT wId,
  2265. HWND hWndCtl,
  2266. UINT wNotify)
  2267. {
  2268. PMCLOCAL pmcl = GetDlgData(hWnd);
  2269. if (!pmcl) return FALSE;
  2270. #ifdef DEBUG
  2271. AuxDebugEx (5, DEBUGLINE TEXT ("MidiClassCommands(%08X,%d,%08X,%d)\r\n"),
  2272. hWnd, wId, hWndCtl, wNotify);
  2273. #endif
  2274. switch (wId)
  2275. {
  2276. case IDB_ADDWIZ:
  2277. MidiInstrumentsWizard (hWnd, &pmcl->mcm, NULL);
  2278. LoadInstruments (&pmcl->mcm, FALSE);
  2279. LoadInstrumentsIntoTree (hWnd, IDL_INSTRUMENTS, 0, NULL, pmcl);
  2280. // flog the parent property sheet to let it know that we have
  2281. // made changes to the advanced midi page structures
  2282. //
  2283. {
  2284. PMPSARGS pmpsa = (LPVOID)pmcl->ppsp->lParam;
  2285. if (pmpsa && pmpsa->lpfnMMExtPSCallback)
  2286. pmpsa->lpfnMMExtPSCallback (MM_EPS_TREECHANGE, 0, 0, pmpsa->lParam);
  2287. }
  2288. break;
  2289. //case ID_APPLY:
  2290. // return TRUE;
  2291. //
  2292. //case IDCANCEL:
  2293. // break;
  2294. }
  2295. return FALSE;
  2296. }
  2297. /*+ MidiClassDlgProc
  2298. *
  2299. *-=================================================================*/
  2300. const static DWORD aMidiClassHelpIds[] = { // Context Help IDs
  2301. IDB_ADDWIZ, IDH_MIDI_ADD_NEW,
  2302. IDC_CLASS_ICON, NO_HELP,
  2303. IDC_CLASS_LABEL, NO_HELP,
  2304. IDL_INSTRUMENTS, IDH_MMCPL_DEVPROP_INST_LIST,
  2305. 0, 0
  2306. };
  2307. INT_PTR CALLBACK MidiClassDlgProc (
  2308. HWND hWnd,
  2309. UINT uMsg,
  2310. WPARAM wParam,
  2311. LPARAM lParam)
  2312. {
  2313. switch (uMsg)
  2314. {
  2315. case WM_COMMAND:
  2316. HANDLE_WM_COMMAND (hWnd, wParam, lParam, MidiClassCommands);
  2317. break;
  2318. case WM_NOTIFY:
  2319. ForwardBillNotify (hWnd, (NMHDR FAR *)lParam);
  2320. break;
  2321. case WM_INITDIALOG:
  2322. {
  2323. PMCLOCAL pmcl;
  2324. TCHAR sz[MAX_ALIAS];
  2325. pmcl = (LPVOID)LocalAlloc(LPTR, sizeof(*pmcl));
  2326. SetDlgData (hWnd, pmcl);
  2327. if (!pmcl)
  2328. {
  2329. break;
  2330. }
  2331. InitLocal (pmcl, lParam, FALSE);
  2332. #ifdef DEBUG
  2333. AuxDebugEx (5, DEBUGLINE TEXT ("midiClass.WM_INITDLG ppsp=%08X\r\n"), pmcl->ppsp);
  2334. #endif
  2335. //AuxDebugDump (8, pmcl->ppsp, sizeof(*pmcl->ppsp));
  2336. LoadString (ghInstance, IDS_MIDI_DEV_AND_INST, sz, NUMELMS(sz));
  2337. SetDlgItemText (hWnd, IDC_CLASS_LABEL, sz);
  2338. Static_SetIcon(GetDlgItem (hWnd, IDC_CLASS_ICON),
  2339. LoadIcon (ghInstance, MAKEINTRESOURCE(IDI_INSTRUMENT)));
  2340. LoadInstrumentsIntoTree (hWnd, IDL_INSTRUMENTS, 0, NULL, pmcl);
  2341. EnableWindow (GetDlgItem (hWnd, IDB_ADDWIZ), pmcl->mcm.bHasExternal & AccessServiceController());
  2342. break;
  2343. }
  2344. case WM_DESTROY:
  2345. {
  2346. PMCLOCAL pmcl = GetDlgData(hWnd);
  2347. if (pmcl)
  2348. {
  2349. if (pmcl->mcm.hkMidi)
  2350. RegCloseKey (pmcl->mcm.hkMidi);
  2351. if (pmcl->ms.hkSchemes)
  2352. RegCloseKey (pmcl->ms.hkSchemes);
  2353. FreeInstruments (&pmcl->mcm);
  2354. LocalFree ((HLOCAL)(UINT_PTR)(DWORD_PTR)pmcl);
  2355. }
  2356. break;
  2357. }
  2358. case WM_CONTEXTMENU:
  2359. WinHelp ((HWND) wParam, NULL, HELP_CONTEXTMENU,
  2360. (UINT_PTR) (LPTSTR) aMidiClassHelpIds);
  2361. return TRUE;
  2362. case WM_HELP:
  2363. {
  2364. LPHELPINFO lphi = (LPVOID) lParam;
  2365. WinHelp (lphi->hItemHandle, NULL, HELP_WM_HELP,
  2366. (UINT_PTR) (LPTSTR) aMidiClassHelpIds);
  2367. return TRUE;
  2368. }
  2369. }
  2370. return FALSE;
  2371. }
  2372. /*+ PropPageCallback
  2373. *
  2374. * add a property page
  2375. *
  2376. *-=================================================================*/
  2377. UINT CALLBACK PropPageCallback (
  2378. HWND hwnd,
  2379. UINT uMsg,
  2380. LPPROPSHEETPAGE ppsp)
  2381. {
  2382. if (uMsg == PSPCB_RELEASE) {
  2383. //LocalFree ((HLOCAL)(UINT)(DWORD)ppsp->pszTitle);
  2384. LocalFree ((HLOCAL)ppsp->lParam);
  2385. }
  2386. return 1;
  2387. }
  2388. /*+ AddPropPage
  2389. *
  2390. * add a property page
  2391. *
  2392. *-=================================================================*/
  2393. STATICFN HPROPSHEETPAGE WINAPI AddPropPage (
  2394. LPCTSTR pszTitle,
  2395. LPFNMMEXTPROPSHEETCALLBACK lpfnAddPropSheetPage,
  2396. DLGPROC fnDlgProc,
  2397. UINT idTemplate,
  2398. LPARAM lParam)
  2399. {
  2400. PROPSHEETPAGE psp;
  2401. PMPSARGS pmpsa;
  2402. UINT cbSize;
  2403. cbSize = sizeof(MPSARGS) + lstrlen (pszTitle) * sizeof(TCHAR);
  2404. if (pmpsa = (PVOID) LocalAlloc (LPTR, cbSize))
  2405. {
  2406. HPROPSHEETPAGE hpsp;
  2407. lstrcpy (pmpsa->szTitle, pszTitle);
  2408. pmpsa->lpfnMMExtPSCallback = lpfnAddPropSheetPage;
  2409. pmpsa->lParam = lParam;
  2410. psp.dwSize = sizeof(psp);
  2411. psp.dwFlags = PSP_USETITLE | PSP_USECALLBACK;
  2412. psp.hInstance = ghInstance;
  2413. psp.pszTemplate = MAKEINTRESOURCE(idTemplate);
  2414. psp.pszIcon = NULL;
  2415. psp.pszTitle = pmpsa->szTitle;
  2416. psp.pfnDlgProc = fnDlgProc;
  2417. psp.lParam = (LPARAM)pmpsa;
  2418. psp.pfnCallback = PropPageCallback;
  2419. psp.pcRefParent = NULL;
  2420. if (hpsp = CreatePropertySheetPage (&psp))
  2421. {
  2422. if ( ! lpfnAddPropSheetPage ||
  2423. lpfnAddPropSheetPage (MM_EPS_ADDSHEET, (DWORD_PTR)hpsp, 0, lParam))
  2424. {
  2425. return hpsp;
  2426. }
  2427. DestroyPropertySheetPage (hpsp);
  2428. LocalFree ((HLOCAL) pmpsa);
  2429. }
  2430. }
  2431. return NULL;
  2432. }
  2433. /*+ AddInstrumentPages
  2434. *
  2435. * add a midi page to a property sheet. Invoked from Advanced tab
  2436. * of Muitimedia control panel when class midi is selected from
  2437. * the list.
  2438. *
  2439. *-=================================================================*/
  2440. BOOL CALLBACK AddInstrumentPages (
  2441. LPCTSTR pszTitle,
  2442. LPFNMMEXTPROPSHEETCALLBACK lpfnAddPropSheetPage,
  2443. LPARAM lParam)
  2444. {
  2445. HPROPSHEETPAGE hpsp;
  2446. TCHAR sz[MAX_ALIAS];
  2447. #ifdef DEBUG
  2448. AuxDebugEx (3, DEBUGLINE TEXT ("AddInstrumentPages(%08X,%08X,%08X)\r\n"),
  2449. pszTitle, lpfnAddPropSheetPage, lParam);
  2450. #endif
  2451. LoadString (ghInstance, IDS_GENERAL, sz, NUMELMS(sz));
  2452. hpsp = AddPropPage (sz,
  2453. lpfnAddPropSheetPage,
  2454. MidiInstrumentDlgProc,
  2455. IDD_INSTRUMENT_GEN,
  2456. lParam);
  2457. if ( ! hpsp)
  2458. return FALSE;
  2459. LoadString (ghInstance, IDS_MIDIDETAILS, sz, NUMELMS(sz));
  2460. hpsp = AddPropPage (sz,
  2461. lpfnAddPropSheetPage,
  2462. MidiInstrumentDlgProc,
  2463. IDD_INSTRUMENT_DETAIL,
  2464. lParam);
  2465. return (hpsp != NULL);
  2466. }
  2467. /*+ AddDevicePages
  2468. *
  2469. * add a midi page to a property sheet. Invoked from Advanced tab
  2470. * of Multimedia control panel when class midi is selected from
  2471. * the list.
  2472. *
  2473. *-=================================================================*/
  2474. BOOL CALLBACK AddDevicePages (
  2475. LPCTSTR pszTitle,
  2476. LPFNMMEXTPROPSHEETCALLBACK lpfnAddPropSheetPage,
  2477. LPARAM lParam)
  2478. {
  2479. HPROPSHEETPAGE hpsp;
  2480. TCHAR sz[MAX_ALIAS];
  2481. #ifdef DEBUG
  2482. AuxDebugEx (3, DEBUGLINE TEXT ("AddInstrumentPages(%08X,%08X,%08X)\r\n"),
  2483. pszTitle, lpfnAddPropSheetPage, lParam);
  2484. #endif
  2485. LoadString (ghInstance, IDS_MIDIDETAILS, sz, NUMELMS(sz));
  2486. hpsp = AddPropPage (sz,
  2487. lpfnAddPropSheetPage,
  2488. MidiInstrumentDlgProc,
  2489. IDD_DEVICE_DETAIL,
  2490. lParam);
  2491. return (hpsp != NULL);
  2492. }
  2493. /*+ ShowDetails
  2494. *
  2495. * Show Instrument or device details sheet and allow edits
  2496. * return TRUE if changes were made
  2497. *
  2498. *-=================================================================*/
  2499. struct _show_details_args {
  2500. PMCLOCAL pmcl;
  2501. BOOL bChanged;
  2502. PROPSHEETHEADER psh;
  2503. HPROPSHEETPAGE hpsp[2];
  2504. };
  2505. BOOL CALLBACK fnPropCallback (
  2506. DWORD dwFunc,
  2507. DWORD_PTR dwParam1,
  2508. DWORD_PTR dwParam2,
  2509. DWORD_PTR dwInstance)
  2510. {
  2511. struct _show_details_args * psda = (LPVOID)dwInstance;
  2512. assert (psda);
  2513. if (!psda)
  2514. return FALSE;
  2515. switch (dwFunc)
  2516. {
  2517. case MM_EPS_GETNODEDESC:
  2518. *(LPTSTR)dwParam1 = 0;
  2519. if (psda->pmcl->piSingle)
  2520. lstrcpyn ((LPTSTR)dwParam1, psda->pmcl->piSingle->szFriendly, (int)(dwParam2/sizeof(TCHAR)));
  2521. break;
  2522. case MM_EPS_GETNODEID:
  2523. *(LPTSTR)dwParam1 = 0;
  2524. if (psda->pmcl->piSingle)
  2525. {
  2526. lstrcpy ((LPTSTR)dwParam1, cszMidiSlash);
  2527. lstrcat ((LPTSTR)dwParam1, psda->pmcl->piSingle->szKey);
  2528. }
  2529. break;
  2530. case MM_EPS_ADDSHEET:
  2531. if (psda->psh.nPages >= NUMELMS(psda->hpsp)-1)
  2532. return FALSE;
  2533. psda->psh.phpage[psda->psh.nPages++] = (HPROPSHEETPAGE)dwParam1;
  2534. break;
  2535. case MM_EPS_TREECHANGE:
  2536. psda->bChanged = TRUE;
  2537. break;
  2538. default:
  2539. return FALSE;
  2540. }
  2541. return TRUE;
  2542. }
  2543. BOOL WINAPI ShowDetails (
  2544. HWND hWnd,
  2545. PMCLOCAL pmcl)
  2546. {
  2547. struct _show_details_args sda;
  2548. TCHAR szTitle[MAX_ALIAS];
  2549. HPROPSHEETPAGE hpsp;
  2550. UINT idDlg;
  2551. idDlg = IDD_DEVICE_DETAIL;
  2552. if (pmcl->piSingle && pmcl->piSingle->piParent)
  2553. idDlg = IDD_INSTRUMENT_DETAIL;
  2554. ZeroMemory (&sda, sizeof(sda));
  2555. sda.pmcl = pmcl;
  2556. sda.psh.dwSize = sizeof(sda.psh);
  2557. sda.psh.dwFlags = PSH_PROPTITLE;
  2558. sda.psh.hwndParent = hWnd;
  2559. sda.psh.hInstance = ghInstance;
  2560. sda.psh.pszCaption = MAKEINTRESOURCE (IDS_MMPROP);
  2561. sda.psh.nPages = 0;
  2562. sda.psh.nStartPage = 0;
  2563. sda.psh.phpage = sda.hpsp;
  2564. LoadString (ghInstance, IDS_MIDIDETAILS, szTitle, NUMELMS(szTitle));
  2565. hpsp = AddPropPage (szTitle,
  2566. fnPropCallback,
  2567. MidiInstrumentDlgProc,
  2568. idDlg,
  2569. (LPARAM)&sda);
  2570. if (hpsp)
  2571. sda.psh.nPages = 1;
  2572. PropertySheet (&sda.psh);
  2573. return sda.bChanged;
  2574. }
  2575. /*+ AddMidiPages
  2576. *
  2577. * add a midi page to a property sheet. Invoked from Advanced tab
  2578. * of Muitimedia control panel when class midi is selected from
  2579. * the list.
  2580. *
  2581. *-=================================================================*/
  2582. BOOL CALLBACK AddMidiPages (
  2583. LPCTSTR pszTitle,
  2584. LPFNMMEXTPROPSHEETCALLBACK lpfnAddPropSheetPage,
  2585. LPARAM lParam)
  2586. {
  2587. HPROPSHEETPAGE hpsp;
  2588. TCHAR sz[MAX_ALIAS];
  2589. LoadString (ghInstance, IDS_GENERAL, sz, NUMELMS(sz));
  2590. hpsp = AddPropPage (sz,
  2591. lpfnAddPropSheetPage,
  2592. MidiClassDlgProc,
  2593. IDD_MIDICLASS_GEN,
  2594. lParam);
  2595. return (hpsp != NULL);
  2596. }
  2597. /*+ AddSimpleMidiPages
  2598. *
  2599. * add a midi page to a MM control panel.
  2600. *
  2601. *-=================================================================*/
  2602. BOOL CALLBACK AddSimpleMidiPages (
  2603. LPTSTR pszTitle,
  2604. LPFNMMEXTPROPSHEETCALLBACK lpfnAddPropSheetPage,
  2605. LPARAM lParam)
  2606. {
  2607. HPROPSHEETPAGE hpsp;
  2608. //static CONST TCHAR sz[13] = TEXT (" ");
  2609. //UINT cch = lstrlen (pszTitle);
  2610. DebugSetOutputLevel (GetProfileInt(TEXT ("Debug"), TEXT ("midiprop"), 0));
  2611. // pad my tab to 12 spaces so it looks nice with the
  2612. // other simple tabls (as per request of vijr)
  2613. //
  2614. //if (cch < NUMELMS(sz)-2)
  2615. //{
  2616. // lstrcpy (sz + NUMELMS(sz)/2 - cch/2, pszTitle);
  2617. // pszTitle = sz;
  2618. // pszTitle[lstrlen(pszTitle)] = TEXT (' ');
  2619. //}
  2620. hpsp = AddPropPage (pszTitle,
  2621. lpfnAddPropSheetPage,
  2622. MidiCplDlgProc,
  2623. IDD_CPL_MIDI2,
  2624. lParam);
  2625. return (hpsp != NULL);
  2626. }
  2627. /*
  2628. ***************************************************************
  2629. * BOOL PASCAL LoadDesc(LPCTSTR pszFile, LPCTSTR pszDesc)
  2630. * This function gets the description string from the executable
  2631. * file specified. We first try to get the string from the version info
  2632. * If that fails then we try to get the string from the exehdr.
  2633. * If that fails we return a NULL string.
  2634. * Return TRUE on success, else FALSE.
  2635. ***************************************************************
  2636. */
  2637. BOOL PASCAL LoadDesc(LPCTSTR pszFile, LPTSTR pszDesc)
  2638. {
  2639. LPTSTR psz;
  2640. static TCHAR szProfile[MAXSTR];
  2641. UINT cchSize;
  2642. HANDLE hFind;
  2643. WIN32_FIND_DATA wfd;
  2644. DPF (TEXT ("LoadDesc: %s\r\n"), pszFile);
  2645. // Make sure file exists
  2646. hFind = FindFirstFile (pszFile, &wfd);
  2647. if (hFind == INVALID_HANDLE_VALUE)
  2648. return(FALSE);
  2649. FindClose (hFind);
  2650. // Get User Friendly name from Version Info
  2651. if (GetVerDesc (wfd.cFileName, pszDesc))
  2652. return TRUE;
  2653. //
  2654. // As a last resort, look at the description in the Executable Header
  2655. //
  2656. cchSize = sizeof(szProfile)/sizeof(TCHAR);
  2657. if ((! GetExeDesc (wfd.cFileName, szProfile, cchSize)) ||
  2658. (lstrlen (szProfile) < 3))
  2659. {
  2660. *pszDesc = 0;
  2661. return(FALSE);
  2662. }
  2663. else
  2664. {
  2665. // There is EXEHDR information Parse according to driver spec
  2666. psz = szProfile;
  2667. while (*psz && *psz++ != TEXT (':'))
  2668. {
  2669. ; // skip type information
  2670. }
  2671. if (!(*psz))
  2672. psz = szProfile;
  2673. lstrcpy (pszDesc, psz);
  2674. return(TRUE);
  2675. }
  2676. }
  2677. /* BOOL FAR PASCAL GetExeDesc(szFile, szBuff, cchBuff)
  2678. *
  2679. * Function will return the an executable's description
  2680. *
  2681. * szFile - Path Name a new exe
  2682. * pszBuf - Buffer to place returned info
  2683. * cchBuf - Size of buffer (in characters
  2684. *
  2685. * returns: TRUE if successful, FALSE otherwise.
  2686. */
  2687. STATIC BOOL FAR PASCAL GetExeDesc(
  2688. LPTSTR szFile,
  2689. LPTSTR pszBuff,
  2690. int cchBuff)
  2691. {
  2692. DWORD dwSig;
  2693. WORD wSig;
  2694. HANDLE hFile;
  2695. DWORD offset;
  2696. BYTE cbLen;
  2697. DWORD cbRead;
  2698. IMAGE_DOS_HEADER doshdr; // Original EXE Header
  2699. // Open File
  2700. hFile = CreateFile (szFile, GENERIC_READ, FILE_SHARE_READ, NULL,
  2701. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  2702. if (hFile == INVALID_HANDLE_VALUE)
  2703. return FALSE;
  2704. // Get Original Dos Header
  2705. if ((! ReadFile (hFile, (LPVOID)&doshdr, sizeof(doshdr), &cbRead, NULL)) ||
  2706. (cbRead != sizeof(doshdr)) || // Read Error
  2707. (doshdr.e_magic != IMAGE_DOS_SIGNATURE)) // Invalid DOS Header
  2708. {
  2709. goto error; /* Abort("Not an exe",h); */
  2710. }
  2711. // Seek to new header
  2712. offset = doshdr.e_lfanew;
  2713. SetFilePointer (hFile, offset, NULL, FILE_BEGIN);
  2714. // Read in signature
  2715. if ((! ReadFile (hFile, (LPVOID)&dwSig, sizeof(dwSig), &cbRead, NULL)) ||
  2716. (cbRead != sizeof(dwSig))) // Read Error
  2717. {
  2718. goto error; /* Abort("Not an exe",h); */
  2719. }
  2720. wSig = LOWORD (dwSig);
  2721. if (dwSig == IMAGE_NT_SIGNATURE)
  2722. {
  2723. DPF (TEXT ("GetExeDesc: NT Portable Executable Format\r\n"));
  2724. // NOTE - The NT Portatble Executable Format does not store
  2725. // the executable's user friendly name.
  2726. goto error;
  2727. }
  2728. else if (wSig == IMAGE_OS2_SIGNATURE)
  2729. {
  2730. IMAGE_OS2_HEADER winhdr; // New Windows/OS2 header
  2731. TCHAR szInfo[256];
  2732. DPF (TEXT ("GetExeDesc: Windows or OS2 Executable Format\r\n"));
  2733. // Seek to Windows Header
  2734. offset = doshdr.e_lfanew;
  2735. SetFilePointer (hFile, offset, NULL, FILE_BEGIN);
  2736. // Read Windows Header
  2737. if ((! ReadFile (hFile, (LPVOID)&winhdr, sizeof(winhdr),
  2738. &cbRead, NULL)) ||
  2739. (cbRead != sizeof(winhdr)) || // Read Error
  2740. (winhdr.ne_magic != IMAGE_OS2_SIGNATURE)) // Invalid Windows Header
  2741. {
  2742. goto error;
  2743. }
  2744. // Seek to module name which is the first entry in the non-resident name table
  2745. offset = winhdr.ne_nrestab;
  2746. SetFilePointer (hFile, offset, NULL, FILE_BEGIN);
  2747. // Get Size of Module Name
  2748. if ((! ReadFile (hFile, (LPVOID)&cbLen, sizeof(BYTE),
  2749. &cbRead, NULL)) ||
  2750. (cbRead != sizeof(BYTE)))
  2751. {
  2752. goto error;
  2753. }
  2754. cchBuff--; // leave room for a \0
  2755. if (cbLen > (BYTE)cchBuff)
  2756. cbLen = (BYTE)cchBuff;
  2757. // Read Module Name
  2758. if ((! ReadFile (hFile, (LPVOID)szInfo, cbLen,
  2759. &cbRead, NULL)) ||
  2760. (cbRead != cbLen))
  2761. {
  2762. goto error;
  2763. }
  2764. szInfo[cbLen] = 0;
  2765. // Copy to Buffer
  2766. lstrcpy (pszBuff, szInfo);
  2767. }
  2768. else if (wSig == IMAGE_VXD_SIGNATURE)
  2769. {
  2770. IMAGE_VXD_HEADER vxdhdr; // New Windows/OS2 VXD Header
  2771. TCHAR szInfo[256];
  2772. DPF (TEXT ("GetExeDesc: Windows or OS2 VXD Executable Format\r\n"));
  2773. // Seek to VXD Header
  2774. offset = doshdr.e_lfanew;
  2775. SetFilePointer (hFile, offset, NULL, FILE_BEGIN);
  2776. // Read VXD Header
  2777. if ((! ReadFile (hFile, (LPVOID)&vxdhdr, sizeof(vxdhdr),
  2778. &cbRead, NULL)) ||
  2779. (cbRead != sizeof(vxdhdr)) || // Read Error
  2780. (vxdhdr.e32_magic != IMAGE_VXD_SIGNATURE)) // Invalid VXD Header
  2781. {
  2782. goto error;
  2783. }
  2784. // Seek to module name which is the first entry in the non-resident name table
  2785. offset = vxdhdr.e32_nrestab;
  2786. SetFilePointer (hFile, offset, NULL, FILE_BEGIN);
  2787. // Get Size of Module Name
  2788. if ((! ReadFile (hFile, (LPVOID)&cbLen, sizeof(BYTE),
  2789. &cbRead, NULL)) ||
  2790. (cbRead != sizeof(BYTE)))
  2791. {
  2792. goto error;
  2793. }
  2794. cchBuff--; // leave room for a \0
  2795. if (cbLen > (BYTE)cchBuff)
  2796. cbLen = (BYTE)cchBuff;
  2797. // Read Module Name
  2798. if ((! ReadFile (hFile, (LPVOID)szInfo, cbLen,
  2799. &cbRead, NULL)) ||
  2800. (cbRead != cbLen))
  2801. {
  2802. goto error;
  2803. }
  2804. szInfo[cbLen] = 0;
  2805. // Copy to Buffer
  2806. lstrcpy (pszBuff, szInfo);
  2807. }
  2808. else
  2809. {
  2810. DPF (TEXT ("GetExeDesc: Unknown Executable\r\n"));
  2811. goto error; /* Abort("Not an exe",h); */
  2812. }
  2813. CloseHandle (hFile);
  2814. return TRUE;
  2815. error:
  2816. CloseHandle (hFile);
  2817. return FALSE;
  2818. }
  2819. /*
  2820. ***************************************************************
  2821. * STATIC INT_PTR GetVerDesc
  2822. * Loads the version DLL and uses it to get Version Description string
  2823. * from the specified file.
  2824. ***************************************************************
  2825. */
  2826. STATIC INT_PTR PASCAL GetVerDesc (LPCTSTR pstrFile, LPTSTR pstrDesc)
  2827. {
  2828. DWORD_PTR dwVerInfoSize;
  2829. DWORD dwVerHnd;
  2830. INT_PTR bRetCode;
  2831. bRetCode = FALSE;
  2832. DPF( TEXT ("Getting VERSION string for %s \r\n"), pstrFile);
  2833. dwVerInfoSize = GetFileVersionInfoSize (pstrFile, &dwVerHnd);
  2834. if (dwVerInfoSize)
  2835. {
  2836. LPBYTE lpVffInfo; // Pointer to block to hold info
  2837. // Get a block big enough to hold version info
  2838. if (lpVffInfo = (LPBYTE) GlobalAllocPtr(GMEM_MOVEABLE, dwVerInfoSize))
  2839. {
  2840. // Get the File Version first
  2841. if (GetFileVersionInfo (pstrFile, 0L,
  2842. dwVerInfoSize, lpVffInfo))
  2843. {
  2844. static SZCODE cszFileDescr[] = TEXT ("\\StringFileInfo\\040904E4\\FileDescription");
  2845. TCHAR szBuf[MAX_PATH];
  2846. LPTSTR lpVersion;
  2847. WORD wVersionLen;
  2848. // Now try to get the FileDescription
  2849. // First try this for the "Translation" entry, and then
  2850. // try the American english translation.
  2851. // Keep track of the string length for easy updating.
  2852. // 040904E4 represents the language ID and the four
  2853. // least significant digits represent the codepage for
  2854. // which the data is formatted. The language ID is
  2855. // composed of two parts: the low ten bits represent
  2856. // the major language and the high six bits represent
  2857. // the sub language.
  2858. lstrcpy(szBuf, cszFileDescr);
  2859. wVersionLen = 0;
  2860. lpVersion = NULL;
  2861. // Look for the corresponding string.
  2862. bRetCode = VerQueryValue((LPVOID)lpVffInfo,
  2863. (LPTSTR)szBuf,
  2864. (void FAR* FAR*)&lpVersion,
  2865. (UINT FAR *) &wVersionLen);
  2866. if (bRetCode && wVersionLen > 2 && lpVersion)
  2867. {
  2868. lstrcpy (pstrDesc, lpVersion);
  2869. }
  2870. else
  2871. bRetCode = FALSE;
  2872. // Let go of the memory
  2873. GlobalFreePtr(lpVffInfo);
  2874. }
  2875. }
  2876. } else
  2877. bRetCode = FALSE;
  2878. return bRetCode;
  2879. }
  2880. LONG SHRegDeleteKey(HKEY hKey, LPCTSTR lpSubKey)
  2881. {
  2882. LONG lResult;
  2883. HKEY hkSubKey;
  2884. DWORD dwIndex;
  2885. TCHAR szSubKeyName[MAX_PATH + 1];
  2886. DWORD cchSubKeyName = ARRAYSIZE(szSubKeyName);
  2887. TCHAR szClass[MAX_PATH];
  2888. DWORD cchClass = ARRAYSIZE(szClass);
  2889. DWORD dwDummy1, dwDummy2, dwDummy3, dwDummy4, dwDummy5, dwDummy6;
  2890. FILETIME ft;
  2891. // Open the subkey so we can enumerate any children
  2892. lResult = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_ALL_ACCESS, &hkSubKey);
  2893. if (ERROR_SUCCESS == lResult)
  2894. {
  2895. // I can't just call RegEnumKey with an ever-increasing index, because
  2896. // I'm deleting the subkeys as I go, which alters the indices of the
  2897. // remaining subkeys in an implementation-dependent way. In order to
  2898. // be safe, I have to count backwards while deleting the subkeys.
  2899. // Find out how many subkeys there are
  2900. lResult = RegQueryInfoKey(hkSubKey,
  2901. szClass,
  2902. &cchClass,
  2903. NULL,
  2904. &dwIndex, // The # of subkeys -- all we need
  2905. &dwDummy1,
  2906. &dwDummy2,
  2907. &dwDummy3,
  2908. &dwDummy4,
  2909. &dwDummy5,
  2910. &dwDummy6,
  2911. &ft);
  2912. if (ERROR_SUCCESS == lResult)
  2913. {
  2914. // dwIndex is now the count of subkeys, but it needs to be
  2915. // zero-based for RegEnumKey, so I'll pre-decrement, rather
  2916. // than post-decrement.
  2917. while (ERROR_SUCCESS == RegEnumKey(hkSubKey, --dwIndex, szSubKeyName, cchSubKeyName))
  2918. {
  2919. SHRegDeleteKey(hkSubKey, szSubKeyName);
  2920. }
  2921. }
  2922. RegCloseKey(hkSubKey);
  2923. lResult = RegDeleteKey(hKey, lpSubKey);
  2924. }
  2925. return lResult;
  2926. } // End SHRegDeleteKey
  2927. /* DeviceIDFromDriverName
  2928. *
  2929. * Query MMSYSTEM to find the given device. Return its base device ID.
  2930. * Return -1 if we cannot find the driver
  2931. */
  2932. static UINT
  2933. DeviceIDFromDriverName(
  2934. PTSTR pstrDriverName)
  2935. {
  2936. UINT idxDev;
  2937. UINT cPorts;
  2938. DWORD cPort;
  2939. PTSTR pstrDriver;
  2940. MMRESULT mmr;
  2941. if (NULL == (pstrDriver = LocalAlloc(LPTR, MAX_ALIAS*sizeof(TCHAR))))
  2942. {
  2943. AuxDebugEx(3, DEBUGLINE TEXT("DN->ID: LocalAlloc() failed.\r\n"));
  2944. return (UINT)-1;
  2945. }
  2946. // Walk through the base device ID of each driver. Use MMSYSTEM's
  2947. // driver query messages to find out how many ports & the driver name
  2948. //
  2949. cPorts = midiOutGetNumDevs();
  2950. for (idxDev = 0; idxDev < cPorts; idxDev++)
  2951. {
  2952. if (MMSYSERR_NOERROR != (mmr = midiOutMessage(HMIDIOUT_INDEX(idxDev),
  2953. DRV_QUERYNUMPORTS,
  2954. (DWORD_PTR)(LPDWORD)&cPort,
  2955. 0)))
  2956. {
  2957. // Something is wrong with this driver. Skip it
  2958. //
  2959. AuxDebugEx(3, DEBUGLINE TEXT("DN->ID: DRV_QUERYNUMPORTS(%u)->%u\r\n"),
  2960. (UINT)idxDev,
  2961. (UINT)mmr);
  2962. continue;
  2963. }
  2964. if (MMSYSERR_NOERROR != (mmr = midiOutMessage(HMIDIOUT_INDEX(idxDev),
  2965. DRV_QUERYDRVENTRY,
  2966. (DWORD_PTR)(LPTSTR)pstrDriver,
  2967. MAX_ALIAS)))
  2968. {
  2969. AuxDebugEx(3, DEBUGLINE TEXT("DN->ID: DRV_QUERYDRVENTRY(%u)->%u\r\n"),
  2970. (UINT)idxDev,
  2971. (UINT)mmr);
  2972. continue;
  2973. }
  2974. if (!_tcscmp(pstrDriver, pstrDriverName))
  2975. break;
  2976. }
  2977. if (idxDev >= cPorts)
  2978. {
  2979. AuxDebugEx(3, DEBUGLINE TEXT("DN->ID: No match for [%s]\r\n"),
  2980. (LPTSTR)pstrDriverName);
  2981. idxDev = (UINT)-1;
  2982. }
  2983. else
  2984. AuxDebugEx(3, DEBUGLINE TEXT("DN->ID: [%s] at %d\r\n"),
  2985. (LPTSTR)pstrDriverName,
  2986. (int)idxDev);
  2987. LocalFree(pstrDriver);
  2988. return (int)idxDev;
  2989. }