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.

1199 lines
46 KiB

  1. /*
  2. * MIDI.C
  3. *
  4. * Copyright (C) 1990 Microsoft Corporation.
  5. *
  6. * The MIDI control panel applet.
  7. *
  8. * History:
  9. *
  10. * t-mikemc 10-Apr-90 Created.
  11. */
  12. /* Revision history:
  13. March 92 Ported to 16/32 common code by Laurie Griffiths (LaurieGr)
  14. */
  15. /*-=-=-=-=- Include Files -=-=-=-=-*/
  16. #include "preclude.h"
  17. #include <windows.h>
  18. #include <mmsystem.h>
  19. #if defined(WIN32)
  20. #include <port1632.h>
  21. #endif
  22. #include "hack.h"
  23. #include "midimap.h"
  24. #include <cpl.h>
  25. #include "cphelp.h"
  26. #include "cparrow.h"
  27. #include "midi.h"
  28. /*-=- poop -=-*/
  29. #define MM_MAXRESLEN 32 // arbitrary maximum resource string length
  30. /*-=-=-=-=- Prototypes -=-=-=-=-*/
  31. INT_PTR CALLBACK MainBox (HWND, UINT, WPARAM, LPARAM);
  32. BOOL NEAR PASCAL LibMain(HINSTANCE,UINT,LPSTR);
  33. #if defined(WIN16)
  34. #pragma alloc_text(_INIT, LibMain)
  35. #endif //WIN16
  36. LRESULT FAR PASCAL _loadds CPlApplet(HWND,UINT,WPARAM,LPARAM);
  37. #if defined(WIN16)
  38. #pragma alloc_text(_INIT, CPlApplet)
  39. #endif //WIN16
  40. void NEAR PASCAL InitCPL(void);
  41. #if defined(WIN16)
  42. #pragma alloc_text(_INIT, InitCPL)
  43. #endif //WIN16
  44. /*-=-=-=-=- Global Variables -=-=-=-=-*/
  45. /* This many global variables is a sure sign of sickness. LaurieGr */
  46. HINSTANCE hLibInst; // Library instance handle.
  47. HGLOBAL hKeyMap; // Midikeymap handle.
  48. HFONT hFont; // Dialog box font handle.
  49. HWND hWnd, // Current window handle.
  50. hCombo, // Combo box handle.
  51. hEdit, // Edit control handle.
  52. hArrow; // Arrow control handle.
  53. RECT rcBox; // Clipping/scroll rectangle.
  54. int rgxPos[8], // horizontal line positions.
  55. yBox, // rows of data y extent
  56. xClient, // Window client area x pixels.
  57. yClient, // Window client area y pixels.
  58. iCurPos, // Current position on screen.
  59. iVertPos, // Current vertical scroll position.
  60. iVertMax, // Maximum veritcal scroll position.
  61. nLines, // Number of lines of data.
  62. yChar, // Height of character in font.
  63. xChar, // Width of average character in font.
  64. iMap; // Current map type being edited.
  65. char szCurrent[MMAP_MAXNAME], // Current map name.
  66. szCurDesc[MMAP_MAXDESC], // Current map description.
  67. szCurSetup[MMAP_MAXNAME], // Current setup
  68. szNone[16], // Generic global string.
  69. szMidiCtl[64], // Window caption for midicpl.
  70. aszSourceKey[32],
  71. aszSourceKeyName[40],
  72. aszPatchNumber[40],
  73. aszSourcePatch[32],
  74. aszSourcePatchName[40],
  75. aszSourceMnumonic[5],
  76. aszSourceChannel[32],
  77. aszActive[32],
  78. szMidiHlp[24];
  79. BOOL fModified, // Flag; Has the map been modified?
  80. fChanged, // Flag; Has anything ever been changed?
  81. fNew, // Flag; Is this a new map?
  82. fHidden; // Flag; Is the acitve line hidden?
  83. BOOL fReadOnly;
  84. char aszClose[16];
  85. static char aszCaptionFormat[24];
  86. static SZCODE szHelpMessage[] = "ShellHelp";
  87. static SZCODE aszTempPrefix[] = "mmr"; // limited to 3 characters
  88. static SZCODE aszFontName[] = "MS Sans Serif";
  89. static BOOL fAppletEntered; // Disallow multiple applet instances
  90. UINT near uHelpMessage;
  91. DWORD near dwContext;
  92. typedef struct {
  93. int idIcon;
  94. int idName;
  95. int idInfo;
  96. BOOL bEnabled;
  97. DWORD dwContext;
  98. PSTR pszHelp;
  99. } APPLET_INFO;
  100. #define NUM_APPLETS 1
  101. APPLET_INFO near applets[NUM_APPLETS];
  102. /* Move the window, if necessary, to keep it on the desktop, as far as possible */
  103. VOID PlaceWindow(HWND hwnd)
  104. {
  105. RECT rcWind; /* window rectangle */
  106. HDC hdc; /* so we can get device capabilities -i.e. screen size */
  107. int up; /* amount to move window up */
  108. int left; /* amount to move window left */
  109. int HorzRes; /* horizontal screen resolution in pixels */
  110. int VertRes; /* vertical screen resolution in lines */
  111. /* GetWindowRect(HWND_DESKTOP, &rcDesk) doesn't work! */
  112. hdc = GetDC(hwnd);
  113. HorzRes = GetDeviceCaps(hdc,HORZRES);
  114. VertRes = GetDeviceCaps(hdc,VERTRES);
  115. GetWindowRect(hwnd, &rcWind);
  116. up = rcWind.bottom - VertRes; /* how much to move up to get onto screen... */
  117. if (up<0) up = 0; /* don't bother to go down to get to the bottom */
  118. if (up>rcWind.top) up = rcWind.top; /* don't ever go off the top */
  119. left = rcWind.right - HorzRes; /* how much to move left to get all on screen... */
  120. if (left<0) left = 0; /* don't bother to go right */
  121. if (left>rcWind.left) left = rcWind.left; /* but don't ever go off the left */
  122. SetWindowPos( hwnd, HWND_TOP, rcWind.left-left, rcWind.top-up, 0,0,SWP_NOSIZE);
  123. } /* PlaceWindow */
  124. VOID NEAR PASCAL CancelToClose(HWND hDlg)
  125. {
  126. if (!fReadOnly) {
  127. char aszText[16];
  128. GetDlgItemText(hDlg, IDOK, aszText, sizeof(aszText));
  129. if (lstrcmp(aszText, aszClose))
  130. SetDlgItemText(hDlg, IDOK, aszClose);
  131. }
  132. }
  133. // - - - - - - - - -
  134. // Windows entry point.
  135. BOOL NEAR PASCAL LibMain(
  136. HINSTANCE hInstance,
  137. UINT uHeapSize,
  138. LPSTR lpCmdLine)
  139. {
  140. hLibInst = hInstance;
  141. return TRUE;
  142. }
  143. void NEAR PASCAL InitCPL(void)
  144. {
  145. if ( applets[0].idIcon == 0 )
  146. {
  147. LoadString(hLibInst, IDS_CLOSE, aszClose, sizeof(aszClose));
  148. applets[0].idIcon = ID_ICON;
  149. applets[0].idName = IDS_NAME;
  150. applets[0].idInfo = IDS_INFO;
  151. applets[0].bEnabled = TRUE;
  152. applets[0].dwContext = IDH_CHILD_MIDI;
  153. applets[0].pszHelp = szMidiHlp;
  154. LoadString(hLibInst, IDS_NONE, szNone, sizeof(szNone));
  155. LoadString(hLibInst, IDS_HELPFILE, szMidiHlp, sizeof(szMidiHlp));
  156. LoadString(hLibInst, IDS_SOURCEKEY, aszSourceKey, sizeof(aszSourceKey));
  157. LoadString(hLibInst, IDS_SOURCEKEYNAME, aszSourceKeyName, sizeof(aszSourceKeyName));
  158. LoadString(hLibInst, IDS_PATCHNUMBER, aszPatchNumber, sizeof(aszPatchNumber));
  159. LoadString(hLibInst, IDS_SOURCEPATCH, aszSourcePatch, sizeof(aszSourcePatch));
  160. LoadString(hLibInst, IDS_SOURCEPATCHNAME, aszSourcePatchName, sizeof(aszSourcePatchName));
  161. LoadString(hLibInst, IDS_SOURCEMNUMONIC, aszSourceMnumonic, sizeof(aszSourceMnumonic));
  162. LoadString(hLibInst, IDS_SOURCECHANNEL, aszSourceChannel, sizeof(aszSourceChannel));
  163. LoadString(hLibInst, IDS_ACTIVETITLE, aszActive, sizeof(aszActive));
  164. }
  165. }
  166. #ifdef STUPID
  167. /*
  168. * ComboBox String Lookup, written because we
  169. * let an intern design this applet.
  170. */
  171. int FAR PASCAL ComboLookup(
  172. HWND hCombo,
  173. LPSTR szLookup)
  174. {
  175. int iEntries;
  176. static char szBuf[29];
  177. PSTR pstrBuf;
  178. iEntries = (int)(LONG)SendMessage(hCombo,CB_GETCOUNT,(WPARAM)0,(LPARAM)0);
  179. if (iEntries > CB_ERR)
  180. {
  181. do
  182. {
  183. iEntries--;
  184. pstrBuf = szBuf;
  185. if ((int)(LONG)SendMessage(hCombo,CB_GETLBTEXT,(WPARAM)iEntries,(LPARAM)(LPSTR)szBuf) == CB_ERR)
  186. return CB_ERR;
  187. if (lstrcmpi(szLookup,pstrBuf) == 0)
  188. return iEntries;
  189. }
  190. while(iEntries);
  191. }
  192. return CB_ERR;
  193. }
  194. #endif
  195. // Given an error code, display an error message. If the error code
  196. // was invalid, displays a default bogus English-language text string.
  197. VOID FAR PASCAL VShowError(
  198. HWND hwnd, // Window to tie the message box to.
  199. MMAPERR mmaperr) // Error code to display text for.
  200. {
  201. char asz[256];
  202. LoadString(hLibInst, IDS_MMAPERR_BASE + mmaperr, asz, sizeof(asz));
  203. MessageBox(hwnd, asz, NULL, MB_ICONEXCLAMATION | MB_OK);
  204. }
  205. // - - - - - - - - -
  206. // Returns TRUE if the file exists and is correct, or was initialized
  207. // properly. Returns FALSE if the user didn't want it initialized, or
  208. // if the initialization failed.
  209. //
  210. // This function deals with English-language specific stuff. There is
  211. // no good reason for this that I can see.
  212. static BOOL FAR PASCAL FGetMapFile(
  213. HWND hwnd)
  214. {
  215. char aszBuf[256];
  216. DWORD dwVersion;
  217. MMAPERR mmaperr;
  218. //
  219. // An error return from "mapFileVersion" indicates a problem that
  220. // I don't want to go into too specifically at this time. The
  221. // most likely event is that the file doesn't exist. The code in
  222. // in this function assumes that this is what happened. If it
  223. // was another problem, hopefully initializing the file will
  224. // solve it. This can be looked into later.
  225. //
  226. dwVersion = mapFileVersion();
  227. if ((HIWORD(dwVersion) == MMAPERR_SUCCESS) &&
  228. (LOWORD(dwVersion) == 1))
  229. return TRUE; // File was fine (opened + was right version).
  230. //
  231. // This code is executing if there was a problem opening the
  232. // file. Hopefully this problem involved non-existence.
  233. //
  234. LoadString(hLibInst, IDS_CREATE_QUESTION, aszBuf, sizeof(aszBuf));
  235. if (MessageBox(hwnd, aszBuf, szMidiCtl,
  236. MB_YESNO | MB_ICONHAND) == IDYES)
  237. if ((mmaperr = mapInitMapFile()) == MMAPERR_SUCCESS)
  238. return TRUE;
  239. else
  240. VShowError(hwnd, mmaperr);
  241. return FALSE;
  242. }
  243. // - - - - - - - - -
  244. // Control panel entry point.
  245. LRESULT FAR PASCAL _loadds CPlApplet(
  246. HWND hCPlWnd,
  247. UINT uMessage,
  248. WPARAM lParam1,
  249. LPARAM lParam2)
  250. {
  251. LPNEWCPLINFO lpCPlInfo;
  252. BOOL fSuccess = TRUE;
  253. BOOL fBackup;
  254. LPSTR lpstrBakPath;
  255. LPSTR lpstrCfgPath;
  256. int iApplet;
  257. switch (uMessage) {
  258. case CPL_INIT :
  259. InitCPL();
  260. uHelpMessage = RegisterWindowMessage(szHelpMessage);
  261. hWnd = hCPlWnd;
  262. return (LRESULT)TRUE;
  263. case CPL_GETCOUNT :
  264. return (LRESULT)NUM_APPLETS;
  265. case CPL_NEWINQUIRE :
  266. lpCPlInfo = (LPNEWCPLINFO)lParam2;
  267. iApplet = (int)(LONG)lParam1;
  268. lpCPlInfo->hIcon = LoadIcon(hLibInst,
  269. MAKEINTRESOURCE(applets[iApplet].idIcon));
  270. LoadString(hLibInst, applets[iApplet].idName, lpCPlInfo->szName, sizeof(lpCPlInfo->szName));
  271. LoadString(hLibInst, applets[iApplet].idInfo, lpCPlInfo->szInfo, sizeof(lpCPlInfo->szInfo));
  272. lpCPlInfo->dwSize = sizeof(NEWCPLINFO);
  273. lpCPlInfo->lData = (LONG)iApplet;
  274. lpCPlInfo->dwHelpContext = applets[iApplet].dwContext;
  275. lstrcpy(lpCPlInfo->szHelpFile, applets[iApplet].pszHelp);
  276. return (LRESULT)TRUE;
  277. case CPL_DBLCLK :
  278. if (fAppletEntered)
  279. break;
  280. //
  281. // We can enter into lots of bizarre states:
  282. // We become READ-ONLY IF:
  283. // We cannot lock the mapper.
  284. // There is a disk or memory exception backing up the
  285. // existing MIDIMAP.CFG file or the MIDIMAP.CFG
  286. // is READ ONLY.
  287. // We DO NOT use a backup IF:
  288. // The mapper is locked.
  289. // No MIDIMAP.CFG file is found.
  290. // There is an exception dealing with backing up the
  291. // the existing MIDIMAP.CFG file.
  292. //
  293. lpstrCfgPath = GlobalLock(GlobalAlloc(GHND,MAXPATHLEN));
  294. if (lpstrCfgPath == NULL)
  295. {
  296. VShowError(hCPlWnd,IDS_MMAPERR_MEMORY);
  297. break;
  298. }
  299. lpstrBakPath = GlobalLock(GlobalAlloc(GHND,MAXPATHLEN));
  300. if (lpstrBakPath == NULL)
  301. {
  302. VShowError(hCPlWnd,IDS_MMAPERR_MEMORY);
  303. goto exitfree;
  304. }
  305. fAppletEntered = TRUE;
  306. if (!mapLock()) // Attempt to lock the mapper
  307. {
  308. char szApp[32],
  309. szMessage[256];
  310. LoadString(hLibInst, IDS_READONLYMODE, szMessage, sizeof(szMessage));
  311. LoadString(hLibInst, IDS_TITLE, szApp, sizeof(szApp));
  312. MessageBox(hCPlWnd, szMessage, szApp,
  313. MB_ICONINFORMATION | MB_OK);
  314. fBackup = FALSE; // No backups
  315. fReadOnly = TRUE; // Read Only Mode
  316. }
  317. else
  318. {
  319. fBackup = TRUE; // Try to do a backup
  320. fReadOnly = FALSE; // Not in READ ONLY mode
  321. }
  322. if (fBackup)
  323. {
  324. char szMapCfg[MMAP_MAXCFGNAME];
  325. LoadString(hLibInst,IDS_MIDIMAPCFG,szMapCfg,MMAP_MAXCFGNAME);
  326. GetSystemDirectory(lpstrCfgPath,MAXPATHLEN - sizeof(szMapCfg));
  327. lstrcat(lpstrCfgPath,szMapCfg);
  328. MGetTempFileName(0, aszTempPrefix,0,lpstrBakPath);
  329. if (DupMapCfg(lpstrCfgPath,lpstrBakPath)) {
  330. mapConnect(lpstrBakPath);
  331. }
  332. else
  333. {
  334. // No Backups.
  335. fBackup = FALSE;
  336. // if fReadOnly == TRUE, the exception
  337. // has forced us into READ-ONLY mode
  338. // else
  339. // we didn't have a MIDIMAP.CFG file
  340. // and we'll read/write directly.
  341. if (fReadOnly)
  342. mapUnlock();
  343. DosDelete(lpstrBakPath); // GetTempFileName Creates a File of size 0
  344. }
  345. }
  346. if (!FGetMapFile(hCPlWnd))
  347. {
  348. fSuccess = FALSE;
  349. goto appexit;
  350. }
  351. // !!! Never unregisters the class, so this will come back
  352. // FALSE on subsequent startups. This is of course bogus.
  353. (VOID)RegisterArrowClass(hLibInst);
  354. #if 0
  355. if ((hFont = CreateFont(8, NULL, NULL, NULL,
  356. FW_NORMAL, NULL, NULL, NULL,
  357. ANSI_CHARSET, OUT_DEFAULT_PRECIS,
  358. CLIP_DEFAULT_PRECIS, PROOF_QUALITY,
  359. VARIABLE_PITCH | FF_DONTCARE, aszFontName)) == NULL)
  360. goto appexit;
  361. #else
  362. {
  363. LOGFONT lf;
  364. SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), (LPVOID)&lf, 0);
  365. if (!(hFont = CreateFontIndirect(&lf)))
  366. goto appexit;
  367. }
  368. #endif
  369. fSuccess = (BOOL)DialogBox(hLibInst, MAKEINTRESOURCE(ID_MAINBOX),
  370. hCPlWnd, MainBox);
  371. UnregisterArrowClass(hLibInst);
  372. DeleteObject(hFont);
  373. appexit:
  374. if (fBackup)
  375. {
  376. MDOUT("Disconnecting from mapper");
  377. mapDisconnect();
  378. if (fSuccess)
  379. {
  380. MDOUT("Updating Backup");
  381. UpdateMapCfg(lpstrCfgPath,lpstrBakPath);
  382. }
  383. mapUnlock();
  384. DosDelete(lpstrBakPath);
  385. }
  386. else
  387. if (!fReadOnly)
  388. {
  389. mapUnlock();
  390. if (!fSuccess)
  391. DosDelete(lpstrCfgPath);
  392. }
  393. fAppletEntered = FALSE;
  394. GlobalFree((HGLOBAL)lpstrBakPath);
  395. exitfree: GlobalFree((HGLOBAL)lpstrCfgPath);
  396. break;
  397. }
  398. return (LRESULT)0;
  399. }
  400. // - - - - - - - - -
  401. // This will return either "MMAPERR_SUCCESS" if everything is fine,
  402. // or will return "MMAPERR_INVALIDPORT" if the setup references a
  403. // bogus port. These are both expected conditions.
  404. //
  405. // Unexpected conditions can also happen, which are returned.
  406. static MMAPERR NEAR PASCAL MmaperrInvalidPortCheck(
  407. LPSTR lszName) // Name of current setup.
  408. {
  409. LPMIDIMAP lpMap;
  410. MMAPERR mmaperr;
  411. DWORD dwSize;
  412. HGLOBAL hMidiMap;
  413. if ((dwSize = mapGetSize(MMAP_SETUP, lszName)) < MMAPERR_MAXERROR)
  414. return (MMAPERR)dwSize;
  415. if ((hMidiMap = GlobalAlloc(GHND, dwSize)) == NULL)
  416. return MMAPERR_MEMORY;
  417. lpMap = (LPMIDIMAP)GlobalLock(hMidiMap);
  418. mmaperr = mapRead(MMAP_SETUP, lszName, (LPVOID)lpMap);
  419. GlobalUnlock(hMidiMap);
  420. GlobalFree(hMidiMap);
  421. return mmaperr;
  422. }
  423. // - - - - - - - - -
  424. // Converts a "MMAP_" into a "IDS_", i.e. converts "MMAP_SETUP" into
  425. // "IDS_SETUP", which can be used to get the word "Setup" out of the
  426. // "midi.rc" file.
  427. static int PASCAL IdsGetMapNameId( int iMap)
  428. {
  429. if (iMap == MMAP_SETUP)
  430. return IDS_SETUP;
  431. if (iMap == MMAP_PATCH)
  432. return IDS_PATCH;
  433. return IDS_KEY;
  434. }
  435. // - - - - - - - - -
  436. /*
  437. * DELETEMAP
  438. *
  439. * This function returns TRUE if it is OK to delete whatever map
  440. * exists in szCurrent.
  441. */
  442. static BOOL NEAR PASCAL FConfirmDeleteMap(
  443. HWND hwnd)
  444. {
  445. char szSetup[MMAP_MAXNAME],
  446. szSrc[MM_MAXRESLEN],
  447. szUsedBy[MM_MAXRESLEN],
  448. szDel[50],
  449. szCap[50],
  450. szRsrc[256],
  451. szBuf[256];
  452. DWORD dwRet;
  453. UINT uSrcID;
  454. UINT uUsage;
  455. MMAPERR mmaperr;
  456. uSrcID = IdsGetMapNameId(iMap);
  457. LoadString(hLibInst, uSrcID, szSrc, sizeof(szSrc));
  458. LoadString(hLibInst, IDS_DELETE, szDel, sizeof(szDel));
  459. wsprintf(szCap, szDel, (LPSTR)szSrc);
  460. // AnsiUpperBuff(szSrc, 1); // Upper-case first character.
  461. switch (iMap) {
  462. case MMAP_SETUP:
  463. if ((mmaperr = mapGetCurrentSetup(szSetup,
  464. MMAP_MAXNAME)) != MMAPERR_SUCCESS) {
  465. VShowError(hwnd, mmaperr);
  466. return FALSE;
  467. }
  468. if (lstrcmpi(szSetup, szCurrent))
  469. break;
  470. LoadString(hLibInst, IDS_NODELISCURRENT, szRsrc, sizeof(szRsrc));
  471. wsprintf(szBuf, szRsrc, (LPSTR)szCurrent);
  472. MessageBox(hwnd, szBuf, szCap,
  473. MB_ICONINFORMATION | MB_OK);
  474. return FALSE;
  475. case MMAP_PATCH:
  476. case MMAP_KEY:
  477. dwRet = mapGetUsageCount(iMap, szCurrent);
  478. if (LOWORD(dwRet) != MMAPERR_SUCCESS) {
  479. VShowError(hwnd, LOWORD(dwRet));
  480. return FALSE;
  481. }
  482. if (!(uUsage = HIWORD(dwRet)))
  483. break;
  484. uSrcID--; // Patch->Setup, Key->Patch
  485. if (uUsage > 1) // Make a singular a plural. This
  486. uSrcID += 3; // "3" is commented in "midi.h".
  487. LoadString(hLibInst, uSrcID, szUsedBy, sizeof(szUsedBy));
  488. // AnsiLowerBuff(szUsedBy, 1); // Lower-case first character.
  489. LoadString(hLibInst, IDS_NODELISREFERENCED, szRsrc, sizeof(szRsrc));
  490. wsprintf(szBuf, szRsrc, (LPSTR)szSrc, (LPSTR)szCurrent,
  491. uUsage, (LPSTR)szUsedBy);
  492. MessageBox (hwnd, szBuf, szCap,
  493. MB_ICONINFORMATION | MB_OK);
  494. return FALSE;
  495. }
  496. LoadString(hLibInst, IDS_VERIFYDELETE, szRsrc, sizeof(szRsrc));
  497. wsprintf(szBuf, szRsrc, (LPSTR)szSrc, (LPSTR)szCurrent);
  498. return (IDYES == MessageBox (hwnd, szBuf, szCap,
  499. MB_ICONEXCLAMATION | MB_YESNO));
  500. }
  501. static VOID NEAR PASCAL VFreeItemData(
  502. HWND hdlg,
  503. int idCtrl)
  504. {
  505. UINT uCount;
  506. uCount = (UINT)SendDlgItemMessage(hdlg, idCtrl, CB_GETCOUNT, (WPARAM)NULL, (LPARAM)0);
  507. for (; uCount--; ) {
  508. HGLOBAL hDescription;
  509. if ((hDescription = (HGLOBAL)(DWORD)SendDlgItemMessage(hdlg, idCtrl,
  510. CB_GETITEMDATA, (WPARAM)uCount, (LPARAM)0)) != NULL)
  511. GlobalFree(hDescription);
  512. }
  513. }
  514. static VOID NEAR PASCAL GetMBData(
  515. UINT uFlag,
  516. LPMBDATA lpmbData)
  517. {
  518. switch (uFlag) {
  519. case MMAP_SETUP:
  520. lpmbData->lpfnBox = SetupBox;
  521. lpmbData->idBox = DLG_SETUPEDIT;
  522. break;
  523. case MMAP_PATCH:
  524. lpmbData->lpfnBox = PatchBox;
  525. lpmbData->idBox = DLG_PATCHEDIT;
  526. break;
  527. case MMAP_KEY:
  528. lpmbData->lpfnBox = KeyBox;
  529. lpmbData->idBox = DLG_KEYEDIT;
  530. break;
  531. default:
  532. lpmbData->lpfnBox = 0L;
  533. lpmbData->idBox = 0;
  534. break;
  535. }
  536. } /* GetMBData */
  537. static BOOL PASCAL FEditMap(
  538. HWND hwnd)
  539. {
  540. HWND hTmpWnd;
  541. MBDATA mbData;
  542. DWORD dwRet;
  543. int iRet;
  544. BOOL fInSetup;
  545. char szSetup[MMAP_MAXNAME];
  546. MMAPERR mmaperr;
  547. if ((mmaperr = mapGetCurrentSetup(szSetup,
  548. MMAP_MAXNAME)) != MMAPERR_SUCCESS) {
  549. VShowError(hwnd, mmaperr);
  550. return FALSE;
  551. }
  552. switch (iMap) {
  553. case MMAP_SETUP :
  554. fInSetup = (BOOL)!lstrcmpi(szCurrent, szSetup);
  555. break;
  556. case MMAP_PATCH :
  557. dwRet = mapPatchMapInSetup(szCurrent, szSetup);
  558. if (LOWORD(dwRet) != MMAPERR_SUCCESS)
  559. return FALSE;
  560. fInSetup = (BOOL)HIWORD(dwRet);
  561. break;
  562. case MMAP_KEY :
  563. dwRet = mapKeyMapInSetup (szCurrent, szSetup);
  564. if (LOWORD(dwRet) != MMAPERR_SUCCESS)
  565. return FALSE;
  566. fInSetup = (BOOL)HIWORD(dwRet);
  567. break;
  568. }
  569. hTmpWnd = hWnd; // "hWnd", not "hwnd".
  570. GetMBData(iMap, &mbData);
  571. iRet = (int)DialogBox(hLibInst, MAKEINTRESOURCE(mbData.idBox),
  572. hWnd, mbData.lpfnBox);
  573. hWnd = hTmpWnd;
  574. return iRet;
  575. } /* FEditMap */
  576. static VOID NEAR PASCAL EnableMain(
  577. BOOL fEnable)
  578. {
  579. char aszNoEntries[48];
  580. EnableWindow(hCombo, fEnable);
  581. if (fReadOnly)
  582. {
  583. EnableWindow(GetDlgItem (hWnd, ID_MAINDELETE), FALSE);
  584. EnableWindow(GetDlgItem (hWnd,ID_MAINNEW),FALSE);
  585. }
  586. else
  587. EnableWindow(GetDlgItem (hWnd, ID_MAINDELETE), fEnable);
  588. EnableWindow(GetDlgItem (hWnd, ID_MAINEDIT), fEnable);
  589. EnableWindow(GetDlgItem (hWnd, ID_MAINDESC), fEnable);
  590. EnableWindow(GetDlgItem (hWnd, ID_MAINNAME), fEnable);
  591. if (!fEnable) {
  592. LoadString(hLibInst, IDS_NOENTRIES, aszNoEntries, sizeof(aszNoEntries));
  593. SetDlgItemText(hWnd, ID_MAINDESC, aszNoEntries);
  594. }
  595. } /* EnableMain */
  596. static VOID NEAR PASCAL ShowMaps (int nMap)
  597. {
  598. if (iMap == nMap)
  599. return;
  600. iMap = nMap;
  601. SendMessage(hWnd, WM_MY_INITDIALOG, (WPARAM)NULL, (LPARAM)0);
  602. } /* ShowMaps */
  603. INT_PTR CALLBACK MainBox(
  604. HWND hdlg,
  605. UINT uMessage,
  606. WPARAM wParam,
  607. LPARAM lParam)
  608. {
  609. static BOOL fChange, // has edittext changed?
  610. fPatchEnum, // have patches been enum'd?
  611. fKeyEnum, // have keys been enum'd?
  612. fEnabled;
  613. static UINT uDeleted; // which maps types deleted
  614. static char aszInitialSetup[MMAP_MAXNAME]; // initial setup name
  615. MMAPERR mmaperr;
  616. HGLOBAL hDesc;
  617. LPSTR lpDesc;
  618. UINT uIdx;
  619. int idCurCombo;
  620. BOOL fEnum;
  621. // char szBuf[128];
  622. char szTmpDesc[MMAP_MAXDESC];
  623. switch (uMessage) {
  624. case WM_INITDIALOG:
  625. // get the current setup name and store in
  626. // static aszInitialSetup
  627. fChanged = FALSE;
  628. if ((mmaperr = mapGetCurrentSetup(aszInitialSetup,
  629. MMAP_MAXNAME)) != MMAPERR_SUCCESS) {
  630. exit00: VShowError(hdlg, mmaperr);
  631. /*exit01:*/ EndDialog (hdlg, FALSE);
  632. return TRUE;
  633. }
  634. lstrcpy(szCurSetup, aszInitialSetup);
  635. // Load caption string and set the window text
  636. LoadString(hLibInst, IDS_TITLE, szMidiCtl, sizeof(szMidiCtl));
  637. hWnd = hdlg;
  638. SetWindowText(hdlg, szMidiCtl);
  639. /*!!
  640. // check for invalid devices
  641. if ((mmaperr = MmaperrInvalidPortCheck(
  642. aszInitialSetup)) == MMAPERR_INVALIDPORT) {
  643. if (!InvalidPortMsgBox(hdlg))
  644. goto exit01;
  645. }
  646. else if (mmaperr != MMAPERR_SUCCESS)
  647. goto exit00;
  648. !!*/
  649. // hide the patch and key comboboxes
  650. ShowWindow(GetDlgItem(hdlg, ID_MAINPATCHCOMBO), SW_HIDE);
  651. ShowWindow(GetDlgItem(hdlg, ID_MAINKEYCOMBO), SW_HIDE);
  652. // enumerate setups into setup combo box
  653. mmaperr = mapEnumerate( MMAP_SETUP
  654. , EnumFunc
  655. , MMENUM_INTOCOMBO
  656. , GetDlgItem( hdlg, ID_MAINSETUPCOMBO)
  657. , NULL
  658. );
  659. if ( mmaperr != MMAPERR_SUCCESS )
  660. goto exit00;
  661. // set up the auto-radiobuttons
  662. CheckRadioButton(hdlg, ID_MAINFIRSTRADIO,
  663. ID_MAINLASTRADIO, ID_MAINSETUP);
  664. // intialize some variables
  665. *szCurrent = 0;
  666. hCombo = NULL;
  667. iMap = MMAP_SETUP;
  668. fEnabled = FALSE; // Fix for bug #2039. 13-Feb-90, BLM.
  669. // It used to set the variable TRUE.
  670. fChange = FALSE;
  671. fPatchEnum = FALSE;
  672. fKeyEnum = FALSE;
  673. uDeleted = 0;
  674. // fall through
  675. case WM_MY_INITDIALOG:
  676. fEnum = FALSE;
  677. switch (iMap) {
  678. case MMAP_SETUP:
  679. idCurCombo = ID_MAINSETUPCOMBO;
  680. uIdx = ComboLookup(GetDlgItem(hdlg,idCurCombo),(LPSTR)szCurSetup);//-jyg
  681. break;
  682. case MMAP_PATCH:
  683. idCurCombo = ID_MAINPATCHCOMBO;
  684. if (!fPatchEnum) {
  685. fEnum = TRUE;
  686. fPatchEnum = TRUE;
  687. }
  688. uIdx = 0;
  689. break;
  690. case MMAP_KEY:
  691. idCurCombo = ID_MAINKEYCOMBO;
  692. if (!fKeyEnum) {
  693. fEnum = TRUE;
  694. fKeyEnum = TRUE;
  695. }
  696. uIdx = 0;
  697. break;
  698. default:uIdx = 0;
  699. idCurCombo = 0; /* kill compiler warning about use before set */
  700. }
  701. // hide the old combobox, if any
  702. if (hCombo != NULL)
  703. ShowWindow (hCombo, SW_HIDE);
  704. // get the new combobox handle
  705. hCombo = GetDlgItem (hdlg, idCurCombo);
  706. // show the new combobox
  707. ShowWindow(hCombo, SW_SHOW);
  708. // if not done already, enumerate maps into the box
  709. if (fEnum)
  710. { mmaperr = mapEnumerate(iMap, EnumFunc, MMENUM_INTOCOMBO, hCombo, NULL);
  711. if (mmaperr != MMAPERR_SUCCESS)
  712. goto exit00;
  713. }
  714. // set the current selection
  715. uIdx = (UINT)SendMessage(hCombo, CB_SETCURSEL, (WPARAM)uIdx, (LPARAM)0);
  716. // if no maps of that type, disable all necessary controls
  717. if (uIdx == CB_ERR) {
  718. *szCurrent = 0;
  719. EnableMain(fEnabled = FALSE);
  720. break;
  721. }
  722. // if we were disabled, enable us
  723. if (!fEnabled)
  724. EnableMain(fEnabled = TRUE);
  725. // fill the edit control with description
  726. #if defined(WIN16)
  727. SendMessage(hdlg, WM_COMMAND, (WPARAM)ID_MAINCOMBO,
  728. MAKELPARAM(hCombo, CBN_SELCHANGE));
  729. #else
  730. SendMessage( hdlg
  731. , WM_COMMAND
  732. , (WPARAM)MAKELONG(ID_MAINCOMBO, CBN_SELCHANGE)
  733. , (LPARAM)hCombo
  734. );
  735. #endif // WIN16
  736. break;
  737. case WM_COMMAND:
  738. { WORD wNotifCode;
  739. #if defined(WIN16)
  740. wNotifCode = HIWORD(lParam);
  741. #else
  742. wNotifCode = HIWORD(wParam);
  743. #endif //WIN16
  744. switch (LOWORD(wParam)) {
  745. case IDH_CHILD_MIDI:
  746. goto DoHelp;
  747. case IDOK:
  748. if (fReadOnly || !fChanged)
  749. {
  750. PostMessage(hdlg,WM_COMMAND,(WPARAM)IDCANCEL,(LPARAM)0);
  751. break;
  752. }
  753. // check for invalid ports
  754. if ((mmaperr = MmaperrInvalidPortCheck(
  755. szCurSetup)) == MMAPERR_INVALIDPORT) {
  756. if (!InvalidPortMsgBox(hdlg))
  757. break;
  758. } else if (mmaperr != MMAPERR_SUCCESS)
  759. goto exit00;
  760. if (lstrcmpi(szCurSetup, aszInitialSetup))
  761. {
  762. mmaperr = mapSetCurrentSetup(
  763. szCurSetup);
  764. if (mmaperr !=
  765. MMAPERR_SUCCESS)
  766. goto exit00;
  767. }
  768. // this is where any deleted maps actually get the axe
  769. //
  770. // I'm going to leave this as is until I figure
  771. // out how to deal with any errors that happen.
  772. // brucemo
  773. //
  774. #if 0
  775. if (uDeleted & MMAP_SETUP)
  776. mapEnumerate( iMap = MMAP_SETUP
  777. , EnumFunc
  778. , MMENUM_DELETE
  779. , GetDlgItem(hdlg,ID_MAINSETUPCOMBO)
  780. , NULL
  781. );
  782. if (uDeleted & MMAP_PATCH)
  783. mapEnumerate( iMap = MMAP_PATCH
  784. , EnumFunc
  785. , MMENUM_DELETE
  786. , GetDlgItem(hdlg,ID_MAINPATCHCOMBO)
  787. , NULL
  788. );
  789. if (uDeleted & MMAP_KEY)
  790. mapEnumerate( iMap = MMAP_KEY
  791. , EnumFunc,
  792. , MMENUM_DELETE
  793. , GetDlgItem (hdlg,ID_MAINKEYCOMBO)
  794. , NULL
  795. );
  796. #endif
  797. case IDCANCEL:
  798. // clean up and go home
  799. VFreeItemData(hdlg, ID_MAINSETUPCOMBO);
  800. if (fPatchEnum)
  801. VFreeItemData(hdlg, ID_MAINPATCHCOMBO);
  802. if (fKeyEnum)
  803. VFreeItemData(hdlg, ID_MAINKEYCOMBO);
  804. if (LOWORD(wParam) == IDOK) // eh?
  805. EndDialog(hdlg,TRUE);
  806. else
  807. EndDialog(hdlg,FALSE);
  808. break;
  809. case ID_MAINDELETE:
  810. if (!FConfirmDeleteMap(hdlg))
  811. break;
  812. CancelToClose(hdlg);
  813. // set a bit in the deleted word
  814. uDeleted |= iMap;
  815. // get the current selections index
  816. uIdx = (UINT)SendMessage(hCombo,
  817. CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
  818. // get the handle to selections description
  819. if ((hDesc = (HGLOBAL)(DWORD)SendMessage(hCombo,
  820. CB_GETITEMDATA, (WPARAM)uIdx, (LPARAM)0)) != NULL)
  821. GlobalFree(hDesc);
  822. // delete the entry from the combobox
  823. SendMessage(hCombo, CB_DELETESTRING, (WPARAM)uIdx, (LPARAM)0);
  824. // -jyg-
  825. mapEnumerate(iMap, EnumFunc, MMENUM_DELETE, hCombo, NULL);
  826. // reset to initial setup or first entry
  827. if (iMap == MMAP_SETUP)
  828. {
  829. uIdx = ComboLookup(hCombo,(LPSTR)aszInitialSetup); //-jyg
  830. lstrcpy(szCurSetup,aszInitialSetup); // reset current string to initial setup
  831. }
  832. else
  833. uIdx = 0;
  834. uIdx = (UINT)SendMessage(hCombo, CB_SETCURSEL, (WPARAM)uIdx, (LPARAM)0);
  835. // if deleted last one then disable window,
  836. // otherwise update the edit control
  837. if (uIdx == CB_ERR) {
  838. EnableMain(fEnabled = FALSE);
  839. SendMessage(hdlg, DM_SETDEFID, (WPARAM)ID_MAINNEW, (LPARAM)0);
  840. SetFocus(GetDlgItem(hdlg, ID_MAINNEW));
  841. } else
  842. #if defined(WIN16)
  843. SendMessage(hdlg, WM_COMMAND,
  844. (WPARAM)ID_MAINCOMBO, MAKELPARAM(hCombo,
  845. CBN_SELCHANGE));
  846. #else
  847. SendMessage( hdlg
  848. , WM_COMMAND
  849. , (WPARAM)MAKELONG(ID_MAINCOMBO, CBN_SELCHANGE)
  850. , (LPARAM)hCombo
  851. );
  852. #endif //WIN16
  853. break;
  854. case ID_MAINNEW:
  855. // if they don't specify a new map get outta here
  856. fNew = TRUE;
  857. if (!DialogBox(hLibInst, MAKEINTRESOURCE(ID_PROPBOX),
  858. hdlg, (DLGPROC)PropBox)) {
  859. fNew = FALSE;
  860. break;
  861. }
  862. // if they don't want to save new map, restore
  863. // name and description and get outta here
  864. if (!FEditMap(hdlg)) {
  865. fNew = FALSE;
  866. GetWindowText(hCombo, (LPSTR)szCurrent,
  867. MMAP_MAXNAME);
  868. GetDlgItemText(hdlg, ID_MAINDESC, szCurDesc,
  869. MMAP_MAXDESC);
  870. break;
  871. }
  872. uIdx = ComboLookup(hCombo,(LPSTR)szCurrent);//-jyg
  873. if (uIdx != CB_ERR) {
  874. char aszName[MMAP_MAXNAME];
  875. SendMessage(hCombo, CB_GETLBTEXT, (WPARAM)uIdx, (LPARAM)(LPSTR)aszName);
  876. if (!lstrcmpi(aszName, szCurrent)) {
  877. hDesc = (HGLOBAL)(DWORD)SendMessage(hCombo, CB_GETITEMDATA, (WPARAM)uIdx, (LPARAM)0);
  878. if (hDesc != NULL)
  879. GlobalFree(hDesc);
  880. //break;
  881. } else
  882. uIdx = (UINT)CB_ERR;
  883. }
  884. if (uIdx == CB_ERR)
  885. uIdx = (UINT)SendMessage(hCombo, CB_ADDSTRING,
  886. (WPARAM)0, (LPARAM)(LPCSTR)szCurrent);
  887. // make the new map the current one
  888. SendMessage(hCombo, CB_SETCURSEL, (WPARAM)uIdx, (LPARAM)0);
  889. if (IsDlgButtonChecked(hdlg, ID_MAINSETUP))
  890. lstrcpy(szCurSetup, szCurrent);
  891. // allocate buffer for map description data
  892. if ((hDesc = GlobalAlloc(GHND, (DWORD)(sizeof(char) *
  893. (lstrlen (szCurDesc) + 1)))) != NULL) {
  894. lpDesc = (LPSTR)GlobalLock(hDesc);
  895. lstrcpy(lpDesc, szCurDesc);
  896. GlobalUnlock(hDesc);
  897. }
  898. SetDlgItemText (hdlg, ID_MAINDESC, szCurDesc);
  899. // put the handle in the entrys item data
  900. SendMessage(hCombo, CB_SETITEMDATA,
  901. (WPARAM)uIdx, (LPARAM)hDesc);
  902. // enable windows if it is the first map of type
  903. if (!IsWindowEnabled(hCombo))
  904. EnableMain(TRUE);
  905. CancelToClose(hdlg);
  906. break;
  907. case ID_MAINEDIT:
  908. if (!FEditMap(hdlg))
  909. break;
  910. CancelToClose(hdlg);
  911. if (iMap != MMAP_SETUP)
  912. break;
  913. // reset to current setup
  914. uIdx = ComboLookup(hCombo,(LPSTR)szCurSetup); //-jyg
  915. SendMessage(hCombo, CB_SETCURSEL, (WPARAM)uIdx, (LPARAM)0);
  916. #if defined(WIN16)
  917. SendMessage(hdlg, WM_COMMAND, (WPARAM)ID_MAINCOMBO,
  918. MAKELPARAM(hCombo, CBN_SELCHANGE));
  919. #else
  920. SendMessage( hdlg
  921. , WM_COMMAND
  922. , (WPARAM)MAKELONG(ID_MAINCOMBO, CBN_SELCHANGE)
  923. , (LPARAM)hCombo
  924. );
  925. #endif //WIN16
  926. break;
  927. case ID_MAINSETUP:
  928. ShowMaps(MMAP_SETUP);
  929. break;
  930. case ID_MAINPATCH:
  931. ShowMaps(MMAP_PATCH);
  932. break;
  933. case ID_MAINKEY:
  934. ShowMaps(MMAP_KEY);
  935. break;
  936. case ID_MAINSETUPCOMBO:
  937. case ID_MAINPATCHCOMBO:
  938. case ID_MAINKEYCOMBO:
  939. case ID_MAINCOMBO:
  940. if (wNotifCode == CBN_SELENDOK) {
  941. CancelToClose(hdlg);
  942. fChanged = TRUE;
  943. }
  944. if (wNotifCode != CBN_SELCHANGE)
  945. return FALSE;
  946. uIdx = (UINT)SendMessage(hCombo, CB_GETCURSEL,
  947. (WPARAM)0, (LPARAM)0);
  948. if (LOWORD(wParam) == ID_MAINSETUPCOMBO)
  949. SendMessage(hCombo, CB_GETLBTEXT, (WPARAM)uIdx,
  950. (LPARAM) (LPSTR) szCurSetup);
  951. hDesc = (HGLOBAL)(DWORD)SendMessage(hCombo, CB_GETITEMDATA,
  952. (WPARAM)uIdx, (LPARAM)0);
  953. lpDesc = GlobalLock(hDesc);
  954. lstrcpy(szCurDesc, lpDesc);
  955. GlobalUnlock(hDesc);
  956. SetDlgItemText (hdlg, ID_MAINDESC, szCurDesc);
  957. SendMessage(hCombo, CB_GETLBTEXT, (WPARAM)uIdx,
  958. (LPARAM)(LPSTR)szCurrent);
  959. break;
  960. case ID_MAINDESC:
  961. // NOTE: this is not implemented.
  962. if (wNotifCode == EN_CHANGE)
  963. fChange = TRUE;
  964. else if ((wNotifCode == EN_KILLFOCUS) && fChange) {
  965. GetDlgItemText (hdlg, ID_MAINDESC, szTmpDesc,
  966. MMAP_MAXDESC);
  967. if (!lstrcmpi(szCurDesc, szTmpDesc)) {
  968. // description change logic here.
  969. // There's no API to changedesc!!
  970. }
  971. }
  972. break;
  973. default:
  974. return FALSE;
  975. }
  976. } /* end of WM_COMMAND */
  977. break;
  978. default:
  979. if (uMessage == uHelpMessage) {
  980. DoHelp:
  981. WinHelp(hWnd, szMidiHlp, HELP_CONTEXT,
  982. IDH_CHILD_MIDI);
  983. return TRUE;
  984. }
  985. else
  986. return FALSE;
  987. break;
  988. }
  989. return TRUE;
  990. } /* MainBox */
  991. BOOL FAR PASCAL InvalidPortMsgBox (
  992. HWND hwnd)
  993. {
  994. int iRet;
  995. char szBuf[256];
  996. LoadString(hLibInst, IDS_INVALIDPORT, szBuf, sizeof(szBuf));
  997. iRet = MessageBox (hwnd, szBuf, szMidiCtl,
  998. MB_ICONSTOP | MB_YESNO);
  999. return iRet == IDYES;
  1000. } /* InvalidPortMsgBox */
  1001. VOID FAR PASCAL Modify(
  1002. BOOL fSet)
  1003. {
  1004. fModified = fSet;
  1005. if (fModified)
  1006. fChanged = TRUE;
  1007. } /* Modify */
  1008. /*
  1009. * ENUMFUNC
  1010. *
  1011. * Enumerate setup, patchmap or keymap names.
  1012. */
  1013. BOOL FAR PASCAL _loadds EnumFunc(
  1014. LPSTR lpName,
  1015. LPSTR lpDesc,
  1016. UINT uCase,
  1017. HWND hCombo,
  1018. LPSTR unused
  1019. )
  1020. {
  1021. HGLOBAL hMem;
  1022. LPSTR lpStr;
  1023. UINT uIdx;
  1024. MMAPERR mmaperr;
  1025. // see if we're dealing with 'delete' enumeration.
  1026. if (uCase == MMENUM_DELETE) {
  1027. uIdx = ComboLookup(hCombo, (LPSTR)lpName);//-jyg
  1028. if (uIdx != CB_ERR)
  1029. return TRUE;
  1030. mmaperr = mapDelete(iMap, lpName);
  1031. if (mmaperr == MMAPERR_SUCCESS)
  1032. return TRUE;
  1033. VShowError(hWnd, mmaperr);
  1034. return FALSE;
  1035. }
  1036. uIdx = (UINT)SendMessage(hCombo, CB_ADDSTRING, (WPARAM)NULL, (LPARAM)lpName);
  1037. // see if we're dealing with enumeration from the main dialog
  1038. if (uCase == MMENUM_INTOCOMBO) {
  1039. hMem = GlobalAlloc(GHND, (DWORD)(lstrlen(lpDesc) + 1));
  1040. if (hMem != NULL) {
  1041. lpStr = (LPSTR)GlobalLock(hMem);
  1042. lstrcpy(lpStr, lpDesc);
  1043. GlobalUnlock(hMem);
  1044. }
  1045. SendMessage( hCombo,
  1046. CB_SETITEMDATA, (WPARAM)uIdx, (LPARAM)hMem);
  1047. }
  1048. return TRUE;
  1049. } /* EnumFunc */
  1050. #if 0
  1051. /*
  1052. * SETWINDOWCAPTION
  1053. *
  1054. * Set the caption of a 'window', such as 'MIDI Setup: "foo"', even though
  1055. * these are actually dialog boxes.
  1056. */
  1057. VOID FAR PASCAL SetWindowCaption(
  1058. VOID)
  1059. {
  1060. char szCaption[80],
  1061. szName[MM_MAXRESLEN];
  1062. LoadString(hLibInst, IdsGetMapNameId(iMap), szName, sizeof(szName));
  1063. wsprintf(szCaption, aszCaptionFormat,
  1064. (LPSTR)szName, (LPSTR)szCurrent);
  1065. SetWindowText(hWnd, szCaption);
  1066. } /* SetWindowCaption */
  1067. #endif //0
  1068. int FAR PASCAL QuerySave (VOID)
  1069. {
  1070. char szBuf[256];
  1071. char aszSave[64];
  1072. char aszFormat[128];
  1073. char szFunc[MM_MAXRESLEN];
  1074. LoadString(hLibInst, IdsGetMapNameId(iMap), szFunc, sizeof(szFunc));
  1075. if (fNew) {
  1076. // AnsiUpperBuff(szFunc, 1); // Upper-case first character.
  1077. LoadString(hLibInst, IDS_NEW_QUESTION, aszFormat, sizeof(aszFormat));
  1078. wsprintf (szBuf, aszFormat, (LPSTR)szCurrent, (LPSTR)szFunc);
  1079. }
  1080. else {
  1081. LoadString(hLibInst, IDS_CHANGE_QUESTION, aszFormat, sizeof(aszFormat));
  1082. wsprintf (szBuf, aszFormat, (LPSTR)szFunc, (LPSTR)szCurrent);
  1083. }
  1084. LoadString(hLibInst, IDS_SAVE_CHANGES, aszSave, sizeof(aszSave));
  1085. return MessageBox(hWnd, szBuf, aszSave, MB_YESNOCANCEL | MB_ICONEXCLAMATION);
  1086. } /* QuerySave */