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.

3260 lines
120 KiB

  1. /*
  2. * MIDIMAP.C
  3. *
  4. * Copyright (C) 1990 Microsoft Corporation. All rights reserved.
  5. *
  6. * File I/O support routines for MIDI mapper and control panel.
  7. *
  8. * History:
  9. *
  10. * gregsi 30-Apr-91 midimap.ini -> midimap.cfg
  11. * t-mikemc 27-Sep-90 mapKeyMapInSetup, mapPatchMapInSetup, mapExists,
  12. * and mapGetUsageCount now all return DWORDS.
  13. * mapGetSize can return an error now.
  14. * t-mikemc 24-Sep-90 Added count to MMTABLE data structure. Made
  15. * deleting setups and patchmaps update usage count
  16. * of patchmaps and keymaps, respectively.
  17. * t-mikemc 23-Sep-90 Finally got that wNameID taken out of memory
  18. * data structures.
  19. * t-mikemc 22-Sep-90 Made MmaperrWriteSetup look for invalid port ID's
  20. * and write "invalid" device names correctly.
  21. * t-mikemc 21-Sep-90 Mucked about with the mapEnumerate function to
  22. * allow for enumeration of ports accessed by a setup.
  23. * t-mikemc 31-Jul-90 Added volume mapping and mapGetUsageCount API.
  24. * t-mikemc 15-Jul-90 Slew-o-changes! Munged Write/Read/Enum/Delete
  25. * API's together into single functions. Finished
  26. * up work on 'use-count' for patch and key maps.
  27. * Commented and generally cleaned up lots-o-code.
  28. * t-mikemc 05-Jul-90 Added mapPatchMapInSetup and mapKeyMapInSetup
  29. * functions.
  30. * t-mikemc 13-Jun-90 Removed wSize element from setup data structure.
  31. * Setups now read in size of each referenced
  32. * patchmap.
  33. * t-mikemc 20-May-90 Added DWORD dwFlags to all internal file data
  34. * structures.
  35. * t-mikemc 11-May-90 Changed enumeration functions so they send
  36. * name and description.
  37. * t-mikemc 19-Apr-90 Changed routines to use binary file format.
  38. * t-mikemc 17-Apr-90 Created.
  39. */
  40. // Please note that the use of "goto" statements in this module isn't
  41. // disgusting.
  42. //
  43. // brucemo
  44. // Well it disgusts me. I put readability before writeability.
  45. // The compiler generates no less than 17 messages saying that a
  46. // variable may be used before initialised, and that means that
  47. // either the thing is full of bugs (so Dijkstra was right) or
  48. // else it's having a tough time following the flow of the logic.
  49. // Me too.
  50. // For good measure, the optimisation in compilers is almost always
  51. // inhibited by goto.
  52. // LaurieGr
  53. #include <windows.h>
  54. #include <string.h>
  55. #define MMNOMCI
  56. #define MMNOJOY
  57. #define MMNOSOUND
  58. #define MMNOWAVE
  59. #include <mmsystem.h>
  60. #if defined(WIN32)
  61. #include <port1632.h>
  62. #endif //WIN32
  63. #include "hack.h"
  64. #include "midimap.h"
  65. #include "midi.h"
  66. #include "extern.h"
  67. /*-=-=-=-=- Global Definitions -=-=-=-=-*/
  68. #define MM_VERSION 1 // mapfile version number
  69. #define MM_NUMSETUP 100 // number of setups
  70. #define MM_NUMPATCH 100 // number of patchmaps
  71. #define MM_NUMKEY 100 // number of keymaps
  72. #define MAP_FOPEN 1 // open file
  73. #define MAP_FCREATE 2 // create/open file
  74. #define MAP_FCLOSE 3 // close file
  75. #define MAKEID(id) ((LPSTR) (LONG) (id))
  76. #define LSB 1 // LSB for usage byte
  77. #define MSB 128 // MSB for usage byte
  78. #define MAX_UNIQUENAME 32 // max length of unique name
  79. /*-=-=-=-=- Internal Data Structures -=-=-=-=-*/
  80. #pragma pack(1)
  81. // Internal file data structures
  82. typedef struct midimapkey_tag {
  83. WORD wUsing; // number of patchmaps using this
  84. BYTE bKMap[MIDIPATCHSIZE]; // translate table for key map
  85. DWORD dwFlags; // flags
  86. } MMKEY;
  87. typedef MMKEY UNALIGNED FAR *LPMMKEY;
  88. typedef struct midimappatch_tag {
  89. WORD wUsing; // number of setups using this
  90. BYTE bVMax; // max volume scalar
  91. WORD wPMap[MIDIPATCHSIZE]; // lobyte=xlat table, hibyte=volume // a PATCHARRAY?
  92. DWORD dwSize; // size of patchmap
  93. WORD idxKMapNames[MIDIPATCHSIZE]; // keymap name table indexes // a KEYARRAY?
  94. DWORD dwFlags; // flags
  95. } MMPATCH;
  96. typedef MMPATCH UNALIGNED FAR *LPMMPATCH;
  97. typedef struct midimapchannel_tag {
  98. WORD wChannel; // port channel of device
  99. BYTE szDevice[MAXPNAMELEN]; // device name
  100. WORD idxPMapName; // patchmap name table index
  101. DWORD dwFlags; // flags
  102. } MMCHANNEL;
  103. typedef MMCHANNEL UNALIGNED FAR *LPMMCHANNEL;
  104. typedef struct midimapsetup_tag {
  105. MMCHANNEL chMap[16]; // array of channel maps
  106. DWORD dwFlags; // flags
  107. } MMSETUP;
  108. typedef MMSETUP UNALIGNED FAR *LPMMSETUP;
  109. typedef struct midimaptableentry_tag {
  110. BYTE szName[MMAP_MAXNAME]; // name of map
  111. BYTE szDesc[MMAP_MAXDESC]; // description of map
  112. WORD idxEntry; // index of this entry in table
  113. DWORD doData; // file offset of data structure
  114. } MMTABLEENTRY;
  115. typedef MMTABLEENTRY UNALIGNED FAR *LPMMTABLEENTRY;
  116. typedef struct midimaptableheader_tag {
  117. WORD wEntrys; // number of entries in table
  118. WORD wUsed; // number of entries being used
  119. } MMTABLEHEADER;
  120. typedef MMTABLEHEADER UNALIGNED FAR *LPMMTABLEHEADER;
  121. typedef struct midimapheader_tag {
  122. WORD wVersion; // version number of file
  123. DWORD dwGarbage; // garbage collection bytes
  124. WORD idxCurSetup; // current setup table index
  125. WORD oSetup; // setup table offset
  126. WORD oPatch; // patchmap table offset
  127. WORD oKey; // keymap table offset
  128. } MMHEADER;
  129. // Internal memory data structures.
  130. typedef struct midimaptable_tag {
  131. WORD wCount; // times this table has been opened
  132. MMTABLEHEADER mmHeader; // header for this table
  133. HANDLE hEntrys; // handle to array of entrys
  134. } MMTABLE;
  135. typedef MMTABLE UNALIGNED FAR *LPMMTABLE;
  136. typedef struct uniquemap_tag {
  137. BYTE szName[MAX_UNIQUENAME];// unique map or port name
  138. DWORD dwOffset; // offset from base or device ID
  139. HANDLE hNext; // next one
  140. } UNIQUEMAP;
  141. typedef UNIQUEMAP UNALIGNED FAR *LPUNIQUEMAP;
  142. #pragma pack()
  143. /*-=-=-=-=- Function Prototypes -=-=-=-=-*/
  144. #define STATIC /**/
  145. STATIC MMAPERR NEAR PASCAL MmaperrAddMap(UINT, LPVOID, LPDWORD);
  146. STATIC MMAPERR NEAR PASCAL MmaperrChangeUsing(UINT, UINT, int);
  147. STATIC MMAPERR NEAR PASCAL MmaperrEnumPorts(ENUMPROC, UINT, HWND, LPSTR);
  148. STATIC MMAPERR NEAR PASCAL MmaperrFileAccess(int, int);
  149. STATIC VOID NEAR PASCAL VFreeUniqueList(LPHANDLE);
  150. STATIC VOID NEAR PASCAL VFreeTable(UINT);
  151. STATIC MMAPERR NEAR PASCAL MmaperrGarbage(UINT);
  152. STATIC DWORD NEAR PASCAL DwGetMapSize(UINT, LPSTR);
  153. STATIC DWORD NEAR PASCAL DwGetSetupSize(LPSTR);
  154. STATIC LPMMTABLEENTRY NEAR PASCAL LpGetTableEntry(HANDLE, LPSTR);
  155. STATIC LPSTR NEAR PASCAL LszGetUniqueAtOffset (DWORD, HANDLE);
  156. STATIC DWORD NEAR PASCAL LiNotUnique(LPSTR, LPHANDLE, DWORD);
  157. STATIC MMAPERR NEAR PASCAL MmaperrReadKeymap (LPSTR, LPMIDIKEYMAP);
  158. STATIC DWORD NEAR PASCAL DwReadPatchmap(LPSTR, LPMIDIPATCHMAP, BOOL);
  159. STATIC MMAPERR NEAR PASCAL MmaperrReadSetup(LPSTR, LPMIDIMAP);
  160. STATIC MMAPERR NEAR PASCAL MmaperrReadTable(UINT);
  161. STATIC MMAPERR NEAR PASCAL MmaperrWriteKeymap(LPMIDIKEYMAP);
  162. STATIC MMAPERR NEAR PASCAL MmaperrWritePatchmap(PATCHMAP FAR*);
  163. STATIC MMAPERR NEAR PASCAL MmaperrWriteSetup (SETUP FAR*);
  164. STATIC MMAPERR NEAR PASCAL MmaperrWriteTabEntry(UINT,
  165. UINT, LPMMTABLEENTRY);
  166. STATIC MMAPERR NEAR PASCAL MmaperrWriteTabHeader(UINT, LPMMTABLEHEADER);
  167. /*-=-=-=-=- Global Constants -=-=-=-=-*/
  168. TCHAR RegEntry[] =
  169. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Midimap");
  170. TCHAR RegCurrent[] = TEXT("Mapping Name");
  171. /*-=-=-=-=- Global Variables -=-=-=-=-*/
  172. char aszMapperPath[MAXPATHLEN+1]; // A Path Buffer to mapper file (real or temp)
  173. static HANDLE hPortList, // Unique port names list.
  174. hPatchList, // Unique patchmaps list.
  175. hKeyList; // Unique keymaps list.
  176. static HANDLE hSetupTable, // Setup table handle.
  177. hPatchTable, // Patch table handle.
  178. hKeyTable; // Key table handle.
  179. static HFILE iFile = HFILE_ERROR; // File handle.
  180. static UINT ucFileOpen; // times the (.CFG?) file has been opened
  181. static BOOL fEditing;
  182. // - - - - - - - - -
  183. void FAR PASCAL mapConnect(LPSTR lpszTmpPath)
  184. {
  185. // mapFileVersion will force the mapper to open the file
  186. // so we can change the filename from under it anyway
  187. lstrcpy(aszMapperPath,lpszTmpPath);
  188. fEditing = TRUE;
  189. }
  190. void FAR PASCAL mapDisconnect(void)
  191. {
  192. // We can't leave the temporary file open. Otherwise someone
  193. // might reference it after the applet disconnects.
  194. if (iFile != HFILE_ERROR)
  195. {
  196. ucFileOpen = 1; // Force it to close
  197. (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  198. }
  199. fEditing = FALSE;
  200. }
  201. /*
  202. * @doc INTERNAL
  203. *
  204. * @api int | mapFileVersion | This function obtains the version number of the
  205. * user's midi data file.
  206. *
  207. * @rdesc Returns a DWORD, the high word of which is an error code. If the
  208. * error code is MMAPERR_SUCCESS, the low word contains the version
  209. * number.
  210. */
  211. DWORD FAR PASCAL mapFileVersion (void)
  212. {
  213. MMHEADER mmHeader;
  214. DWORD dwRet;
  215. MMAPERR mmaperr;
  216. // This kludge is here in case MMSYSTEM crashes inside one of the
  217. // midimap functions that has the file open. In this case, iFile
  218. // will be non-null and the cpl applet will think there is no
  219. // midimap.cfg file.
  220. hPortList = NULL;
  221. hPatchList = NULL;
  222. hKeyList = NULL;
  223. hSetupTable = NULL;
  224. hPatchTable = NULL;
  225. hKeyTable = NULL;
  226. iFile = HFILE_ERROR;
  227. ucFileOpen = 0;
  228. mmaperr = MmaperrFileAccess(MAP_FOPEN,OF_READ);
  229. if (mmaperr != MMAPERR_SUCCESS)
  230. return MAKELONG(0, mmaperr);
  231. dwRet = ( _lread(iFile, (LPSTR)&mmHeader,sizeof(MMHEADER))
  232. != sizeof(MMHEADER)
  233. )
  234. ? MAKELONG(0, MMAPERR_READ)
  235. : MAKELONG(mmHeader.wVersion, MMAPERR_SUCCESS);
  236. (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  237. return dwRet;
  238. } /* mapFileVersion */
  239. // - - - - - - - - -
  240. /*
  241. * @doc INTERNAL
  242. *
  243. * @api BOOL | mapInitMapFile | This function initializes the user's
  244. * midi data file. It creates a file in the user's windows directory,
  245. * and fills it with the necessary header information. If the file
  246. * exists, it will be truncated to zero length first.
  247. *
  248. * @rdesc Returns non-zero if successful, otherwise zero.
  249. */
  250. // Issues:
  251. //
  252. // 1. Need to install "DeleteFile" code.
  253. MMAPERR FAR PASCAL mapInitMapFile (void)
  254. {
  255. SETUP setup;
  256. MMHEADER mmHeader;
  257. MMTABLEHEADER mmtHeader;
  258. MMTABLEENTRY mmtEntry;
  259. MMAPERR mmaperr;
  260. WORD wNum ;
  261. if ((mmaperr = MmaperrFileAccess(MAP_FCREATE,
  262. 0)) != MMAPERR_SUCCESS)
  263. return mmaperr;
  264. mmHeader.wVersion = MM_VERSION;
  265. mmHeader.dwGarbage = 0L;
  266. mmHeader.idxCurSetup = 0; // Set later in mapSetCurrentSetup
  267. mmHeader.oSetup = (wNum = sizeof(MMHEADER));
  268. mmHeader.oPatch = ( wNum += sizeof(MMTABLEHEADER) + MM_NUMSETUP*sizeof(MMTABLEENTRY) );
  269. mmHeader.oKey = (wNum += sizeof(MMTABLEHEADER) + MM_NUMPATCH*sizeof(MMTABLEENTRY) );
  270. if (_lwrite(iFile, (LPSTR)&mmHeader, sizeof(MMHEADER))
  271. != sizeof(MMHEADER)
  272. ) {
  273. mmaperr = MMAPERR_WRITE;
  274. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  275. exit01: // Delete file here.
  276. return mmaperr;
  277. }
  278. _fmemset(&mmtEntry, 0, sizeof(MMTABLEENTRY));
  279. mmtHeader.wUsed = 0;
  280. { UINT i;
  281. for (i = 0; i < 3; i++) {
  282. switch (i) {
  283. case 0:
  284. mmtHeader.wEntrys = MM_NUMSETUP;
  285. break;
  286. case 1:
  287. mmtHeader.wEntrys = MM_NUMPATCH;
  288. break;
  289. case 2:
  290. mmtHeader.wEntrys = MM_NUMKEY;
  291. break;
  292. }
  293. if (_lwrite(iFile, (LPSTR)&mmtHeader, sizeof(MMTABLEHEADER))
  294. != sizeof(MMTABLEHEADER)
  295. ) {
  296. mmaperr = MMAPERR_WRITE;
  297. goto exit00;
  298. }
  299. for (wNum = mmtHeader.wEntrys; wNum ; wNum --)
  300. if (_lwrite(iFile, (LPSTR)&mmtEntry,
  301. sizeof(MMTABLEENTRY)) !=
  302. sizeof(MMTABLEENTRY)) {
  303. mmaperr = MMAPERR_WRITE;
  304. goto exit00;
  305. }
  306. }
  307. }
  308. _fmemset(&setup, 0, sizeof(SETUP));
  309. LoadString( hLibInst
  310. , IDS_VANILLANAME
  311. , setup.aszSetupName
  312. , sizeof(setup.aszSetupName)
  313. );
  314. LoadString( hLibInst
  315. , IDS_VANILLADESC
  316. , setup.aszSetupDescription
  317. , sizeof(setup.aszSetupDescription)
  318. );
  319. { UINT wChan;
  320. for (wChan = 0; wChan < 16; wChan++) {
  321. setup.channels[wChan].wDeviceID = MMAP_ID_NOPORT;
  322. setup.channels[wChan].wChannel = (WORD)wChan;
  323. }
  324. }
  325. if ((mmaperr = MmaperrWriteSetup(&setup)) != MMAPERR_SUCCESS)
  326. goto exit00;
  327. if ((mmaperr = mapSetCurrentSetup(MAKEID(1))) != MMAPERR_SUCCESS)
  328. goto exit00;
  329. if ((mmaperr = MmaperrFileAccess(MAP_FCLOSE, 0)) != MMAPERR_SUCCESS)
  330. goto exit01; // 01, not 00.
  331. return MMAPERR_SUCCESS;
  332. } /* mapInitMapFile */
  333. // - - - - - - - - -
  334. /*
  335. * @doc INTERNAL
  336. *
  337. * @api UINT | mapSetCurrentSetup | This function sets the name of the current
  338. * setup.
  339. *
  340. * @parm LPSTR | lpSetupName | Specifies the name of a setup which you
  341. * want to be the current setup.
  342. *
  343. * @rdesc The return value is currently undefined.
  344. */
  345. // Issues:
  346. //
  347. // 1. None.
  348. MMAPERR FAR PASCAL mapSetCurrentSetup (LPSTR lpSetupName)
  349. {
  350. LPMMTABLEENTRY lpmmEntry;
  351. MMHEADER mmHeader;
  352. MMAPERR mmaperr;
  353. HKEY hKey;
  354. LONG lRet;
  355. /*
  356. ** See if the information is stored in the registry.
  357. ** If so write the stuff there. Otherwise fall thru and try to
  358. ** write the stuff into the mapper file.
  359. */
  360. lRet = RegOpenKey( HKEY_LOCAL_MACHINE, RegEntry, &hKey );
  361. if ( lRet == ERROR_SUCCESS ) {
  362. lRet = RegSetValueEx( hKey, RegCurrent, 0L, REG_SZ,
  363. (LPBYTE)lpSetupName,
  364. sizeof(TCHAR) * (1 + lstrlen(lpSetupName)));
  365. RegCloseKey( hKey );
  366. if ( lRet == ERROR_SUCCESS) {
  367. return MMAPERR_SUCCESS;
  368. }
  369. }
  370. if ((mmaperr = MmaperrFileAccess(MAP_FOPEN,
  371. OF_READWRITE)) != MMAPERR_SUCCESS)
  372. return mmaperr;
  373. if ((mmaperr = MmaperrReadTable(MMAP_SETUP)) != MMAPERR_SUCCESS) {
  374. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  375. return mmaperr;
  376. }
  377. lpmmEntry = LpGetTableEntry(hSetupTable,
  378. lpSetupName);
  379. if (_llseek(iFile, 0L, 0) == -1L) {
  380. mmaperr = MMAPERR_READ;
  381. exit01: VFreeTable(MMAP_SETUP);
  382. goto exit00;
  383. }
  384. if (_lread(iFile, (LPSTR)&mmHeader,
  385. sizeof(MMHEADER)) != sizeof(MMHEADER)) {
  386. mmaperr = MMAPERR_READ;
  387. goto exit01;
  388. }
  389. mmHeader.idxCurSetup = lpmmEntry->idxEntry;
  390. if (_llseek(iFile, 0L, 0) == -1L) {
  391. mmaperr = MMAPERR_WRITE;
  392. goto exit01;
  393. }
  394. if (_lwrite(iFile, (LPSTR)&mmHeader,
  395. sizeof(MMHEADER)) != sizeof(MMHEADER)) {
  396. mmaperr = MMAPERR_WRITE;
  397. goto exit01;
  398. }
  399. VFreeTable(MMAP_SETUP);
  400. if ((mmaperr = MmaperrFileAccess(MAP_FCLOSE, 0)) != MMAPERR_SUCCESS)
  401. return mmaperr;
  402. return MMAPERR_SUCCESS;
  403. } /* mapSetCurrentSetup */
  404. // - - - - - - - - -
  405. /*
  406. * @doc INTERNAL
  407. *
  408. * @api LPSTR | mapGetCurrentSetup | This function retrieves the name of the
  409. * current setup.
  410. *
  411. * @parm LPSTR | lpBuf | Specifies a buffer into which the current setup
  412. * name will be copied.
  413. *
  414. * @parm UINT | wSize | Specifies the size in bytes of <p lpBuf>.
  415. *
  416. * @rdesc Returns an MMAP error, or zero on success.
  417. *
  418. * @comm You should make sure that the supplied buffer and size are at
  419. * least MMAP_MAXNAME characters (defined in MMSYSTEM.H).
  420. */
  421. // Issues:
  422. //
  423. // 1. None.
  424. MMAPERR FAR PASCAL mapGetCurrentSetup(
  425. LPSTR lpBuf,
  426. UINT uSize)
  427. {
  428. LPMMTABLEENTRY lpmmEntry;
  429. MMHEADER mmHeader;
  430. MMAPERR mmaperr;
  431. LPSTR lpEntryName;
  432. LPSTR lp;
  433. HKEY hKey;
  434. LONG lRet;
  435. /*
  436. ** See if the information is stored in the registry.
  437. ** If so read the stuff from there. Otherwise fall thru and try to
  438. ** get the stuff from the mapper file.
  439. */
  440. lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  441. RegEntry,
  442. 0L,
  443. KEY_QUERY_VALUE,
  444. &hKey );
  445. if (lRet == ERROR_SUCCESS) {
  446. DWORD dwType, dwLen;
  447. dwLen = uSize;
  448. lRet = RegQueryValueEx( hKey, RegCurrent, 0L, &dwType,
  449. (LPBYTE)lpBuf, &dwLen );
  450. RegCloseKey( hKey );
  451. if ( lRet == ERROR_SUCCESS) {
  452. return MMAPERR_SUCCESS;
  453. }
  454. }
  455. /* attempt to open file, read setup table */
  456. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READ);
  457. if (mmaperr != MMAPERR_SUCCESS)
  458. return mmaperr;
  459. mmaperr = MmaperrReadTable(MMAP_SETUP);
  460. if (mmaperr != MMAPERR_SUCCESS) {
  461. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  462. return mmaperr;
  463. }
  464. // read the file header
  465. if (_llseek(iFile, 0L, 0) == -1L) {
  466. mmaperr = MMAPERR_READ;
  467. exit01: VFreeTable(MMAP_SETUP);
  468. goto exit00;
  469. }
  470. if (_lread(iFile, (LPSTR)&mmHeader, sizeof(MMHEADER))
  471. != sizeof(MMHEADER)
  472. ) {
  473. mmaperr = MMAPERR_READ;
  474. goto exit01;
  475. }
  476. lpmmEntry = LpGetTableEntry(hSetupTable, MAKEID(mmHeader.idxCurSetup)); // Always succeed.
  477. // lstrncmp (lpBuf, lpmmEntry->szName, uSize - 1);
  478. for (lp = lpBuf, lpEntryName = (LPSTR)(lpmmEntry->szName); --uSize; )
  479. *lp++ = *lpEntryName++;
  480. *lp = '\0';
  481. // free table, close file and leave
  482. VFreeTable(MMAP_SETUP);
  483. (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  484. return MMAPERR_SUCCESS;
  485. } /* mapGetCurrentSetup */
  486. // - - - - - - - - -
  487. MMAPERR FAR PASCAL mapReadSetup(
  488. LPSTR lszSetupName,
  489. SETUP FAR* lpSetup)
  490. {
  491. LPMMCHANNEL lpmmChan;
  492. LPMMTABLEENTRY lpmmEntry;
  493. MMSETUP mmSetup;
  494. MMAPERR mmaperr;
  495. UINT wNumDevs;
  496. BOOL fNoPort;
  497. int i;
  498. UINT wDev;
  499. // open file, read in pertinent tables
  500. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READ);
  501. if (mmaperr != MMAPERR_SUCCESS) {
  502. return mmaperr;
  503. }
  504. fNoPort = FALSE;
  505. mmaperr = MmaperrReadTable(MMAP_SETUP | MMAP_PATCH | MMAP_KEY);
  506. if (mmaperr != MMAPERR_SUCCESS) {
  507. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  508. return mmaperr;
  509. }
  510. lpmmEntry = LpGetTableEntry(hSetupTable, lszSetupName);
  511. if (lpmmEntry == NULL) {
  512. mmaperr = MMAPERR_INVALIDSETUP;
  513. exit01: VFreeTable(MMAP_SETUP | MMAP_PATCH | MMAP_KEY);
  514. goto exit00;
  515. }
  516. // read in setup data from file
  517. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  518. mmaperr = MMAPERR_READ;
  519. goto exit01;
  520. }
  521. if (_lread(iFile, (LPSTR)&mmSetup, sizeof(MMSETUP)) != sizeof(MMSETUP)){
  522. mmaperr = MMAPERR_READ;
  523. goto exit01;
  524. }
  525. // copy over setup name, description, and flags
  526. lstrcpy(lpSetup->aszSetupName, (LPCSTR)(lpmmEntry->szName));
  527. lstrcpy(lpSetup->aszSetupDescription, (LPCSTR)(lpmmEntry->szDesc));
  528. lpSetup->dFlags = mmSetup.dwFlags;
  529. // grab the number of devices in the current environment
  530. wNumDevs = midiOutGetNumDevs();
  531. // set up a couple of optimization-pointers
  532. lpmmChan = (LPMMCHANNEL)(mmSetup.chMap); // MIPS silliness
  533. for (i = 0; i < 16; i++, lpmmChan++) {
  534. // convert device name to device ID. If device name doesn't
  535. // exist in the current environment, set ID to MMAP_ID_NOPORT
  536. if (!*lpmmChan->szDevice)
  537. wDev = wNumDevs;
  538. else
  539. for (wDev = 0; wDev < wNumDevs; wDev++) {
  540. MIDIOUTCAPS moCaps;
  541. midiOutGetDevCaps(wDev, &moCaps, sizeof(MIDIOUTCAPS));
  542. if (!lstrcmpi( moCaps.szPname
  543. , (LPCSTR)(lpmmChan->szDevice)))
  544. break;
  545. }
  546. // copy over channel and flag info
  547. lpSetup->channels[i].wChannel = lpmmChan->wChannel;
  548. lpSetup->channels[i].dFlags = lpmmChan->dwFlags;
  549. if (wDev < wNumDevs)
  550. lpSetup->channels[i].wDeviceID = (WORD)wDev;
  551. else {
  552. lpSetup->channels[i].wDeviceID = MMAP_ID_NOPORT;
  553. // this error code only if there was a port
  554. // name but it does not exist on the current system.
  555. if (*lpmmChan->szDevice)
  556. fNoPort = TRUE;
  557. }
  558. // if channel has no patchmap then on to next channel
  559. if (!lpmmChan->idxPMapName) {
  560. lstrcpy(lpSetup->channels[i].aszPatchName, szNone);
  561. continue;
  562. }
  563. lpmmEntry = LpGetTableEntry(hPatchTable, MAKEID(lpmmChan->idxPMapName));
  564. lstrcpy( lpSetup->channels[i].aszPatchName
  565. , (LPCSTR)(lpmmEntry->szName));
  566. }
  567. VFreeTable(MMAP_SETUP | MMAP_PATCH | MMAP_KEY);
  568. MmaperrFileAccess(MAP_FCLOSE, 0);
  569. if (fNoPort)
  570. return MMAPERR_INVALIDPORT;
  571. return MMAPERR_SUCCESS;
  572. }
  573. MMAPERR FAR PASCAL mapReadPatchMap(
  574. LPSTR lszPatchMapName,
  575. PATCHMAP FAR* lpPatch)
  576. {
  577. LPMMTABLEENTRY lpmmEntry;
  578. MMPATCH mmPatch;
  579. UNALIGNED WORD *lpwKey;
  580. MMAPERR mmaperr;
  581. int i;
  582. // open file, read in pertinent tables
  583. mmaperr = MmaperrFileAccess(MAP_FOPEN,OF_READ);
  584. if (mmaperr != MMAPERR_SUCCESS)
  585. return mmaperr;
  586. mmaperr = MmaperrReadTable(MMAP_PATCH | MMAP_KEY);
  587. if (mmaperr != MMAPERR_SUCCESS) {
  588. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  589. return mmaperr;
  590. }
  591. lpmmEntry = LpGetTableEntry(hPatchTable, lszPatchMapName);
  592. if (lpmmEntry == NULL) {
  593. mmaperr = MMAPERR_INVALIDPATCH;
  594. exit01: VFreeTable(MMAP_PATCH | MMAP_KEY);
  595. goto exit00;
  596. }
  597. // read in patch data from file
  598. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  599. mmaperr = MMAPERR_READ;
  600. goto exit01;
  601. }
  602. if ( _lread(iFile, (LPSTR)&mmPatch, sizeof(MMPATCH))
  603. != sizeof(MMPATCH)
  604. ) {
  605. mmaperr = MMAPERR_READ;
  606. goto exit01;
  607. }
  608. // copy data from file structure to memory structure
  609. lstrcpy(lpPatch->aszPatchMapName, (LPCSTR)(lpmmEntry->szName));
  610. lstrcpy(lpPatch->aszPatchMapDescription, (LPCSTR)(lpmmEntry->szDesc));
  611. // set up an optimization pointer
  612. lpwKey = mmPatch.idxKMapNames;
  613. for (i = 0; i < MIDIPATCHSIZE; i++, lpwKey++) {
  614. lpPatch->keymaps[i].bVolume = HIBYTE(mmPatch.wPMap[i]);
  615. lpPatch->keymaps[i].bDestination = LOBYTE(mmPatch.wPMap[i]);
  616. if (!*lpwKey) {
  617. lstrcpy(lpPatch->keymaps[i].aszKeyMapName, szNone);
  618. continue;
  619. }
  620. lpmmEntry = LpGetTableEntry(hKeyTable, MAKEID(*lpwKey));
  621. lstrcpy( lpPatch->keymaps[i].aszKeyMapName
  622. , (LPCSTR)(lpmmEntry->szName));
  623. }
  624. // free table, close file and leave
  625. VFreeTable(MMAP_PATCH | MMAP_KEY);
  626. (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  627. return MMAPERR_SUCCESS;
  628. }
  629. // - - - - - - - - -
  630. /* @doc INTERNAL
  631. *
  632. * @api DWORD | mapRead | Read a map specified by <p lpName> into a buffer
  633. * specified by <p lpvBuf>. This includes any patchmaps or keymaps
  634. * that the map may contain.
  635. *
  636. * @parm UINT | wFlag | Specifies the type of map to be read into memory.
  637. * It may be any of the following:
  638. *
  639. * @flag MMAP_SETUP | Read a setup.
  640. * @flag MMAP_PATCH | Read a patchmap.
  641. * @flag MMAP_KEY | Read a keymap.
  642. *
  643. * @parm LPSTR | lpName | Specifies the name of the map of which you
  644. * want read into memory.
  645. *
  646. * @rdesc Returns an MMAP error code, or zero on success.
  647. */
  648. // Issues:
  649. //
  650. // 1. None.
  651. MMAPERR FAR PASCAL mapRead(
  652. UINT uFlag,
  653. LPSTR lpName,
  654. LPVOID lpvBuf)
  655. {
  656. switch (uFlag) {
  657. DWORD dwRet;
  658. case MMAP_SETUP:
  659. return MmaperrReadSetup(lpName, (LPMIDIMAP)lpvBuf);
  660. case MMAP_PATCH:
  661. dwRet = DwReadPatchmap(lpName,(LPMIDIPATCHMAP)lpvBuf, FALSE);
  662. if (dwRet < MMAPERR_MAXERROR)
  663. return LOWORD(dwRet);
  664. return MMAPERR_SUCCESS;
  665. case MMAP_KEY:
  666. return MmaperrReadKeymap(lpName, (LPMIDIKEYMAP)lpvBuf);
  667. }
  668. } /* mapRead */
  669. // - - - - - - - - -
  670. // MmaperrReadSetup
  671. //
  672. // Read a setup into a buffer. This includes any patchmaps or keymaps
  673. // that the setup may contain.
  674. //
  675. // NOTE: This function will return MMAPERR_INVALIDPORT if the setup to
  676. // be read accesses ports that are not available on the system. That is,
  677. // if it accesses ports not listed as a 'midix=xxx.drv' entry under the
  678. // [drivers] section in system.ini. The entire setup WILL BE read into
  679. // memory but the uDeviceID for the channels with inaccessible ports will
  680. // be set to MMAP_ID_NOPORT. This error also has NO EFFECT on the
  681. // active/inactive status of any such channels.
  682. //
  683. // Issues:
  684. //
  685. // 1. There's a comment about something breaking a segment
  686. // boundary in here, but if it does break the segment boundary
  687. // the way it's dealt with it looks like it will wipe out.
  688. //
  689. // 2. Freeing the "hKeyList" chain may be unnecessary if the
  690. // patch map read routine cleans up after itself properly.
  691. STATIC MMAPERR NEAR PASCAL MmaperrReadSetup(
  692. LPSTR lpName,
  693. LPMIDIMAP lpmMap)
  694. {
  695. LPMIDICHANNELMAP lpChan;
  696. LPMMCHANNEL lpmmChan;
  697. LPMIDIPATCHMAP lpPatch;
  698. LPMMTABLEENTRY lpmmEntry;
  699. MMSETUP mmSetup;
  700. MIDIOUTCAPS moCaps;
  701. MMAPERR mmaperr;
  702. DWORD dwOffset;
  703. UINT wNumDevs;
  704. BOOL fNoPort;
  705. int i;
  706. UINT wDev;
  707. // open file, read in pertinent tables
  708. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READ);
  709. if (mmaperr != MMAPERR_SUCCESS)
  710. return mmaperr;
  711. fNoPort = FALSE;
  712. mmaperr = MmaperrReadTable(MMAP_SETUP | MMAP_PATCH | MMAP_KEY);
  713. if (mmaperr != MMAPERR_SUCCESS) {
  714. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  715. return mmaperr;
  716. }
  717. dwOffset = sizeof(MIDIMAP);
  718. lpmmEntry = LpGetTableEntry(hSetupTable, lpName);
  719. if (lpmmEntry == NULL) {
  720. mmaperr = MMAPERR_INVALIDSETUP;
  721. exit01: VFreeTable(MMAP_SETUP | MMAP_PATCH | MMAP_KEY);
  722. goto exit00;
  723. }
  724. // read in setup data from file
  725. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  726. mmaperr = MMAPERR_READ;
  727. goto exit01;
  728. }
  729. if (_lread(iFile, (LPSTR)&mmSetup, sizeof(MMSETUP)) != sizeof(MMSETUP)){
  730. mmaperr = MMAPERR_READ;
  731. goto exit01;
  732. }
  733. // copy over setup name, description, and flags
  734. lstrcpy(lpmMap->szName, (LPCSTR)(lpmmEntry->szName));
  735. lstrcpy(lpmMap->szDesc, (LPCSTR)(lpmmEntry->szDesc));
  736. lpmMap->dwFlags = mmSetup.dwFlags;
  737. // grab the number of devices in the current environment
  738. wNumDevs = midiOutGetNumDevs();
  739. // set up a couple of optimization-pointers
  740. lpChan = lpmMap->chMap;
  741. lpmmChan = (LPMMCHANNEL)(mmSetup.chMap); // MIPS silliness
  742. for (i = 0; i < 16; i++, lpChan++, lpmmChan++) {
  743. // convert device name to device ID. If device name doesn't
  744. // exist in the current environment, set ID to MMAP_ID_NOPORT
  745. if (!*lpmmChan->szDevice)
  746. wDev = wNumDevs;
  747. else
  748. for (wDev = 0; wDev < wNumDevs; wDev++) {
  749. midiOutGetDevCaps(wDev, &moCaps, sizeof(MIDIOUTCAPS));
  750. if (!lstrcmpi(moCaps.szPname,
  751. (LPCSTR)(lpmmChan->szDevice)))
  752. break;
  753. }
  754. // copy over channel and flag info
  755. lpChan->wChannel = lpmmChan->wChannel;
  756. lpChan->dwFlags = lpmmChan->dwFlags;
  757. if (wDev < wNumDevs)
  758. lpChan->wDeviceID = (WORD)wDev;
  759. else {
  760. lpChan->wDeviceID = MMAP_ID_NOPORT;
  761. // this error code only if there was a port
  762. // name but it does not exist on the current system.
  763. if (*lpmmChan->szDevice)
  764. fNoPort = TRUE;
  765. }
  766. // if channel has no patchmap then on to next channel
  767. if (!lpmmChan->idxPMapName)
  768. continue;
  769. // channel has a patchmap - if its not unique, point offset
  770. // to first occurance, otherwise offset = dwOffset.
  771. // assuming this patchmap ID is valid!
  772. lpmmEntry = LpGetTableEntry(hPatchTable,
  773. MAKEID(lpmmChan->idxPMapName));
  774. lpChan->oPMap = LiNotUnique( (LPSTR)(lpmmEntry->szName)
  775. , &hPatchList
  776. , dwOffset
  777. );
  778. if (lpChan->oPMap == -1L) {
  779. mmaperr = MMAPERR_MEMORY;
  780. exit02: VFreeUniqueList(&hPatchList);
  781. VFreeUniqueList(&hKeyList);
  782. goto exit01;
  783. } else if (!lpChan->oPMap) {
  784. DWORD dwRet;
  785. lpChan->oPMap = dwOffset;
  786. // setup patchmap pointer; could break segment bounds
  787. lpPatch = (LPMIDIPATCHMAP)((LPSTR)lpmMap + dwOffset);
  788. // read in patchmap (this also updates global offset)
  789. dwRet = DwReadPatchmap(0L, lpPatch, TRUE);
  790. if (dwRet < MMAPERR_MAXERROR) {
  791. mmaperr = LOWORD(dwRet);
  792. goto exit02;
  793. }
  794. dwOffset += dwRet;
  795. }
  796. }
  797. VFreeUniqueList(&hPatchList);
  798. VFreeUniqueList(&hKeyList);
  799. VFreeTable(MMAP_SETUP | MMAP_PATCH | MMAP_KEY);
  800. (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  801. if (fNoPort)
  802. return MMAPERR_INVALIDPORT;
  803. return MMAPERR_SUCCESS;
  804. } /* MmaperrReadSetup */
  805. // - - - - - - - - -
  806. // DwReadPatchmap
  807. //
  808. // Read a patchmap into a buffer. This includes any keymaps the patchmap
  809. // may contain.
  810. //
  811. // Remarks:
  812. //
  813. // 1. Use of "fInSetup" flag is very bogus, may cause problems, is
  814. // probably wrong.
  815. STATIC DWORD NEAR PASCAL DwReadPatchmap(
  816. LPSTR lpName,
  817. LPMIDIPATCHMAP lpPatch,
  818. BOOL fInSetup)
  819. {
  820. LPMMTABLEENTRY lpmmEntry;
  821. LPMIDIKEYMAP lpKey;
  822. MMPATCH mmPatch;
  823. UNALIGNED WORD *lpwKey;
  824. MMAPERR mmaperr;
  825. DWORD dwOffset;
  826. int i;
  827. // open file, read in pertinent tables
  828. mmaperr = MmaperrFileAccess(MAP_FOPEN,OF_READ);
  829. if (mmaperr != MMAPERR_SUCCESS)
  830. return MAKELONG(mmaperr, 0);
  831. mmaperr = MmaperrReadTable(MMAP_PATCH |MMAP_KEY);
  832. if (mmaperr != MMAPERR_SUCCESS) {
  833. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  834. return MAKELONG(mmaperr, 0);
  835. }
  836. // save global offset then initialize it to patch size
  837. dwOffset = sizeof(MIDIPATCHMAP);
  838. lpmmEntry = LpGetTableEntry(hPatchTable, lpName);
  839. if (lpmmEntry == NULL) {
  840. mmaperr = MMAPERR_INVALIDPATCH;
  841. exit01: VFreeTable(MMAP_PATCH | MMAP_KEY);
  842. goto exit00;
  843. }
  844. // read in patch data from file
  845. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  846. mmaperr = MMAPERR_READ;
  847. goto exit01;
  848. }
  849. if (_lread(iFile, (LPSTR)&mmPatch,sizeof(MMPATCH)) != sizeof(MMPATCH)) {
  850. mmaperr = MMAPERR_READ;
  851. goto exit01;
  852. }
  853. // copy data from file structure to memory structure
  854. lstrcpy(lpPatch->szName, (LPCSTR)(lpmmEntry->szName));
  855. lstrcpy(lpPatch->szDesc, (LPCSTR)(lpmmEntry->szDesc));
  856. _fmemcpy((LPSTR)lpPatch->wPMap, (LPSTR)mmPatch.wPMap, MIDIPATCHSIZE * sizeof(WORD));
  857. _fmemset((LPSTR)lpPatch->okMaps, 0, MIDIPATCHSIZE * sizeof(DWORD));
  858. lpPatch->dwFlags = mmPatch.dwFlags;
  859. lpPatch->bVMax = mmPatch.bVMax;
  860. // set up an optimization pointer
  861. lpwKey = mmPatch.idxKMapNames;
  862. for (i = 0; i < MIDIPATCHSIZE; i++, lpwKey++) {
  863. // if no keymap for this patch then continue
  864. if (!*lpwKey)
  865. continue;
  866. // patch has a keymap - if its unique point offset to
  867. // to first occurance, otherwise offset = dwOffset.
  868. // assuming this keymap ID is valid!
  869. lpmmEntry = LpGetTableEntry(hKeyTable, MAKEID(*lpwKey));
  870. lpPatch->okMaps[i] = LiNotUnique( (LPSTR)(lpmmEntry->szName)
  871. , &hKeyList, dwOffset);
  872. if (lpPatch->okMaps[i] == -1L) {
  873. mmaperr = MMAPERR_MEMORY;
  874. goto exit01;
  875. } else if (!lpPatch->okMaps[i]) {
  876. lpPatch->okMaps[i] = dwOffset;
  877. // set the keymap pointer; could break segment bounds
  878. lpKey = (LPMIDIKEYMAP)((LPSTR)lpPatch + dwOffset);
  879. // read in the keymap, update global offset
  880. mmaperr = MmaperrReadKeymap(0L, lpKey);
  881. if (mmaperr != MMAPERR_SUCCESS) {
  882. VFreeUniqueList(&hKeyList);
  883. goto exit01;
  884. }
  885. dwOffset += sizeof(MIDIKEYMAP);
  886. }
  887. }
  888. if (!fInSetup) {
  889. // if we're not called from ReadSetup, free the unique
  890. // keymap name list.
  891. VFreeUniqueList(&hKeyList);
  892. }
  893. // free table, close file and leave
  894. VFreeTable(MMAP_PATCH | MMAP_KEY);
  895. (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  896. return dwOffset;
  897. } /* DwReadPatchmap */
  898. // - - - - - - - - -
  899. // MmaperrReadKeymap
  900. //
  901. // Read a keymap into a buffer.
  902. //
  903. // Remarks:
  904. //
  905. // 1. None.
  906. STATIC MMAPERR NEAR PASCAL MmaperrReadKeymap(
  907. LPSTR lpName,
  908. LPMIDIKEYMAP lpKey)
  909. {
  910. LPMMTABLEENTRY lpmmEntry;
  911. MMKEY mmKey;
  912. MMAPERR mmaperr;
  913. // open file, read in pertinent tables
  914. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READ);
  915. if (mmaperr != MMAPERR_SUCCESS)
  916. return mmaperr;
  917. mmaperr = MmaperrReadTable(MMAP_KEY);
  918. if (mmaperr != MMAPERR_SUCCESS) {
  919. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  920. return mmaperr;
  921. }
  922. // assuming keymap exists
  923. lpmmEntry = LpGetTableEntry(hKeyTable, lpName);
  924. // read in key data from file
  925. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  926. mmaperr = MMAPERR_READ;
  927. exit01: VFreeTable(MMAP_KEY);
  928. goto exit00;
  929. }
  930. if (_lread(iFile, (LPSTR)&mmKey, sizeof(mmKey)) != sizeof(mmKey)) {
  931. mmaperr = MMAPERR_READ;
  932. goto exit01;
  933. }
  934. // copy data from file structure to memory structure
  935. lstrcpy(lpKey->szName, (LPCSTR)(lpmmEntry->szName));
  936. lstrcpy(lpKey->szDesc, (LPCSTR)(lpmmEntry->szDesc));
  937. _fmemcpy(lpKey->bKMap, (LPCSTR)(mmKey.bKMap), MIDIPATCHSIZE * sizeof(BYTE));
  938. lpKey->dwFlags = mmKey.dwFlags;
  939. // free table, close file and leave
  940. VFreeTable(MMAP_KEY);
  941. (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  942. return MMAPERR_SUCCESS;
  943. } /* MmaperrReadKeymap */
  944. // - - - - - - - - -
  945. /* @doc INTERNAL
  946. *
  947. * @api DWORD | mapWrite | Write a map specified by <p lpvMap> to the
  948. * midi data file.
  949. *
  950. * @parm UINT | uFlag | Specifies the type of map to write.
  951. * It may be any of the following:
  952. *
  953. * @flag MMAP_SETUP | Write a setup.
  954. * @flag MMAP_PATCH | Write a patchmap.
  955. * @flag MMAP_KEY | Write a keymap.
  956. *
  957. * @parm LPVOID | lpvMap | Specifies the map to write to the midi data file.
  958. *
  959. * @rdesc Returns non-zero if it could do the write, zero if it failed.
  960. */
  961. // Remarks:
  962. //
  963. // 1. None.
  964. MMAPERR FAR PASCAL mapWrite(
  965. UINT uFlag,
  966. LPVOID lpvMap)
  967. {
  968. switch (uFlag) {
  969. case MMAP_SETUP :
  970. return MmaperrWriteSetup((SETUP FAR*)lpvMap);
  971. case MMAP_PATCH :
  972. return MmaperrWritePatchmap((PATCHMAP FAR*)lpvMap);
  973. case MMAP_KEY :
  974. return MmaperrWriteKeymap((LPMIDIKEYMAP)lpvMap);
  975. }
  976. } /* mapWrite */
  977. // - - - - - - - - -
  978. // MmaperrWriteSetup
  979. //
  980. // Write a setup to the midi data file.
  981. STATIC MMAPERR NEAR PASCAL MmaperrWriteSetup(SETUP FAR* lpSetup)
  982. {
  983. HANDLE hPatchUsage;
  984. LPMMTABLE lpmmTable;
  985. LPMMTABLEENTRY lpmmEntry;
  986. LPMMCHANNEL lpmmChan;
  987. LPBYTE lpbPatchUsage = NULL; // Kill spurious use before set diagnostic
  988. MMSETUP mmOldSetup;
  989. MMSETUP mmSetup;
  990. MIDIOUTCAPS moCaps;
  991. MMAPERR mmaperr;
  992. DWORD doData;
  993. UINT wNumDevs;
  994. UINT wOldDevs;
  995. UINT uSize;
  996. BOOL fExists;
  997. UINT uIndex;
  998. UINT wDev;
  999. // open file, read in pertinent tables
  1000. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READWRITE);
  1001. if (mmaperr != MMAPERR_SUCCESS)
  1002. return mmaperr;
  1003. mmaperr = MmaperrReadTable(MMAP_SETUP | MMAP_PATCH);
  1004. if (mmaperr != MMAPERR_SUCCESS) {
  1005. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  1006. return mmaperr;
  1007. }
  1008. // check to see if setup name already exists
  1009. fExists = FALSE;
  1010. lpmmEntry = LpGetTableEntry(hSetupTable, lpSetup->aszSetupName);
  1011. if (lpmmEntry != NULL) {
  1012. // setup name exists. if the description has changed, we
  1013. // have to re-write the table entry with new description
  1014. if (lstrcmpi((LPCSTR)(lpmmEntry->szDesc)
  1015. , lpSetup->aszSetupDescription)) {
  1016. lstrcpy( (LPSTR)(lpmmEntry->szDesc)
  1017. , lpSetup->aszSetupDescription);
  1018. mmaperr = MmaperrWriteTabEntry(MMAP_SETUP, 0, lpmmEntry);
  1019. if (mmaperr != MMAPERR_SUCCESS) {
  1020. exit01: VFreeTable(MMAP_SETUP | MMAP_PATCH);
  1021. goto exit00;
  1022. }
  1023. }
  1024. doData = lpmmEntry->doData;
  1025. fExists = TRUE;
  1026. }
  1027. // name non-existent, so add a new table entry
  1028. else if ((mmaperr = MmaperrAddMap(MMAP_SETUP, (LPVOID)lpSetup, &doData))
  1029. != MMAPERR_SUCCESS
  1030. )
  1031. goto exit01;
  1032. // zero-out the new setup data structure
  1033. _fmemset((LPSTR)&mmSetup, 0, sizeof(MMSETUP));
  1034. // obtain the number of entrys in the patch table
  1035. lpmmTable = (LPMMTABLE)GlobalLock(hPatchTable);
  1036. uSize = lpmmTable->mmHeader.wEntrys;
  1037. GlobalUnlock(hPatchTable);
  1038. // if there are any patchmaps
  1039. hPatchUsage = NULL;
  1040. if (uSize) {
  1041. // Create table which is 'number-of-patchmaps' in length
  1042. hPatchUsage = GlobalAlloc(GHND, (LONG)uSize);
  1043. if (hPatchUsage == NULL) {
  1044. mmaperr = MMAPERR_MEMORY;
  1045. goto exit01;
  1046. }
  1047. lpbPatchUsage = (LPBYTE)GlobalLock(hPatchUsage);
  1048. // if this is not a new map
  1049. if (fExists) {
  1050. // read in old setup data from file
  1051. if (_llseek(iFile, doData, 0) == -1L) {
  1052. mmaperr = MMAPERR_READ;
  1053. exit02: if (hPatchUsage != NULL) {
  1054. GlobalUnlock(hPatchUsage);
  1055. GlobalFree(hPatchUsage);
  1056. }
  1057. goto exit01;
  1058. }
  1059. if ( _lread(iFile, (LPSTR)&mmOldSetup,sizeof(MMSETUP))
  1060. != sizeof(MMSETUP)
  1061. ) {
  1062. mmaperr = MMAPERR_READ;
  1063. goto exit02;
  1064. }
  1065. // set LSB of usage table indices where old setup
  1066. // referenced any respective patchmaps
  1067. for (uIndex = 0; uIndex < 16; uIndex++)
  1068. {
  1069. UINT u;
  1070. u = mmOldSetup.chMap[uIndex].idxPMapName;
  1071. if (u)
  1072. lpbPatchUsage[u - 1] = LSB;
  1073. }
  1074. }
  1075. }
  1076. // get the number of devices
  1077. wNumDevs = wOldDevs = midiOutGetNumDevs();
  1078. // enumerate any invalid ports from old setup this is not a new map
  1079. if (fExists) {
  1080. uIndex = 0;
  1081. lpmmChan = (LPMMCHANNEL)(mmOldSetup.chMap); // MIPS silliness
  1082. } else {
  1083. uIndex = 16;
  1084. lpmmChan = 0; // wasn't set. LKG
  1085. }
  1086. for (; uIndex < 16; uIndex++, lpmmChan++) {
  1087. // find out if the port is in the current environment
  1088. wDev = *lpmmChan->szDevice ? 0 : wNumDevs;
  1089. for (; wDev < wNumDevs; wDev++) {
  1090. midiOutGetDevCaps(wDev, &moCaps, sizeof(MIDIOUTCAPS));
  1091. if (!lstrcmpi(moCaps.szPname, (LPCSTR)(lpmmChan->szDevice)))
  1092. break;
  1093. }
  1094. // if not, add the unique port name to the invalid port list
  1095. if (wDev == wNumDevs) {
  1096. DWORD dwUniqueRet;
  1097. // unique-list entry will save this offset
  1098. dwUniqueRet = LiNotUnique( (LPSTR)(lpmmChan->szDevice)
  1099. , &hPortList
  1100. , (DWORD)wOldDevs);
  1101. if (dwUniqueRet == -1L) {
  1102. mmaperr = MMAPERR_MEMORY;
  1103. exit03: VFreeUniqueList(&hPortList);
  1104. goto exit02;
  1105. } else if (!dwUniqueRet)
  1106. wOldDevs++;
  1107. }
  1108. }
  1109. // copy over the data for each channel
  1110. lpmmChan = (LPMMCHANNEL)(mmSetup.chMap); // MIPS silliness
  1111. for (uIndex = 0; uIndex < 16; uIndex++, lpmmChan++) {
  1112. // convert the device ID to a device name.
  1113. if (lpSetup->channels[uIndex].wDeviceID == MMAP_ID_NOPORT)
  1114. *lpmmChan->szDevice = 0;
  1115. else if (lpSetup->channels[uIndex].wDeviceID >= wNumDevs)
  1116. lstrcpy( (LPSTR)(lpmmChan->szDevice)
  1117. , LszGetUniqueAtOffset( (DWORD)lpSetup->channels[uIndex].wDeviceID
  1118. , hPortList
  1119. )
  1120. );
  1121. else {
  1122. midiOutGetDevCaps( lpSetup->channels[uIndex].wDeviceID
  1123. , &moCaps
  1124. , sizeof(MIDIOUTCAPS)
  1125. );
  1126. lstrcpy((LPSTR)(lpmmChan->szDevice), moCaps.szPname);
  1127. }
  1128. // copy over channel number and flags.
  1129. lpmmChan->wChannel = lpSetup->channels[uIndex].wChannel;
  1130. lpmmChan->dwFlags = lpSetup->channels[uIndex].dFlags;
  1131. if (lpmmChan->dwFlags & MMAP_PATCHMAP) {
  1132. // do I want a uniqueness-check in here?
  1133. // get the table entry
  1134. lpmmEntry = LpGetTableEntry(hPatchTable,
  1135. lpSetup->channels[uIndex].aszPatchName);
  1136. // set patch name table entry index
  1137. lpmmChan->idxPMapName = lpmmEntry->idxEntry;
  1138. // set MSB at current table index where
  1139. // this setup references a patchmap
  1140. if (uSize)
  1141. lpbPatchUsage[lpmmChan->idxPMapName - 1] |= MSB;
  1142. }
  1143. // not needed if MMAP_PATCHMAP isn't there, seems clean though
  1144. else
  1145. lpmmChan->idxPMapName = 0;
  1146. }
  1147. // if there are any patchmaps
  1148. if (uSize) {
  1149. // Check for differences in patchmap referencing. Compare
  1150. // what patchmaps are now being used to what patchmaps were
  1151. // being used before. Change the using count accordingly.
  1152. for (uIndex = 0; uIndex < uSize; uIndex++, lpbPatchUsage++)
  1153. if ((*lpbPatchUsage & MSB) &&
  1154. (!(*lpbPatchUsage & LSB))) {
  1155. mmaperr = MmaperrChangeUsing(MMAP_PATCH,uIndex + 1, 1);
  1156. if (mmaperr != MMAPERR_SUCCESS)
  1157. goto exit03;
  1158. } else if (! (*lpbPatchUsage & MSB)
  1159. && (*lpbPatchUsage & LSB)
  1160. )
  1161. mmaperr = MmaperrChangeUsing(MMAP_PATCH,uIndex + 1, -1);
  1162. if (mmaperr != MMAPERR_SUCCESS)
  1163. goto exit03;
  1164. // nuke the usage table
  1165. GlobalUnlock(hPatchUsage);
  1166. GlobalFree(hPatchUsage);
  1167. hPatchUsage = NULL;
  1168. }
  1169. // copy over the setup flags.
  1170. mmSetup.dwFlags = lpSetup->dFlags;
  1171. // write the setup
  1172. if (_llseek(iFile, doData, 0) == -1L) {
  1173. mmaperr = MMAPERR_WRITE;
  1174. goto exit03;
  1175. }
  1176. if ( _lwrite(iFile, (LPSTR)&mmSetup, sizeof(MMSETUP))
  1177. != sizeof(MMSETUP)
  1178. ) {
  1179. mmaperr = MMAPERR_WRITE;
  1180. goto exit03;
  1181. }
  1182. // free the unique invalid port name list
  1183. VFreeUniqueList(&hPortList);
  1184. // free tables, close file and leave
  1185. VFreeTable(MMAP_SETUP | MMAP_PATCH);
  1186. mmaperr = MmaperrFileAccess(MAP_FCLOSE, 0);
  1187. if (mmaperr != MMAPERR_SUCCESS)
  1188. return mmaperr;
  1189. return MMAPERR_SUCCESS;
  1190. } /* MmaperrWriteSetup */
  1191. // - - - - - - - - -
  1192. // MmaperrWritePatchmap
  1193. //
  1194. // Write a patchmap to the midi data file.
  1195. STATIC MMAPERR NEAR PASCAL MmaperrWritePatchmap(
  1196. PATCHMAP FAR* lpPatch)
  1197. {
  1198. KEYMAP FAR* keymap;
  1199. HANDLE hKeyUsage;
  1200. LPMMTABLE lpmmTable;
  1201. LPMMTABLEENTRY lpmmEntry;
  1202. MMPATCH mmOldPatch;
  1203. MMPATCH mmPatch;
  1204. UNALIGNED WORD *lpidxNames;
  1205. LPBYTE lpbKeyUsage = NULL; // Kill spurious use before set diagnostic
  1206. DWORD doData;
  1207. DWORD dwOffset;
  1208. UINT uSize = 0;
  1209. BOOL fExists = FALSE;
  1210. MMAPERR mmaperr;
  1211. UINT uIndex;
  1212. // open file, read in pertinent tables
  1213. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READWRITE);
  1214. if (mmaperr != MMAPERR_SUCCESS)
  1215. return mmaperr;
  1216. mmaperr = MmaperrReadTable(MMAP_PATCH | MMAP_KEY);
  1217. if (mmaperr != MMAPERR_SUCCESS) {
  1218. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  1219. return mmaperr;
  1220. }
  1221. // check to see if patch name already exists
  1222. lpmmEntry = LpGetTableEntry(hPatchTable, lpPatch->aszPatchMapName);
  1223. if (lpmmEntry != NULL) {
  1224. // patch name exists. if the description has changed, we
  1225. // have to re-write the table entry with new description
  1226. if (lstrcmpi( (LPSTR)(lpmmEntry->szDesc)
  1227. , lpPatch->aszPatchMapDescription)) {
  1228. lstrcpy( (LPSTR)(lpmmEntry->szDesc)
  1229. , lpPatch->aszPatchMapDescription);
  1230. mmaperr = MmaperrWriteTabEntry(MMAP_PATCH, 0, lpmmEntry);
  1231. if (mmaperr != MMAPERR_SUCCESS) {
  1232. exit01: VFreeTable(MMAP_PATCH | MMAP_KEY);
  1233. goto exit00;
  1234. }
  1235. }
  1236. doData = lpmmEntry->doData;
  1237. fExists = TRUE;
  1238. }
  1239. // name is non-existent, so add a new table entry
  1240. else {
  1241. mmaperr = MmaperrAddMap(MMAP_PATCH,lpPatch, &doData);
  1242. if (mmaperr != MMAPERR_SUCCESS)
  1243. goto exit01;
  1244. }
  1245. // zero-out the patch data structure.
  1246. _fmemset((LPSTR)&mmPatch, 0, sizeof(MMPATCH));
  1247. // obtain the number of entrys in the key table
  1248. lpmmTable = (LPMMTABLE)GlobalLock(hKeyTable);
  1249. uSize = lpmmTable->mmHeader.wEntrys;
  1250. GlobalUnlock(hKeyTable);
  1251. // Create table which is 'number-of-keymaps' in length
  1252. hKeyUsage = NULL;
  1253. if (uSize) {
  1254. hKeyUsage = GlobalAlloc(GHND, (LONG)uSize);
  1255. if (hKeyUsage == NULL) {
  1256. mmaperr = MMAPERR_MEMORY;
  1257. goto exit01;
  1258. }
  1259. lpbKeyUsage = (LPBYTE)GlobalLock(hKeyUsage);
  1260. }
  1261. // if not a new patchmap, we need old usage count
  1262. if (fExists) {
  1263. // read in old patch data from file
  1264. if (_llseek(iFile, doData, 0) == -1L) {
  1265. mmaperr = MMAPERR_READ;
  1266. exit02: if (hKeyUsage != NULL) {
  1267. GlobalUnlock(hKeyUsage);
  1268. GlobalFree(hKeyUsage);
  1269. }
  1270. goto exit01;
  1271. }
  1272. if ( _lread(iFile, (LPSTR)&mmOldPatch, sizeof(MMPATCH))
  1273. != sizeof(MMPATCH)
  1274. ) {
  1275. mmaperr = MMAPERR_READ;
  1276. goto exit02;
  1277. }
  1278. mmPatch.wUsing = mmOldPatch.wUsing;
  1279. // if there are keymaps and map is not new, set LSB
  1280. // of usage table indices where old patchmap referenced
  1281. // any respective keymaps
  1282. if (uSize) {
  1283. lpidxNames = mmOldPatch.idxKMapNames;
  1284. for (uIndex = 0; uIndex < MIDIPATCHSIZE; uIndex++, lpidxNames++)
  1285. if (*lpidxNames)
  1286. lpbKeyUsage[*lpidxNames - 1] = LSB;
  1287. }
  1288. }
  1289. dwOffset = sizeof(MIDIPATCHMAP);
  1290. // set max volume scalar to minimum value
  1291. mmPatch.bVMax = 1;
  1292. // copy over data for each patch entry
  1293. keymap = lpPatch->keymaps;
  1294. lpidxNames = mmPatch.idxKMapNames;
  1295. for (uIndex = 0; uIndex < MIDIPATCHSIZE; uIndex++, keymap++, lpidxNames++) {
  1296. DWORD dwUniqueRet;
  1297. mmPatch.wPMap[uIndex] = ((WORD)keymap->bVolume << 8) | keymap->bDestination;
  1298. // if the current volume is greater than the max volume
  1299. // then set max volume to it
  1300. if (keymap->bVolume > mmPatch.bVMax)
  1301. mmPatch.bVMax = keymap->bVolume;
  1302. // if patch has no keymap, zero out keymap table entry
  1303. // index in file data structure and continue
  1304. if (!lstrcmpi(keymap->aszKeyMapName, szNone)) {
  1305. *lpidxNames = 0;
  1306. continue;
  1307. }
  1308. // get the table entry
  1309. lpmmEntry = LpGetTableEntry(hKeyTable, keymap->aszKeyMapName);
  1310. // set keymap table entry index in file data structure
  1311. *lpidxNames = lpmmEntry->idxEntry;
  1312. // if keymap is unique, add size to global offset
  1313. dwUniqueRet = LiNotUnique(keymap->aszKeyMapName, &hKeyList, dwOffset);
  1314. if (dwUniqueRet == -1L) {
  1315. mmaperr = MMAPERR_MEMORY;
  1316. exit03: VFreeUniqueList(&hKeyList);
  1317. goto exit02;
  1318. } else if (!dwUniqueRet) {
  1319. DWORD dwSize;
  1320. dwSize = DwGetMapSize(MMAP_KEY,keymap->aszKeyMapName);
  1321. if (dwSize < MMAPERR_MAXERROR) {
  1322. mmaperr = LOWORD(dwSize);
  1323. goto exit03;
  1324. }
  1325. dwOffset += dwSize;
  1326. // set MSB at current usage table index where
  1327. // this patchmap references a keymap
  1328. if (uSize)
  1329. lpbKeyUsage[*lpidxNames - 1] |= MSB;
  1330. }
  1331. }
  1332. // if there are any keymaps
  1333. if (uSize) {
  1334. // Check for differences in keymap referencing. Compare
  1335. // what keymaps are now being used to what keymaps were being
  1336. // used before. Change the using count accordingly.
  1337. for (uIndex = 0; uIndex < uSize; uIndex++, lpbKeyUsage++)
  1338. if ((*lpbKeyUsage & MSB) && (!(*lpbKeyUsage & LSB))) {
  1339. mmaperr = MmaperrChangeUsing(MMAP_KEY,uIndex + 1, 1);
  1340. if (mmaperr != MMAPERR_SUCCESS)
  1341. goto exit03;
  1342. } else if (! (*lpbKeyUsage & MSB) &&
  1343. (*lpbKeyUsage & LSB))
  1344. mmaperr = MmaperrChangeUsing(MMAP_KEY, uIndex + 1, -1);
  1345. if (mmaperr != MMAPERR_SUCCESS)
  1346. goto exit03;
  1347. // nuke the usage table
  1348. GlobalUnlock(hKeyUsage);
  1349. GlobalFree(hKeyUsage);
  1350. hKeyUsage = NULL;
  1351. }
  1352. // set patch size to global offset.
  1353. mmPatch.dwSize = dwOffset;
  1354. // write the patchmap
  1355. if (_llseek(iFile, doData, 0) == -1L) {
  1356. mmaperr = MMAPERR_WRITE;
  1357. goto exit03;
  1358. }
  1359. if ( _lwrite(iFile, (LPSTR)&mmPatch,sizeof(MMPATCH))
  1360. != sizeof(MMPATCH)
  1361. ) {
  1362. mmaperr = MMAPERR_WRITE;
  1363. goto exit03;
  1364. }
  1365. // free the unique keymap name list
  1366. VFreeUniqueList(&hKeyList);
  1367. // free tables, close file and leave
  1368. VFreeTable(MMAP_PATCH | MMAP_KEY);
  1369. mmaperr = MmaperrFileAccess(MAP_FCLOSE, 0);
  1370. if (mmaperr != MMAPERR_SUCCESS)
  1371. return mmaperr;
  1372. return MMAPERR_SUCCESS;
  1373. } /* MmaperrWritePatchmap */
  1374. // - - - - - - - - -
  1375. // MmaperrWriteKeymap
  1376. //
  1377. // Write a keymap to the midi data file.
  1378. //
  1379. // 1. If this routine fails it will corrupt the database.
  1380. STATIC MMAPERR NEAR PASCAL MmaperrWriteKeymap (LPMIDIKEYMAP lpKey)
  1381. {
  1382. LPMMTABLEENTRY lpmmEntry;
  1383. MMKEY mmOldKey;
  1384. MMKEY mmKey;
  1385. MMAPERR mmaperr;
  1386. DWORD doData;
  1387. BOOL fExists;
  1388. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READWRITE);
  1389. if (mmaperr != MMAPERR_SUCCESS)
  1390. return mmaperr;
  1391. mmaperr = MmaperrReadTable(MMAP_KEY);
  1392. if (mmaperr != MMAPERR_SUCCESS) {
  1393. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  1394. return mmaperr;
  1395. }
  1396. lpmmEntry = LpGetTableEntry(hKeyTable, lpKey->szName);
  1397. if (lpmmEntry != NULL) {
  1398. if (lstrcmpi((LPSTR)(lpmmEntry->szDesc), lpKey->szDesc)) {
  1399. lstrcpy((LPSTR)(lpmmEntry->szDesc), lpKey->szDesc);
  1400. mmaperr = MmaperrWriteTabEntry(MMAP_KEY, 0, lpmmEntry);
  1401. if (mmaperr != MMAPERR_SUCCESS) {
  1402. exit01: VFreeTable(MMAP_KEY);
  1403. goto exit00;
  1404. }
  1405. }
  1406. doData = lpmmEntry->doData;
  1407. fExists = TRUE;
  1408. } else {
  1409. mmaperr = MmaperrAddMap(MMAP_KEY, (LPVOID)lpKey, &doData);
  1410. if (mmaperr != MMAPERR_SUCCESS)
  1411. goto exit01;
  1412. mmKey.wUsing = 0;
  1413. fExists = FALSE;
  1414. }
  1415. // zero-out the keymap data structure
  1416. _fmemset((LPSTR)&mmKey, 0, sizeof(MMKEY));
  1417. // if not a new keymap, get old usage count
  1418. if (fExists) {
  1419. if ( _llseek(iFile, doData, 0) == -1L) {
  1420. mmaperr = MMAPERR_READ;
  1421. goto exit01;
  1422. }
  1423. if ( _lread(iFile, (LPSTR)&mmOldKey, sizeof(MMKEY))
  1424. != sizeof(MMKEY)
  1425. ) {
  1426. mmaperr = MMAPERR_READ;
  1427. goto exit01;
  1428. }
  1429. mmKey.wUsing = mmOldKey.wUsing;
  1430. }
  1431. // copy over flags and keymap data
  1432. mmKey.dwFlags = lpKey->dwFlags;
  1433. _fmemcpy( (LPSTR)(mmKey.bKMap)
  1434. , lpKey->bKMap
  1435. , MIDIPATCHSIZE * sizeof(BYTE));
  1436. if (_llseek(iFile, doData, 0) == -1L) {
  1437. mmaperr = MMAPERR_WRITE;
  1438. goto exit01;
  1439. }
  1440. if (_lwrite(iFile, (LPSTR)&mmKey, sizeof(MMKEY)) != sizeof(MMKEY)) {
  1441. mmaperr = MMAPERR_WRITE;
  1442. goto exit01;
  1443. }
  1444. VFreeTable(MMAP_KEY);
  1445. mmaperr = MmaperrFileAccess(MAP_FCLOSE, 0);
  1446. if (mmaperr != MMAPERR_SUCCESS)
  1447. return mmaperr;
  1448. return MMAPERR_SUCCESS;
  1449. } /* MmaperrWriteKeymap */
  1450. // - - - - - - - - -
  1451. // MmaperrAddMap
  1452. //
  1453. // Generic add map routine.
  1454. // Add a map table entry, increment table use count.
  1455. //
  1456. // Issues:
  1457. //
  1458. // 1. None.
  1459. STATIC MMAPERR NEAR PASCAL MmaperrAddMap(
  1460. UINT uFlag,
  1461. LPVOID lpvMap,
  1462. LPDWORD lpdoData)
  1463. {
  1464. HANDLE hTable;
  1465. LPMMTABLE lpmmTable;
  1466. LPMMTABLEENTRY lpmmEntry;
  1467. LPSTR lpName;
  1468. LPSTR lpDesc;
  1469. MMTABLEENTRY mmEntry;
  1470. MMAPERR mmaperr;
  1471. DWORD doData;
  1472. WORD wEntry;
  1473. WORD wEntrys;
  1474. switch (uFlag) {
  1475. case MMAP_SETUP :
  1476. hTable = hSetupTable;
  1477. lpName = ((SETUP FAR*)lpvMap)->aszSetupName;
  1478. lpDesc = ((SETUP FAR*)lpvMap)->aszSetupDescription;
  1479. break;
  1480. case MMAP_PATCH :
  1481. hTable = hPatchTable;
  1482. lpName = ((PATCHMAP FAR*)lpvMap)->aszPatchMapName;
  1483. lpDesc = ((PATCHMAP FAR*)lpvMap)->aszPatchMapDescription;
  1484. break;
  1485. case MMAP_KEY :
  1486. hTable = hKeyTable;
  1487. lpName = ((LPMIDIKEYMAP)lpvMap)->szName;
  1488. lpDesc = ((LPMIDIKEYMAP)lpvMap)->szDesc;
  1489. break;
  1490. default:lpDesc = NULL; // Kill spurious use before set diagnostic
  1491. lpName = NULL; // Kill spurious use before set diagnostic
  1492. hTable = NULL; // Kill spurious use before set diagnostic
  1493. }
  1494. lpmmTable = (LPMMTABLE)GlobalLock(hTable);
  1495. wEntrys = lpmmTable->mmHeader.wEntrys;
  1496. lpmmEntry = (LPMMTABLEENTRY)GlobalLock(lpmmTable->hEntrys);
  1497. for (wEntry = 0; wEntry < wEntrys; wEntry++, lpmmEntry++)
  1498. if (!*lpmmEntry->szName)
  1499. break;
  1500. GlobalUnlock(lpmmTable->hEntrys);
  1501. if (wEntry == wEntrys) {
  1502. // Filled table;
  1503. mmaperr = MMAPERR_FULL;
  1504. goto exit00;
  1505. }
  1506. _fmemset(&mmEntry, 0, sizeof(MMTABLEENTRY));
  1507. lstrcpy((LPSTR)(mmEntry.szName), lpName);
  1508. lstrcpy((LPSTR)(mmEntry.szDesc), lpDesc);
  1509. mmEntry.idxEntry = wEntry + 1;
  1510. doData = mmEntry.doData = _llseek(iFile, 0L, 2);
  1511. if (doData == -1L) {
  1512. mmaperr = MMAPERR_WRITE;
  1513. exit00: GlobalUnlock(hTable);
  1514. return mmaperr;
  1515. }
  1516. mmaperr = MmaperrWriteTabEntry(uFlag, 0, &mmEntry);
  1517. if (mmaperr != MMAPERR_SUCCESS)
  1518. goto exit00;
  1519. lpmmTable->mmHeader.wUsed++;
  1520. mmaperr = MmaperrWriteTabHeader( uFlag
  1521. , (LPMMTABLEHEADER)(&lpmmTable->mmHeader));
  1522. if (mmaperr != MMAPERR_SUCCESS)
  1523. goto exit00;
  1524. GlobalUnlock(hTable);
  1525. *lpdoData = doData;
  1526. return MMAPERR_SUCCESS;
  1527. } /* MmaperrAddMap */
  1528. // - - - - - - - - -
  1529. /*
  1530. * @doc INTERNAL
  1531. *
  1532. * @api DWORD | mapGetSize | This function retrieves the size in bytes
  1533. * that will be required to read an entire map into memory. This
  1534. * includes the size of any patchmaps and keymaps that the map may
  1535. * contain.
  1536. *
  1537. * @parm UINT | uFlag | Specifies the type of map of which to get the size.
  1538. * It may be any of the following:
  1539. *
  1540. * @flag MMAP_SETUP | Get the size of a setup.
  1541. * @flag MMAP_PATCH | Get the size of a patchmap.
  1542. * @flag MMAP_KEY | Get the size of a keymap.
  1543. *
  1544. * @parm LPSTR | lpName | Specifies the name of the map of which you
  1545. * want to get the size.
  1546. *
  1547. * @rdesc An MMAP error code, or the size in bytes required to read in the
  1548. * map specified by <p lpName>. If the return value is greater than
  1549. * MMAPERR_MAXERROR then the return value is a size and not an error.
  1550. */
  1551. //
  1552. // This function returns either an error code or the size of the thing.
  1553. // The way you tell the difference is to guess. The best way to guess
  1554. // is to compare the return value against MMAPERR_MAXERROR, and if it is
  1555. // greater than or equal to that value you've got a size, not an error.
  1556. //
  1557. // Issues:
  1558. //
  1559. // 1. None.
  1560. DWORD FAR PASCAL mapGetSize(
  1561. UINT uFlag,
  1562. LPSTR lpName)
  1563. {
  1564. switch (uFlag) {
  1565. case MMAP_SETUP :
  1566. return DwGetSetupSize(lpName);
  1567. case MMAP_PATCH :
  1568. case MMAP_KEY :
  1569. return DwGetMapSize(uFlag, lpName);
  1570. }
  1571. } /* mapGetSize */
  1572. // - - - - - - - - -
  1573. // DwGetSetupSize
  1574. //
  1575. // Get the size of a setup.
  1576. //
  1577. // This function returns either an error code or the size of the thing.
  1578. // The way you tell the difference is to guess. The best way to guess
  1579. // is to compare the return value against MMAPERR_MAXERROR, and if it is
  1580. // greater than or equal to that value you've got a size, not an error.
  1581. //
  1582. // Issues:
  1583. //
  1584. // 1. None.
  1585. STATIC DWORD NEAR PASCAL DwGetSetupSize(
  1586. LPSTR lpName)
  1587. {
  1588. LPMMTABLEENTRY lpmmEntry;
  1589. LPMMCHANNEL lpmmChan;
  1590. MMAPERR mmaperr;
  1591. MMSETUP mmSetup;
  1592. DWORD dwRet;
  1593. DWORD dwOffset;
  1594. int i;
  1595. mmaperr = MmaperrFileAccess(MAP_FOPEN,OF_READ);
  1596. if (mmaperr != MMAPERR_SUCCESS)
  1597. return (DWORD)mmaperr;
  1598. mmaperr = MmaperrReadTable(MMAP_SETUP | MMAP_PATCH);
  1599. if (mmaperr != MMAPERR_SUCCESS) {
  1600. dwRet = (DWORD)mmaperr;
  1601. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  1602. return dwRet;
  1603. }
  1604. // if name isn't in the file, get outta here
  1605. lpmmEntry = LpGetTableEntry(hSetupTable, lpName);
  1606. if (lpmmEntry == NULL) {
  1607. dwRet = (DWORD)MMAPERR_INVALIDSETUP;
  1608. exit01: VFreeTable(MMAP_SETUP | MMAP_PATCH);
  1609. goto exit00;
  1610. }
  1611. // intialize offset
  1612. dwOffset = sizeof(MIDIMAP);
  1613. // read in the setup data
  1614. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  1615. dwRet = (DWORD)MMAPERR_READ;
  1616. goto exit01;
  1617. }
  1618. if (_lread(iFile, (LPSTR)&mmSetup,
  1619. sizeof(MMSETUP)) != sizeof(MMSETUP)) {
  1620. dwRet = (DWORD)MMAPERR_READ;
  1621. goto exit01;
  1622. }
  1623. lpmmChan = (LPMMCHANNEL)(mmSetup.chMap); // MIPS silliness
  1624. for (i = 0; i < 16; i++, lpmmChan++) {
  1625. DWORD dwUniqueRet;
  1626. // if no patchmap then continue
  1627. if (!lpmmChan->idxPMapName)
  1628. continue;
  1629. // assuming patchmap actually exists here
  1630. lpmmEntry = LpGetTableEntry(hPatchTable,
  1631. MAKEID(lpmmChan->idxPMapName));
  1632. // if patchmap is unique, add size to global offset
  1633. dwUniqueRet = LiNotUnique( (LPSTR)(lpmmEntry->szName)
  1634. , &hPatchList
  1635. , dwOffset);
  1636. if (dwUniqueRet == -1L) {
  1637. dwRet = (DWORD)MMAPERR_MEMORY;
  1638. goto exit01;
  1639. } else if (!dwUniqueRet) {
  1640. dwRet = DwGetMapSize(MMAP_PATCH,NULL);
  1641. if (dwRet < MMAPERR_MAXERROR) {
  1642. VFreeUniqueList(&hPatchList);
  1643. goto exit01;
  1644. }
  1645. dwOffset += dwRet;
  1646. }
  1647. }
  1648. // free the unique patchmap list
  1649. VFreeUniqueList(&hPatchList);
  1650. VFreeTable(MMAP_SETUP | MMAP_PATCH);
  1651. (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  1652. return (dwOffset < (DWORD)MMAPERR_MAXERROR) ? (DWORD)MMAPERR_INVALIDSETUP : dwOffset;
  1653. } /* DwGetSetupSize */
  1654. // - - - - - - - - -
  1655. // DwGetMapSize
  1656. //
  1657. // Get the size of a patchmap or keymap.
  1658. //
  1659. // This function returns either an error code or the size of the thing.
  1660. // The way you tell the difference is to guess. The best way to guess
  1661. // is to compare the return value against MMAPERR_MAXERROR, and if it is
  1662. // greater than or equal to that value you've got a size, not an error.
  1663. //
  1664. // Remarks:
  1665. //
  1666. // 1. None.
  1667. STATIC DWORD NEAR PASCAL DwGetMapSize(
  1668. UINT uFlag,
  1669. LPSTR lpName)
  1670. {
  1671. LPMMTABLEENTRY lpmmEntry;
  1672. LPHANDLE lphTable;
  1673. MMPATCH mmPatch;
  1674. MMAPERR mmaperr;
  1675. DWORD dwRet;
  1676. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READ);
  1677. if (mmaperr != MMAPERR_SUCCESS)
  1678. return (DWORD)mmaperr;
  1679. mmaperr = MmaperrReadTable(uFlag);
  1680. if (mmaperr != MMAPERR_SUCCESS) {
  1681. dwRet = (DWORD)mmaperr;
  1682. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  1683. return dwRet;
  1684. }
  1685. lphTable = (uFlag == MMAP_PATCH) ? &hPatchTable : &hKeyTable;
  1686. lpmmEntry = LpGetTableEntry(*lphTable, lpName);
  1687. if (lpmmEntry == NULL) {
  1688. dwRet = (uFlag == MMAP_PATCH)
  1689. ? (DWORD)MMAPERR_INVALIDPATCH
  1690. : (DWORD)MMAPERR_INVALIDKEY;
  1691. VFreeTable(uFlag);
  1692. goto exit00;
  1693. }
  1694. switch (uFlag) {
  1695. case MMAP_PATCH :
  1696. // patchmaps have the size stored in the file.
  1697. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  1698. dwRet = (DWORD)MMAPERR_READ;
  1699. break;
  1700. }
  1701. if ( _lread(iFile, (LPSTR)&mmPatch, sizeof(MMPATCH))
  1702. != sizeof(MMPATCH)
  1703. ) {
  1704. dwRet = (DWORD)MMAPERR_READ;
  1705. break;
  1706. }
  1707. dwRet = mmPatch.dwSize;
  1708. if (dwRet < (DWORD)MMAPERR_MAXERROR)
  1709. dwRet = MMAPERR_INVALIDPATCH;
  1710. break;
  1711. case MMAP_KEY:
  1712. // keymaps are all the same size.
  1713. dwRet = sizeof(MIDIKEYMAP);
  1714. break;
  1715. default: dwRet = (DWORD)MMAPERR_READ;
  1716. }
  1717. VFreeTable(uFlag);
  1718. (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  1719. return dwRet;
  1720. } /* DwGetMapSize */
  1721. // - - - - - - - - -
  1722. /*
  1723. * @doc INTERNAL
  1724. *
  1725. * @api DWORD | mapDelete | This function deletes a map from the midi
  1726. * data file.
  1727. *
  1728. * @parm UINT | uFlag | Specifies the type of map to be deleted.
  1729. * It may be any of the following:
  1730. *
  1731. * @flag MMAP_SETUP | Delete a setup.
  1732. * @flag MMAP_PATCH | Delete a patchmap.
  1733. * @flag MMAP_KEY | Delete a keymap.
  1734. *
  1735. * @parm LPSTR | lpName | Specifies the name of the map to be deleted.
  1736. *
  1737. * @rdesc Returns a MMAP error code or zero on success.
  1738. */
  1739. // Issues:
  1740. //
  1741. // 1. If this function fails it will corrupt the database.
  1742. MMAPERR FAR PASCAL mapDelete(
  1743. UINT uFlag,
  1744. LPSTR lpName)
  1745. {
  1746. HANDLE hUsage;
  1747. LPMMCHANNEL lpmmChan = NULL; // Kill spurious use before set diag
  1748. LPMMTABLE lpmmTable;
  1749. LPMMTABLEHEADER lpmmHeader;
  1750. LPMMTABLEENTRY lpmmEntry;
  1751. LPHANDLE lphTable;
  1752. LPHANDLE lphUsageTable;
  1753. UNALIGNED WORD *lpidxNames = NULL; // Kill spurious use before set diagnostic
  1754. LPBYTE lpbUsage;
  1755. MMSETUP mmSetup;
  1756. MMPATCH mmPatch;
  1757. MMAPERR mmaperr;
  1758. UINT uGarbage; // size of thing getting deleted
  1759. UINT uSize;
  1760. UINT uIdx; // index of deleted entry in table
  1761. UINT uUsageFlag = 0; // SETUP or PATCH => same as uFlag, else 0
  1762. UINT uNumPos; // # of positions; setup=16, patch=128
  1763. int idxEntry; // table index
  1764. UINT uIndex;
  1765. // grab the appropriate table, structure size and usage info
  1766. switch (uFlag) {
  1767. case MMAP_SETUP:
  1768. lphTable = &hSetupTable;
  1769. uGarbage = sizeof(MIDIMAP);
  1770. lphUsageTable = &hPatchTable;
  1771. uUsageFlag = MMAP_PATCH;
  1772. uNumPos = 16;
  1773. break;
  1774. case MMAP_PATCH:
  1775. lphTable = &hPatchTable;
  1776. lphUsageTable = &hKeyTable;
  1777. uUsageFlag = MMAP_KEY;
  1778. uGarbage = sizeof(MIDIPATCHMAP);
  1779. uNumPos = MIDIPATCHSIZE;
  1780. break;
  1781. case MMAP_KEY:
  1782. lphTable = &hKeyTable;
  1783. uGarbage = sizeof(MIDIKEYMAP);
  1784. uNumPos = 0; // Kill spurious diagnostic
  1785. lphUsageTable = NULL; // Kill spurious diagnostic
  1786. break;
  1787. default:uGarbage = 0;
  1788. lphTable = NULL; // kill spurious use before set diagnostic
  1789. lphUsageTable = NULL; // Kill spurious diagnostic
  1790. uNumPos = 0; // kill spurious use before set diagnostic
  1791. }
  1792. // open file, read in appropriate table(s)
  1793. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READWRITE);
  1794. if (mmaperr != MMAPERR_SUCCESS)
  1795. return mmaperr;
  1796. mmaperr = MmaperrReadTable(uFlag |uUsageFlag);
  1797. if (mmaperr != MMAPERR_SUCCESS) {
  1798. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  1799. return mmaperr;
  1800. }
  1801. lpmmEntry = LpGetTableEntry(*lphTable, lpName);
  1802. if (lpmmEntry == NULL) {
  1803. switch (uFlag) {
  1804. case MMAP_SETUP:
  1805. mmaperr = MMAPERR_INVALIDSETUP;
  1806. break;
  1807. case MMAP_PATCH:
  1808. mmaperr = MMAPERR_INVALIDPATCH;
  1809. break;
  1810. case MMAP_KEY:
  1811. mmaperr = MMAPERR_INVALIDKEY;
  1812. break;
  1813. }
  1814. exit01: VFreeTable(uFlag | uUsageFlag);
  1815. goto exit00;
  1816. }
  1817. // save the table index
  1818. idxEntry = lpmmEntry->idxEntry;
  1819. if (uUsageFlag) {
  1820. // obtain the number of entrys in the usage table
  1821. lpmmTable = (LPMMTABLE)GlobalLock(*lphUsageTable);
  1822. uSize = lpmmTable->mmHeader.wEntrys;
  1823. GlobalUnlock(*lphUsageTable);
  1824. // read in setup or patchmap, set optimization pointer
  1825. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  1826. mmaperr = MMAPERR_READ;
  1827. goto exit01;
  1828. }
  1829. if (uUsageFlag == MMAP_PATCH) {
  1830. if (_lread(iFile, (LPSTR)&mmSetup,
  1831. sizeof(MMSETUP)) != sizeof(MMSETUP)) {
  1832. mmaperr = MMAPERR_READ;
  1833. goto exit01;
  1834. }
  1835. lpmmChan =(LPMMCHANNEL)(mmSetup.chMap); // MIPS silliness
  1836. } else {
  1837. if (_lread(iFile, (LPSTR)&mmPatch,
  1838. sizeof(MMPATCH)) != sizeof(MMPATCH)) {
  1839. mmaperr = MMAPERR_READ;
  1840. goto exit01;
  1841. }
  1842. lpidxNames = mmPatch.idxKMapNames;
  1843. }
  1844. // create table which is 'number-of-maps' in length
  1845. if (uSize) {
  1846. hUsage = GlobalAlloc(GHND, (LONG)uSize);
  1847. if (hUsage == NULL) {
  1848. mmaperr = MMAPERR_MEMORY;
  1849. goto exit01;
  1850. }
  1851. lpbUsage = (LPBYTE)GlobalLock(hUsage);
  1852. // set flags in table saying which patchmaps or
  1853. // keymaps this setup or patchmap references,
  1854. // respectively
  1855. for (uIndex = 0; uIndex < uNumPos; uIndex++) {
  1856. if (uUsageFlag == MMAP_PATCH) {
  1857. uIdx = lpmmChan->idxPMapName;
  1858. lpmmChan++;
  1859. } else {
  1860. uIdx = *lpidxNames;
  1861. lpidxNames++;
  1862. }
  1863. if (uIdx)
  1864. lpbUsage[uIdx - 1] = 1;
  1865. }
  1866. // go through table and decrement usage count
  1867. // of any entrys that are non zero
  1868. for (uIndex = 0; uIndex < uSize; uIndex++, lpbUsage++) {
  1869. if (!*lpbUsage)
  1870. continue;
  1871. mmaperr = MmaperrChangeUsing(uUsageFlag,uIndex + 1, -1);
  1872. // uIndex + -1, 1)
  1873. if (mmaperr != MMAPERR_SUCCESS) {
  1874. GlobalUnlock(hUsage);
  1875. GlobalFree(hUsage);
  1876. goto exit01;
  1877. }
  1878. }
  1879. GlobalUnlock(hUsage);
  1880. GlobalFree(hUsage);
  1881. }
  1882. }
  1883. _fmemset((LPSTR)(lpmmEntry->szName), 0L, MMAP_MAXNAME);
  1884. _fmemset((LPSTR)(lpmmEntry->szDesc), 0L, MMAP_MAXDESC);
  1885. lpmmEntry->doData = 0L;
  1886. lpmmEntry->idxEntry = 0L;
  1887. mmaperr = MmaperrWriteTabEntry(uFlag, idxEntry, lpmmEntry);
  1888. if (mmaperr != MMAPERR_SUCCESS)
  1889. goto exit01; // Yes, 01, not 02.
  1890. lpmmTable = (LPMMTABLE)GlobalLock(*lphTable);
  1891. lpmmHeader = (LPMMTABLEHEADER)(&lpmmTable->mmHeader);
  1892. lpmmHeader->wUsed--;
  1893. mmaperr = MmaperrWriteTabHeader(uFlag,lpmmHeader);
  1894. if (mmaperr != MMAPERR_SUCCESS) {
  1895. GlobalUnlock(*lphTable);
  1896. goto exit01; // Yes, 01, not 02.
  1897. }
  1898. GlobalUnlock(*lphTable);
  1899. mmaperr = MmaperrGarbage(uGarbage);
  1900. if (mmaperr != MMAPERR_SUCCESS)
  1901. goto exit01; // Yes, 01, not 02.
  1902. VFreeTable(uFlag | uUsageFlag);
  1903. mmaperr = MmaperrFileAccess(MAP_FCLOSE, 0);
  1904. if (mmaperr != MMAPERR_SUCCESS)
  1905. return mmaperr;
  1906. return MMAPERR_SUCCESS;
  1907. } /* mapDelete */
  1908. // - - - - - - - - -
  1909. /*
  1910. * @doc INTERNAL
  1911. *
  1912. * @api DWORD | mapEnumerate | This function enumerates the names and
  1913. * descriptions of all the maps of the specified type found in the
  1914. * midi data file, or the names and device id's of the ports a setup
  1915. * accesses.
  1916. *
  1917. * @parm UINT | uFlag | Specifies the type of enumerate to be performed. It
  1918. * may be any one of the following values:
  1919. *
  1920. * @flag MMAP_SETUP | Enumerate setup names.
  1921. * @flag MMAP_PATCH | Enumerate patchmap names.
  1922. * @flag MMAP_KEY | Enumerate keymap names.
  1923. * @flag MMAP_PORTS | Enumerate ports in a setup.
  1924. *
  1925. * @parm ENUMPROC | lpfnCallback | Specifies the procedure-instance address of
  1926. * the callback function to be called with the name of each map.
  1927. *
  1928. * @parm DWORD | dwUser | If <p uFlag> is <f MMAP_SETUP>, <f MMAP_PATCH>, or
  1929. * <f MMAP_KEY>, this parameter specifies a user variable that will be
  1930. * passed to the callback function along with the name of each map. If
  1931. * <p uFlag> is <f MMAP_PORTS>, this parameter specifies a far pointer
  1932. * to a setup name.
  1933. *
  1934. * @rdesc Returns a MMAP error code or zero on success.
  1935. *
  1936. * @comm <p lpfnCallBack> must be obtained using the <f MakeProcInstance>
  1937. * call, must use the pascal calling convention, must be declared FAR,
  1938. * and must be under the EXPORTS section in your applications .DEF file.
  1939. *
  1940. * @cb BOOL FAR PASCAL | EnumerateCallback | The callback function for
  1941. * <f mapEnumerate>.
  1942. *
  1943. * @parm LPSTR | lpName | If <p uFlag> is <f MMAP_SETUP>, <f MMAP_PATCH>, or
  1944. * <f MMAP_KEY>, this parameter specifies the name of a map of that type.
  1945. * If <p uFlag> is <f MMAP_PORTS>, this parameter is a number in the
  1946. * range of 1 to 16 which specifies the channel on which the supplied
  1947. * port <p lpDesc> is mapped.
  1948. *
  1949. * @parm LPSTR | lpDesc | If <p uFlag> is <f MMAP_SETUP>, <f MMAP_PATCH>, or
  1950. * <f MMAP_KEY>, this parameter specifies the description of the map in
  1951. * the <p lpName> parameter. If <p uFlag> is <f MMAP_PORTS>, this
  1952. * parameter specifies the name of a port accessed by the setup.
  1953. *
  1954. * @parm DWORD | dwUser | If <p uFlag> is <f MMAP_SETUP>, <f MMAP_PATCH>, or
  1955. * <f MMAP_KEY>, this parameter specifies a user variable. If <p uFlag>
  1956. * is <f MMAP_PORTS>, this parameter specifies the device ID of the
  1957. * supplied port <p lpDesc>. In this case, if the port is not available
  1958. * in the current environment, the device ID is equal to the constant
  1959. * MMAP_ID_NOPORT.
  1960. *
  1961. * @rdesc It should return non-zero as long as it wants to continue being
  1962. * called with successive map or port names. <f mapEnumerate> will stop
  1963. * enumerating when the callback function returns zero.
  1964. */
  1965. // Issues:
  1966. //
  1967. // 1. It regards elements with a zero first byte as "not counting"
  1968. // in the count of elements in a table. If this is a bad
  1969. // assertion, this routine has a bug.
  1970. MMAPERR FAR PASCAL mapEnumerate ( UINT uFlag
  1971. , ENUMPROC lpfnCallback
  1972. , UINT uCase // passed to lpfnCallback
  1973. , HWND hCombo // passed to lpfnCallback
  1974. , LPSTR lpSetupName // passed to lpfnCallback
  1975. )
  1976. {
  1977. LPHANDLE lphTable;
  1978. LPMMTABLE lpmmTable;
  1979. LPMMTABLEENTRY lpmmEntry;
  1980. UINT wEnum;
  1981. UINT wUsed;
  1982. MMAPERR mmaperr;
  1983. switch (uFlag) {
  1984. case MMAP_SETUP :
  1985. lphTable = &hSetupTable;
  1986. break;
  1987. case MMAP_PATCH :
  1988. lphTable = &hPatchTable;
  1989. break;
  1990. case MMAP_KEY :
  1991. lphTable = &hKeyTable;
  1992. break;
  1993. case MMAP_PORTS :
  1994. return MmaperrEnumPorts(lpfnCallback, uCase, hCombo, lpSetupName);
  1995. default: lphTable = NULL; // kill spurious use before set diagnostic
  1996. }
  1997. mmaperr = MmaperrReadTable(uFlag);
  1998. if (mmaperr != MMAPERR_SUCCESS)
  1999. return mmaperr;
  2000. lpmmTable = (LPMMTABLE)GlobalLock(*lphTable);
  2001. lpmmEntry = (LPMMTABLEENTRY)GlobalLock(lpmmTable->hEntrys);
  2002. wUsed = lpmmTable->mmHeader.wUsed;
  2003. for (wEnum = 0; wEnum < wUsed; lpmmEntry++) {
  2004. if (!*lpmmEntry->szName)
  2005. continue;
  2006. if (!(*lpfnCallback)( (LPSTR)lpmmEntry->szName
  2007. , (LPSTR)lpmmEntry->szDesc
  2008. , uCase
  2009. , hCombo
  2010. , lpSetupName
  2011. )
  2012. )
  2013. break;
  2014. wEnum++;
  2015. }
  2016. GlobalUnlock(lpmmTable->hEntrys);
  2017. GlobalUnlock(*lphTable);
  2018. VFreeTable(uFlag);
  2019. return MMAPERR_SUCCESS;
  2020. } /* mapEnumerate */
  2021. // - - - - - - - - -
  2022. // MmaperrEnumPorts
  2023. //
  2024. // Enumerate the ports in a setup.
  2025. //
  2026. // Side-effects:
  2027. //
  2028. // 1. None.
  2029. //
  2030. // Remarks:
  2031. //
  2032. // 1. If the enumeration function fails, this function won't
  2033. // let you know.
  2034. STATIC MMAPERR NEAR PASCAL MmaperrEnumPorts(
  2035. ENUMPROC lpfnCallback,
  2036. UINT uCase, // unused
  2037. HWND hCombo, // unused
  2038. LPSTR lpSetupName)
  2039. {
  2040. LPMMTABLEENTRY lpmmEntry;
  2041. LPMMCHANNEL lpmmChan;
  2042. MIDIOUTCAPS moCaps;
  2043. MMSETUP mmSetup;
  2044. MMAPERR mmaperr;
  2045. UINT wNumDevs;
  2046. UINT uDeviceID;
  2047. int i;
  2048. // open file, read in setup table
  2049. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READ);
  2050. if (mmaperr != MMAPERR_SUCCESS)
  2051. return mmaperr;
  2052. mmaperr = MmaperrReadTable(MMAP_SETUP);
  2053. if (mmaperr != MMAPERR_SUCCESS) {
  2054. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  2055. return mmaperr;
  2056. }
  2057. // assuming setup actually exists
  2058. lpmmEntry = LpGetTableEntry(hSetupTable, lpSetupName);
  2059. if (lpmmEntry == NULL) {
  2060. mmaperr = MMAPERR_INVALIDSETUP;
  2061. exit01: VFreeTable(MMAP_SETUP);
  2062. goto exit00;
  2063. }
  2064. // read in setup data from file
  2065. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  2066. mmaperr = MMAPERR_READ;
  2067. goto exit01;
  2068. }
  2069. if (_lread(iFile, (LPSTR)&mmSetup, sizeof(MMSETUP)) != sizeof(MMSETUP)) {
  2070. mmaperr = MMAPERR_READ;
  2071. goto exit01;
  2072. }
  2073. // grab the number of devices in the current environment
  2074. wNumDevs = midiOutGetNumDevs();
  2075. // set an optimization-pointer
  2076. lpmmChan = (LPMMCHANNEL)(mmSetup.chMap); // MIPS silliness
  2077. for (i = 0; i < 16; i++, lpmmChan++) {
  2078. // if no device name, then nothing to enumerate
  2079. if (!*lpmmChan->szDevice)
  2080. continue;
  2081. // convert device name to device ID. If device name doesn't
  2082. // exist in the current environment, set ID to MMAP_ID_NOPORT
  2083. for (uDeviceID = 0; uDeviceID < wNumDevs; uDeviceID++) {
  2084. midiOutGetDevCaps(uDeviceID, &moCaps, sizeof(MIDIOUTCAPS));
  2085. if (!lstrcmpi( moCaps.szPname
  2086. , (LPCSTR)(lpmmChan->szDevice)))
  2087. break;
  2088. }
  2089. if (uDeviceID == wNumDevs)
  2090. uDeviceID = MMAP_ID_NOPORT;
  2091. if (!(*lpfnCallback)( (LPSTR)(DWORD)i + 1
  2092. , (LPSTR)(lpmmChan->szDevice)
  2093. , uCase // garbage parameter
  2094. , hCombo // garbage parameter
  2095. , (LPSTR)uDeviceID
  2096. )
  2097. )
  2098. break;
  2099. }
  2100. // free table, close file and leave
  2101. VFreeTable(MMAP_SETUP);
  2102. (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  2103. return MMAPERR_SUCCESS;
  2104. } /* MmaperrEnumPorts */
  2105. // - - - - - - - - -
  2106. /*
  2107. * @doc INTERNAL
  2108. *
  2109. * @api DWORD | mapGetUsageCount | Get the usage count for a patchmap or
  2110. * keymap.
  2111. *
  2112. * @parm UINT | uFlag | Specifies the type of map to get the usage count for.
  2113. * It may be any one of the following values:
  2114. *
  2115. * @flag MMAP_PATCH | Get the usage count for a patchmap.
  2116. * @flag MMAP_KEY | Get the usage count for a keymap.
  2117. *
  2118. * @parm LPSTR | lpName | Specifies the name of the map to get the usage
  2119. * count for.
  2120. *
  2121. * @rdesc Returns a MMAP error code, or the usage count for the map
  2122. * specified by <p lpName> in the high-order word.
  2123. *
  2124. * @comm Usage counts are used in order to determine whether it is okay to
  2125. * delete a patchmap or keymap. If a setup accesses a patchmap, the
  2126. * usage count for that patchmap will be 1, and hence it should not be
  2127. * deleted. The same is true for patchmaps accessing keymaps. The
  2128. * mapDelete function does not look for or care about this number, so
  2129. * it is up to YOU to determine whether a patchmap or keymap has a zero
  2130. * usage count before calling mapDelete.
  2131. */
  2132. // Side-effects:
  2133. //
  2134. // 1. None.
  2135. DWORD FAR PASCAL mapGetUsageCount(
  2136. UINT uFlag,
  2137. LPSTR lpName)
  2138. {
  2139. LPMMTABLEENTRY lpmmEntry;
  2140. MMPATCH mmPatch;
  2141. MMKEY mmKey;
  2142. MMAPERR mmaperr;
  2143. DWORD dwRet;
  2144. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READ);
  2145. if (mmaperr != MMAPERR_SUCCESS)
  2146. return MAKELONG(mmaperr, 0);
  2147. mmaperr = MmaperrReadTable(uFlag);
  2148. if (mmaperr != MMAPERR_SUCCESS) {
  2149. dwRet = MAKELONG(mmaperr, 0);
  2150. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  2151. return dwRet;
  2152. }
  2153. switch (uFlag) {
  2154. case MMAP_PATCH:
  2155. lpmmEntry = LpGetTableEntry(hPatchTable, lpName);
  2156. if (lpmmEntry != NULL) {
  2157. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  2158. dwRet = MAKELONG(MMAPERR_READ, 0);
  2159. exit01: VFreeTable(uFlag);
  2160. goto exit00;
  2161. }
  2162. if ( _lread(iFile, (LPSTR)&mmPatch, sizeof(MMPATCH))
  2163. != sizeof(MMPATCH)
  2164. ) {
  2165. dwRet = MAKELONG(MMAPERR_READ, 0);
  2166. goto exit01;
  2167. }
  2168. dwRet = MAKELONG(MMAPERR_SUCCESS, mmPatch.wUsing);
  2169. exit02: VFreeTable(uFlag);
  2170. (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  2171. return dwRet;
  2172. } else {
  2173. dwRet = MAKELONG(MMAPERR_INVALIDPATCH, 0);
  2174. goto exit01;
  2175. }
  2176. break; // This "break" is actually unreachable.
  2177. case MMAP_KEY:
  2178. lpmmEntry = LpGetTableEntry(hKeyTable, lpName);
  2179. if (lpmmEntry != NULL) {
  2180. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  2181. dwRet = MAKELONG(MMAPERR_READ, 0);
  2182. goto exit01;
  2183. }
  2184. if (_lread(iFile, (LPSTR)&mmKey, sizeof(MMKEY))
  2185. != sizeof(MMKEY)
  2186. ) {
  2187. dwRet = MAKELONG(MMAPERR_READ, 0);
  2188. goto exit01;
  2189. }
  2190. dwRet = MAKELONG (MMAPERR_SUCCESS, mmKey.wUsing);
  2191. goto exit02;
  2192. } else {
  2193. dwRet = MAKELONG(MMAPERR_INVALIDPATCH, 0);
  2194. goto exit01;
  2195. }
  2196. break; // This "break" is actually unreachable.
  2197. }
  2198. } /* mapGetUsageCount */
  2199. // - - - - - - - - -
  2200. /*
  2201. * @doc INTERNAL
  2202. *
  2203. * @api DWORD | mapPatchMapInSetup | Determine if a patchmap is used within a
  2204. * setup.
  2205. *
  2206. * @parm LPSTR | lpPatchName | Specifies the name of the patchmap.
  2207. *
  2208. * @parm LPSTR | lpSetupName | Specifies the name of the setup.
  2209. *
  2210. * @rdesc Returns a MMAP error code, or non-zero in the high-order word if the
  2211. * given patchmap is used within the given setup.
  2212. *
  2213. * @xref mapKeyMapInSetup
  2214. */
  2215. // Side-effects:
  2216. //
  2217. // 1. None.
  2218. DWORD FAR PASCAL mapPatchMapInSetup(
  2219. LPSTR lpPatchName,
  2220. LPSTR lpSetupName)
  2221. {
  2222. LPMMTABLEENTRY lpmmEntry;
  2223. LPMMCHANNEL lpmmChan;
  2224. MMSETUP mmSetup;
  2225. DWORD dwRet;
  2226. MMAPERR mmaperr;
  2227. int i;
  2228. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READ);
  2229. if (mmaperr != MMAPERR_SUCCESS)
  2230. return MAKELONG(mmaperr, 0);
  2231. mmaperr = MmaperrReadTable(MMAP_SETUP | MMAP_PATCH);
  2232. if (mmaperr != MMAPERR_SUCCESS) {
  2233. dwRet = MAKELONG(mmaperr, 0);
  2234. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  2235. return dwRet;
  2236. }
  2237. lpmmEntry = LpGetTableEntry(hSetupTable, lpSetupName);
  2238. if (lpmmEntry == NULL) {
  2239. dwRet = MAKELONG(MMAPERR_INVALIDSETUP, 0);
  2240. exit01: VFreeTable(MMAP_SETUP | MMAP_PATCH);
  2241. goto exit00;
  2242. }
  2243. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  2244. dwRet = MAKELONG(MMAPERR_READ, 0);
  2245. goto exit01;
  2246. }
  2247. if (_lread(iFile, (LPSTR)&mmSetup, sizeof(MMSETUP)) != sizeof(MMSETUP)){
  2248. dwRet = MAKELONG(MMAPERR_READ, 0);
  2249. goto exit01;
  2250. }
  2251. lpmmChan = (LPMMCHANNEL)(mmSetup.chMap); // MIPS silliness
  2252. for (i = 0; i < 16; i++, lpmmChan++) {
  2253. if (!lpmmChan->idxPMapName)
  2254. continue;
  2255. lpmmEntry = LpGetTableEntry(hPatchTable,
  2256. MAKEID(lpmmChan->idxPMapName));
  2257. if (!lstrcmpi(lpPatchName, (LPCSTR)(lpmmEntry->szName)))
  2258. break;
  2259. }
  2260. VFreeTable(MMAP_SETUP | MMAP_PATCH);
  2261. (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  2262. return MAKELONG(MMAPERR_SUCCESS, (i < 16) ? 1 : 0);
  2263. } /* mapPatchMapInSetup */
  2264. // - - - - - - - - -
  2265. /*
  2266. * @doc INTERNAL
  2267. *
  2268. * @api DWORD | mapKeyMapInSetup | Determine if a keymap is used within a
  2269. * setup.
  2270. *
  2271. * @parm LPSTR | lpKeyName | Specifies the name of the keymap.
  2272. *
  2273. * @parm LPSTR | lpSetupName | Specifies the name of the setup.
  2274. *
  2275. * @rdesc Returns a MMAP error code, or non-zero in the high-order word
  2276. * if the given keymap is used within the given patchmap.
  2277. *
  2278. * @xref mapPatchMapInSetup
  2279. */
  2280. DWORD FAR PASCAL mapKeyMapInSetup(
  2281. LPSTR lpKeyName,
  2282. LPSTR lpSetupName)
  2283. {
  2284. LPMMTABLEENTRY lpmmEntry;
  2285. LPMMCHANNEL lpmmChan;
  2286. MMSETUP mmSetup;
  2287. MMPATCH mmPatch;
  2288. UNALIGNED WORD *lpidxKMap;
  2289. DWORD dwRet;
  2290. MMAPERR mmaperr;
  2291. int i;
  2292. int j;
  2293. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READ);
  2294. if (mmaperr != MMAPERR_SUCCESS)
  2295. return MAKELONG(mmaperr, 0);
  2296. mmaperr = MmaperrReadTable(MMAP_SETUP | MMAP_PATCH | MMAP_KEY);
  2297. if (mmaperr != MMAPERR_SUCCESS) {
  2298. dwRet = MAKELONG(mmaperr, 0);
  2299. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  2300. return dwRet;
  2301. }
  2302. if ((lpmmEntry = LpGetTableEntry(hSetupTable, lpSetupName)) == NULL) {
  2303. dwRet = MAKELONG(MMAPERR_INVALIDSETUP, 0);
  2304. exit01: VFreeTable(MMAP_SETUP | MMAP_PATCH | MMAP_KEY);
  2305. goto exit00;
  2306. }
  2307. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  2308. dwRet = MAKELONG(MMAPERR_READ, 0);
  2309. goto exit01;
  2310. }
  2311. if (_lread(iFile, (LPSTR)&mmSetup, sizeof(MMSETUP)) != sizeof(MMSETUP)){
  2312. dwRet = MAKELONG(MMAPERR_READ, 0);
  2313. goto exit01;
  2314. }
  2315. lpmmChan = (LPMMCHANNEL)(mmSetup.chMap); // MIPS silliness
  2316. dwRet = MAKELONG(MMAPERR_SUCCESS, 0);
  2317. for (i = 0; i < 16; i++, lpmmChan++) {
  2318. DWORD dwUniqueRet;
  2319. if (!lpmmChan->idxPMapName)
  2320. continue;
  2321. lpmmEntry = LpGetTableEntry(hPatchTable,
  2322. MAKEID(lpmmChan->idxPMapName));
  2323. dwUniqueRet = LiNotUnique( (LPSTR)(lpmmEntry->szName)
  2324. , &hPatchList
  2325. , 0L);
  2326. // 0L in the "dwOffset" field because it's never used.
  2327. if (dwUniqueRet == -1L) {
  2328. dwRet = MAKELONG(MMAPERR_MEMORY, 0);
  2329. exit02: VFreeUniqueList(&hPatchList);
  2330. goto exit01;
  2331. } else if (dwUniqueRet)
  2332. continue;
  2333. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  2334. dwRet = MAKELONG(MMAPERR_READ, 0);
  2335. goto exit02;
  2336. }
  2337. if ( _lread(iFile, (LPSTR)&mmPatch, sizeof(MMPATCH))
  2338. != sizeof(MMPATCH)
  2339. ) {
  2340. dwRet = MAKELONG(MMAPERR_READ, 0);
  2341. goto exit02;
  2342. }
  2343. lpidxKMap = mmPatch.idxKMapNames;
  2344. for (j = 0; j < MIDIPATCHSIZE; j++, lpidxKMap++) {
  2345. if (!*lpidxKMap)
  2346. continue;
  2347. lpmmEntry = LpGetTableEntry(hKeyTable,
  2348. MAKEID(*lpidxKMap));
  2349. if (!lstrcmpi(lpKeyName, (LPCSTR)(lpmmEntry->szName))) {
  2350. dwRet = MAKELONG(MMAPERR_SUCCESS, 1);
  2351. break;
  2352. }
  2353. }
  2354. if (j < MIDIPATCHSIZE)
  2355. break;
  2356. }
  2357. VFreeUniqueList(&hPatchList);
  2358. // free tables, close file and leave
  2359. VFreeTable(MMAP_SETUP | MMAP_PATCH | MMAP_KEY);
  2360. (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  2361. return dwRet;
  2362. } /* mapKeyMapInSetup */
  2363. // - - - - - - - - -
  2364. /*
  2365. * @doc INTERNAL
  2366. *
  2367. * @api DWORD | mapExists | Deterine if a map exists by the given name.
  2368. *
  2369. * @parm UINT | uFlag | Specifies the type of map of which existence is
  2370. * to be determined. It may be any of the following:
  2371. *
  2372. * @flag MMAP_SETUP | Determine if a setup exists.
  2373. * @flag MMAP_PATCH | Determine if a patchmap exists.
  2374. * @flag MMAP_KEY | Determine if a keymap exists.
  2375. *
  2376. * @parm LPSTR | lpName | Specifies the name of the map.
  2377. *
  2378. * @rdesc Returns a MMAP error code in the low word. The the call succeeds,
  2379. * returns non-zero in the high-order word if a map exists by the given
  2380. * name.
  2381. */
  2382. // Side-effects:
  2383. //
  2384. // 1. None.
  2385. DWORD FAR PASCAL mapExists(
  2386. UINT uFlag,
  2387. LPSTR lpName)
  2388. {
  2389. LPHANDLE lphTable;
  2390. LPMMTABLEENTRY lpmmEntry;
  2391. MMAPERR mmaperr;
  2392. switch (uFlag) {
  2393. case MMAP_SETUP:
  2394. lphTable = &hSetupTable;
  2395. break;
  2396. case MMAP_PATCH:
  2397. lphTable = &hPatchTable;
  2398. break;
  2399. case MMAP_KEY:
  2400. lphTable = &hKeyTable;
  2401. break;
  2402. default:lphTable = NULL; // kill spurious use before sete diagnostic
  2403. }
  2404. if ((mmaperr = MmaperrReadTable(uFlag)) != MMAPERR_SUCCESS)
  2405. return MAKELONG(mmaperr, 0);
  2406. lpmmEntry = LpGetTableEntry(*lphTable, lpName);
  2407. VFreeTable(uFlag);
  2408. return MAKELONG(MMAPERR_SUCCESS, (lpmmEntry != NULL) ? 1 : 0);
  2409. } /* mapExists */
  2410. // - - - - - - - - -
  2411. // LiNotUnique
  2412. //
  2413. // Return 0L if the supplied name is unique, and in this case add it to
  2414. // the end of the list with the offset given in parm 3.
  2415. //
  2416. // Return -1 if the GlobalAlloc fails so that the unique name
  2417. // cannot be added.
  2418. //
  2419. // Otherwise return an offset from the base of the current setup
  2420. // or patchmap where the map exists, or the channel number which
  2421. // accesses the invalid port.
  2422. //
  2423. // Uniqueness is determined by the presence of the name on its respective
  2424. // list; hPatchList for patchmap names; hKeyList for keymap names;
  2425. // hPortList for port names. It's up to the caller to give us the
  2426. // right list to search.
  2427. //
  2428. STATIC DWORD NEAR PASCAL LiNotUnique(
  2429. LPSTR lpName,
  2430. LPHANDLE lphList,
  2431. DWORD dwOffset)
  2432. {
  2433. LPUNIQUEMAP lpumEntry = NULL; //; kill spurious use before set diag
  2434. HANDLE hCur;
  2435. HANDLE hPrev = NULL;
  2436. for (hCur = *lphList; hCur;) {
  2437. lpumEntry = (LPUNIQUEMAP)GlobalLock(hCur);
  2438. if (!lstrcmpi((LPCSTR)(lpumEntry->szName), lpName)) {
  2439. DWORD liRet;
  2440. liRet = lpumEntry->dwOffset;
  2441. GlobalUnlock(hCur);
  2442. return liRet;
  2443. }
  2444. hPrev = hCur;
  2445. hCur = lpumEntry->hNext;
  2446. if (hCur != NULL) {
  2447. GlobalUnlock(hPrev);
  2448. }
  2449. }
  2450. hCur = GlobalAlloc(GHND, (DWORD)sizeof(UNIQUEMAP));
  2451. if (hCur == NULL) {
  2452. if (hPrev != NULL) {
  2453. GlobalUnlock(hPrev);
  2454. }
  2455. return (DWORD)-1L;
  2456. }
  2457. if (hPrev != NULL) {
  2458. lpumEntry->hNext = hCur;
  2459. GlobalUnlock(hPrev);
  2460. } else
  2461. *lphList = hCur;
  2462. lpumEntry = (LPUNIQUEMAP)GlobalLock(hCur);
  2463. lstrcpy((LPSTR)(lpumEntry->szName), lpName);
  2464. lpumEntry->dwOffset = dwOffset;
  2465. lpumEntry->hNext = NULL;
  2466. GlobalUnlock(hCur);
  2467. return 0L;
  2468. } /* LiNotUnique */
  2469. // - - - - - - - - -
  2470. // LszGetUniqueAtOffset
  2471. //
  2472. // Return a unique name given an offset.
  2473. //
  2474. // Remarks:
  2475. //
  2476. // 1. I don't think this can fail, although there's a weird case
  2477. // if you run out of list. In this case you get an empty string.
  2478. // I'm not sure if this is bad or not.
  2479. STATIC LPSTR NEAR PASCAL LszGetUniqueAtOffset(
  2480. DWORD dwOffset,
  2481. HANDLE hList)
  2482. {
  2483. static char szUnique[MAX_UNIQUENAME];
  2484. *szUnique = 0;
  2485. while (hList) {
  2486. HANDLE hNext;
  2487. LPUNIQUEMAP lpumEntry;
  2488. lpumEntry = (LPUNIQUEMAP)GlobalLock(hList);
  2489. if (dwOffset == lpumEntry->dwOffset) {
  2490. lstrcpy(szUnique, (LPCSTR)(lpumEntry->szName));
  2491. GlobalUnlock(hList);
  2492. break;
  2493. }
  2494. hNext = lpumEntry->hNext;
  2495. GlobalUnlock(hList);
  2496. hList = hNext;
  2497. }
  2498. return (LPSTR)szUnique;
  2499. } /* LszGetUniqueAtOffset */
  2500. // - - - - - - - - -
  2501. //
  2502. // VFreeUniqueList
  2503. //
  2504. // Free up the memory associated with a unique name list.
  2505. //
  2506. // Side-effects:
  2507. //
  2508. // 1. None.
  2509. STATIC VOID NEAR PASCAL VFreeUniqueList(
  2510. LPHANDLE lphList)
  2511. {
  2512. // there was a code generation compiler bug
  2513. // it thought that hPrev and *lphList were synonyms. Worrying!!
  2514. HANDLE hPrev;
  2515. HANDLE hList;
  2516. hList = *lphList;
  2517. *lphList = NULL;
  2518. for (; hList != NULL; ) {
  2519. LPUNIQUEMAP lpumEntry;
  2520. hPrev = hList;
  2521. lpumEntry = (LPUNIQUEMAP)GlobalLock(hPrev);
  2522. hList = lpumEntry->hNext;
  2523. GlobalUnlock(hPrev);
  2524. GlobalFree(hPrev);
  2525. }
  2526. } /* VFreeUniqueList */
  2527. // - - - - - - - - -
  2528. // MmaperrChangeUsing
  2529. //
  2530. // Change the usage count of a patchmap or keymap.
  2531. //
  2532. // Side-effects:
  2533. //
  2534. // 1. None.
  2535. STATIC MMAPERR NEAR PASCAL MmaperrChangeUsing(
  2536. UINT uFlag,
  2537. UINT uIdx,
  2538. int iVal)
  2539. {
  2540. HANDLE hTable;
  2541. LPMMTABLEENTRY lpmmEntry;
  2542. MMPATCH mmPatch;
  2543. MMAPERR mmaperr;
  2544. MMKEY mmKey;
  2545. if ((mmaperr = MmaperrFileAccess(MAP_FOPEN,
  2546. OF_READWRITE)) != MMAPERR_SUCCESS)
  2547. return mmaperr;
  2548. if ((mmaperr = MmaperrReadTable(uFlag)) != MMAPERR_SUCCESS) {
  2549. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  2550. return mmaperr;
  2551. }
  2552. hTable = (uFlag == MMAP_PATCH) ? hPatchTable : hKeyTable;
  2553. lpmmEntry = LpGetTableEntry(hTable, // No error return
  2554. MAKEID(uIdx)); // is possible.
  2555. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  2556. mmaperr = MMAPERR_READ;
  2557. exit01: VFreeTable(uFlag);
  2558. goto exit00;
  2559. }
  2560. switch (uFlag) {
  2561. case MMAP_PATCH:
  2562. if ( _lread(iFile, (LPSTR)&mmPatch, sizeof(MMPATCH))
  2563. != sizeof(MMPATCH)
  2564. ) {
  2565. mmaperr = MMAPERR_READ;
  2566. goto exit01;
  2567. }
  2568. mmPatch.wUsing += (WORD)iVal;
  2569. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  2570. mmaperr = MMAPERR_WRITE;
  2571. goto exit01;
  2572. }
  2573. if ( _lwrite(iFile, (LPSTR)&mmPatch, sizeof(MMPATCH))
  2574. != sizeof(MMPATCH)
  2575. ) {
  2576. mmaperr = MMAPERR_WRITE;
  2577. goto exit01;
  2578. }
  2579. break;
  2580. case MMAP_KEY:
  2581. if (_lread(iFile, (LPSTR)&mmKey, sizeof(MMKEY)) != sizeof(MMKEY)) {
  2582. mmaperr = MMAPERR_READ;
  2583. goto exit01;
  2584. }
  2585. mmKey.wUsing += (WORD)iVal;
  2586. if (_llseek(iFile, lpmmEntry->doData, 0) == -1L) {
  2587. mmaperr = MMAPERR_WRITE;
  2588. goto exit01;
  2589. }
  2590. if (_lwrite(iFile, (LPSTR)&mmKey, sizeof(MMKEY)) != sizeof(MMKEY)) {
  2591. mmaperr = MMAPERR_WRITE;
  2592. goto exit01;
  2593. }
  2594. break;
  2595. }
  2596. VFreeTable(uFlag);
  2597. if ((mmaperr = MmaperrFileAccess(MAP_FCLOSE, 0)) != MMAPERR_SUCCESS)
  2598. return mmaperr;
  2599. return MMAPERR_SUCCESS;
  2600. } /* MmaperrChangeUsing */
  2601. // - - - - - - - - -
  2602. //
  2603. // MmaperrReadTable
  2604. //
  2605. // Read in table(s) of names/descriptions from the midimap file.
  2606. //
  2607. // Returns boolean.
  2608. //
  2609. // Side-effects:
  2610. //
  2611. // 1. None anymore.
  2612. STATIC MMAPERR NEAR PASCAL MmaperrReadTable(
  2613. UINT APIn)
  2614. {
  2615. MMHEADER mmHeader;
  2616. LPMMTABLE lpmmTable;
  2617. LPMMTABLEENTRY lpmmEntry;
  2618. LPHANDLE lpTable;
  2619. MMAPERR mmaperr;
  2620. UINT oPos;
  2621. UINT uTableSize;
  2622. UINT mmap;
  2623. UINT mmapCompleted;
  2624. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READ);
  2625. if (mmaperr != MMAPERR_SUCCESS)
  2626. return mmaperr;
  2627. if (_llseek(iFile, 0L, 0) == -1L) {
  2628. mmaperr = MMAPERR_READ;
  2629. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  2630. return mmaperr;
  2631. }
  2632. if (_lread(iFile, (LPSTR)&mmHeader, sizeof(MMHEADER)) != sizeof(MMHEADER)) {
  2633. mmaperr = MMAPERR_READ;
  2634. goto exit00;
  2635. }
  2636. mmapCompleted = 0;
  2637. for (mmap = 1; mmap < 5; mmap <<= 1) {
  2638. if (!(APIn & mmap))
  2639. continue;
  2640. switch (mmap) {
  2641. default:
  2642. continue;
  2643. case MMAP_SETUP:
  2644. lpTable = &hSetupTable;
  2645. oPos = mmHeader.oSetup;
  2646. break;
  2647. case MMAP_PATCH:
  2648. lpTable = &hPatchTable;
  2649. oPos = mmHeader.oPatch;
  2650. break;
  2651. case MMAP_KEY:
  2652. lpTable = &hKeyTable;
  2653. oPos = mmHeader.oKey;
  2654. break;
  2655. }
  2656. if (*lpTable)
  2657. lpmmTable = (LPMMTABLE)GlobalLock(*lpTable);
  2658. else {
  2659. *lpTable = GlobalAlloc(GHND, (DWORD)sizeof(MMTABLE));
  2660. if (*lpTable == NULL) {
  2661. mmaperr = MMAPERR_MEMORY;
  2662. exit01: VFreeTable(mmapCompleted);
  2663. goto exit00;
  2664. }
  2665. lpmmTable = (LPMMTABLE)GlobalLock(*lpTable);
  2666. if (_llseek(iFile, (LONG)oPos, 0) == -1L) {
  2667. mmaperr = MMAPERR_READ;
  2668. exit02: GlobalUnlock(*lpTable);
  2669. GlobalFree(*lpTable);
  2670. *lpTable = NULL;
  2671. goto exit01;
  2672. }
  2673. if ( _lread(iFile, (LPSTR)&lpmmTable->mmHeader,sizeof(MMTABLEHEADER))
  2674. != sizeof(MMTABLEHEADER)
  2675. ) {
  2676. mmaperr = MMAPERR_READ;
  2677. goto exit02;
  2678. }
  2679. uTableSize = lpmmTable->mmHeader.wEntrys *
  2680. sizeof(MMTABLEENTRY);
  2681. lpmmTable->hEntrys = GlobalAlloc( GHND
  2682. , (DWORD)uTableSize
  2683. );
  2684. if (lpmmTable->hEntrys == NULL) {
  2685. mmaperr = MMAPERR_MEMORY;
  2686. goto exit02;
  2687. }
  2688. lpmmEntry = (LPMMTABLEENTRY)GlobalLock(
  2689. lpmmTable->hEntrys);
  2690. if ( _lread(iFile, (LPSTR)lpmmEntry, uTableSize)
  2691. != uTableSize
  2692. ) {
  2693. mmaperr = MMAPERR_READ;
  2694. /*exit03:*/ GlobalUnlock(lpmmTable->hEntrys);
  2695. GlobalFree(lpmmTable->hEntrys);
  2696. goto exit02;
  2697. }
  2698. GlobalUnlock(lpmmTable->hEntrys);
  2699. }
  2700. lpmmTable->wCount++;
  2701. GlobalUnlock(*lpTable);
  2702. mmapCompleted |= mmap;
  2703. }
  2704. (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  2705. return MMAPERR_SUCCESS;
  2706. } /* MmaperrReadTable */
  2707. // - - - - - - - - -
  2708. //
  2709. // VFreeTable
  2710. //
  2711. // Free a table (or tables) from memory.
  2712. //
  2713. // Side-effects:
  2714. //
  2715. // 1. None.
  2716. STATIC VOID NEAR PASCAL VFreeTable(
  2717. UINT APIn)
  2718. {
  2719. LPMMTABLE lpmmTable;
  2720. LPHANDLE lpTable;
  2721. UINT mmap;
  2722. for (mmap = 1; mmap < 5; mmap <<= 1) {
  2723. if (!(APIn & mmap))
  2724. continue;
  2725. switch (mmap) {
  2726. default:
  2727. continue;
  2728. case MMAP_SETUP:
  2729. lpTable = &hSetupTable;
  2730. break;
  2731. case MMAP_PATCH:
  2732. lpTable = &hPatchTable;
  2733. break;
  2734. case MMAP_KEY:
  2735. lpTable = &hKeyTable;
  2736. break;
  2737. }
  2738. if (!*lpTable)
  2739. continue;
  2740. lpmmTable = (LPMMTABLE)GlobalLock(*lpTable);
  2741. if (--lpmmTable->wCount) {
  2742. GlobalUnlock(*lpTable);
  2743. continue;
  2744. }
  2745. GlobalFree(lpmmTable->hEntrys);
  2746. GlobalUnlock(*lpTable);
  2747. GlobalFree(*lpTable);
  2748. *lpTable = NULL;
  2749. }
  2750. } /* VFreeTable */
  2751. // - - - - - - - - -
  2752. //
  2753. // LpGetTableEntry
  2754. //
  2755. // Given a name or index, return a table entry. If lpName is NULL, it
  2756. // assumes you have already called this and simply returns whatever
  2757. // happens to be in the local static mmEntry.
  2758. //
  2759. // Side-effects:
  2760. //
  2761. // 1. None.
  2762. //
  2763. // Remarks:
  2764. //
  2765. // 1. This can't return an error if "lpName" is NULL, or if the
  2766. // HIWORD of it is zero.
  2767. STATIC LPMMTABLEENTRY NEAR PASCAL LpGetTableEntry(
  2768. HANDLE hTable,
  2769. LPSTR lpName // Name or index
  2770. )
  2771. {
  2772. static MMTABLEENTRY mmEntry;
  2773. LPMMTABLE lpmmTable;
  2774. LPMMTABLEENTRY lpmmEntry;
  2775. UINT wNum ;
  2776. UINT wUsed;
  2777. if (lpName == NULL) {
  2778. return &mmEntry;
  2779. }
  2780. lpmmTable = (LPMMTABLE)GlobalLock(hTable);
  2781. lpmmEntry = (LPMMTABLEENTRY)GlobalLock(lpmmTable->hEntrys);
  2782. wNum = 0;
  2783. if (!HIWORD(lpName)) {
  2784. lpmmEntry += LOWORD ((LONG_PTR)lpName) - 1;
  2785. wUsed = 1;
  2786. } else {
  2787. /* search through storage handled by lpmmTable->hEntrys for lpName */
  2788. /* set wNum to its number and lpmmEntry to the entry */
  2789. wUsed = lpmmTable->mmHeader.wUsed;
  2790. for (; wNum < wUsed; lpmmEntry++) {
  2791. if (!*lpmmEntry->szName) {
  2792. continue;
  2793. }
  2794. if (!lstrcmpi((LPCSTR)(lpmmEntry->szName), lpName))
  2795. break;
  2796. wNum++;
  2797. }
  2798. }
  2799. if (wNum < wUsed)
  2800. mmEntry = *lpmmEntry;
  2801. GlobalUnlock(lpmmTable->hEntrys);
  2802. GlobalUnlock(hTable);
  2803. if (wNum == wUsed)
  2804. return NULL;
  2805. return (LPMMTABLEENTRY)&mmEntry;
  2806. } /* LpGetTableEntry */
  2807. // - - - - - - - - -
  2808. /*
  2809. * @doc INTERNAL
  2810. *
  2811. * @api MMAPERR | MmaperrWriteTabEntry | Write a table entry to disk.
  2812. *
  2813. * uIdx may be a table entry index (1 ... n) or it may be zero if
  2814. * you want to use lpmmEntry->idxEntry as the index.
  2815. */
  2816. // Side-effects of failure:
  2817. //
  2818. // 1. If the "close" fails something bad has happened to the file.
  2819. //
  2820. // Remarks:
  2821. //
  2822. // 1. This function used to modify the in-memory table first, then
  2823. // go on to tackle the on-disk entry. It now does this in
  2824. // reverse order in order to avoid a situation where the
  2825. // in-memory table is changed but the disk representation isn't.
  2826. STATIC MMAPERR NEAR PASCAL MmaperrWriteTabEntry(
  2827. UINT uFlag,
  2828. UINT uIdx,
  2829. LPMMTABLEENTRY lpmmEntry)
  2830. {
  2831. HANDLE hTable;
  2832. LPMMTABLE lpmmTable;
  2833. LPMMTABLEENTRY lpmmOldEntry;
  2834. MMHEADER mmHeader;
  2835. UNALIGNED WORD *lpoTable;
  2836. MMAPERR mmaperr;
  2837. switch (uFlag) {
  2838. case MMAP_SETUP:
  2839. lpoTable = &mmHeader.oSetup;
  2840. hTable = hSetupTable;
  2841. break;
  2842. case MMAP_PATCH:
  2843. lpoTable = &mmHeader.oPatch;
  2844. hTable = hPatchTable;
  2845. break;
  2846. case MMAP_KEY:
  2847. lpoTable = &mmHeader.oKey;
  2848. hTable = hKeyTable;
  2849. break;
  2850. default:hTable = NULL; // Kill spurious use before set diag
  2851. lpoTable = NULL; // Kill spurious use before set diag
  2852. }
  2853. if (!uIdx)
  2854. uIdx = lpmmEntry->idxEntry;
  2855. uIdx--;
  2856. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READWRITE);
  2857. if (mmaperr != MMAPERR_SUCCESS)
  2858. return mmaperr;
  2859. if (_llseek(iFile, 0L, 0) == -1L) {
  2860. mmaperr = MMAPERR_READ;
  2861. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  2862. exit01: return mmaperr;
  2863. }
  2864. if ( _lread(iFile, (LPSTR)&mmHeader, sizeof(MMHEADER))
  2865. != sizeof(MMHEADER)
  2866. ) {
  2867. mmaperr = MMAPERR_READ;
  2868. goto exit00; // 00, not 01.
  2869. }
  2870. if (_llseek( iFile
  2871. , (LONG) ( *lpoTable
  2872. + sizeof(MMTABLEHEADER)
  2873. + uIdx * sizeof(MMTABLEENTRY)
  2874. )
  2875. , 0
  2876. ) == -1L
  2877. ) {
  2878. mmaperr = MMAPERR_WRITE;
  2879. goto exit00; // 00, not 01.
  2880. }
  2881. if ( _lwrite(iFile, (LPSTR)lpmmEntry, sizeof(MMTABLEENTRY))
  2882. != sizeof(MMTABLEENTRY)
  2883. ) {
  2884. mmaperr = MMAPERR_WRITE;
  2885. goto exit00; // 00, not 01.
  2886. }
  2887. mmaperr = MmaperrFileAccess(MAP_FCLOSE, 0);
  2888. if (mmaperr != MMAPERR_SUCCESS)
  2889. goto exit01;
  2890. // if the table is in memory, modify the in-memory table entry
  2891. if (hTable) {
  2892. lpmmTable = (LPMMTABLE)GlobalLock(hTable);
  2893. lpmmOldEntry = (LPMMTABLEENTRY)GlobalLock(lpmmTable->hEntrys);
  2894. lpmmOldEntry += uIdx;
  2895. *lpmmOldEntry = *lpmmEntry;
  2896. GlobalUnlock(lpmmTable->hEntrys);
  2897. GlobalUnlock(hTable);
  2898. }
  2899. return MMAPERR_SUCCESS;
  2900. } /* MmaperrWriteTabEntry */
  2901. // - - - - - - - - -
  2902. // MmaperrWriteTabHeader
  2903. //
  2904. // Write a table header.
  2905. //
  2906. // Side-effects of failure:
  2907. //
  2908. // 1. If the "close" fails something bad has happened to the file.
  2909. STATIC MMAPERR NEAR PASCAL MmaperrWriteTabHeader(
  2910. UINT uFlag,
  2911. LPMMTABLEHEADER lpmmHeader)
  2912. {
  2913. MMHEADER mmHeader;
  2914. UNALIGNED WORD *lpoTable;
  2915. MMAPERR mmaperr;
  2916. switch (uFlag) {
  2917. case MMAP_SETUP:
  2918. lpoTable = &mmHeader.oSetup;
  2919. break;
  2920. case MMAP_PATCH:
  2921. lpoTable = &mmHeader.oPatch;
  2922. break;
  2923. case MMAP_KEY:
  2924. lpoTable = &mmHeader.oKey;
  2925. break;
  2926. default:lpoTable = NULL; // Kill spurious use before set diagnostic
  2927. }
  2928. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READWRITE);
  2929. if (mmaperr != MMAPERR_SUCCESS)
  2930. return mmaperr;
  2931. if (_llseek(iFile, 0L, 0) == -1L) {
  2932. mmaperr = MMAPERR_READ;
  2933. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  2934. return mmaperr;
  2935. }
  2936. if (_lread(iFile, (LPSTR)&mmHeader, sizeof(MMHEADER)) != sizeof(MMHEADER))
  2937. {
  2938. mmaperr = MMAPERR_READ;
  2939. goto exit00;
  2940. }
  2941. if (_llseek(iFile, (LONG)*lpoTable, 0) == -1L) {
  2942. mmaperr = MMAPERR_WRITE;
  2943. goto exit00;
  2944. }
  2945. if ( _lwrite(iFile, (LPSTR)lpmmHeader, sizeof(MMTABLEHEADER))
  2946. != sizeof(MMTABLEHEADER)
  2947. ) {
  2948. mmaperr = MMAPERR_WRITE;
  2949. goto exit00;
  2950. }
  2951. return MmaperrFileAccess(MAP_FCLOSE, 0);
  2952. } /* MmaperrWriteTabHeader */
  2953. // MmaperrGarbage
  2954. //
  2955. // Increase the garbage-byte count.
  2956. //
  2957. // Side-effects:
  2958. //
  2959. // 1. None.
  2960. STATIC MMAPERR NEAR PASCAL MmaperrGarbage(
  2961. UINT uBytes)
  2962. {
  2963. MMHEADER mmHeader;
  2964. MMAPERR mmaperr;
  2965. mmaperr = MmaperrFileAccess(MAP_FOPEN, OF_READWRITE);
  2966. if (mmaperr != MMAPERR_SUCCESS)
  2967. return mmaperr;
  2968. if (_llseek(iFile, 0L, 0) == -1L) {
  2969. mmaperr = MMAPERR_READ;
  2970. exit00: (VOID)MmaperrFileAccess(MAP_FCLOSE, 0);
  2971. return mmaperr;
  2972. }
  2973. if (_lread(iFile, (LPSTR)&mmHeader, sizeof(MMHEADER)) != sizeof(MMHEADER)) {
  2974. mmaperr = MMAPERR_READ;
  2975. goto exit00;
  2976. }
  2977. mmHeader.dwGarbage += uBytes;
  2978. if (_llseek(iFile, 0L, 0) == -1L) {
  2979. mmaperr = MMAPERR_WRITE;
  2980. goto exit00;
  2981. }
  2982. if (_lwrite(iFile, (LPSTR)&mmHeader, sizeof(MMHEADER)) != sizeof(MMHEADER)) {
  2983. mmaperr = MMAPERR_WRITE;
  2984. goto exit00;
  2985. }
  2986. return MmaperrFileAccess(MAP_FCLOSE, 0);
  2987. } /* MmaperrGarbage */
  2988. // - - - - - - - - -
  2989. //
  2990. // MmaperrFileAccess
  2991. //
  2992. // Control the global file descriptor.
  2993. //
  2994. // Returns TRUE on success, FALSE on error.
  2995. //
  2996. // Remarks:
  2997. //
  2998. // 1. Opens/closes file potentially.
  2999. // 2. Modifies "iFile".
  3000. // 3. Modifies "ucFileOpen".
  3001. MMAPERR NEAR PASCAL MmaperrFileAccess(
  3002. int iFunc, /* MAP_FOPEN, MAP_FCREATE or MAP_FCLOSE */
  3003. int iMode)
  3004. {
  3005. OFSTRUCT of;
  3006. if (!fEditing)
  3007. {
  3008. char szMapCfg[MMAP_MAXCFGNAME];
  3009. GetSystemDirectory(aszMapperPath, sizeof(aszMapperPath));
  3010. LoadString(hLibInst,IDS_MIDIMAPCFG,szMapCfg,MMAP_MAXCFGNAME);
  3011. lstrcat(aszMapperPath, szMapCfg);
  3012. }
  3013. switch (iFunc) {
  3014. case MAP_FOPEN :
  3015. if (iFile != HFILE_ERROR) {
  3016. ucFileOpen++;
  3017. break;
  3018. }
  3019. iFile = OpenFile(aszMapperPath, &of, iMode);
  3020. if (iFile == HFILE_ERROR) {
  3021. if (of.nErrCode == 0x05)
  3022. return MMAPERR_OPEN_READONLY;
  3023. else
  3024. return MMAPERR_OPEN;
  3025. }
  3026. ucFileOpen++;
  3027. break;
  3028. case MAP_FCREATE :
  3029. iFile = OpenFile(aszMapperPath, &of,iMode|OF_CREATE|OF_READWRITE);
  3030. if (iFile == HFILE_ERROR)
  3031. return MMAPERR_CREATE;
  3032. ucFileOpen++;
  3033. break;
  3034. case MAP_FCLOSE :
  3035. if (!--ucFileOpen) {
  3036. _lclose(iFile);
  3037. iFile = HFILE_ERROR;
  3038. }
  3039. break;
  3040. }
  3041. return MMAPERR_SUCCESS;
  3042. } /* MmaperrFileAccess */
  3043. // - - - - - - - - -