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

2318 lines
61 KiB

  1. /*==========================================================================*/
  2. //
  3. // class.c
  4. //
  5. // Copyright (C) 1993-1994 Microsoft Corporation. All Rights Reserved.
  6. // Mod Log: Modified by Shawn Brown (10/95)
  7. // - Ported to NT (Unicode, etc.)
  8. /*==========================================================================*/
  9. #include "mmcpl.h"
  10. #include <windowsx.h>
  11. #include <mmsystem.h>
  12. #include <mmddk.h>
  13. #include <cpl.h>
  14. #define NOSTATUSBAR
  15. #include <commctrl.h>
  16. #include <prsht.h>
  17. #include <string.h>
  18. #include <memory.h>
  19. #include <idf.h>
  20. #include <regstr.h>
  21. #include "utils.h"
  22. #include "midi.h"
  23. #include "mmdebug.h"
  24. #if defined DEBUG || defined DEBUG_RETAIL
  25. extern TCHAR szNestLevel[];
  26. #endif
  27. #include "medhelp.h"
  28. #ifndef TVIS_ALL
  29. #define TVIS_ALL 0xFF7F
  30. #endif
  31. static CONST TCHAR cszIdfWildcard[] = TEXT ("*.idf");
  32. static CONST TCHAR cszIdf[] = TEXT (".idf");
  33. static CONST TCHAR cszSetupKey[] = REGSTR_PATH_SETUP REGSTR_KEY_SETUP;
  34. static CONST TCHAR cszMachineDir[] = REGSTR_VAL_WINDIR;
  35. static CONST TCHAR cszConfigDir[] = TEXT ("config\\");
  36. extern CONST TCHAR cszMidiSlash[];
  37. extern CONST TCHAR cszFriendlyName[];
  38. extern CONST TCHAR cszDescription[];
  39. extern CONST TCHAR cszSlashInstruments[];
  40. extern CONST TCHAR cszExternal[];
  41. extern CONST TCHAR cszDefinition[];
  42. extern CONST TCHAR cszPort[];
  43. extern CONST TCHAR cszDriversRoot[];
  44. extern CONST TCHAR cszSchemeRoot[];
  45. extern CONST TCHAR cszMidiMapRoot[];
  46. extern CONST TCHAR cszDriversRoot[];
  47. extern CONST TCHAR csz02d[];
  48. extern CONST TCHAR cszSlash[];
  49. extern CONST TCHAR cszEmpty[];
  50. extern int lstrnicmp (LPTSTR pszA, LPTSTR pszB, size_t cch);
  51. typedef struct _midi_class {
  52. LPPROPSHEETPAGE ppsp;
  53. HKEY hkMidi;
  54. BOOL bDetails;
  55. BOOL bRemote; // device connected via midi cable
  56. UINT bChanges;
  57. UINT ixDevice; // registry enum index of driver key
  58. BYTE nPort;
  59. BYTE bFill[3];
  60. BOOL bFillingList;
  61. #ifdef USE_IDF_ICONS
  62. HIMAGELIST hIDFImageList;
  63. #endif
  64. LPTSTR pszKey;
  65. TCHAR szFullKey[MAX_PATH];
  66. TCHAR szAlias[MAX_PATH];
  67. TCHAR szFile[MAX_PATH*2];
  68. } MCLASS, FAR * PMCLASS;
  69. #define MCL_ALIAS_CHANGED 1
  70. #define MCL_TREE_CHANGED 2
  71. #define MCL_IDF_CHANGED 4
  72. #define MCL_PORT_CHANGED 8
  73. /*+
  74. * Determines if a given string has a given prefix and if
  75. * the next character in the string is a given charater.
  76. *
  77. * if so, it returns a pointer to the first character in the
  78. * string after the prefix.
  79. *
  80. * this is useful for parsing off the file in file<Instrument>
  81. * or parts of registry paths.
  82. *
  83. * note that we do NOT consider a string to be a prefix of itself.
  84. * psz MUST be longer than than pszPrefix or this function returns NULL.
  85. *
  86. *-=================================================================*/
  87. STATICFN LPTSTR WINAPI IsPrefix (
  88. LPTSTR pszPrefix,
  89. LPTSTR psz,
  90. TCHAR chTerm)
  91. {
  92. UINT cb = lstrlen(pszPrefix);
  93. UINT cb2 = lstrlen(psz);
  94. TCHAR ch;
  95. if (cb2 < cb)
  96. return NULL;
  97. ch = psz[cb];
  98. if (ch != chTerm)
  99. return NULL;
  100. psz[cb] = 0;
  101. if (lstrcmpi(pszPrefix, psz))
  102. {
  103. psz[cb] = ch;
  104. return NULL;
  105. }
  106. psz[cb] = ch;
  107. return psz + cb;
  108. }
  109. /*+ IsFullPath
  110. *
  111. * returns true if the filename passed in is a fully qualified
  112. * pathname. returns false if it is a relative path
  113. *
  114. * unc paths are treated as fully qualified always
  115. *
  116. *-=================================================================*/
  117. BOOL IsFullPath (
  118. LPTSTR pszFile)
  119. {
  120. // fully qualified paths either begin with a backslash
  121. // or with a drive letter, colon, then backslash
  122. //
  123. if ((pszFile[0] == TEXT('\\')) ||
  124. (pszFile[1] == TEXT(':') && pszFile[2] == TEXT('\\')))
  125. return TRUE;
  126. return FALSE;
  127. }
  128. /*+ GetIDFDirectory
  129. *
  130. *-=================================================================*/
  131. BOOL GetIDFDirectory (
  132. LPTSTR pszDir,
  133. UINT cchDir)
  134. {
  135. HKEY hKey;
  136. UINT cbSize;
  137. *pszDir = 0;
  138. #if(_WIN32_WINNT >= 0x0400)
  139. if (!GetSystemDirectory (pszDir, cchDir))
  140. return FALSE;
  141. #else
  142. if (!RegOpenKey (HKEY_LOCAL_MACHINE, cszSetupKey, &hKey))
  143. {
  144. cbSize = cchDir * sizeof(TCHAR);
  145. RegQueryValueEx (hKey,
  146. cszMachineDir,
  147. NULL,
  148. NULL,
  149. (LPBYTE)pszDir,
  150. &cbSize);
  151. RegCloseKey (hKey);
  152. cchDir = cbSize/sizeof(TCHAR);
  153. if (!cchDir--)
  154. return FALSE;
  155. }
  156. else if (!GetWindowsDirectory (pszDir, cchDir))
  157. return FALSE;
  158. #endif
  159. cchDir = lstrlen (pszDir);
  160. if (pszDir[cchDir -1] != TEXT('\\'))
  161. pszDir[cchDir++] = TEXT('\\');
  162. lstrcpy (pszDir + cchDir, cszConfigDir);
  163. #ifdef DEBUG
  164. AuxDebugEx (4, DEBUGLINE TEXT("IDFDir='%s'\r\n"), pszDir);
  165. #endif
  166. return TRUE;
  167. }
  168. /*+ GetIDFFileName
  169. *
  170. *-=================================================================*/
  171. BOOL GetIDFFileName (
  172. HWND hWnd,
  173. LPTSTR lpszFile,
  174. UINT cchFile)
  175. {
  176. OPENFILENAME ofn;
  177. TCHAR szFilter[MAX_PATH];
  178. UINT cch;
  179. assert (hWnd);
  180. // load filter string from resource and convert '#' characters
  181. // into NULLs
  182. //
  183. LoadString (ghInstance, IDS_IDFFILES, szFilter, NUMELMS(szFilter));
  184. cch = lstrlen(szFilter);
  185. assert2 (cch, TEXT ("IDFFILES resource is empty!"));
  186. while (cch--)
  187. {
  188. if (TEXT('#') == szFilter[cch])
  189. szFilter[cch] = 0;
  190. }
  191. ZeroMemory (&ofn, sizeof(ofn));
  192. ofn.lStructSize = sizeof(ofn);
  193. ofn.hwndOwner = hWnd;
  194. ofn.hInstance = ghInstance;
  195. ofn.lpstrFilter = szFilter;
  196. ofn.nFilterIndex = 1;
  197. ofn.lpstrFile = lpszFile;
  198. ofn.nMaxFile = cchFile;
  199. ofn.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
  200. ofn.lpstrDefExt = cszIdf;
  201. return GetOpenFileName (&ofn);
  202. }
  203. /*+ InstallNewIDF
  204. *
  205. *-=================================================================*/
  206. BOOL WINAPI InstallNewIDF (
  207. HWND hWnd)
  208. {
  209. TCHAR szWinPath[MAX_PATH];
  210. TCHAR szNewIDF[MAX_PATH];
  211. UINT cch;
  212. UINT oBasename;
  213. // prompt for an IDF file
  214. //
  215. szNewIDF[0] = 0;
  216. if ( ! GetIDFFileName (hWnd, szNewIDF, NUMELMS(szNewIDF)))
  217. return FALSE;
  218. // set oBasename to pointer to the first character of the
  219. // basename of the new idf file
  220. //
  221. oBasename = lstrlen (szNewIDF);
  222. if (!oBasename)
  223. return FALSE;
  224. while (oBasename && (TEXT('\\') != szNewIDF[oBasename-1]))
  225. --oBasename;
  226. // build the new filename from windows directory and idf basename
  227. //
  228. GetIDFDirectory (szWinPath, NUMELMS(szWinPath));
  229. cch = lstrlen (szWinPath);
  230. if (cch && szWinPath[cch-1] != TEXT('\\'))
  231. szWinPath[cch++] = TEXT('\\');
  232. lstrcpyn (szWinPath + cch, szNewIDF + oBasename, NUMELMS(szWinPath)-cch);
  233. oBasename = cch;
  234. #ifdef DEBUG
  235. AuxDebugEx (5, DEBUGLINE TEXT("install IDF to '%s'\r\n"), szWinPath);
  236. #endif
  237. // now force .idf as the extension for new file
  238. //
  239. for (cch = lstrlen (szWinPath); cch && szWinPath[cch] != TEXT('.'); --cch)
  240. if (TEXT('\\') == szWinPath[cch])
  241. {
  242. cch = lstrlen(szWinPath);
  243. break;
  244. }
  245. lstrcpy (szWinPath + cch, cszIdf);
  246. // quit now if we are trying to copy a file to itself
  247. //
  248. if (IsSzEqual(szWinPath, szNewIDF))
  249. return FALSE;
  250. // copy the file, but fail if destination already exists
  251. //
  252. #ifdef DEBUG
  253. AuxDebugEx (5, DEBUGLINE TEXT("Copying %s to %s\r\n"), szNewIDF, szWinPath);
  254. #endif
  255. if (CopyFile (szNewIDF, szWinPath, TRUE))
  256. return TRUE;
  257. //
  258. // if copy fails, query to overwrite because destination
  259. // already exists.
  260. //
  261. else
  262. {
  263. TCHAR szQuery[255];
  264. TCHAR sz[255];
  265. #ifdef DEBUG
  266. AuxDebugEx (1, DEBUGLINE TEXT ("InstallIDF -CopyFile failed w/ %d\r\n"),
  267. GetLastError());
  268. #endif
  269. LoadString (ghInstance, IDS_QUERY_OVERIDF, sz, NUMELMS(sz));
  270. wsprintf (szQuery, sz, szWinPath + oBasename);
  271. LoadString (ghInstance, IDS_IDF_CAPTION, sz, NUMELMS(sz));
  272. if (MessageBox (hWnd, szQuery, sz, MB_YESNO | MB_ICONQUESTION) == IDYES)
  273. return CopyFile (szNewIDF, szWinPath, FALSE);
  274. }
  275. return FALSE;
  276. }
  277. /*+
  278. *
  279. * FEATURE: Please remove the #ifdef UNICODE sections
  280. * when mmioOpen gets UNICODE enabled !!!
  281. *-=================================================================*/
  282. typedef BOOL (WINAPI * FNIDFENUM)(LPVOID pvArg,
  283. UINT nEnum,
  284. LPIDFHEADER pHdr,
  285. LPIDFINSTINFO pInst);
  286. UINT WINAPI idfEnumInstruments (
  287. LPTSTR lpszFile,
  288. FNIDFENUM fnEnum,
  289. LPVOID lpvArg)
  290. {
  291. MMCKINFO chkIDFX; // Grandparent chunk
  292. MMCKINFO chkMMAP; // Parent chunk
  293. HMMIO hmmio; // Handle to the file.
  294. UINT nInstruments;
  295. #ifdef DEBUG
  296. AuxDebugEx (3, DEBUGLINE TEXT("idfEnumInstruments('%s',%08X,%08X)\r\n"),
  297. lpszFile, fnEnum, lpvArg);
  298. #endif
  299. // Open the file for reading.
  300. hmmio = mmioOpen(lpszFile, NULL, MMIO_READ);
  301. if ( ! hmmio)
  302. {
  303. // What were they thinking?? You can't assert this.
  304. // assert3(0, TEXT("Cant open IDF file %s"), lpszFile ? lpszFile : TEXT("<null>"));
  305. return 0;
  306. }
  307. // the whole IDF instrument stuff is wrapped in an 'IDF ' RIFF chunk
  308. //
  309. chkIDFX.fccType = MAKEFOURCC('I','D','F',' ');
  310. if (mmioDescend(hmmio, &chkIDFX, NULL, MMIO_FINDRIFF))
  311. {
  312. #ifdef DEBUG
  313. AuxDebugEx (0, DEBUGLINE TEXT ("idfEnum: '%s' is not a valid IDF File\r\n"), lpszFile);
  314. #endif
  315. mmioClose(hmmio, 0);
  316. return 0;
  317. }
  318. // Count the number of instruments by counting
  319. // the number of "MMAP"'s in the file.
  320. //
  321. nInstruments = 0;
  322. chkMMAP.fccType = MAKEFOURCC('M','M','A','P');
  323. while ( ! mmioDescend(hmmio, &chkMMAP, &chkIDFX, MMIO_FINDLIST))
  324. {
  325. union {
  326. IDFHEADER idf;
  327. TCHAR sz[MAX_ALIAS + sizeof(IDFHEADER)];
  328. } hdr;
  329. union {
  330. IDFINSTINFO iii;
  331. BYTE ab[MAX_ALIAS * 8 + sizeof(IDFINSTINFO)];
  332. } inst;
  333. MMCKINFO chk;
  334. DWORD cb;
  335. #ifdef DEBUG
  336. AuxDebugEx (15, DEBUGLINE TEXT ("MMAP[%d] id=%08X siz=%08x\r\n"),
  337. nInstruments, chkMMAP.ckid, chkMMAP.cksize);
  338. #endif
  339. // read the hdr chunk
  340. //
  341. chk.ckid = MAKEFOURCC('h','d','r',' ');
  342. if (mmioDescend(hmmio, &chk, &chkMMAP, MMIO_FINDCHUNK))
  343. break;
  344. #ifdef DEBUG
  345. AuxDebugEx (15, DEBUGLINE TEXT(" hdr.id=%08X hdr.siz=%08x\r\n"),
  346. chk.ckid, chk.cksize);
  347. #endif
  348. assert (chk.cksize > 0 && chk.cksize < 0x0080000);
  349. //AuxDebugDump (6, &chk, sizeof(chk));
  350. cb = min(chk.cksize, sizeof(hdr));
  351. if ((DWORD)mmioRead (hmmio, (LPVOID)&hdr, cb) != cb)
  352. break;
  353. //AuxDebugDump (6, &chk, sizeof(chk));
  354. hdr.sz[NUMELMS(hdr.sz)-1] = 0;
  355. mmioAscend (hmmio, &chk, 0);
  356. #ifdef DEBUG
  357. AuxDebugEx (15, DEBUGLINE TEXT("hdr = '%s'\r\n"), hdr.idf.abInstID);
  358. #endif
  359. //AuxDebugDump (6, &chk, sizeof(chk));
  360. // read the inst chunk and locate the product name
  361. // field.
  362. //
  363. chk.ckid = MAKEFOURCC('i','n','s','t');
  364. if (mmioDescend(hmmio, &chk, &chkMMAP, MMIO_FINDCHUNK))
  365. {
  366. #ifdef DEBUG
  367. AuxDebug (TEXT ("mmioDescend failed for 'inst' chunk"));
  368. #endif
  369. }
  370. #ifdef DEBUG
  371. AuxDebugEx (15, DEBUGLINE TEXT(" inst.id=%08X inst.siz=%08x\r\n"),
  372. chk.ckid, chk.cksize);
  373. #endif
  374. assert (chk.cksize > 0 && chk.cksize < 0x0080000);
  375. cb = min(chk.cksize, sizeof(inst));
  376. if ((DWORD)mmioRead (hmmio, (LPVOID)&inst, cb) != cb)
  377. {
  378. #ifdef DEBUG
  379. AuxDebug ( TEXT ("mmioRead failed for 'inst' chunk"));
  380. #endif
  381. }
  382. inst.ab[NUMELMS(inst.ab)-1] = 0;
  383. mmioAscend (hmmio, &chk, 0);
  384. #ifdef DEBUG
  385. AuxDebugEx (15, DEBUGLINE TEXT ("inst.mfg = '%s'\r\n"), inst.iii.abData);
  386. AuxDebugEx (15, TEXT ("\t.prod = '%s'\r\n"), inst.iii.abData
  387. + inst.iii.cbManufactASCII
  388. + inst.iii.cbManufactUNICODE);
  389. #endif
  390. // call the enum callback for this instrument
  391. //
  392. if ( ! fnEnum (lpvArg, nInstruments, &hdr.idf, &inst.iii))
  393. break;
  394. ++nInstruments;
  395. assert (nInstruments < 20);
  396. // ascend and loop back to look for the next instrument
  397. //
  398. if (mmioAscend(hmmio, &chkMMAP, 0))
  399. break;
  400. }
  401. mmioClose(hmmio, 0);
  402. return nInstruments;
  403. }
  404. /*+ LoadTypesIntoTree
  405. *
  406. *-=================================================================*/
  407. struct types_enum_data {
  408. HANDLE hWndT;
  409. TV_INSERTSTRUCT * pti;
  410. LPTSTR pszInstr;
  411. HTREEITEM htiSel;
  412. };
  413. STATICFN BOOL WINAPI fnTypesEnum (
  414. LPVOID lpv,
  415. UINT nEnum,
  416. LPIDFHEADER pHdr,
  417. LPIDFINSTINFO pInst)
  418. {
  419. struct types_enum_data * pted = lpv;
  420. HTREEITEM hti;
  421. assert (pted);
  422. #ifdef DEBUG
  423. AuxDebugEx (7, DEBUGLINE TEXT ("enum[%d] '%s' instr=%x\r\n"),
  424. nEnum, pHdr->abInstID, pted->pszInstr);
  425. #endif
  426. MultiByteToWideChar(GetACP(), 0,
  427. pHdr->abInstID, -1,
  428. pted->pti->item.pszText, sizeof(pted->pti->item.pszText));
  429. hti = TreeView_InsertItem (pted->hWndT, pted->pti);
  430. // this item is the 'selected' one, if it is the first
  431. // item or if it matches the name
  432. //
  433. if ((nEnum == 0) ||
  434. (pted->pszInstr && pted->pszInstr[0] &&
  435. IsPrefix(pted->pti->item.pszText, pted->pszInstr + sizeof(TCHAR), TEXT('>'))))
  436. {
  437. pted->htiSel = hti;
  438. #ifdef DEBUG
  439. AuxDebugEx (7, DEBUGLINE TEXT("\t'%s' hti %08X is select\r\n"),
  440. pted->pszInstr ? pted->pszInstr : TEXT (""), hti);
  441. #endif
  442. }
  443. // return true to continue enumeration
  444. //
  445. return TRUE;
  446. }
  447. STATICFN void SetTypesEdit (
  448. HWND hWnd,
  449. UINT uId,
  450. PMCLASS pmcl)
  451. {
  452. SetDlgItemText (hWnd, uId, pmcl->szFile);
  453. }
  454. STATICFN void LoadTypesIntoTree (
  455. HWND hWnd,
  456. UINT uId,
  457. PMCLASS pmcl)
  458. {
  459. HWND hWndT;
  460. UINT cchBase;
  461. TCHAR szPath[MAX_PATH];
  462. TCHAR szDefaultIDF[MAX_PATH];
  463. int ix;
  464. WIN32_FIND_DATA ffd;
  465. HANDLE hFind;
  466. #ifdef USE_IDF_ICONS
  467. HIMAGELIST hImageList;
  468. #endif
  469. HTREEITEM htiSelect = NULL; // item to select
  470. hWndT = GetDlgItem (hWnd, uId);
  471. if (!hWndT)
  472. return;
  473. #ifdef DEBUG
  474. AuxDebugEx (5, DEBUGLINE TEXT ("LoadTypesIntoTree( ,%x, )\r\n"), uId);
  475. #endif
  476. LoadString (ghInstance, IDS_GENERAL, szDefaultIDF, NUMELMS(szDefaultIDF));
  477. #ifdef USE_IDF_ICONS
  478. // if we have not already loaded an image list for the IDF types
  479. // do so now.
  480. //
  481. if (!(hImageList = pmcl->hIDFImageList))
  482. {
  483. static LPCTSTR aid[] = {
  484. MAKEINTRESOURCE(IDI_IDFICON),
  485. MAKEINTRESOURCE(IDI_BLANK),
  486. };
  487. int cx = GetSystemMetrics(SM_CXSMICON);
  488. int cy = GetSystemMetrics(SM_CYSMICON);
  489. DWORD dwLayout;
  490. UINT uFlags = ILC_MASK | ILC_COLOR32;
  491. if (GetProcessDefaultLayout(&dwLayout) &&
  492. (dwLayout & LAYOUT_RTL))
  493. {
  494. uFlags |= ILC_MIRROR;
  495. }
  496. pmcl->hIDFImageList =
  497. hImageList = ImageList_Create (cx, cy, uFlags, NUMELMS(aid), 2);
  498. if (hImageList)
  499. {
  500. UINT ii;
  501. for (ii = 0; ii < NUMELMS(aid); ++ii)
  502. {
  503. HICON hIcon = LoadImage (ghInstance, aid[ii], IMAGE_ICON,
  504. cx, cy, LR_DEFAULTCOLOR);
  505. if (hIcon)
  506. ImageList_AddIcon (hImageList, hIcon);
  507. }
  508. }
  509. }
  510. #endif
  511. pmcl->bFillingList = TRUE;
  512. //SetWindowRedraw (hWndT, FALSE);
  513. #ifdef DEBUG
  514. AuxDebugEx (6, DEBUGLINE TEXT ("tv_deleteAllItems(%08X)\r\n"), hWndT);
  515. #endif
  516. TreeView_DeleteAllItems(hWndT);
  517. #ifdef DEBUG
  518. AuxDebugEx (6, DEBUGLINE TEXT ("tv_deleteAllItems(%08X) ends\r\n"), hWndT);
  519. #endif
  520. #ifdef USE_IDF_ICONS
  521. TreeView_SetImageList (hWndT, hImageList, TVSIL_NORMAL);
  522. #endif
  523. htiSelect = NULL;
  524. pmcl->bFillingList = FALSE;
  525. GetIDFDirectory (szPath, NUMELMS(szPath));
  526. cchBase = lstrlen (szPath);
  527. if (cchBase && szPath[cchBase-1] != TEXT('\\'))
  528. szPath[cchBase++] = TEXT('\\');
  529. lstrcpyn (szPath + cchBase, cszIdfWildcard, NUMELMS(szPath)-cchBase);
  530. #ifdef DEBUG
  531. AuxDebugEx (3, DEBUGLINE TEXT ("scanning for idfs at '%s'\r\n"), szPath);
  532. #endif
  533. ix = 0;
  534. hFind = FindFirstFile (szPath, &ffd);
  535. if (hFind != INVALID_HANDLE_VALUE)
  536. {
  537. TV_INSERTSTRUCT ti;
  538. struct types_enum_data ted = {hWndT, &ti, NULL, NULL};
  539. ZeroMemory (&ti, sizeof(ti));
  540. do
  541. {
  542. UINT nInstr;
  543. UINT cch;
  544. // patch off the extension before we add
  545. // this name to the list
  546. //
  547. cch = lstrlen(ffd.cFileName);
  548. while (cch)
  549. if (ffd.cFileName[--cch] == TEXT('.'))
  550. {
  551. ffd.cFileName[cch] = 0;
  552. break;
  553. }
  554. ti.hParent = TVI_ROOT;
  555. ti.hInsertAfter = TVI_SORT;
  556. #ifdef USE_IDF_ICONS
  557. ti.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  558. #else
  559. ti.item.mask = TVIF_TEXT | TVIF_STATE;
  560. #endif
  561. // the TV_ITEM structure may not be unicode enabled ?!?
  562. ti.item.pszText = ffd.cFileName;
  563. ti.item.state = 0;
  564. ti.item.stateMask = TVIS_ALL;
  565. #ifdef DEBUG
  566. AuxDebugEx (7, DEBUGLINE TEXT ("adding '%s' to types tree\r\n"), ti.item.pszText);
  567. #endif
  568. ti.hParent = TreeView_InsertItem (hWndT, &ti);
  569. if ( ! ti.hParent)
  570. break;
  571. ti.hInsertAfter = TVI_LAST;
  572. // put the extension back
  573. //
  574. if (cch > 0)
  575. ffd.cFileName[cch] = TEXT('.');
  576. // check to see if this file is a match for the
  577. // current definition file.
  578. //
  579. #ifdef DEBUG
  580. AuxDebugEx (7, DEBUGLINE TEXT ("comparing '%s' with '%s'\r\n"),
  581. ffd.cFileName, pmcl->szFile);
  582. #endif
  583. ted.pszInstr = IsPrefix (ffd.cFileName, pmcl->szFile, TEXT('<'));
  584. #ifdef DEBUG
  585. AuxDebugEx (7, DEBUGLINE TEXT ("\tpszInstr = '%s'\r\n"), ted.pszInstr ? ted.pszInstr : TEXT ("NULL"));
  586. #endif
  587. // add instruments as subkeys to this file
  588. // this also has the side effect of setting ted.htiSel
  589. // when the instrument name matches
  590. //
  591. lstrcpy (szPath + cchBase, ffd.cFileName);
  592. nInstr = idfEnumInstruments (szPath, fnTypesEnum, &ted);
  593. // if this idf has no instruments. ignore it.
  594. // if it has more than one instrument, expand the list
  595. // so that instruments are visible
  596. //
  597. if (0 == nInstr)
  598. TreeView_DeleteItem (hWndT, ti.hParent);
  599. else if (nInstr > 1)
  600. TreeView_Expand (hWndT, ti.hParent, TVE_EXPAND);
  601. else
  602. ted.htiSel = ti.hParent;
  603. // if we have a match on filename, then we need to select
  604. // either the parent or one of the children
  605. //
  606. if (ted.pszInstr ||
  607. IsSzEqual(ffd.cFileName,pmcl->szFile) ||
  608. IsSzEqual(ffd.cFileName,szDefaultIDF))
  609. {
  610. #ifdef DEBUG
  611. AuxDebugEx (7, DEBUGLINE TEXT ("will be selecting %08X '%s'\r\n"),
  612. ted.htiSel, ffd.cFileName);
  613. #endif
  614. htiSelect = ted.htiSel;
  615. }
  616. } while (FindNextFile (hFind, &ffd));
  617. FindClose (hFind);
  618. }
  619. if (htiSelect)
  620. {
  621. pmcl->bFillingList = TRUE;
  622. #ifdef DEBUG
  623. AuxDebugEx (7, DEBUGLINE TEXT ("selecting %08X\r\n"), htiSelect);
  624. #endif
  625. TreeView_SelectItem (hWndT, htiSelect);
  626. #ifdef DEBUG
  627. AuxDebugEx (7, DEBUGLINE TEXT ("FirstVisible %08X\r\n"), htiSelect);
  628. #endif
  629. TreeView_SelectSetFirstVisible (hWndT, htiSelect);
  630. pmcl->bFillingList = FALSE;
  631. }
  632. #ifdef DEBUG
  633. AuxDebugEx (5, DEBUGLINE TEXT ("LoadTypesIntoTree( ,%d, ) ends\r\n"), uId);
  634. #endif
  635. //SetWindowRedraw (hWndT, TRUE);
  636. }
  637. /*+
  638. *
  639. *-=================================================================*/
  640. STATICFN void WINAPI HandleTypesSelChange (
  641. PMCLASS pmcl,
  642. LPNMHDR lpnm)
  643. {
  644. LPNM_TREEVIEW pntv = (LPVOID)lpnm;
  645. LPTV_ITEM pti = &pntv->itemNew;
  646. HTREEITEM htiParent;
  647. TV_ITEM ti;
  648. assert (pmcl->bDetails);
  649. // setup ti to get text & # of children
  650. // from the IDF filename entry.
  651. //
  652. ti.mask = TVIF_TEXT;
  653. ti.pszText = pmcl->szFile;
  654. ti.cchTextMax = NUMELMS(pmcl->szFile);
  655. ti.hItem = pti->hItem;
  656. #ifdef DEBUG
  657. AuxDebugEx (6, DEBUGLINE TEXT ("Type Change pti=%08X hItem=%08X\r\n"), pti, pti->hItem);
  658. #endif
  659. // if this entry has a parent, it must be a IDF
  660. // instrument name. if so, then we want to read
  661. // from its parent first.
  662. //
  663. htiParent = TreeView_GetParent (lpnm->hwndFrom, pti->hItem);
  664. if (htiParent)
  665. ti.hItem = htiParent;
  666. TreeView_GetItem (lpnm->hwndFrom, &ti);
  667. lstrcat (pmcl->szFile, cszIdf);
  668. #ifdef DEBUG
  669. AuxDebugEx (6, DEBUGLINE TEXT ("mask=%08x htiParent=%08X %08x nChild=%d '%s'\r\n"),
  670. ti.mask, htiParent, ti.hItem, ti.cChildren, ti.pszText);
  671. #endif
  672. // if the selection had a parent, and we are not it's first child
  673. // then we need to append child (delimited by <>) after parent
  674. //
  675. if (htiParent &&
  676. (TreeView_GetChild(lpnm->hwndFrom, htiParent) != pti->hItem))
  677. {
  678. static CONST TCHAR cszAngle[] = TEXT(">");
  679. UINT cch = lstrlen(pmcl->szFile);
  680. pmcl->szFile[cch++] = TEXT('<');
  681. ti.mask = TVIF_TEXT;
  682. ti.pszText = pmcl->szFile + cch;
  683. ti.cchTextMax = NUMELMS(pmcl->szFile) - cch;
  684. ti.hItem = pti->hItem;
  685. TreeView_GetItem (lpnm->hwndFrom, &ti);
  686. lstrcat (pmcl->szFile, cszAngle);
  687. #ifdef DEBUG
  688. AuxDebugEx (6, DEBUGLINE TEXT ("appending child %08X; '%s'\r\n"), pti->hItem, pmcl->szFile);
  689. #endif
  690. }
  691. pmcl->bChanges |= MCL_IDF_CHANGED;
  692. }
  693. /*+
  694. *
  695. *-=================================================================*/
  696. STATICFN void LoadDevicesIntoList (
  697. HWND hWnd,
  698. UINT uId,
  699. PMCLASS pmcl,
  700. BOOL bList)
  701. {
  702. HWND hWndT;
  703. TCHAR sz[MAX_ALIAS];
  704. DWORD cch = sizeof(sz) / sizeof(TCHAR);
  705. UINT ii;
  706. BOOL bAdded = FALSE;
  707. hWndT = GetDlgItem (hWnd, uId);
  708. if (!hWndT)
  709. return;
  710. SetWindowRedraw (hWndT, FALSE);
  711. if (bList)
  712. ListBox_ResetContent(hWndT);
  713. else
  714. ComboBox_ResetContent(hWndT);
  715. if (!pmcl->hkMidi &&
  716. RegCreateKey (HKEY_LOCAL_MACHINE, cszDriversRoot, &pmcl->hkMidi))
  717. return;
  718. for (cch = sizeof(sz)/sizeof(TCHAR), ii = 0; ! RegEnumKey (pmcl->hkMidi, ii, sz, cch); ++ii)
  719. {
  720. TCHAR szAlias[MAX_ALIAS];
  721. int ix;
  722. BOOL bExtern;
  723. BOOL bActive;
  724. // read in the friendly name for this driver
  725. //
  726. if (GetAlias (pmcl->hkMidi, sz, szAlias, sizeof(szAlias)/sizeof(TCHAR), &bExtern, &bActive))
  727. continue;
  728. if (IsPrefix (sz, pmcl->pszKey, TEXT('\\')))
  729. pmcl->ixDevice = ii;
  730. // ignore if this is not an external device or if it is disabled
  731. //
  732. if ( ! bExtern || ! bActive)
  733. continue;
  734. // otherwise, add the driver name to the combobox/list
  735. //
  736. if (bList)
  737. {
  738. ix = ListBox_AddString (hWndT, szAlias);
  739. if (ix >= 0)
  740. {
  741. ListBox_SetItemData (hWndT, ix, ii);
  742. bAdded = TRUE;
  743. }
  744. }
  745. else
  746. {
  747. ix = ComboBox_AddString (hWndT, szAlias);
  748. if (ix >= 0)
  749. {
  750. ComboBox_SetItemData (hWndT, ix, ii);
  751. bAdded = TRUE;
  752. }
  753. }
  754. }
  755. SetWindowRedraw (hWndT, TRUE);
  756. EnableWindow (hWndT, bAdded);
  757. if (ii > 0)
  758. InvalidateRect (hWndT, NULL, TRUE);
  759. // iterate back through the items and select the one
  760. // that has item data that corresponds to driver that
  761. // owns the current device
  762. //
  763. if (bList)
  764. {
  765. UINT jj;
  766. for (jj = 0; jj < ii; ++jj)
  767. {
  768. if ((UINT)ListBox_GetItemData (hWndT, jj) == pmcl->ixDevice)
  769. {
  770. ListBox_SetCurSel (hWndT, jj);
  771. break;
  772. }
  773. }
  774. if (jj >= ii)
  775. ListBox_SetCurSel (hWndT, 0);
  776. }
  777. else
  778. {
  779. UINT jj;
  780. for (jj = 0; jj < ii ; ++jj)
  781. {
  782. if ((UINT)ComboBox_GetItemData (hWndT, jj) == pmcl->ixDevice)
  783. {
  784. ComboBox_SetCurSel (hWndT, jj);
  785. break;
  786. }
  787. }
  788. if (jj >= ii)
  789. ComboBox_SetCurSel (hWndT, 0);
  790. }
  791. }
  792. /*+ LoadClass
  793. *
  794. *-=================================================================*/
  795. STATICFN BOOL WINAPI LoadClass (
  796. HWND hWnd,
  797. PMCLASS pmcl)
  798. {
  799. HKEY hKeyA = NULL;
  800. BOOL bRet = FALSE;
  801. UINT cbSize;
  802. UINT cch;
  803. DWORD dw;
  804. if (!pmcl->hkMidi &&
  805. RegCreateKey (HKEY_LOCAL_MACHINE, cszDriversRoot, &pmcl->hkMidi))
  806. goto cleanup;
  807. if (RegOpenKey (pmcl->hkMidi, pmcl->pszKey, &hKeyA))
  808. goto cleanup;
  809. // read data from this key
  810. //
  811. cbSize = sizeof(pmcl->szFile);
  812. RegQueryValueEx (hKeyA, cszDefinition, NULL, &dw, (LPBYTE)pmcl->szFile, &cbSize);
  813. // strip off leading directory (if there is one).
  814. //
  815. cch = lstrlen(pmcl->szFile);
  816. while (cch && (pmcl->szFile[cch-1] != TEXT('\\')))
  817. --cch;
  818. if (cch)
  819. {
  820. TCHAR szFile[MAX_PATH];
  821. lstrcpy (szFile, pmcl->szFile + cch);
  822. lstrcpy (pmcl->szFile, szFile);
  823. }
  824. // get scheme alias
  825. //
  826. cbSize = sizeof(pmcl->szAlias);
  827. RegQueryValueEx (hKeyA, cszFriendlyName, NULL, &dw, (LPBYTE)pmcl->szAlias, &cbSize);
  828. //
  829. //
  830. pmcl->nPort = 0;
  831. cbSize = sizeof(pmcl->nPort);
  832. RegQueryValueEx (hKeyA, cszPort, NULL, &dw, (LPVOID)&pmcl->nPort, &cbSize);
  833. pmcl->bChanges = 0;
  834. bRet = TRUE;
  835. cleanup:
  836. if (hKeyA)
  837. RegCloseKey (hKeyA);
  838. return bRet;
  839. }
  840. /*+ RebuildSchemes
  841. *
  842. * correct key references in the midi schemes when an instrument
  843. * is moved from one external midi port to another
  844. *
  845. *-=================================================================*/
  846. STATICFN BOOL WINAPI RebuildSchemes (
  847. LPTSTR pszOldKey,
  848. LPTSTR pszNewKey)
  849. {
  850. HKEY hkSchemes;
  851. UINT ii;
  852. TCHAR sz[MAX_ALIAS];
  853. UINT cchNew;
  854. cchNew = 0;
  855. if (pszNewKey)
  856. cchNew = lstrlen(pszNewKey) + 1;
  857. #ifdef DEBUG
  858. AuxDebugEx (3, DEBUGLINE TEXT ("RebuildSchemes('%s','%s')\r\n"),
  859. pszOldKey, pszNewKey ? pszNewKey : TEXT ("NULL"));
  860. #endif
  861. if (RegCreateKey (HKEY_LOCAL_MACHINE, cszSchemeRoot, &hkSchemes))
  862. return FALSE;
  863. for (ii = 0; ! RegEnumKey (hkSchemes, ii, sz, sizeof(sz)/sizeof(TCHAR)); ++ii)
  864. {
  865. HKEY hKeyA;
  866. UINT jj;
  867. if (RegOpenKey (hkSchemes, sz, &hKeyA))
  868. continue;
  869. for (jj = 0; ! RegEnumKey (hKeyA, jj, sz, sizeof(sz)/sizeof(TCHAR)); ++jj)
  870. {
  871. UINT cb;
  872. TCHAR szKey[MAX_PATH];
  873. cb = sizeof(szKey);
  874. if (RegQueryValue (hKeyA, sz, szKey, &cb))
  875. continue;
  876. if (IsSzEqual(pszOldKey, szKey))
  877. {
  878. if (cchNew)
  879. RegSetValue (hKeyA, sz, REG_SZ, pszNewKey, cchNew);
  880. else
  881. RegDeleteKey (hKeyA, sz);
  882. #ifdef DEBUG
  883. AuxDebugEx (4, DEBUGLINE TEXT ("RebuildSchemes - fixing %d\\%d\r\n"), ii, jj);
  884. #endif
  885. }
  886. }
  887. }
  888. return TRUE;
  889. }
  890. /*+ OpenInstrumentKey
  891. *
  892. *-=================================================================*/
  893. STATICFN HKEY WINAPI OpenInstrumentKey (
  894. HWND hWnd,
  895. PMCLASS pmcl,
  896. BOOL bCreate) // create an new key (do not remove or rebuild existing)
  897. {
  898. TCHAR szKey[MAX_ALIAS];
  899. HKEY hkInst;
  900. HKEY hKeyA = NULL;
  901. ZeroMemory (szKey, sizeof (szKey));
  902. #ifdef DEBUG
  903. AuxDebugEx (5, DEBUGLINE TEXT ("OpenInstrumentKey(%X,%08X,%d) szKey=%s\r\n"),
  904. hWnd, pmcl, bCreate, pmcl->pszKey ? pmcl->pszKey : TEXT ("NULL"));
  905. #endif
  906. hkInst = NULL;
  907. if (!pmcl->hkMidi &&
  908. RegCreateKey (HKEY_LOCAL_MACHINE, cszDriversRoot, &pmcl->hkMidi))
  909. goto cleanup;
  910. if (RegEnumKey (pmcl->hkMidi, pmcl->ixDevice, szKey, sizeof(szKey)/sizeof(TCHAR)))
  911. {
  912. assert3(0, TEXT ("Failed to enum Midi device %d"), pmcl->ixDevice);
  913. goto cleanup;
  914. }
  915. #ifdef DEBUG
  916. AuxDebugEx (6, DEBUGLINE TEXT ("ixDevice = %d, Key is %s\r\n"),
  917. pmcl->ixDevice, szKey);
  918. #endif
  919. // if this is a driver key, or if we are not creating and
  920. // the instrument has not changed parentage, we can just
  921. // open the existing key and update its content
  922. //
  923. if (!pmcl->bRemote ||
  924. (!bCreate && IsPrefix (szKey, pmcl->pszKey, TEXT('\\'))))
  925. {
  926. if (RegOpenKey (pmcl->hkMidi, pmcl->pszKey, &hKeyA))
  927. goto cleanup;
  928. #ifdef DEBUG
  929. AuxDebugEx (6, DEBUGLINE TEXT ("opened key %s\r\n"), pmcl->pszKey);
  930. #endif
  931. }
  932. else
  933. {
  934. UINT kk;
  935. TCHAR szEnum[10];
  936. pmcl->bChanges |= MCL_TREE_CHANGED;
  937. lstrcat (szKey, cszSlashInstruments);
  938. if (RegCreateKey (pmcl->hkMidi, szKey, &hkInst))
  939. goto cleanup;
  940. // find an unused keyname
  941. //
  942. for (kk = 0; kk < 128; ++kk)
  943. {
  944. wsprintf (szEnum, csz02d, kk);
  945. if (RegOpenKey (hkInst, szEnum, &hKeyA))
  946. break;
  947. RegCloseKey (hKeyA);
  948. }
  949. lstrcat (szKey, cszSlash);
  950. lstrcat (szKey, szEnum);
  951. // create a key with that name
  952. //
  953. if (RegCreateKey (hkInst, szEnum, &hKeyA))
  954. goto cleanup;
  955. #ifdef DEBUG
  956. AuxDebugEx (6, DEBUGLINE TEXT ("created key %s\r\n"), szKey);
  957. #endif
  958. // we are moving an instrument from one
  959. // external midi port to another
  960. //
  961. if (!bCreate)
  962. {
  963. #ifdef DEBUG
  964. AuxDebugEx (3, DEBUGLINE TEXT ("Deleting key midi\\%s\r\n"), pmcl->pszKey);
  965. #endif
  966. RegDeleteKey (pmcl->hkMidi, pmcl->pszKey);
  967. RebuildSchemes (pmcl->pszKey, szKey);
  968. }
  969. lstrcpy (pmcl->pszKey, szKey);
  970. }
  971. cleanup:
  972. if (hkInst)
  973. RegCloseKey (hkInst);
  974. return hKeyA;
  975. }
  976. /*+ SaveDetails
  977. *
  978. *-=================================================================*/
  979. STATICFN UINT WINAPI SaveDetails (
  980. HWND hWnd,
  981. PMCLASS pmcl,
  982. BOOL bCreate)
  983. {
  984. HWND hWndT;
  985. HKEY hKeyA;
  986. UINT bChanges;
  987. UINT cbSize;
  988. // this should only be called on shutdown
  989. // of details page (or on exit of wizard)
  990. //
  991. assert (pmcl->bDetails);
  992. hKeyA = OpenInstrumentKey (hWnd, pmcl, bCreate);
  993. if ( ! hKeyA)
  994. return FALSE;
  995. hWndT = GetDlgItem (hWnd, IDE_ALIAS);
  996. if (hWndT)
  997. {
  998. TCHAR sz[NUMELMS(pmcl->szAlias)];
  999. GetWindowText (hWndT, sz, NUMELMS(sz));
  1000. if ( ! IsSzEqual(sz, pmcl->szAlias))
  1001. {
  1002. lstrcpy (pmcl->szAlias, sz);
  1003. pmcl->bChanges |= MCL_ALIAS_CHANGED;
  1004. }
  1005. }
  1006. #ifdef DEBUG
  1007. AuxDebugEx (2, DEBUGLINE TEXT ("--------SaveInstrument---------\r\n"));
  1008. AuxDebugEx (2, TEXT ("\tChanges=%x\r\n"), pmcl->bChanges);
  1009. AuxDebugEx (2, TEXT ("\tFriendly='%s'\r\n"), pmcl->szAlias);
  1010. AuxDebugEx (2, TEXT ("\tDefinition='%s'\r\n"), pmcl->szFile);
  1011. #endif
  1012. // save value data from this key
  1013. //
  1014. cbSize = (lstrlen(pmcl->szFile)+1) * sizeof(TCHAR);
  1015. RegSetValueEx (hKeyA, cszDefinition, 0, REG_SZ, (LPBYTE)pmcl->szFile,
  1016. cbSize);
  1017. cbSize = (lstrlen(pmcl->szAlias)+1) * sizeof(TCHAR);
  1018. RegSetValueEx (hKeyA, cszFriendlyName, 0, REG_SZ,
  1019. (LPBYTE)pmcl->szAlias, cbSize);
  1020. RegSetValueEx (hKeyA, cszPort, 0, REG_BINARY, (LPVOID)&pmcl->nPort, 1);
  1021. RegCloseKey (hKeyA);
  1022. bChanges = pmcl->bChanges;
  1023. pmcl->bChanges = 0;
  1024. // return 'changed' flag
  1025. //
  1026. return bChanges;
  1027. }
  1028. /*+ ParseAngleBrackets
  1029. *
  1030. * replace '<>' delimiters with 0s and return a pointer
  1031. * to the delimited string. This function does nothing if
  1032. * the string does not end in a '>' delimiter
  1033. *
  1034. *-=================================================================*/
  1035. static LPTSTR __inline WINAPI ParseAngleBrackets (
  1036. LPTSTR pszArg)
  1037. {
  1038. LPTSTR psz = pszArg + lstrlen(pszArg);
  1039. while (--psz > pszArg)
  1040. {
  1041. if (*psz == TEXT('>'))
  1042. {
  1043. *psz = 0;
  1044. while (--psz >= pszArg)
  1045. {
  1046. if (*psz == TEXT('<'))
  1047. {
  1048. *psz = 0;
  1049. return psz+1;
  1050. }
  1051. }
  1052. }
  1053. }
  1054. return NULL;
  1055. }
  1056. /*+ fnFindDevice
  1057. *
  1058. *-=================================================================*/
  1059. struct _find_data {
  1060. HWND hWnd;
  1061. UINT idMfg;
  1062. UINT idProd;
  1063. LPTSTR pszInstr;
  1064. };
  1065. STATICFN BOOL WINAPI fnFindDevice (
  1066. LPVOID lpv,
  1067. UINT nEnum,
  1068. LPIDFHEADER pHdr,
  1069. LPIDFINSTINFO pInst)
  1070. {
  1071. struct _find_data * pfd = lpv;
  1072. TCHAR szTemp[MAX_PATH];
  1073. assert (pfd);
  1074. MultiByteToWideChar(GetACP(), 0,
  1075. pHdr->abInstID, -1,
  1076. szTemp, sizeof(szTemp)/sizeof(TCHAR));
  1077. if (!pfd->pszInstr ||
  1078. IsSzEqual (pfd->pszInstr, szTemp))
  1079. {
  1080. if (SetDlgItemText (pfd->hWnd, pfd->idMfg, (TCHAR*)(pInst->abData+pInst->cbManufactASCII )))
  1081. pfd->idMfg = 0;
  1082. if (SetDlgItemText (pfd->hWnd, pfd->idProd,
  1083. (TCHAR*)(pInst->abData
  1084. + pInst->cbManufactASCII + pInst->cbManufactUNICODE)))
  1085. pfd->idProd = 0;
  1086. // we can stop enumerating now
  1087. //
  1088. return FALSE;
  1089. }
  1090. // return true to consider ennumeration
  1091. //
  1092. return TRUE;
  1093. }
  1094. /*+ ActivateInstrumentPage
  1095. *
  1096. *-=================================================================*/
  1097. STATICFN void WINAPI ActivateInstrumentPage (
  1098. HWND hWnd,
  1099. PMCLASS pmcl)
  1100. {
  1101. pmcl->bDetails = FALSE;
  1102. if (GetDlgItem (hWnd, IDC_TYPES))
  1103. {
  1104. pmcl->bDetails = TRUE;
  1105. LoadTypesIntoTree (hWnd, IDC_TYPES, pmcl);
  1106. SetTypesEdit (hWnd, IDE_TYPES, pmcl);
  1107. LoadDevicesIntoList (hWnd, IDC_DEVICES, pmcl, FALSE);
  1108. if ( ! pmcl->bRemote)
  1109. {
  1110. HWND hWndT = GetDlgItem (hWnd, IDC_DEVICES);
  1111. if (hWndT)
  1112. EnableWindow (hWndT, FALSE);
  1113. }
  1114. }
  1115. else
  1116. {
  1117. struct _find_data fd;
  1118. TCHAR szFile[NUMELMS(pmcl->szFile)];
  1119. if ( ! IsFullPath (pmcl->szFile))
  1120. {
  1121. UINT cch;
  1122. GetIDFDirectory (szFile, NUMELMS(szFile));
  1123. cch = lstrlen (szFile);
  1124. if (cch && szFile[cch-1] != TEXT('\\'))
  1125. szFile[cch++] = TEXT('\\');
  1126. lstrcpyn (szFile + cch, pmcl->szFile, NUMELMS(szFile)-cch);
  1127. }
  1128. else
  1129. lstrcpy (szFile, pmcl->szFile);
  1130. fd.hWnd = hWnd;
  1131. fd.idMfg = IDC_MANUFACTURER;
  1132. fd.idProd = IDC_DEVICE_TYPE;
  1133. fd.pszInstr = ParseAngleBrackets(szFile);
  1134. idfEnumInstruments (szFile, fnFindDevice, &fd);
  1135. if (fd.idMfg)
  1136. SetDlgItemText (hWnd, fd.idMfg, cszEmpty);
  1137. if (fd.idProd)
  1138. {
  1139. LoadString (ghInstance, IDS_UNSPECIFIED, szFile, NUMELMS(szFile));
  1140. SetDlgItemText (hWnd, fd.idProd, szFile);
  1141. }
  1142. }
  1143. }
  1144. /*+ IsInstrumentKey
  1145. *
  1146. * return TRUE if the keyname passed refers to an instrument key
  1147. * rather than a device key. device keys usually end in '>',
  1148. * while instrument keys will always be of the form
  1149. * <dev>\Instruments\<enum> where <dev> and <enum> can be arbitrary
  1150. * strings.
  1151. *
  1152. *-=================================================================*/
  1153. STATICFN BOOL WINAPI IsInstrumentKey (
  1154. LPTSTR pszKey)
  1155. {
  1156. UINT cch = lstrlen(pszKey);
  1157. if (!cch)
  1158. return FALSE;
  1159. if (pszKey[cch-1] == TEXT('>'))
  1160. return FALSE;
  1161. while (--cch)
  1162. if (pszKey[cch] == TEXT('\\'))
  1163. return TRUE;
  1164. return FALSE;
  1165. }
  1166. /*+ InitInstrumentProps
  1167. *
  1168. *-=================================================================*/
  1169. STATICFN BOOL WINAPI InitInstrumentProps (
  1170. HWND hWnd,
  1171. PMCLASS pmcl)
  1172. {
  1173. LPPROPSHEETPAGE ppsp = pmcl->ppsp;
  1174. PMPSARGS pmpsa;
  1175. assert (ppsp && ppsp->dwSize == sizeof(*ppsp));
  1176. if (!ppsp)
  1177. return FALSE; // EndDialog (hWnd, FALSE);
  1178. pmcl->bRemote = FALSE;
  1179. pmpsa = (LPVOID)ppsp->lParam;
  1180. if (pmpsa && pmpsa->lpfnMMExtPSCallback)
  1181. {
  1182. pmpsa->lpfnMMExtPSCallback (MM_EPS_GETNODEDESC,
  1183. (DWORD_PTR)pmcl->szAlias,
  1184. sizeof(pmcl->szAlias),
  1185. (DWORD_PTR)pmpsa->lParam);
  1186. #ifdef DEBUG
  1187. AuxDebugEx (3, TEXT ("\tgot szAlias='%s'\r\n"), pmcl->szAlias);
  1188. #endif
  1189. pmpsa->lpfnMMExtPSCallback (MM_EPS_GETNODEID,
  1190. (DWORD_PTR)pmcl->szFullKey,
  1191. sizeof(pmcl->szFullKey),
  1192. (DWORD_PTR)pmpsa->lParam);
  1193. #ifdef DEBUG
  1194. AuxDebugEx (3, TEXT ("\tgot szFullKey='%s'\r\n"), pmcl->szFullKey);
  1195. #endif
  1196. // skip over the midi\ part of the key if we have been
  1197. // passed that. we want the driver name to be the first
  1198. // part of the key
  1199. //
  1200. pmcl->pszKey = pmcl->szFullKey;
  1201. if (!lstrnicmp (pmcl->pszKey,
  1202. (LPTSTR)cszMidiSlash,
  1203. lstrlen(cszMidiSlash)))
  1204. {
  1205. pmcl->pszKey += lstrlen(cszMidiSlash);
  1206. }
  1207. // If this is an instrument key, set bRemote to true
  1208. //
  1209. if (IsInstrumentKey(pmcl->pszKey))
  1210. pmcl->bRemote = TRUE;
  1211. }
  1212. else
  1213. LoadString (ghInstance, IDS_UNSPECIFIED,
  1214. pmcl->szAlias, NUMELMS(pmcl->szAlias));
  1215. SetDlgItemText (hWnd, IDE_ALIAS, pmcl->szAlias);
  1216. Static_SetIcon(GetDlgItem (hWnd, IDC_CLASS_ICON),
  1217. LoadIcon (ghInstance, MAKEINTRESOURCE(IDI_INSTRUMENT)));
  1218. LoadClass (hWnd, pmcl);
  1219. //ActivateInstrumentPage(hWnd, pmcl);
  1220. return TRUE;
  1221. }
  1222. /*+ NotifyMapper
  1223. *
  1224. *-=================================================================*/
  1225. STATICFN void WINAPI NotifyMapper (
  1226. PMCLASS pmcl,
  1227. UINT bChanges,
  1228. HWND hWnd)
  1229. {
  1230. // tell midi mapper about tree changes, IDF changes and port changes
  1231. //
  1232. if (bChanges & (MCL_TREE_CHANGED | MCL_IDF_CHANGED | MCL_PORT_CHANGED))
  1233. {
  1234. KickMapper (hWnd);
  1235. }
  1236. }
  1237. /*+
  1238. *
  1239. *-=================================================================*/
  1240. STATICFN BOOL WINAPI RemoveInstrument (
  1241. HWND hWnd,
  1242. PMCLASS pmcl)
  1243. {
  1244. RegDeleteKey (pmcl->hkMidi, pmcl->pszKey);
  1245. RebuildSchemes (pmcl->pszKey, NULL);
  1246. return TRUE;
  1247. }
  1248. BOOL WINAPI RemoveInstrumentByKeyName (
  1249. LPCTSTR pszKey)
  1250. {
  1251. MCLASS mcl;
  1252. BOOL rc = FALSE;
  1253. memset ((TCHAR *)&mcl, 0x00, sizeof(mcl));
  1254. mcl.pszKey = (LPTSTR)pszKey;
  1255. if (!lstrnicmp (mcl.pszKey,
  1256. (LPTSTR)cszMidiSlash,
  1257. lstrlen(cszMidiSlash)))
  1258. {
  1259. mcl.pszKey += lstrlen(cszMidiSlash);
  1260. }
  1261. if (LoadClass (NULL, &mcl))
  1262. {
  1263. rc = RemoveInstrument (NULL, &mcl);
  1264. if (mcl.hkMidi)
  1265. RegCloseKey (mcl.hkMidi);
  1266. }
  1267. return rc;
  1268. }
  1269. /*+ MidiInstrumentCommands
  1270. *
  1271. *-=================================================================*/
  1272. BOOL WINAPI MidiInstrumentCommands (
  1273. HWND hWnd,
  1274. UINT_PTR uId,
  1275. LPNMHDR lpnm)
  1276. {
  1277. PMCLASS pmcl = GetDlgData(hWnd);
  1278. #ifdef DEBUG
  1279. AuxDebugEx (4, DEBUGLINE TEXT ("InstrumentCommands(..%d..) %d(%xx)\r\n"),
  1280. uId, lpnm->code, lpnm->code);
  1281. #endif
  1282. if (!pmcl)
  1283. return FALSE;
  1284. switch (uId)
  1285. {
  1286. case IDE_ALIAS:
  1287. if (lpnm->code == EN_CHANGE)
  1288. PropSheet_Changed(GetParent(hWnd), hWnd);
  1289. break;
  1290. case IDB_REMOVE:
  1291. if (RemoveInstrument (hWnd, pmcl))
  1292. {
  1293. PMPSARGS pmpsa = (LPVOID)pmcl->ppsp->lParam;
  1294. if (pmpsa && pmpsa->lpfnMMExtPSCallback)
  1295. pmpsa->lpfnMMExtPSCallback (MM_EPS_TREECHANGE, 0, 0, (DWORD_PTR)pmpsa->lParam);
  1296. NotifyMapper (pmcl, MCL_TREE_CHANGED, hWnd);
  1297. SetDlgData(hWnd, NULL);
  1298. if (pmcl->hkMidi)
  1299. RegCloseKey (pmcl->hkMidi), pmcl->hkMidi = NULL;
  1300. LocalFree ((HLOCAL)(UINT_PTR)(DWORD_PTR)pmcl);
  1301. PropSheet_PressButton(GetParent(hWnd), PSBTN_CANCEL);
  1302. }
  1303. break;
  1304. case IDB_NEWTYPE:
  1305. InstallNewIDF (hWnd);
  1306. LoadTypesIntoTree (hWnd, IDC_TYPES, pmcl);
  1307. SetTypesEdit (hWnd, IDE_TYPES, pmcl);
  1308. break;
  1309. case IDC_TYPES:
  1310. if ((lpnm->code == TVN_SELCHANGED) && !pmcl->bFillingList)
  1311. {
  1312. HandleTypesSelChange (pmcl, lpnm);
  1313. SetTypesEdit (hWnd, IDE_TYPES, pmcl);
  1314. PropSheet_Changed(GetParent(hWnd), hWnd);
  1315. #ifdef DEBUG
  1316. AuxDebugEx (5, DEBUGLINE TEXT ("file='%s'\r\n"), pmcl->szFile);
  1317. #endif
  1318. }
  1319. break;
  1320. case IDC_DEVICES:
  1321. if (lpnm->code == CBN_SELCHANGE)
  1322. {
  1323. int ix = ComboBox_GetCurSel (lpnm->hwndFrom);
  1324. pmcl->ixDevice = (UINT) ((ix >= 0) ? ComboBox_GetItemData (lpnm->hwndFrom, ix) : -1);
  1325. PropSheet_Changed(GetParent(hWnd), hWnd);
  1326. #ifdef DEBUG
  1327. AuxDebugEx (4, DEBUGLINE TEXT ("IDC_DEVICES.selChange(%d) %d\r\n"), ix, pmcl->ixDevice);
  1328. #endif
  1329. }
  1330. break;
  1331. // we get these only if invoked as a dialog, not as a property
  1332. // sheet
  1333. //
  1334. case IDOK:
  1335. {
  1336. UINT bChanges = SaveDetails (hWnd, pmcl, FALSE);
  1337. NotifyMapper (pmcl, bChanges, hWnd);
  1338. }
  1339. // fall through
  1340. case IDCANCEL:
  1341. EndDialog (hWnd, uId);
  1342. break;
  1343. case 0:
  1344. {
  1345. LONG lRet = FALSE;
  1346. switch (lpnm->code)
  1347. {
  1348. case PSN_APPLY:
  1349. #ifdef DEBUG
  1350. AuxDebugEx (4, DEBUGLINE TEXT ("ID_APPLY\r\n"));
  1351. #endif
  1352. if (pmcl->bDetails)
  1353. {
  1354. UINT bChanges = SaveDetails (hWnd, pmcl, FALSE);
  1355. NotifyMapper (pmcl, bChanges, hWnd);
  1356. // tell mmsys.cpl about tree & alias changes
  1357. //
  1358. if (bChanges & (MCL_TREE_CHANGED | MCL_ALIAS_CHANGED))
  1359. {
  1360. PMPSARGS pmpsa = (LPVOID)pmcl->ppsp->lParam;
  1361. if (pmpsa && pmpsa->lpfnMMExtPSCallback)
  1362. pmpsa->lpfnMMExtPSCallback (MM_EPS_TREECHANGE, 0, 0, (DWORD_PTR)pmpsa->lParam);
  1363. }
  1364. // we do this because the SysTreeView for IDF files
  1365. // forgets its selection when APPLY is pressed. go figure
  1366. //
  1367. #ifdef DEBUG
  1368. AuxDebugEx (7, DEBUGLINE TEXT ("PSN_APPLY: re-doing selection '%s'\r\n"), pmcl->szFile);
  1369. //ActivateInstrumentPage (hWnd, pmcl);
  1370. AuxDebugEx (7, DEBUGLINE TEXT ("PSN_APPLY: done re-doing selection '%s'\r\n"), pmcl->szFile);
  1371. #endif
  1372. }
  1373. break;
  1374. case PSN_KILLACTIVE:
  1375. break;
  1376. case PSN_SETACTIVE:
  1377. #ifdef DEBUG
  1378. AuxDebugEx (4, DEBUGLINE TEXT ("PSN_SETACTIVE\r\n"));
  1379. #endif
  1380. ActivateInstrumentPage (hWnd, pmcl);
  1381. #ifdef DEBUG
  1382. AuxDebugEx (4, DEBUGLINE TEXT ("PSN_SETACTIVE ends\r\n"));
  1383. #endif
  1384. break;
  1385. }
  1386. SetWindowLongPtr (hWnd, DWLP_MSGRESULT, (LONG_PTR)lRet);
  1387. break;
  1388. }
  1389. }
  1390. return FALSE;
  1391. }
  1392. const static DWORD aKeyWordIds[] = { // Context Help IDs
  1393. IDC_CLASS_ICON, IDH_MMCPL_DEVPROP_DETAILS_INSTRUMENT,
  1394. IDE_ALIAS, IDH_MMCPL_DEVPROP_DETAILS_INSTRUMENT,
  1395. IDC_DEVICES, IDH_MMCPL_DEVPROP_DETAILS_MIDI_PORT,
  1396. IDC_TYPES, IDH_MMCPL_DEVPROP_DETAILS_INS_DEF,
  1397. IDB_NEWTYPE, IDH_MMCPL_DEVPROP_DETAILS_BROWSE,
  1398. 0, 0
  1399. };
  1400. /*+ MidiInstrumentDlgProc
  1401. *
  1402. *-=================================================================*/
  1403. INT_PTR CALLBACK MidiInstrumentDlgProc (
  1404. HWND hWnd,
  1405. UINT uMsg,
  1406. WPARAM wParam,
  1407. LPARAM lParam)
  1408. {
  1409. #if defined DEBUG || defined DEBUG_RETAIL
  1410. TCHAR chNest = szNestLevel[0]++;
  1411. #endif
  1412. switch (uMsg)
  1413. {
  1414. case WM_COMMAND:
  1415. {
  1416. NMHDR nmh;
  1417. nmh.hwndFrom = GET_WM_COMMAND_HWND(wParam, lParam);
  1418. nmh.idFrom = GET_WM_COMMAND_ID(wParam, lParam);
  1419. nmh.code = GET_WM_COMMAND_CMD(wParam, lParam);
  1420. MidiInstrumentCommands(hWnd, nmh.idFrom, &nmh);
  1421. }
  1422. break;
  1423. case WM_NOTIFY:
  1424. #ifdef DEBUG
  1425. AuxDebugEx (3, DEBUGLINE TEXT ("WM_NOTIFY(%x,%x,%x)\r\n"), hWnd, wParam, lParam);
  1426. #endif
  1427. #if defined DEBUG || defined DEBUG_RETAIL
  1428. ++szNestLevel[0];
  1429. #endif
  1430. MidiInstrumentCommands(hWnd, wParam, (LPVOID)lParam);
  1431. #if defined DEBUG || defined DEBUG_RETAIL
  1432. --szNestLevel[0];
  1433. #endif
  1434. break;
  1435. case WM_INITDIALOG:
  1436. {
  1437. PMCLASS pmcl;
  1438. pmcl = (LPVOID)LocalAlloc(LPTR, sizeof(*pmcl));
  1439. if (!pmcl)
  1440. {
  1441. EndDialog(hWnd, FALSE);
  1442. break;
  1443. }
  1444. pmcl->ppsp = (LPVOID)lParam;
  1445. SetDlgData (hWnd, pmcl);
  1446. #ifdef DEBUG
  1447. AuxDebugEx (5, DEBUGLINE TEXT ("midiInstrument.WM_INITDLG ppsp=%08X\r\n"));
  1448. #endif
  1449. //AuxDebugDump (8, pmcl->ppsp, sizeof(*(pmcl->ppsp)));
  1450. InitInstrumentProps (hWnd, pmcl);
  1451. break;
  1452. }
  1453. case WM_DESTROY:
  1454. {
  1455. PMCLASS pmcl = GetDlgData(hWnd);
  1456. if (pmcl)
  1457. {
  1458. if (pmcl->hkMidi)
  1459. RegCloseKey (pmcl->hkMidi), pmcl->hkMidi = NULL;
  1460. #ifdef USE_IDF_ICONS
  1461. if (pmcl->hIDFImageList)
  1462. {
  1463. HWND hWndT = GetDlgItem (hWnd, IDC_TYPES);
  1464. if (hWndT)
  1465. TreeView_SetImageList (hWndT, NULL, TVSIL_NORMAL);
  1466. ImageList_Destroy (pmcl->hIDFImageList);
  1467. pmcl->hIDFImageList = NULL;
  1468. }
  1469. #endif
  1470. LocalFree ((HLOCAL)(UINT_PTR)(DWORD_PTR)pmcl);
  1471. }
  1472. break;
  1473. }
  1474. case WM_CONTEXTMENU:
  1475. WinHelp ((HWND) wParam, NULL, HELP_CONTEXTMENU,
  1476. (UINT_PTR) (LPTSTR) aKeyWordIds);
  1477. break;
  1478. case WM_HELP:
  1479. {
  1480. LPHELPINFO lphi = (LPVOID) lParam;
  1481. WinHelp (lphi->hItemHandle, NULL, HELP_WM_HELP,
  1482. (UINT_PTR) (LPTSTR) aKeyWordIds);
  1483. break;
  1484. }
  1485. }
  1486. #if defined DEBUG || defined DEBUG_RETAIL
  1487. szNestLevel[0] = chNest;
  1488. #endif
  1489. return FALSE;
  1490. }
  1491. /// --------------------- Wizard stuff ----------------------
  1492. static LPTSTR aidWiz[] = {
  1493. MAKEINTRESOURCE(IDD_MIDIWIZ02),
  1494. MAKEINTRESOURCE(IDD_MIDIWIZ03),
  1495. MAKEINTRESOURCE(IDD_MIDIWIZ04)
  1496. };
  1497. #define WIZ_TEMPLATE_DEVICE aidWiz[0]
  1498. #define WIZ_TEMPLATE_IDF aidWiz[1]
  1499. #define WIZ_TEMPLATE_ALIAS aidWiz[2]
  1500. typedef struct _wizdata {
  1501. LPPROPSHEETPAGE ppspActive;
  1502. HBITMAP hBmp;
  1503. MCLASS mcl;
  1504. PMCMIDI pmcm;
  1505. HPROPSHEETPAGE ahpsp[NUMELMS(aidWiz)];
  1506. } WIZDATA, * PWIZDATA;
  1507. /*+ FindInstrument
  1508. *
  1509. *-=================================================================*/
  1510. STATICFN PINSTRUM WINAPI FindInstrument (
  1511. PMCMIDI pmcm,
  1512. LPTSTR pszFriendly)
  1513. {
  1514. UINT ii;
  1515. for (ii = 0; ii < pmcm->nInstr; ++ii)
  1516. {
  1517. assert (pmcm->api[ii]);
  1518. if (IsSzEqual(pszFriendly, pmcm->api[ii]->szFriendly))
  1519. return pmcm->api[ii];
  1520. }
  1521. return NULL;
  1522. }
  1523. /*+ UniqueFriendlyName
  1524. *
  1525. *-=================================================================*/
  1526. STATICFN BOOL WINAPI fnFirstInstr (
  1527. LPVOID lpv,
  1528. UINT nEnum,
  1529. LPIDFHEADER pHdr,
  1530. LPIDFINSTINFO pInst)
  1531. {
  1532. LPTSTR pszInstr = lpv;
  1533. assert (pszInstr);
  1534. MultiByteToWideChar(GetACP(), 0,
  1535. pHdr->abInstID, -1,
  1536. pszInstr, MAX_ALIAS);
  1537. return FALSE;
  1538. }
  1539. STATICFN BOOL WINAPI UniqueFriendlyName (
  1540. PMCMIDI pmcm,
  1541. PMCLASS pmcl,
  1542. LPTSTR pszAlias,
  1543. UINT cchAlias)
  1544. {
  1545. TCHAR szFile[MAX_PATH * 2];
  1546. LPTSTR pszInstr;
  1547. UINT cch;
  1548. UINT ii;
  1549. GetIDFDirectory (szFile, sizeof(szFile)/sizeof(TCHAR));
  1550. cch = lstrlen(szFile);
  1551. if (cch && szFile[cch-1] != TEXT('\\'))
  1552. szFile[cch++] = TEXT('\\');
  1553. lstrcpy (szFile + cch, pmcl->szFile);
  1554. pszInstr = ParseAngleBrackets (szFile);
  1555. if ( ! pszInstr)
  1556. {
  1557. pszInstr = szFile + lstrlen(szFile) + 1;
  1558. idfEnumInstruments (szFile, fnFirstInstr, pszInstr);
  1559. }
  1560. // if no instrument name from the IDF file, get a default
  1561. // from our resources
  1562. //
  1563. if ( ! lstrlen (pszInstr))
  1564. {
  1565. LoadString (ghInstance, IDS_DEF_INSTRNAME, pszInstr, MAX_ALIAS);
  1566. return FALSE;
  1567. }
  1568. // make the instrument name the same as the alias, and prepare
  1569. // to append a number if the alias turns out not to be unique
  1570. //
  1571. lstrcpyn (pszAlias, pszInstr, cchAlias);
  1572. cch = lstrlen (pszAlias);
  1573. cch = min (cch, (UINT)MAX_ALIAS-3);
  1574. ii = 1;
  1575. // loop while we are trying to use an instrument name
  1576. // that has already been used
  1577. //
  1578. while (FindInstrument (pmcm, pszAlias))
  1579. {
  1580. static CONST TCHAR cszSpaceD[] = TEXT (" %d");
  1581. wsprintf (pszAlias + cch, cszSpaceD, ++ii);
  1582. if (ii > NUMELMS(pmcm->api))
  1583. {
  1584. assert2(0, TEXT ("infinite loop in UniqueFriendlyName!"));
  1585. break;
  1586. }
  1587. }
  1588. return TRUE;
  1589. }
  1590. /*+ MidiWizardCommands
  1591. *
  1592. *-=================================================================*/
  1593. BOOL WINAPI MidiWizardCommands (
  1594. HWND hWnd,
  1595. UINT_PTR uId,
  1596. LPNMHDR lpnm)
  1597. {
  1598. PWIZDATA pwd;
  1599. LPPROPSHEETPAGE ppsp = GetDlgData(hWnd);
  1600. LONG lRet = TRUE;
  1601. #ifdef DEBUG
  1602. AuxDebugEx (4, DEBUGLINE TEXT ("WizardCmd ppsp=%08X code=%d(0x%X)\r\n"),
  1603. ppsp, lpnm->code, lpnm->code);
  1604. #endif
  1605. pwd = NULL;
  1606. if (ppsp)
  1607. pwd = (LPVOID)ppsp->lParam;
  1608. assert (pwd);
  1609. switch (uId)
  1610. {
  1611. case IDC_TYPES:
  1612. if ((lpnm->code == TVN_SELCHANGED) && !pwd->mcl.bFillingList)
  1613. {
  1614. HandleTypesSelChange (&pwd->mcl, lpnm);
  1615. UniqueFriendlyName (pwd->pmcm, &pwd->mcl, pwd->mcl.szAlias, NUMELMS(pwd->mcl.szAlias));
  1616. #ifdef DEBUG
  1617. AuxDebugEx (5, DEBUGLINE TEXT ("file='%s'\r\n"), pwd->mcl.szFile);
  1618. #endif
  1619. }
  1620. break;
  1621. case IDB_NEWTYPE:
  1622. InstallNewIDF (hWnd);
  1623. LoadTypesIntoTree (hWnd, IDC_TYPES, &pwd->mcl);
  1624. break;
  1625. //case IDC_DEVICES:
  1626. // break;
  1627. //case IDE_ALIAS:
  1628. // break;
  1629. case 0:
  1630. {
  1631. switch (lpnm->code)
  1632. {
  1633. case PSN_HELP:
  1634. break;
  1635. case PSN_KILLACTIVE:
  1636. #ifdef DEBUG
  1637. AuxDebugEx (4, DEBUGLINE TEXT ("PSN_KILLACTIVE\r\n"));
  1638. #endif
  1639. break;
  1640. case PSN_SETACTIVE:
  1641. {
  1642. DWORD dwWizBtn;
  1643. #ifdef DEBUG
  1644. AuxDebugEx (4, DEBUGLINE TEXT ("PSN_SETACTIVE\r\n"));
  1645. #endif
  1646. if (pwd)
  1647. pwd->ppspActive = ppsp;
  1648. if (ppsp->pszTemplate == WIZ_TEMPLATE_DEVICE) // midi device
  1649. LoadDevicesIntoList (hWnd, IDC_DEVICES, &pwd->mcl, TRUE);
  1650. else if (ppsp->pszTemplate == WIZ_TEMPLATE_IDF) // idf file
  1651. LoadTypesIntoTree (hWnd, IDC_TYPES, &pwd->mcl);
  1652. else if (ppsp->pszTemplate == WIZ_TEMPLATE_ALIAS) // alias
  1653. SetDlgItemText (hWnd, IDE_ALIAS, pwd->mcl.szAlias);
  1654. dwWizBtn = PSWIZB_NEXT | PSWIZB_BACK;
  1655. if (ppsp->pszTemplate == aidWiz[NUMELMS(aidWiz)-1])
  1656. dwWizBtn = PSWIZB_FINISH | PSWIZB_BACK;
  1657. else if (ppsp->pszTemplate == aidWiz[0])
  1658. dwWizBtn = PSWIZB_NEXT;
  1659. PropSheet_SetWizButtons (GetParent(hWnd), dwWizBtn);
  1660. }
  1661. break;
  1662. case PSN_WIZNEXT:
  1663. #ifdef DEBUG
  1664. AuxDebugEx (4, DEBUGLINE TEXT ("PSN_WIZNEXT\r\n"));
  1665. #endif
  1666. if (ppsp->pszTemplate == WIZ_TEMPLATE_DEVICE) // midi device
  1667. {
  1668. HWND hWndT;
  1669. int ix;
  1670. pwd->mcl.ixDevice = (UINT)-1;
  1671. pwd->mcl.nPort = 0;
  1672. hWndT = GetDlgItem (hWnd, IDC_DEVICES);
  1673. if (hWndT)
  1674. {
  1675. ix = ListBox_GetCurSel (hWndT);
  1676. if (ix >= 0)
  1677. pwd->mcl.ixDevice = (UINT) ListBox_GetItemData (hWndT, ix);
  1678. }
  1679. if (pwd->mcl.ixDevice == (UINT)-1)
  1680. SetWindowLongPtr (hWnd, DWLP_MSGRESULT, (LONG_PTR)-1);
  1681. }
  1682. else if (ppsp->pszTemplate == WIZ_TEMPLATE_IDF) // idf file
  1683. {
  1684. if ( ! pwd->mcl.szAlias[0])
  1685. {
  1686. LoadString (ghInstance, IDS_DEF_INSTRNAME,
  1687. pwd->mcl.szAlias,
  1688. NUMELMS(pwd->mcl.szAlias));
  1689. }
  1690. }
  1691. else if (ppsp->pszTemplate == WIZ_TEMPLATE_IDF) // alias
  1692. {
  1693. GetDlgItemText (hWnd, IDE_ALIAS, pwd->mcl.szAlias,
  1694. NUMELMS(pwd->mcl.szAlias));
  1695. }
  1696. break;
  1697. case PSN_WIZBACK:
  1698. #ifdef DEBUG
  1699. AuxDebugEx (4, DEBUGLINE TEXT ("PSN_WIZBACK\r\n"));
  1700. #endif
  1701. break;
  1702. case PSN_WIZFINISH:
  1703. #ifdef DEBUG
  1704. AuxDebugEx (4, DEBUGLINE TEXT ("PSN_WIZFINISH\r\n"));
  1705. #endif
  1706. //if (!save success)
  1707. lRet = FALSE;
  1708. //SetWindowLong (hWnd, DWL_MSGRESULT, lRet);
  1709. SaveDetails (hWnd, &pwd->mcl, TRUE);
  1710. break;
  1711. default:
  1712. lRet = FALSE;
  1713. }
  1714. }
  1715. break;
  1716. }
  1717. return lRet;
  1718. }
  1719. /*+ MidiWizardDlgProc
  1720. *
  1721. *-=================================================================*/
  1722. INT_PTR CALLBACK MidiWizardDlgProc (
  1723. HWND hWnd,
  1724. UINT uMsg,
  1725. WPARAM wParam,
  1726. LPARAM lParam)
  1727. {
  1728. BOOL bRet = TRUE;
  1729. #if defined DEBUG || defined DEBUG_RETAIL
  1730. TCHAR chNest = szNestLevel[0]++;
  1731. #endif
  1732. switch (uMsg)
  1733. {
  1734. case WM_COMMAND:
  1735. {
  1736. NMHDR nmh;
  1737. nmh.hwndFrom = GET_WM_COMMAND_HWND(wParam, lParam);
  1738. nmh.idFrom = GET_WM_COMMAND_ID(wParam, lParam);
  1739. nmh.code = GET_WM_COMMAND_CMD(wParam, lParam);
  1740. bRet = MidiWizardCommands(hWnd, nmh.idFrom, &nmh);
  1741. }
  1742. break;
  1743. case WM_NOTIFY:
  1744. #ifdef DEBUG
  1745. AuxDebugEx (6, DEBUGLINE TEXT ("WM_NOTIFY(%x,%x,%x)\r\n"), hWnd, wParam, lParam);
  1746. #endif
  1747. bRet = MidiWizardCommands(hWnd, wParam, (LPVOID)lParam);
  1748. break;
  1749. case WM_INITDIALOG:
  1750. {
  1751. PWIZDATA pwd;
  1752. LPPROPSHEETPAGE ppsp = (LPVOID)lParam;
  1753. SetDlgData (hWnd, lParam);
  1754. pwd = (LPVOID)ppsp->lParam;
  1755. SendDlgItemMessage(hWnd, IDC_WIZBMP, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)pwd->hBmp);
  1756. #ifdef DEBUG
  1757. AuxDebugEx (5, DEBUGLINE TEXT ("MidiWizard.WM_INITDLG ppsp=%08X\r\n"), ppsp);
  1758. #endif
  1759. }
  1760. break;
  1761. case WM_DESTROY:
  1762. {
  1763. PWIZDATA pwd;
  1764. LPPROPSHEETPAGE ppsp = GetDlgData(hWnd);
  1765. if (ppsp && (pwd = (LPVOID)ppsp->lParam) != NULL)
  1766. {
  1767. if (pwd->mcl.hkMidi)
  1768. RegCloseKey (pwd->mcl.hkMidi), pwd->mcl.hkMidi = NULL;
  1769. #ifdef USE_IDF_ICONS
  1770. if (pwd->mcl.hIDFImageList)
  1771. {
  1772. HWND hWndT = GetDlgItem (hWnd, IDC_TYPES);
  1773. if (hWndT)
  1774. TreeView_SetImageList (hWndT, NULL, TVSIL_NORMAL);
  1775. ImageList_Destroy (pwd->mcl.hIDFImageList);
  1776. pwd->mcl.hIDFImageList = NULL;
  1777. }
  1778. #endif
  1779. }
  1780. }
  1781. break;
  1782. default:
  1783. bRet = FALSE;
  1784. break;
  1785. }
  1786. #if defined DEBUG || defined DEBUG_RETAIL
  1787. szNestLevel[0] = chNest;
  1788. #endif
  1789. return bRet;
  1790. }
  1791. INT CALLBACK
  1792. iSetupDlgCallback(
  1793. IN HWND hwndDlg,
  1794. IN UINT uMsg,
  1795. IN LPARAM lParam
  1796. )
  1797. /*++
  1798. Routine Description:
  1799. Call back used to remove the "?" from the wizard page.
  1800. Arguments:
  1801. hwndDlg - Handle to the property sheet dialog box.
  1802. uMsg - Identifies the message being received. This parameter
  1803. is one of the following values:
  1804. PSCB_INITIALIZED - Indicates that the property sheet is
  1805. being initialized. The lParam value is zero for this message.
  1806. PSCB_PRECREATE Indicates that the property sheet is about
  1807. to be created. The hwndDlg parameter is NULL and the lParam
  1808. parameter is a pointer to a dialog template in memory. This
  1809. template is in the form of a DLGTEMPLATE structure followed
  1810. by one or more DLGITEMTEMPLATE structures.
  1811. lParam - Specifies additional information about the message. The
  1812. meaning of this value depends on the uMsg parameter.
  1813. Return Value:
  1814. The function returns zero.
  1815. --*/
  1816. {
  1817. switch( uMsg )
  1818. {
  1819. case PSCB_INITIALIZED:
  1820. break;
  1821. case PSCB_PRECREATE:
  1822. if( lParam ){
  1823. DLGTEMPLATE *pDlgTemplate = (DLGTEMPLATE *)lParam;
  1824. pDlgTemplate->style &= ~DS_CONTEXTHELP;
  1825. }
  1826. break;
  1827. }
  1828. return FALSE;
  1829. }
  1830. /*+ MidiInstrumentsWizard
  1831. *
  1832. *-=================================================================*/
  1833. INT_PTR MidiInstrumentsWizard (
  1834. HWND hWnd,
  1835. PMCMIDI pmcm, // optional
  1836. LPTSTR pszDriverKey) // optional
  1837. {
  1838. WIZDATA wd;
  1839. PROPSHEETHEADER psh;
  1840. PROPSHEETPAGE psp;
  1841. UINT ii;
  1842. INT_PTR iRet = -1;
  1843. LPTSTR psz;
  1844. ZeroMemory (&wd, sizeof(wd));
  1845. wd.mcl.bDetails = TRUE;
  1846. wd.mcl.bRemote = TRUE;
  1847. wd.mcl.ixDevice = 0;
  1848. LoadString (ghInstance, IDS_DEF_DEFINITION, wd.mcl.szFile,
  1849. NUMELMS(wd.mcl.szFile));
  1850. // set the default driver key to what was passed.
  1851. // If someone passed us a path, rather than a driver key
  1852. // null out the '\\' characters so that we see only the
  1853. // leading driver part of the key.
  1854. //
  1855. wd.mcl.pszKey = wd.mcl.szFullKey;
  1856. if (pszDriverKey)
  1857. lstrcpy (wd.mcl.szFullKey, pszDriverKey);
  1858. if (!lstrnicmp (wd.mcl.pszKey, (LPTSTR)cszMidiSlash, lstrlen(cszMidiSlash)))
  1859. wd.mcl.pszKey += lstrlen(cszMidiSlash);
  1860. psz = wd.mcl.pszKey;
  1861. while (*psz)
  1862. {
  1863. if (*psz == TEXT('\\'))
  1864. *psz = 0;
  1865. ++psz;
  1866. }
  1867. // load all current instrument names from the registry
  1868. //
  1869. if (!(wd.pmcm = pmcm))
  1870. {
  1871. wd.pmcm = (LPVOID) LocalAlloc (LPTR, sizeof(MCMIDI));
  1872. if (!wd.pmcm) return -1;
  1873. LoadInstruments (wd.pmcm, FALSE);
  1874. }
  1875. psp.dwSize = sizeof(psp);
  1876. psp.dwFlags = PSP_DEFAULT;
  1877. psp.hInstance = ghInstance;
  1878. psp.pfnDlgProc = MidiWizardDlgProc;
  1879. psp.lParam = (LPARAM)&wd;
  1880. for (psh.nPages = 0, ii = 0; ii < NUMELMS(aidWiz); ++ii)
  1881. {
  1882. HPROPSHEETPAGE hpsp;
  1883. psp.pszTemplate = aidWiz[ii];
  1884. wd.ahpsp[psh.nPages] = hpsp = CreatePropertySheetPage(&psp);
  1885. if (hpsp)
  1886. ++psh.nPages;
  1887. }
  1888. if ( ! psh.nPages)
  1889. return -1;
  1890. wd.hBmp = LoadBitmap(ghInstance, MAKEINTRESOURCE(IDB_WIZBMP));
  1891. #ifdef DEBUG
  1892. AuxDebugEx (3, DEBUGLINE TEXT ("Wizard bitmap = %08X\r\n"));
  1893. #endif
  1894. psh.dwSize = sizeof(psh);
  1895. psh.dwFlags = PSH_PROPTITLE | PSH_WIZARD_LITE | PSH_USECALLBACK;
  1896. psh.hwndParent = hWnd;
  1897. psh.hInstance = ghInstance;
  1898. psh.pszCaption = MAKEINTRESOURCE(IDS_WIZNAME);
  1899. psh.nPages = NUMELMS(aidWiz);
  1900. psh.nStartPage = 0;
  1901. psh.phpage = wd.ahpsp;
  1902. psh.pfnCallback = iSetupDlgCallback;
  1903. iRet = PropertySheet (&psh);
  1904. // free dynamically allocated stuff.
  1905. //
  1906. if (wd.hBmp)
  1907. DeleteObject (wd.hBmp);
  1908. // if no MCMIDI was passed, we dynamically loaded one,
  1909. // so now we need to free it.
  1910. //
  1911. if ( ! pmcm)
  1912. {
  1913. if (wd.pmcm->hkMidi)
  1914. RegCloseKey (wd.pmcm->hkMidi);
  1915. FreeInstruments (wd.pmcm);
  1916. LocalFree ((HLOCAL)(UINT_PTR)(DWORD_PTR)wd.pmcm);
  1917. }
  1918. return iRet;
  1919. }