/* * MIDI.C * * Copyright (C) 1990 Microsoft Corporation. * * The MIDI control panel applet. * * History: * * t-mikemc 10-Apr-90 Created. */ /* Revision history: March 92 Ported to 16/32 common code by Laurie Griffiths (LaurieGr) */ /*-=-=-=-=- Include Files -=-=-=-=-*/ #include "preclude.h" #include #include #if defined(WIN32) #include #endif #include "hack.h" #include "midimap.h" #include #include "cphelp.h" #include "cparrow.h" #include "midi.h" /*-=- poop -=-*/ #define MM_MAXRESLEN 32 // arbitrary maximum resource string length /*-=-=-=-=- Prototypes -=-=-=-=-*/ INT_PTR CALLBACK MainBox (HWND, UINT, WPARAM, LPARAM); BOOL NEAR PASCAL LibMain(HINSTANCE,UINT,LPSTR); #if defined(WIN16) #pragma alloc_text(_INIT, LibMain) #endif //WIN16 LRESULT FAR PASCAL _loadds CPlApplet(HWND,UINT,WPARAM,LPARAM); #if defined(WIN16) #pragma alloc_text(_INIT, CPlApplet) #endif //WIN16 void NEAR PASCAL InitCPL(void); #if defined(WIN16) #pragma alloc_text(_INIT, InitCPL) #endif //WIN16 /*-=-=-=-=- Global Variables -=-=-=-=-*/ /* This many global variables is a sure sign of sickness. LaurieGr */ HINSTANCE hLibInst; // Library instance handle. HGLOBAL hKeyMap; // Midikeymap handle. HFONT hFont; // Dialog box font handle. HWND hWnd, // Current window handle. hCombo, // Combo box handle. hEdit, // Edit control handle. hArrow; // Arrow control handle. RECT rcBox; // Clipping/scroll rectangle. int rgxPos[8], // horizontal line positions. yBox, // rows of data y extent xClient, // Window client area x pixels. yClient, // Window client area y pixels. iCurPos, // Current position on screen. iVertPos, // Current vertical scroll position. iVertMax, // Maximum veritcal scroll position. nLines, // Number of lines of data. yChar, // Height of character in font. xChar, // Width of average character in font. iMap; // Current map type being edited. char szCurrent[MMAP_MAXNAME], // Current map name. szCurDesc[MMAP_MAXDESC], // Current map description. szCurSetup[MMAP_MAXNAME], // Current setup szNone[16], // Generic global string. szMidiCtl[64], // Window caption for midicpl. aszSourceKey[32], aszSourceKeyName[40], aszPatchNumber[40], aszSourcePatch[32], aszSourcePatchName[40], aszSourceMnumonic[5], aszSourceChannel[32], aszActive[32], szMidiHlp[24]; BOOL fModified, // Flag; Has the map been modified? fChanged, // Flag; Has anything ever been changed? fNew, // Flag; Is this a new map? fHidden; // Flag; Is the acitve line hidden? BOOL fReadOnly; char aszClose[16]; static char aszCaptionFormat[24]; static SZCODE szHelpMessage[] = "ShellHelp"; static SZCODE aszTempPrefix[] = "mmr"; // limited to 3 characters static SZCODE aszFontName[] = "MS Sans Serif"; static BOOL fAppletEntered; // Disallow multiple applet instances UINT near uHelpMessage; DWORD near dwContext; typedef struct { int idIcon; int idName; int idInfo; BOOL bEnabled; DWORD dwContext; PSTR pszHelp; } APPLET_INFO; #define NUM_APPLETS 1 APPLET_INFO near applets[NUM_APPLETS]; /* Move the window, if necessary, to keep it on the desktop, as far as possible */ VOID PlaceWindow(HWND hwnd) { RECT rcWind; /* window rectangle */ HDC hdc; /* so we can get device capabilities -i.e. screen size */ int up; /* amount to move window up */ int left; /* amount to move window left */ int HorzRes; /* horizontal screen resolution in pixels */ int VertRes; /* vertical screen resolution in lines */ /* GetWindowRect(HWND_DESKTOP, &rcDesk) doesn't work! */ hdc = GetDC(hwnd); HorzRes = GetDeviceCaps(hdc,HORZRES); VertRes = GetDeviceCaps(hdc,VERTRES); GetWindowRect(hwnd, &rcWind); up = rcWind.bottom - VertRes; /* how much to move up to get onto screen... */ if (up<0) up = 0; /* don't bother to go down to get to the bottom */ if (up>rcWind.top) up = rcWind.top; /* don't ever go off the top */ left = rcWind.right - HorzRes; /* how much to move left to get all on screen... */ if (left<0) left = 0; /* don't bother to go right */ if (left>rcWind.left) left = rcWind.left; /* but don't ever go off the left */ SetWindowPos( hwnd, HWND_TOP, rcWind.left-left, rcWind.top-up, 0,0,SWP_NOSIZE); } /* PlaceWindow */ VOID NEAR PASCAL CancelToClose(HWND hDlg) { if (!fReadOnly) { char aszText[16]; GetDlgItemText(hDlg, IDOK, aszText, sizeof(aszText)); if (lstrcmp(aszText, aszClose)) SetDlgItemText(hDlg, IDOK, aszClose); } } // - - - - - - - - - // Windows entry point. BOOL NEAR PASCAL LibMain( HINSTANCE hInstance, UINT uHeapSize, LPSTR lpCmdLine) { hLibInst = hInstance; return TRUE; } void NEAR PASCAL InitCPL(void) { if ( applets[0].idIcon == 0 ) { LoadString(hLibInst, IDS_CLOSE, aszClose, sizeof(aszClose)); applets[0].idIcon = ID_ICON; applets[0].idName = IDS_NAME; applets[0].idInfo = IDS_INFO; applets[0].bEnabled = TRUE; applets[0].dwContext = IDH_CHILD_MIDI; applets[0].pszHelp = szMidiHlp; LoadString(hLibInst, IDS_NONE, szNone, sizeof(szNone)); LoadString(hLibInst, IDS_HELPFILE, szMidiHlp, sizeof(szMidiHlp)); LoadString(hLibInst, IDS_SOURCEKEY, aszSourceKey, sizeof(aszSourceKey)); LoadString(hLibInst, IDS_SOURCEKEYNAME, aszSourceKeyName, sizeof(aszSourceKeyName)); LoadString(hLibInst, IDS_PATCHNUMBER, aszPatchNumber, sizeof(aszPatchNumber)); LoadString(hLibInst, IDS_SOURCEPATCH, aszSourcePatch, sizeof(aszSourcePatch)); LoadString(hLibInst, IDS_SOURCEPATCHNAME, aszSourcePatchName, sizeof(aszSourcePatchName)); LoadString(hLibInst, IDS_SOURCEMNUMONIC, aszSourceMnumonic, sizeof(aszSourceMnumonic)); LoadString(hLibInst, IDS_SOURCECHANNEL, aszSourceChannel, sizeof(aszSourceChannel)); LoadString(hLibInst, IDS_ACTIVETITLE, aszActive, sizeof(aszActive)); } } #ifdef STUPID /* * ComboBox String Lookup, written because we * let an intern design this applet. */ int FAR PASCAL ComboLookup( HWND hCombo, LPSTR szLookup) { int iEntries; static char szBuf[29]; PSTR pstrBuf; iEntries = (int)(LONG)SendMessage(hCombo,CB_GETCOUNT,(WPARAM)0,(LPARAM)0); if (iEntries > CB_ERR) { do { iEntries--; pstrBuf = szBuf; if ((int)(LONG)SendMessage(hCombo,CB_GETLBTEXT,(WPARAM)iEntries,(LPARAM)(LPSTR)szBuf) == CB_ERR) return CB_ERR; if (lstrcmpi(szLookup,pstrBuf) == 0) return iEntries; } while(iEntries); } return CB_ERR; } #endif // Given an error code, display an error message. If the error code // was invalid, displays a default bogus English-language text string. VOID FAR PASCAL VShowError( HWND hwnd, // Window to tie the message box to. MMAPERR mmaperr) // Error code to display text for. { char asz[256]; LoadString(hLibInst, IDS_MMAPERR_BASE + mmaperr, asz, sizeof(asz)); MessageBox(hwnd, asz, NULL, MB_ICONEXCLAMATION | MB_OK); } // - - - - - - - - - // Returns TRUE if the file exists and is correct, or was initialized // properly. Returns FALSE if the user didn't want it initialized, or // if the initialization failed. // // This function deals with English-language specific stuff. There is // no good reason for this that I can see. static BOOL FAR PASCAL FGetMapFile( HWND hwnd) { char aszBuf[256]; DWORD dwVersion; MMAPERR mmaperr; // // An error return from "mapFileVersion" indicates a problem that // I don't want to go into too specifically at this time. The // most likely event is that the file doesn't exist. The code in // in this function assumes that this is what happened. If it // was another problem, hopefully initializing the file will // solve it. This can be looked into later. // dwVersion = mapFileVersion(); if ((HIWORD(dwVersion) == MMAPERR_SUCCESS) && (LOWORD(dwVersion) == 1)) return TRUE; // File was fine (opened + was right version). // // This code is executing if there was a problem opening the // file. Hopefully this problem involved non-existence. // LoadString(hLibInst, IDS_CREATE_QUESTION, aszBuf, sizeof(aszBuf)); if (MessageBox(hwnd, aszBuf, szMidiCtl, MB_YESNO | MB_ICONHAND) == IDYES) if ((mmaperr = mapInitMapFile()) == MMAPERR_SUCCESS) return TRUE; else VShowError(hwnd, mmaperr); return FALSE; } // - - - - - - - - - // Control panel entry point. LRESULT FAR PASCAL _loadds CPlApplet( HWND hCPlWnd, UINT uMessage, WPARAM lParam1, LPARAM lParam2) { LPNEWCPLINFO lpCPlInfo; BOOL fSuccess = TRUE; BOOL fBackup; LPSTR lpstrBakPath; LPSTR lpstrCfgPath; int iApplet; switch (uMessage) { case CPL_INIT : InitCPL(); uHelpMessage = RegisterWindowMessage(szHelpMessage); hWnd = hCPlWnd; return (LRESULT)TRUE; case CPL_GETCOUNT : return (LRESULT)NUM_APPLETS; case CPL_NEWINQUIRE : lpCPlInfo = (LPNEWCPLINFO)lParam2; iApplet = (int)(LONG)lParam1; lpCPlInfo->hIcon = LoadIcon(hLibInst, MAKEINTRESOURCE(applets[iApplet].idIcon)); LoadString(hLibInst, applets[iApplet].idName, lpCPlInfo->szName, sizeof(lpCPlInfo->szName)); LoadString(hLibInst, applets[iApplet].idInfo, lpCPlInfo->szInfo, sizeof(lpCPlInfo->szInfo)); lpCPlInfo->dwSize = sizeof(NEWCPLINFO); lpCPlInfo->lData = (LONG)iApplet; lpCPlInfo->dwHelpContext = applets[iApplet].dwContext; lstrcpy(lpCPlInfo->szHelpFile, applets[iApplet].pszHelp); return (LRESULT)TRUE; case CPL_DBLCLK : if (fAppletEntered) break; // // We can enter into lots of bizarre states: // We become READ-ONLY IF: // We cannot lock the mapper. // There is a disk or memory exception backing up the // existing MIDIMAP.CFG file or the MIDIMAP.CFG // is READ ONLY. // We DO NOT use a backup IF: // The mapper is locked. // No MIDIMAP.CFG file is found. // There is an exception dealing with backing up the // the existing MIDIMAP.CFG file. // lpstrCfgPath = GlobalLock(GlobalAlloc(GHND,MAXPATHLEN)); if (lpstrCfgPath == NULL) { VShowError(hCPlWnd,IDS_MMAPERR_MEMORY); break; } lpstrBakPath = GlobalLock(GlobalAlloc(GHND,MAXPATHLEN)); if (lpstrBakPath == NULL) { VShowError(hCPlWnd,IDS_MMAPERR_MEMORY); goto exitfree; } fAppletEntered = TRUE; if (!mapLock()) // Attempt to lock the mapper { char szApp[32], szMessage[256]; LoadString(hLibInst, IDS_READONLYMODE, szMessage, sizeof(szMessage)); LoadString(hLibInst, IDS_TITLE, szApp, sizeof(szApp)); MessageBox(hCPlWnd, szMessage, szApp, MB_ICONINFORMATION | MB_OK); fBackup = FALSE; // No backups fReadOnly = TRUE; // Read Only Mode } else { fBackup = TRUE; // Try to do a backup fReadOnly = FALSE; // Not in READ ONLY mode } if (fBackup) { char szMapCfg[MMAP_MAXCFGNAME]; LoadString(hLibInst,IDS_MIDIMAPCFG,szMapCfg,MMAP_MAXCFGNAME); GetSystemDirectory(lpstrCfgPath,MAXPATHLEN - sizeof(szMapCfg)); lstrcat(lpstrCfgPath,szMapCfg); MGetTempFileName(0, aszTempPrefix,0,lpstrBakPath); if (DupMapCfg(lpstrCfgPath,lpstrBakPath)) { mapConnect(lpstrBakPath); } else { // No Backups. fBackup = FALSE; // if fReadOnly == TRUE, the exception // has forced us into READ-ONLY mode // else // we didn't have a MIDIMAP.CFG file // and we'll read/write directly. if (fReadOnly) mapUnlock(); DosDelete(lpstrBakPath); // GetTempFileName Creates a File of size 0 } } if (!FGetMapFile(hCPlWnd)) { fSuccess = FALSE; goto appexit; } // !!! Never unregisters the class, so this will come back // FALSE on subsequent startups. This is of course bogus. (VOID)RegisterArrowClass(hLibInst); #if 0 if ((hFont = CreateFont(8, NULL, NULL, NULL, FW_NORMAL, NULL, NULL, NULL, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | FF_DONTCARE, aszFontName)) == NULL) goto appexit; #else { LOGFONT lf; SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), (LPVOID)&lf, 0); if (!(hFont = CreateFontIndirect(&lf))) goto appexit; } #endif fSuccess = (BOOL)DialogBox(hLibInst, MAKEINTRESOURCE(ID_MAINBOX), hCPlWnd, MainBox); UnregisterArrowClass(hLibInst); DeleteObject(hFont); appexit: if (fBackup) { MDOUT("Disconnecting from mapper"); mapDisconnect(); if (fSuccess) { MDOUT("Updating Backup"); UpdateMapCfg(lpstrCfgPath,lpstrBakPath); } mapUnlock(); DosDelete(lpstrBakPath); } else if (!fReadOnly) { mapUnlock(); if (!fSuccess) DosDelete(lpstrCfgPath); } fAppletEntered = FALSE; GlobalFree((HGLOBAL)lpstrBakPath); exitfree: GlobalFree((HGLOBAL)lpstrCfgPath); break; } return (LRESULT)0; } // - - - - - - - - - // This will return either "MMAPERR_SUCCESS" if everything is fine, // or will return "MMAPERR_INVALIDPORT" if the setup references a // bogus port. These are both expected conditions. // // Unexpected conditions can also happen, which are returned. static MMAPERR NEAR PASCAL MmaperrInvalidPortCheck( LPSTR lszName) // Name of current setup. { LPMIDIMAP lpMap; MMAPERR mmaperr; DWORD dwSize; HGLOBAL hMidiMap; if ((dwSize = mapGetSize(MMAP_SETUP, lszName)) < MMAPERR_MAXERROR) return (MMAPERR)dwSize; if ((hMidiMap = GlobalAlloc(GHND, dwSize)) == NULL) return MMAPERR_MEMORY; lpMap = (LPMIDIMAP)GlobalLock(hMidiMap); mmaperr = mapRead(MMAP_SETUP, lszName, (LPVOID)lpMap); GlobalUnlock(hMidiMap); GlobalFree(hMidiMap); return mmaperr; } // - - - - - - - - - // Converts a "MMAP_" into a "IDS_", i.e. converts "MMAP_SETUP" into // "IDS_SETUP", which can be used to get the word "Setup" out of the // "midi.rc" file. static int PASCAL IdsGetMapNameId( int iMap) { if (iMap == MMAP_SETUP) return IDS_SETUP; if (iMap == MMAP_PATCH) return IDS_PATCH; return IDS_KEY; } // - - - - - - - - - /* * DELETEMAP * * This function returns TRUE if it is OK to delete whatever map * exists in szCurrent. */ static BOOL NEAR PASCAL FConfirmDeleteMap( HWND hwnd) { char szSetup[MMAP_MAXNAME], szSrc[MM_MAXRESLEN], szUsedBy[MM_MAXRESLEN], szDel[50], szCap[50], szRsrc[256], szBuf[256]; DWORD dwRet; UINT uSrcID; UINT uUsage; MMAPERR mmaperr; uSrcID = IdsGetMapNameId(iMap); LoadString(hLibInst, uSrcID, szSrc, sizeof(szSrc)); LoadString(hLibInst, IDS_DELETE, szDel, sizeof(szDel)); wsprintf(szCap, szDel, (LPSTR)szSrc); // AnsiUpperBuff(szSrc, 1); // Upper-case first character. switch (iMap) { case MMAP_SETUP: if ((mmaperr = mapGetCurrentSetup(szSetup, MMAP_MAXNAME)) != MMAPERR_SUCCESS) { VShowError(hwnd, mmaperr); return FALSE; } if (lstrcmpi(szSetup, szCurrent)) break; LoadString(hLibInst, IDS_NODELISCURRENT, szRsrc, sizeof(szRsrc)); wsprintf(szBuf, szRsrc, (LPSTR)szCurrent); MessageBox(hwnd, szBuf, szCap, MB_ICONINFORMATION | MB_OK); return FALSE; case MMAP_PATCH: case MMAP_KEY: dwRet = mapGetUsageCount(iMap, szCurrent); if (LOWORD(dwRet) != MMAPERR_SUCCESS) { VShowError(hwnd, LOWORD(dwRet)); return FALSE; } if (!(uUsage = HIWORD(dwRet))) break; uSrcID--; // Patch->Setup, Key->Patch if (uUsage > 1) // Make a singular a plural. This uSrcID += 3; // "3" is commented in "midi.h". LoadString(hLibInst, uSrcID, szUsedBy, sizeof(szUsedBy)); // AnsiLowerBuff(szUsedBy, 1); // Lower-case first character. LoadString(hLibInst, IDS_NODELISREFERENCED, szRsrc, sizeof(szRsrc)); wsprintf(szBuf, szRsrc, (LPSTR)szSrc, (LPSTR)szCurrent, uUsage, (LPSTR)szUsedBy); MessageBox (hwnd, szBuf, szCap, MB_ICONINFORMATION | MB_OK); return FALSE; } LoadString(hLibInst, IDS_VERIFYDELETE, szRsrc, sizeof(szRsrc)); wsprintf(szBuf, szRsrc, (LPSTR)szSrc, (LPSTR)szCurrent); return (IDYES == MessageBox (hwnd, szBuf, szCap, MB_ICONEXCLAMATION | MB_YESNO)); } static VOID NEAR PASCAL VFreeItemData( HWND hdlg, int idCtrl) { UINT uCount; uCount = (UINT)SendDlgItemMessage(hdlg, idCtrl, CB_GETCOUNT, (WPARAM)NULL, (LPARAM)0); for (; uCount--; ) { HGLOBAL hDescription; if ((hDescription = (HGLOBAL)(DWORD)SendDlgItemMessage(hdlg, idCtrl, CB_GETITEMDATA, (WPARAM)uCount, (LPARAM)0)) != NULL) GlobalFree(hDescription); } } static VOID NEAR PASCAL GetMBData( UINT uFlag, LPMBDATA lpmbData) { switch (uFlag) { case MMAP_SETUP: lpmbData->lpfnBox = SetupBox; lpmbData->idBox = DLG_SETUPEDIT; break; case MMAP_PATCH: lpmbData->lpfnBox = PatchBox; lpmbData->idBox = DLG_PATCHEDIT; break; case MMAP_KEY: lpmbData->lpfnBox = KeyBox; lpmbData->idBox = DLG_KEYEDIT; break; default: lpmbData->lpfnBox = 0L; lpmbData->idBox = 0; break; } } /* GetMBData */ static BOOL PASCAL FEditMap( HWND hwnd) { HWND hTmpWnd; MBDATA mbData; DWORD dwRet; int iRet; BOOL fInSetup; char szSetup[MMAP_MAXNAME]; MMAPERR mmaperr; if ((mmaperr = mapGetCurrentSetup(szSetup, MMAP_MAXNAME)) != MMAPERR_SUCCESS) { VShowError(hwnd, mmaperr); return FALSE; } switch (iMap) { case MMAP_SETUP : fInSetup = (BOOL)!lstrcmpi(szCurrent, szSetup); break; case MMAP_PATCH : dwRet = mapPatchMapInSetup(szCurrent, szSetup); if (LOWORD(dwRet) != MMAPERR_SUCCESS) return FALSE; fInSetup = (BOOL)HIWORD(dwRet); break; case MMAP_KEY : dwRet = mapKeyMapInSetup (szCurrent, szSetup); if (LOWORD(dwRet) != MMAPERR_SUCCESS) return FALSE; fInSetup = (BOOL)HIWORD(dwRet); break; } hTmpWnd = hWnd; // "hWnd", not "hwnd". GetMBData(iMap, &mbData); iRet = (int)DialogBox(hLibInst, MAKEINTRESOURCE(mbData.idBox), hWnd, mbData.lpfnBox); hWnd = hTmpWnd; return iRet; } /* FEditMap */ static VOID NEAR PASCAL EnableMain( BOOL fEnable) { char aszNoEntries[48]; EnableWindow(hCombo, fEnable); if (fReadOnly) { EnableWindow(GetDlgItem (hWnd, ID_MAINDELETE), FALSE); EnableWindow(GetDlgItem (hWnd,ID_MAINNEW),FALSE); } else EnableWindow(GetDlgItem (hWnd, ID_MAINDELETE), fEnable); EnableWindow(GetDlgItem (hWnd, ID_MAINEDIT), fEnable); EnableWindow(GetDlgItem (hWnd, ID_MAINDESC), fEnable); EnableWindow(GetDlgItem (hWnd, ID_MAINNAME), fEnable); if (!fEnable) { LoadString(hLibInst, IDS_NOENTRIES, aszNoEntries, sizeof(aszNoEntries)); SetDlgItemText(hWnd, ID_MAINDESC, aszNoEntries); } } /* EnableMain */ static VOID NEAR PASCAL ShowMaps (int nMap) { if (iMap == nMap) return; iMap = nMap; SendMessage(hWnd, WM_MY_INITDIALOG, (WPARAM)NULL, (LPARAM)0); } /* ShowMaps */ INT_PTR CALLBACK MainBox( HWND hdlg, UINT uMessage, WPARAM wParam, LPARAM lParam) { static BOOL fChange, // has edittext changed? fPatchEnum, // have patches been enum'd? fKeyEnum, // have keys been enum'd? fEnabled; static UINT uDeleted; // which maps types deleted static char aszInitialSetup[MMAP_MAXNAME]; // initial setup name MMAPERR mmaperr; HGLOBAL hDesc; LPSTR lpDesc; UINT uIdx; int idCurCombo; BOOL fEnum; // char szBuf[128]; char szTmpDesc[MMAP_MAXDESC]; switch (uMessage) { case WM_INITDIALOG: // get the current setup name and store in // static aszInitialSetup fChanged = FALSE; if ((mmaperr = mapGetCurrentSetup(aszInitialSetup, MMAP_MAXNAME)) != MMAPERR_SUCCESS) { exit00: VShowError(hdlg, mmaperr); /*exit01:*/ EndDialog (hdlg, FALSE); return TRUE; } lstrcpy(szCurSetup, aszInitialSetup); // Load caption string and set the window text LoadString(hLibInst, IDS_TITLE, szMidiCtl, sizeof(szMidiCtl)); hWnd = hdlg; SetWindowText(hdlg, szMidiCtl); /*!! // check for invalid devices if ((mmaperr = MmaperrInvalidPortCheck( aszInitialSetup)) == MMAPERR_INVALIDPORT) { if (!InvalidPortMsgBox(hdlg)) goto exit01; } else if (mmaperr != MMAPERR_SUCCESS) goto exit00; !!*/ // hide the patch and key comboboxes ShowWindow(GetDlgItem(hdlg, ID_MAINPATCHCOMBO), SW_HIDE); ShowWindow(GetDlgItem(hdlg, ID_MAINKEYCOMBO), SW_HIDE); // enumerate setups into setup combo box mmaperr = mapEnumerate( MMAP_SETUP , EnumFunc , MMENUM_INTOCOMBO , GetDlgItem( hdlg, ID_MAINSETUPCOMBO) , NULL ); if ( mmaperr != MMAPERR_SUCCESS ) goto exit00; // set up the auto-radiobuttons CheckRadioButton(hdlg, ID_MAINFIRSTRADIO, ID_MAINLASTRADIO, ID_MAINSETUP); // intialize some variables *szCurrent = 0; hCombo = NULL; iMap = MMAP_SETUP; fEnabled = FALSE; // Fix for bug #2039. 13-Feb-90, BLM. // It used to set the variable TRUE. fChange = FALSE; fPatchEnum = FALSE; fKeyEnum = FALSE; uDeleted = 0; // fall through case WM_MY_INITDIALOG: fEnum = FALSE; switch (iMap) { case MMAP_SETUP: idCurCombo = ID_MAINSETUPCOMBO; uIdx = ComboLookup(GetDlgItem(hdlg,idCurCombo),(LPSTR)szCurSetup);//-jyg break; case MMAP_PATCH: idCurCombo = ID_MAINPATCHCOMBO; if (!fPatchEnum) { fEnum = TRUE; fPatchEnum = TRUE; } uIdx = 0; break; case MMAP_KEY: idCurCombo = ID_MAINKEYCOMBO; if (!fKeyEnum) { fEnum = TRUE; fKeyEnum = TRUE; } uIdx = 0; break; default:uIdx = 0; idCurCombo = 0; /* kill compiler warning about use before set */ } // hide the old combobox, if any if (hCombo != NULL) ShowWindow (hCombo, SW_HIDE); // get the new combobox handle hCombo = GetDlgItem (hdlg, idCurCombo); // show the new combobox ShowWindow(hCombo, SW_SHOW); // if not done already, enumerate maps into the box if (fEnum) { mmaperr = mapEnumerate(iMap, EnumFunc, MMENUM_INTOCOMBO, hCombo, NULL); if (mmaperr != MMAPERR_SUCCESS) goto exit00; } // set the current selection uIdx = (UINT)SendMessage(hCombo, CB_SETCURSEL, (WPARAM)uIdx, (LPARAM)0); // if no maps of that type, disable all necessary controls if (uIdx == CB_ERR) { *szCurrent = 0; EnableMain(fEnabled = FALSE); break; } // if we were disabled, enable us if (!fEnabled) EnableMain(fEnabled = TRUE); // fill the edit control with description #if defined(WIN16) SendMessage(hdlg, WM_COMMAND, (WPARAM)ID_MAINCOMBO, MAKELPARAM(hCombo, CBN_SELCHANGE)); #else SendMessage( hdlg , WM_COMMAND , (WPARAM)MAKELONG(ID_MAINCOMBO, CBN_SELCHANGE) , (LPARAM)hCombo ); #endif // WIN16 break; case WM_COMMAND: { WORD wNotifCode; #if defined(WIN16) wNotifCode = HIWORD(lParam); #else wNotifCode = HIWORD(wParam); #endif //WIN16 switch (LOWORD(wParam)) { case IDH_CHILD_MIDI: goto DoHelp; case IDOK: if (fReadOnly || !fChanged) { PostMessage(hdlg,WM_COMMAND,(WPARAM)IDCANCEL,(LPARAM)0); break; } // check for invalid ports if ((mmaperr = MmaperrInvalidPortCheck( szCurSetup)) == MMAPERR_INVALIDPORT) { if (!InvalidPortMsgBox(hdlg)) break; } else if (mmaperr != MMAPERR_SUCCESS) goto exit00; if (lstrcmpi(szCurSetup, aszInitialSetup)) { mmaperr = mapSetCurrentSetup( szCurSetup); if (mmaperr != MMAPERR_SUCCESS) goto exit00; } // this is where any deleted maps actually get the axe // // I'm going to leave this as is until I figure // out how to deal with any errors that happen. // brucemo // #if 0 if (uDeleted & MMAP_SETUP) mapEnumerate( iMap = MMAP_SETUP , EnumFunc , MMENUM_DELETE , GetDlgItem(hdlg,ID_MAINSETUPCOMBO) , NULL ); if (uDeleted & MMAP_PATCH) mapEnumerate( iMap = MMAP_PATCH , EnumFunc , MMENUM_DELETE , GetDlgItem(hdlg,ID_MAINPATCHCOMBO) , NULL ); if (uDeleted & MMAP_KEY) mapEnumerate( iMap = MMAP_KEY , EnumFunc, , MMENUM_DELETE , GetDlgItem (hdlg,ID_MAINKEYCOMBO) , NULL ); #endif case IDCANCEL: // clean up and go home VFreeItemData(hdlg, ID_MAINSETUPCOMBO); if (fPatchEnum) VFreeItemData(hdlg, ID_MAINPATCHCOMBO); if (fKeyEnum) VFreeItemData(hdlg, ID_MAINKEYCOMBO); if (LOWORD(wParam) == IDOK) // eh? EndDialog(hdlg,TRUE); else EndDialog(hdlg,FALSE); break; case ID_MAINDELETE: if (!FConfirmDeleteMap(hdlg)) break; CancelToClose(hdlg); // set a bit in the deleted word uDeleted |= iMap; // get the current selections index uIdx = (UINT)SendMessage(hCombo, CB_GETCURSEL, (WPARAM)0, (LPARAM)0); // get the handle to selections description if ((hDesc = (HGLOBAL)(DWORD)SendMessage(hCombo, CB_GETITEMDATA, (WPARAM)uIdx, (LPARAM)0)) != NULL) GlobalFree(hDesc); // delete the entry from the combobox SendMessage(hCombo, CB_DELETESTRING, (WPARAM)uIdx, (LPARAM)0); // -jyg- mapEnumerate(iMap, EnumFunc, MMENUM_DELETE, hCombo, NULL); // reset to initial setup or first entry if (iMap == MMAP_SETUP) { uIdx = ComboLookup(hCombo,(LPSTR)aszInitialSetup); //-jyg lstrcpy(szCurSetup,aszInitialSetup); // reset current string to initial setup } else uIdx = 0; uIdx = (UINT)SendMessage(hCombo, CB_SETCURSEL, (WPARAM)uIdx, (LPARAM)0); // if deleted last one then disable window, // otherwise update the edit control if (uIdx == CB_ERR) { EnableMain(fEnabled = FALSE); SendMessage(hdlg, DM_SETDEFID, (WPARAM)ID_MAINNEW, (LPARAM)0); SetFocus(GetDlgItem(hdlg, ID_MAINNEW)); } else #if defined(WIN16) SendMessage(hdlg, WM_COMMAND, (WPARAM)ID_MAINCOMBO, MAKELPARAM(hCombo, CBN_SELCHANGE)); #else SendMessage( hdlg , WM_COMMAND , (WPARAM)MAKELONG(ID_MAINCOMBO, CBN_SELCHANGE) , (LPARAM)hCombo ); #endif //WIN16 break; case ID_MAINNEW: // if they don't specify a new map get outta here fNew = TRUE; if (!DialogBox(hLibInst, MAKEINTRESOURCE(ID_PROPBOX), hdlg, (DLGPROC)PropBox)) { fNew = FALSE; break; } // if they don't want to save new map, restore // name and description and get outta here if (!FEditMap(hdlg)) { fNew = FALSE; GetWindowText(hCombo, (LPSTR)szCurrent, MMAP_MAXNAME); GetDlgItemText(hdlg, ID_MAINDESC, szCurDesc, MMAP_MAXDESC); break; } uIdx = ComboLookup(hCombo,(LPSTR)szCurrent);//-jyg if (uIdx != CB_ERR) { char aszName[MMAP_MAXNAME]; SendMessage(hCombo, CB_GETLBTEXT, (WPARAM)uIdx, (LPARAM)(LPSTR)aszName); if (!lstrcmpi(aszName, szCurrent)) { hDesc = (HGLOBAL)(DWORD)SendMessage(hCombo, CB_GETITEMDATA, (WPARAM)uIdx, (LPARAM)0); if (hDesc != NULL) GlobalFree(hDesc); //break; } else uIdx = (UINT)CB_ERR; } if (uIdx == CB_ERR) uIdx = (UINT)SendMessage(hCombo, CB_ADDSTRING, (WPARAM)0, (LPARAM)(LPCSTR)szCurrent); // make the new map the current one SendMessage(hCombo, CB_SETCURSEL, (WPARAM)uIdx, (LPARAM)0); if (IsDlgButtonChecked(hdlg, ID_MAINSETUP)) lstrcpy(szCurSetup, szCurrent); // allocate buffer for map description data if ((hDesc = GlobalAlloc(GHND, (DWORD)(sizeof(char) * (lstrlen (szCurDesc) + 1)))) != NULL) { lpDesc = (LPSTR)GlobalLock(hDesc); lstrcpy(lpDesc, szCurDesc); GlobalUnlock(hDesc); } SetDlgItemText (hdlg, ID_MAINDESC, szCurDesc); // put the handle in the entrys item data SendMessage(hCombo, CB_SETITEMDATA, (WPARAM)uIdx, (LPARAM)hDesc); // enable windows if it is the first map of type if (!IsWindowEnabled(hCombo)) EnableMain(TRUE); CancelToClose(hdlg); break; case ID_MAINEDIT: if (!FEditMap(hdlg)) break; CancelToClose(hdlg); if (iMap != MMAP_SETUP) break; // reset to current setup uIdx = ComboLookup(hCombo,(LPSTR)szCurSetup); //-jyg SendMessage(hCombo, CB_SETCURSEL, (WPARAM)uIdx, (LPARAM)0); #if defined(WIN16) SendMessage(hdlg, WM_COMMAND, (WPARAM)ID_MAINCOMBO, MAKELPARAM(hCombo, CBN_SELCHANGE)); #else SendMessage( hdlg , WM_COMMAND , (WPARAM)MAKELONG(ID_MAINCOMBO, CBN_SELCHANGE) , (LPARAM)hCombo ); #endif //WIN16 break; case ID_MAINSETUP: ShowMaps(MMAP_SETUP); break; case ID_MAINPATCH: ShowMaps(MMAP_PATCH); break; case ID_MAINKEY: ShowMaps(MMAP_KEY); break; case ID_MAINSETUPCOMBO: case ID_MAINPATCHCOMBO: case ID_MAINKEYCOMBO: case ID_MAINCOMBO: if (wNotifCode == CBN_SELENDOK) { CancelToClose(hdlg); fChanged = TRUE; } if (wNotifCode != CBN_SELCHANGE) return FALSE; uIdx = (UINT)SendMessage(hCombo, CB_GETCURSEL, (WPARAM)0, (LPARAM)0); if (LOWORD(wParam) == ID_MAINSETUPCOMBO) SendMessage(hCombo, CB_GETLBTEXT, (WPARAM)uIdx, (LPARAM) (LPSTR) szCurSetup); hDesc = (HGLOBAL)(DWORD)SendMessage(hCombo, CB_GETITEMDATA, (WPARAM)uIdx, (LPARAM)0); lpDesc = GlobalLock(hDesc); lstrcpy(szCurDesc, lpDesc); GlobalUnlock(hDesc); SetDlgItemText (hdlg, ID_MAINDESC, szCurDesc); SendMessage(hCombo, CB_GETLBTEXT, (WPARAM)uIdx, (LPARAM)(LPSTR)szCurrent); break; case ID_MAINDESC: // NOTE: this is not implemented. if (wNotifCode == EN_CHANGE) fChange = TRUE; else if ((wNotifCode == EN_KILLFOCUS) && fChange) { GetDlgItemText (hdlg, ID_MAINDESC, szTmpDesc, MMAP_MAXDESC); if (!lstrcmpi(szCurDesc, szTmpDesc)) { // description change logic here. // There's no API to changedesc!! } } break; default: return FALSE; } } /* end of WM_COMMAND */ break; default: if (uMessage == uHelpMessage) { DoHelp: WinHelp(hWnd, szMidiHlp, HELP_CONTEXT, IDH_CHILD_MIDI); return TRUE; } else return FALSE; break; } return TRUE; } /* MainBox */ BOOL FAR PASCAL InvalidPortMsgBox ( HWND hwnd) { int iRet; char szBuf[256]; LoadString(hLibInst, IDS_INVALIDPORT, szBuf, sizeof(szBuf)); iRet = MessageBox (hwnd, szBuf, szMidiCtl, MB_ICONSTOP | MB_YESNO); return iRet == IDYES; } /* InvalidPortMsgBox */ VOID FAR PASCAL Modify( BOOL fSet) { fModified = fSet; if (fModified) fChanged = TRUE; } /* Modify */ /* * ENUMFUNC * * Enumerate setup, patchmap or keymap names. */ BOOL FAR PASCAL _loadds EnumFunc( LPSTR lpName, LPSTR lpDesc, UINT uCase, HWND hCombo, LPSTR unused ) { HGLOBAL hMem; LPSTR lpStr; UINT uIdx; MMAPERR mmaperr; // see if we're dealing with 'delete' enumeration. if (uCase == MMENUM_DELETE) { uIdx = ComboLookup(hCombo, (LPSTR)lpName);//-jyg if (uIdx != CB_ERR) return TRUE; mmaperr = mapDelete(iMap, lpName); if (mmaperr == MMAPERR_SUCCESS) return TRUE; VShowError(hWnd, mmaperr); return FALSE; } uIdx = (UINT)SendMessage(hCombo, CB_ADDSTRING, (WPARAM)NULL, (LPARAM)lpName); // see if we're dealing with enumeration from the main dialog if (uCase == MMENUM_INTOCOMBO) { hMem = GlobalAlloc(GHND, (DWORD)(lstrlen(lpDesc) + 1)); if (hMem != NULL) { lpStr = (LPSTR)GlobalLock(hMem); lstrcpy(lpStr, lpDesc); GlobalUnlock(hMem); } SendMessage( hCombo, CB_SETITEMDATA, (WPARAM)uIdx, (LPARAM)hMem); } return TRUE; } /* EnumFunc */ #if 0 /* * SETWINDOWCAPTION * * Set the caption of a 'window', such as 'MIDI Setup: "foo"', even though * these are actually dialog boxes. */ VOID FAR PASCAL SetWindowCaption( VOID) { char szCaption[80], szName[MM_MAXRESLEN]; LoadString(hLibInst, IdsGetMapNameId(iMap), szName, sizeof(szName)); wsprintf(szCaption, aszCaptionFormat, (LPSTR)szName, (LPSTR)szCurrent); SetWindowText(hWnd, szCaption); } /* SetWindowCaption */ #endif //0 int FAR PASCAL QuerySave (VOID) { char szBuf[256]; char aszSave[64]; char aszFormat[128]; char szFunc[MM_MAXRESLEN]; LoadString(hLibInst, IdsGetMapNameId(iMap), szFunc, sizeof(szFunc)); if (fNew) { // AnsiUpperBuff(szFunc, 1); // Upper-case first character. LoadString(hLibInst, IDS_NEW_QUESTION, aszFormat, sizeof(aszFormat)); wsprintf (szBuf, aszFormat, (LPSTR)szCurrent, (LPSTR)szFunc); } else { LoadString(hLibInst, IDS_CHANGE_QUESTION, aszFormat, sizeof(aszFormat)); wsprintf (szBuf, aszFormat, (LPSTR)szFunc, (LPSTR)szCurrent); } LoadString(hLibInst, IDS_SAVE_CHANGES, aszSave, sizeof(aszSave)); return MessageBox(hWnd, szBuf, aszSave, MB_YESNOCANCEL | MB_ICONEXCLAMATION); } /* QuerySave */