|
|
/*==========================================================================*/ //
// midi.c
//
// Copyright (C) 1993-1994 Microsoft Corporation. All Rights Reserved.
/*==========================================================================*/
#include "mmcpl.h"
#include <windowsx.h>
#include <mmsystem.h>
#include <mmddkp.h>
#include <mmreg.h>
#include <cpl.h>
#define NOSTATUSBAR
#include <commctrl.h>
#include <prsht.h>
#include <string.h>
#include <memory.h>
#include <regstr.h>
#include "draw.h"
#include "utils.h"
#include "roland.h"
#include "midi.h"
#include "tchar.h"
//#include "newexe.h"
#include <winnt.h>
#if defined DEBUG || defined DEBUG_RETAIL
extern TCHAR szNestLevel[]; TCHAR szNestLevel[] = TEXT ("0MidiProp:"); #define MODULE_DEBUG_PREFIX szNestLevel
#endif
#define _INC_MMDEBUG_CODE_ TRUE
#include "mmdebug.h"
#include "medhelp.h"
#ifndef TVIS_ALL
#define TVIS_ALL 0xFF7F // internal
#endif
#ifndef MIDI_IO_CONTROL
#define MIDI_IO_CONTROL 0x00000008L // internal
#endif
#ifndef DRV_F_ADD // FEATURE: These should be in MMDDK.H
#define DRV_F_ADD 0x00000000
#define DRV_F_REMOVE 0x00000001
#define DRV_F_CHANGE 0x00000002
#define DRV_F_PROP_INSTR 0x00000004
#define DRV_F_NEWDEFAULTS 0x00000008
#define DRV_F_PARAM_IS_DEVNODE 0x10000000
#endif
/*==========================================================================*/
// containing struct for what would otherwise be global variables
//
struct _globalstate gs;
// this is the registry key that has midi instrument aliases
// as subkeys
//
SZCODE cszSchemeRoot[] = REGSTR_PATH_PRIVATEPROPERTIES TEXT ("\\MIDI\\Schemes");
SZCODE cszMidiMapRoot[] = REGSTR_PATH_MULTIMEDIA TEXT ("\\MIDIMap");
// this is the registry key that has midi driver/port names
//
SZCODE cszDriversRoot[] = REGSTR_PATH_MEDIARESOURCES TEXT ("\\MIDI");
// this is the list of known hindered midi drivers (or rather,
// known drivers that require special idf's)
//
SZCODE cszHinderedMidiList[] = REGSTR_PATH_MEDIARESOURCES TEXT ("\\NonGeneralMIDIDriverList");
SZCODE cszFriendlyName[] = TEXT ("FriendlyName"); SZCODE cszDescription[] = TEXT ("Description"); SZCODE cszSlashInstruments[] = TEXT ("\\Instruments"); SZCODE cszExternal[] = TEXT ("External"); SZCODE cszActive[] = TEXT ("Active"); SZCODE cszDefinition[] = TEXT ("Definition"); SZCODE cszPort[] = TEXT ("Port"); SZCODE cszMidiSlash[] = TEXT ("midi\\"); SZCODE csz02d[] = TEXT ("%02d"); SZCODE cszEmpty[] = TEXT ("");
static SZCODE cszChannels[] = TEXT ("Channels"); static SZCODE cszCurrentScheme[] = TEXT ("CurrentScheme"); static SZCODE cszCurrentInstrument[] = TEXT ("CurrentInstrument"); static SZCODE cszUseScheme[] = TEXT ("UseScheme"); static SZCODE cszAutoScheme[] = TEXT ("AutoScheme"); static SZCODE cszRunOnceCount[] = TEXT ("ConfigureCount"); static SZCODE cszDriverList[] = TEXT ("DriverList"); static SZCODE cszDriverVal[] = TEXT ("Driver");
//
// structures used to hold data for the control panel dialogs.
//
//
typedef struct _midi_scheme { PMCMIDI pmcm; HKEY hkSchemes; TCHAR szNone[MAX_ALIAS]; DWORD dwChanMask; TCHAR szName[MAX_ALIAS]; UINT nChildren; BOOL bDirty; struct { PINSTRUM pi; DWORD dwMask; } a[NUM_CHANNEL*4 +1]; } MSCHEME, * PMSCHEME;
typedef struct _midi_cpl { LPPROPSHEETPAGE ppsp;
MSCHEME ms; TCHAR szScheme[MAX_ALIAS]; TCHAR szDefault[MAX_ALIAS]; PINSTRUM piSingle; BOOL bUseScheme; BOOL bAutoScheme; // TRUE if scheme was auto created
DWORD dwRunCount; // counts the number of times runonce
LPTSTR pszReason; // reason for choosing external port
BOOL bDlgType2; BOOL bPastInit; BOOL bIgnoreSelChange;
MCMIDI mcm;
} MCLOCAL, * PMCLOCAL;
BOOL WINAPI ShowDetails ( HWND hWnd, PMCLOCAL pmcl);
LONG SHRegDeleteKey(HKEY hKey, LPCTSTR lpSubKey);
static UINT DeviceIDFromDriverName( PTSTR pstrDriverName);
extern BOOL AccessServiceController(void);
/*+ SimulateNotify
* *-=================================================================*/
STATICFN LRESULT SimulateNotify ( HWND hWnd, WORD uId, WORD wNotify) { #ifdef _WIN32
return SendMessage (hWnd, WM_COMMAND, MAKELONG(uId, wNotify), (LPARAM)GetDlgItem (hWnd, uId)); #else
#error this code is not designed for 16 bits
#endif
}
/*+ Confirm
* *-=================================================================*/
STATICFN UINT Confirm ( HWND hWnd, UINT idQuery, LPTSTR pszArg) { TCHAR szQuery[255]; TCHAR sz[255];
LoadString (ghInstance, idQuery, sz, NUMELMS(sz)); wsprintf (szQuery, sz, pszArg);
LoadString (ghInstance, IDS_DEF_CAPTION, sz, NUMELMS(sz));
return MessageBox (hWnd, szQuery, sz, MB_YESNO | MB_ICONQUESTION); }
/*+ TellUser
* *-=================================================================*/
STATICFN UINT TellUser ( HWND hWnd, UINT idQuery, LPTSTR pszArg) { TCHAR szQuery[255]; TCHAR sz[255];
LoadString (ghInstance, idQuery, sz, NUMELMS(sz)); wsprintf (szQuery, sz, pszArg);
LoadString (ghInstance, IDS_DEF_CAPTION, sz, NUMELMS(sz));
return MessageBox (hWnd, szQuery, sz, MB_OK | MB_ICONINFORMATION); }
/*+ ForwardBillNotify
* *-=================================================================*/
STATICFN void ForwardBillNotify ( HWND hWnd, NMHDR FAR * lpnm) { static struct { UINT code; UINT uId; } amap[] = {PSN_KILLACTIVE, IDOK, PSN_APPLY, ID_APPLY, PSN_SETACTIVE, ID_INIT, PSN_RESET, IDCANCEL, }; UINT ii;
#ifdef DEBUG
AuxDebugEx (4, DEBUGLINE TEXT ("ForwardBillNotify() code = %X\r\n"), lpnm->code); #endif
for (ii = 0; ii < NUMELMS(amap); ++ii) if (lpnm->code == amap[ii].code) { FORWARD_WM_COMMAND (hWnd, amap[ii].uId, 0, 0, SendMessage); break; } return; }
/*+
* *-=================================================================*/
STATICFN void EnumChildrenIntoCombo ( HWND hWndT, LPTSTR pszSelect, HKEY hKey) { TCHAR sz[MAX_ALIAS]; DWORD cch = sizeof(sz)/sizeof(TCHAR); UINT ii = 0;
//SetWindowRedraw (hWndT, FALSE);
ComboBox_ResetContent (hWndT);
if (!hKey) return;
while (RegEnumKey (hKey, ii, sz, cch) == ERROR_SUCCESS) { int ix = ComboBox_AddString (hWndT, sz); //ComboBox_SetItemData (hWndT, ix, ii);
++ii; }
ii = 0; if (pszSelect) ii = ComboBox_FindString (hWndT, -1, pszSelect);
ComboBox_SetCurSel (hWndT, ii); }
STDAPI_(BOOL) QueryGSSynth(LPTSTR pszDriver) { MIDIOUTCAPS moc; MMRESULT mmr; UINT mid; BOOL fGSSynth = FALSE;
if (pszDriver) { mid = DeviceIDFromDriverName(pszDriver);
if (mid!=(UINT)-1) { mmr = midiOutGetDevCaps(mid, &moc, sizeof(moc));
if (MMSYSERR_NOERROR == mmr) { if ((moc.wMid == MM_MICROSOFT) && (moc.wPid == MM_MSFT_WDMAUDIO_MIDIOUT) && (moc.wTechnology == MOD_SWSYNTH)) { fGSSynth = TRUE; } //end if synth
} //end if no mm error
} //end if mid is valid
} //end if driver is valid string
return(fGSSynth); }
/*+
* *-=================================================================*/
LONG WINAPI GetAlias ( HKEY hKey, LPTSTR szSub, LPTSTR pszAlias, DWORD cchAlias, BOOL * pbExtern, BOOL * pbActive) { LONG lRet; DWORD cbSize; HKEY hkSub; DWORD dw;
#ifdef DEBUG
AuxDebugEx (8, DEBUGLINE TEXT ("GetAlias(%08x,'%s',%08x,%d,%08x)\r\n"), hKey, szSub, pszAlias, cchAlias, pbExtern); #endif
if (!(lRet = RegOpenKeyEx (hKey, szSub, 0, KEY_QUERY_VALUE, &hkSub))) { cbSize = cchAlias * sizeof (TCHAR); if ((lRet = RegQueryValueEx (hkSub, cszFriendlyName, NULL, &dw, (LPBYTE)pszAlias, &cbSize)) || cbSize <= 2) { cbSize = cchAlias * sizeof (TCHAR); if ((lRet = RegQueryValueEx (hkSub, cszDescription, NULL, &dw, (LPBYTE)pszAlias, &cbSize)) || cbSize <= 2) { TCHAR szDriver[MAXSTR];
cbSize = sizeof(szDriver); if (!RegQueryValueEx(hkSub, cszDriverVal, NULL, &dw, (LPBYTE)szDriver, &cbSize)) { LoadVERSION(); if (!LoadDesc(szDriver, pszAlias)) lstrcpy(pszAlias, szDriver); FreeVERSION();
cbSize = (lstrlen(pszAlias)+1) * sizeof(TCHAR); RegSetValueEx(hkSub, cszFriendlyName, (DWORD)0, REG_SZ, (LPBYTE)pszAlias, cbSize); RegSetValueEx(hkSub, cszDescription, (DWORD)0, REG_SZ, (LPBYTE)pszAlias, cbSize); } else pszAlias[0] = 0; } }
if (pbExtern) { *pbExtern = 0; cbSize = sizeof(*pbExtern); if (!(lRet = RegQueryValueEx (hkSub, cszExternal, NULL, &dw, (LPBYTE)pbExtern, &cbSize))) { if (REG_SZ == dw) *pbExtern = (*(LPTSTR)pbExtern == TEXT('0')) ? FALSE : TRUE; } }
if (pbActive) { *pbActive = 0; cbSize = sizeof(*pbActive); if (!(lRet = RegQueryValueEx (hkSub, cszActive, NULL, &dw, (LPBYTE)pbActive, &cbSize))) { if (REG_SZ == dw) *pbActive = (*(LPTSTR)pbActive == TEXT('1')) ? TRUE : FALSE; } }
RegCloseKey (hkSub); }
#ifdef DEBUG
if (lRet) { TCHAR szErr[MAX_PATH];
FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lRet, 0, szErr, NUMELMS(szErr), NULL);
#ifdef DEBUG
AuxDebugEx (1, DEBUGLINE TEXT ("GetAlias failed: %d %s\r\n"), lRet, szErr); #endif
} #endif
return lRet; }
/*+
* *-=================================================================*/
LONG WINAPI GetDriverFilename ( HKEY hKey, LPTSTR szSub, LPTSTR pszDriver, DWORD cchDriver) { HKEY hkSub; LONG lRet;
if (!(lRet = RegOpenKeyEx (hKey, szSub, 0, KEY_QUERY_VALUE, &hkSub))) { DWORD dwType; TCHAR sz[MAX_PATH]; UINT cb = sizeof(sz);
// get the contents of the 'driver' value of the given key.
// then copy the filename part
//
lRet = RegQueryValueEx(hkSub, cszDriverVal, NULL, &dwType, (LPBYTE)sz, &cb); if (lRet || dwType != REG_SZ) *pszDriver = 0; else { LPTSTR psz = sz; UINT ii;
// scan forward till we get to the file part of the pathname
// then copy that part into the supplied buffer
//
for (ii = 0; psz[ii]; ) { if (psz[ii] == TEXT('\\') || psz[ii] == TEXT(':')) { psz += ii+1; ii = 0; } else ++ii; } lstrcpyn (pszDriver, psz, cchDriver); } RegCloseKey (hkSub); } return lRet; }
/*+ LoadInstruments
* * load interesting data for all instruments, if bDriverAsAlias * is true, then put driver filename in szFriendly field of each * instrument. (scheme init uses this for hindered driver detection) * if !bDriverAsAlias, put friendly name in friendly name slot * * *-=================================================================*/
void WINAPI LoadInstruments ( PMCMIDI pmcm, BOOL bDriverAsAlias) { HKEY hkMidi; TCHAR sz[MAX_ALIAS]; DWORD cch = sizeof(sz)/sizeof(TCHAR); UINT ii; UINT nInstr; PINSTRUM pi; UINT idxPort = 0;
pmcm->nInstr = 0; pmcm->bHasExternal = FALSE;
if (!(hkMidi = pmcm->hkMidi)) { if (RegCreateKey (HKEY_LOCAL_MACHINE, cszDriversRoot, &hkMidi)) return; pmcm->hkMidi = hkMidi; }
if (!(pi = pmcm->api[0])) { pmcm->api[0] = pi = (LPVOID)LocalAlloc (LPTR, sizeof(*pi)); if (!pi) return; }
for (cch = sizeof(pi->szKey)/sizeof(TCHAR), nInstr = 0, ii = 0; ! RegEnumKey (hkMidi, ii, pi->szKey, cch); ++ii) { UINT jj; HKEY hkInst; PINSTRUM piParent; BOOL bActive = FALSE;
// get driver alias, external, and active flags. This has the side
// effect of initializing the friendly name key for legacy drivers
// that have neither friendly name, nor description
//
GetAlias (hkMidi, pi->szKey, pi->szFriendly, NUMELMS(pi->szFriendly), &pi->bExternal, &bActive);
// if requested, stomp friendly name with driver filename
//
if (bDriverAsAlias) GetDriverFilename (hkMidi, pi->szKey, pi->szFriendly, NUMELMS(pi->szFriendly));
pi->fGSSynth = QueryGSSynth(pi->szKey); pi->uID = idxPort;
if (pi->bExternal) pmcm->bHasExternal = TRUE;
pi->piParent = 0; pi->bActive = bActive; piParent = pi;
++nInstr; if (nInstr >= NUMELMS(pmcm->api)) { assert2 (0, TEXT ("Tell JohnKn to make midi instrument table bigger")); break; }
if (!(pi = pmcm->api[nInstr])) { pmcm->api[nInstr] = pi = (LPVOID)LocalAlloc (LPTR, sizeof(*pi)); if (!pi) break; }
// open the parent's instruments subkey
//
lstrcpy (sz, piParent->szKey); lstrcat (sz, cszSlashInstruments); if (RegCreateKey (hkMidi, sz, &hkInst)) continue;
// enum the instruments and add them to the list
//
for (jj = 0; ! RegEnumKey (hkInst, jj, sz, cch); ++jj) { lstrcpy (pi->szKey, piParent->szKey); lstrcat (pi->szKey, cszSlashInstruments); lstrcat (pi->szKey, cszSlash); lstrcat (pi->szKey, sz);
GetAlias (hkInst, sz, pi->szFriendly, NUMELMS(pi->szFriendly), NULL, NULL); pi->piParent = piParent; pi->bExternal = FALSE; pi->bActive = bActive;
++nInstr; if (nInstr >= NUMELMS(pmcm->api)) { assert2 (0, TEXT ("Tell JohnKn to make midi instrument table bigger")); break; }
if (!(pi = pmcm->api[nInstr])) { pmcm->api[nInstr] = pi = (LPVOID)LocalAlloc (LPTR, sizeof(*pi)); if (!pi) break; } }
RegCloseKey (hkInst); }
// create a 'none' entry at the end
//
if (pi) { pi->piParent = 0; pi->bExternal = FALSE; pi->bActive = TRUE; pi->szKey[0] = 0; LoadString (ghInstance, IDS_NONE, pi->szFriendly, NUMELMS(pi->szFriendly)); ++nInstr; }
pmcm->nInstr = nInstr; }
/*+
* *-=================================================================*/
void WINAPI FreeInstruments ( PMCMIDI pmcm) { UINT ii;
for (ii = 0; ii < NUMELMS (pmcm->api); ++ii) if (pmcm->api[ii]) LocalFree ((HLOCAL)(PVOID)pmcm->api[ii]), pmcm->api[ii] = NULL;
pmcm->nInstr = 0; }
#ifdef DEBUG
/*+ CleanStringCopy
* * Replaces unprintable characters with '.' * *-=================================================================*/
STATICFN LPTSTR CleanStringCopy ( LPTSTR pszOut, LPTSTR pszIn, UINT cbOut) { LPTSTR psz = pszOut; while (cbOut && *pszIn) { *psz = (*pszIn >= 32 && *pszIn < 127) ? *pszIn : TEXT('.'); ++psz; ++pszIn; }
*psz = 0; return pszOut; }
/*+ DumpInstruments
* *-=================================================================*/
STATICFN void DumpInstruments ( PMCMIDI pmcm) { UINT ii; PINSTRUM pi;
#ifdef DEBUG
AuxDebugEx (3, DEBUGLINE TEXT ("DumpInstruments(%08x) nInstr=%d\r\n"), pmcm, pmcm->nInstr); #endif
for (ii = 0; ii < pmcm->nInstr; ++ii) { TCHAR szKey[MAX_ALIAS]; TCHAR szFriendly[MAX_ALIAS];
pi = pmcm->api[ii]; if (!pi) { #ifdef DEBUG
AuxDebugEx (2, TEXT ("\tapi[%d] NULL\r\n"), ii); #endif
continue; }
CleanStringCopy (szKey, pi->szKey, NUMELMS(szKey)); CleanStringCopy (szFriendly, pi->szFriendly, NUMELMS(szFriendly));
#ifdef DEBUG
AuxDebugEx (3, TEXT ("\tapi[%d]%08X p:%08x x:%d a:%d '%s' '%s'\r\n"), ii, pi, pi->piParent, pi->bExternal, pi->bActive, szKey, szFriendly); #endif
} } #endif
/*+
* *-=================================================================*/
STATICFN PINSTRUM WINAPI FindInstrumPath ( PMCMIDI pmcm, LPTSTR pszPath) { UINT ii;
for (ii = 0; ii < pmcm->nInstr; ++ii) { assert (pmcm->api[ii]); if (IsSzEqual(pszPath, pmcm->api[ii]->szKey)) return pmcm->api[ii]; }
return NULL; }
/*+
* *-=================================================================*/
PINSTRUM WINAPI FindInstrumentFromKey ( PMCMIDI pmcm, LPTSTR pszKey) { UINT ii;
if (!pszKey || !pszKey[0]) return NULL;
for (ii = 0; ii < pmcm->nInstr; ++ii) { assert (pmcm->api[ii]); if (IsSzEqual(pszKey, pmcm->api[ii]->szKey)) return pmcm->api[ii]; }
return NULL; }
/*+
* *-=================================================================*/
STATICFN void LoadInstrumentsIntoCombo ( HWND hWnd, UINT uId, PINSTRUM piSelect, PMCMIDI pmcm) { HWND hWndT = GetDlgItem (hWnd, uId); UINT ii; int ix;
#ifdef DEBUG
AuxDebugEx (4, DEBUGLINE TEXT ("LoadInstrumentsIntoCombo(%08X,%d,%08x,%08x)\r\n"), hWnd, uId, piSelect, pmcm); #endif
assert (hWndT); if (!hWndT) return;
if (pmcm->nInstr > 0) SetWindowRedraw (hWndT, FALSE); ComboBox_ResetContent(hWndT);
for (ii = 0; ii < pmcm->nInstr; ++ii) { if (ii == pmcm->nInstr-1) SetWindowRedraw (hWndT, TRUE);
if (pmcm->api[ii]->bActive #ifdef EXCLUDE_EXTERNAL
&& !pmcm->api[ii]->bExternal #endif
) { #ifdef DEBUG
AuxDebugEx (7, DEBUGLINE TEXT ("Instrument[%d] = '%s'\r\n"), ii, pmcm->api[ii]->szFriendly); #endif
ix = ComboBox_AddString (hWndT, pmcm->api[ii]->szFriendly); ComboBox_SetItemData (hWndT, ix, (LPARAM)pmcm->api[ii]);
if (piSelect && pmcm->api[ii] == piSelect) ComboBox_SetCurSel (hWndT, ix); } } }
/*+
* *-=================================================================*/
STATICFN void LoadInstrumentsIntoTree ( HWND hWnd, UINT uId, UINT uIdSingle, PINSTRUM piSelect, PMCLOCAL pmcl) { PMCMIDI pmcm = &pmcl->mcm; HWND hWndT = GetDlgItem (hWnd, uId); UINT ii; HTREEITEM htiSelect = NULL; HTREEITEM htiParent = TVI_ROOT;
assert (hWndT); if (!hWndT) return;
#ifdef UNICODE
TreeView_SetUnicodeFormat(hWndT,TRUE); #endif
//if (pmcm->nInstr > 0)
// SetWindowRedraw (hWndT, FALSE);
pmcl->bIgnoreSelChange = TRUE; #ifdef DEBUG
AuxDebugEx (6, DEBUGLINE TEXT ("tv_DeleteAllItems(%08X)\r\n"), hWndT); #endif
TreeView_DeleteAllItems(hWndT); #ifdef DEBUG
AuxDebugEx (6, DEBUGLINE TEXT ("tv_DeleteAllItems(%08X) ends\r\n"), hWndT); #endif
pmcl->bIgnoreSelChange = FALSE;
for (ii = 0; ii < pmcm->nInstr; ++ii) { PINSTRUM pi = pmcm->api[ii]; TV_INSERTSTRUCT ti; HTREEITEM hti;
//if (ii == pmcm->nInstr-1)
// SetWindowRedraw (hWndT, TRUE);
if (!pi->szKey[0] || !pi->bActive) continue;
ZeroMemory (&ti, sizeof(ti));
ti.hParent = TVI_ROOT; if (pi->piParent) ti.hParent = htiParent;
ti.hInsertAfter = TVI_SORT; ti.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
// TV_ITEM may not be ported to UNICODE ?!?
ti.item.pszText = pi->szFriendly; ti.item.state = TVIS_EXPANDED; ti.item.stateMask = TVIS_ALL; ti.item.lParam = (LPARAM)pi;
hti = TreeView_InsertItem (hWndT, &ti);
if (piSelect && (piSelect == pi)) htiSelect = hti;
if ( ! pi->piParent) htiParent = hti; }
// if a 'single' control id has been specified, propagate
// selected item text into this control
//
if (uIdSingle) { if (htiSelect) { assert (piSelect); TreeView_SelectItem (hWndT, htiSelect); SetDlgItemText (hWnd, uIdSingle, piSelect->szFriendly); EnableWindow(GetDlgItem(hWnd, IDC_ABOUTSYNTH), piSelect->fGSSynth); } else SetDlgItemText (hWnd, uIdSingle, cszEmpty); }
}
/*+
* *-=================================================================*/
STATICFN void LoadSchemesIntoCombo ( HWND hWnd, UINT uId, LPTSTR pszSelect, PMSCHEME pms) { HWND hWndT = GetDlgItem (hWnd, uId); HKEY hKey;
assert (hWndT); if (!hWndT) return;
hKey = pms->hkSchemes; if (!hKey && !RegCreateKey (HKEY_LOCAL_MACHINE, cszSchemeRoot, &hKey)) pms->hkSchemes = hKey;
EnumChildrenIntoCombo (hWndT, pszSelect, hKey); }
/*+ ChildKeyExists
* * given an open registry key, and the name of a child of that * registry key, returns true if a child key with the given * name exists. * *-=================================================================*/
STATICFN BOOL ChildKeyExists ( HKEY hKey, LPTSTR pszChild) { TCHAR sz[MAX_ALIAS]; UINT ii;
if (!hKey) return FALSE;
for (ii = 0; ! RegEnumKey (hKey, ii, sz, sizeof(sz)/sizeof(TCHAR)); ++ii) { if (IsSzEqual (pszChild, sz)) return TRUE; }
return FALSE; }
/*+ LoadSchemeFromReg
* *-=================================================================*/
STATICFN void LoadSchemeFromReg ( PMCMIDI pmcm, PMSCHEME pms, LPTSTR pszName) { HKEY hKey; DWORD dwAccum; UINT count;
// try to open the indicated scheme key in the registry
// and read channel map from it. Failure here is permissible.
// it indicates that we are createing a new scheme.
//
count = 0; if (RegOpenKey (pms->hkSchemes, pszName, &hKey) == ERROR_SUCCESS) { DWORD cb; TCHAR sz[MAX_ALIAS];
while (RegEnumKey (hKey, count, sz, sizeof(sz)/sizeof(TCHAR)) == ERROR_SUCCESS) { HKEY hKeyA; DWORD dwType;
if (RegOpenKey (hKey, sz, &hKeyA) != ERROR_SUCCESS) break;
pms->a[count].pi = NULL; cb = sizeof(sz); if ( ! RegQueryValue (hKeyA, NULL, sz, &cb)) pms->a[count].pi = FindInstrumPath (pmcm, sz);
pms->a[count].dwMask = 0; cb = sizeof(pms->a[count].dwMask); RegQueryValueEx (hKeyA, cszChannels, NULL, &dwType, (LPBYTE)&pms->a[count].dwMask, &cb);
assert (dwType == REG_DWORD);
RegCloseKey (hKeyA);
// Don't allow empty entries
//assert (pms->a[ii].dwMask);
if (0 == pms->a[count].dwMask) { pms->a[count].pi = NULL; } ++count;
#ifdef DEBUG
AuxDebugEx (4, DEBUGLINE TEXT ("[%d]Chan %08X Alias '%s'\r\n"), count, pms->a[count].dwMask, pms->a[count].pi ? pms->a[count].pi->szFriendly : TEXT ("(null)")); #endif
if (count == NUMELMS(pms->a) -1) break; }
RegCloseKey (hKey); } pms->nChildren = count; lstrcpyn (pms->szName, pszName, NUMELMS(pms->szName));
// slam a dummy (none) alias that matches all channels
// at the end of our channel/alias list
//
assert (count < NUMELMS(pms->a)); pms->a[count].dwMask = (DWORD)~0; pms->a[count].pi = NULL;
#ifdef DEBUG
AuxDebugEx (4, DEBUGLINE TEXT ("[%d]Chan %08X Alias '%s'\r\n"), count, pms->a[count].dwMask, "null"); #endif
// make sure scheme channel masks are in a valid state
//
for (dwAccum = 0, count = 0; count < NUMELMS(pms->a); ++count) { pms->a[count].dwMask &= ~dwAccum; dwAccum |= pms->a[count].dwMask; }
return; }
/*+ KickMapper
* *-=================================================================*/
void WINAPI KickMapper ( HWND hWnd) { HMIDIOUT hmo;
if (! midiOutOpen(&hmo, MIDI_MAPPER, 0, 0, MIDI_IO_CONTROL)) { BOOL bDone;
#ifdef DEBUG
AuxDebugEx (2, DEBUGLINE TEXT ("Kicking Midi Mapper\r\n")); #endif
bDone = midiOutMessage(hmo, DRVM_MAPPER_RECONFIGURE, 0, DRV_F_PROP_INSTR); midiOutClose(hmo); /*
//no longer necessary due to winmm change allowing configure during play
if (!bDone && hWnd) TellUser (hWnd, IDS_MAPPER_BUSY, NULL); */ }
#ifdef DEBUG
AuxDebugEx (2, DEBUGLINE TEXT ("Done Kicking Midi Mapper\r\n")); #endif
}
/*+ SaveSchemeToReg
* *-=================================================================*/
STATICFN void SaveSchemeToReg ( PMCMIDI pmcm, PMSCHEME pms, LPTSTR pszName, HWND hWnd) { TCHAR sz[MAX_ALIAS]; HKEY hKey; DWORD dwAccum; UINT ii; UINT kk; UINT cb;
#ifdef DEBUG
AuxDebugEx (4, DEBUGLINE TEXT ("Saving Scheme '%s' children=%d\r\n"), pszName, pms->nChildren); for (ii = 0; ii < NUMELMS(pms->a); ++ii) { AuxDebugEx (4, TEXT ("\t%08X '%s'\r\n"), pms->a[ii].dwMask, pms->a[ii].pi ? pms->a[ii].pi->szKey : TEXT ("(null)")); } #endif
// make sure scheme channel masks are in a valid state,
// that is, prevent a channel bit from being set in more
// than one member of a scheme
//
for (dwAccum = 0, ii = 0; ii < NUMELMS(pms->a); ++ii) { pms->a[ii].dwMask &= ~dwAccum; dwAccum |= pms->a[ii].dwMask; }
// try to open/create the indicated scheme key in the registry
// and write/update channel map to it.
//
if (!RegCreateKey (pms->hkSchemes, pszName, &hKey)) { HKEY hKeyA; BOOL bKill;
// salvage all of the existing keys that we can. delete
// the rest.
//
for (dwAccum = 0, ii = 0; !RegEnumKey (hKey, ii, sz, sizeof(sz)/sizeof(TCHAR)); ++ii) { if (ii >= NUMELMS(pms->a)) break;
// we reuse the first N keys in this scheme
// and delete the rest.
//
bKill = TRUE; if (((dwAccum & 0xFFFF) != 0xFFFF) && pms->a[ii].pi && (!ii || (pms->a[ii].pi->szKey[0] && pms->a[ii].dwMask))) bKill = FALSE;
dwAccum |= pms->a[ii].dwMask;
// if we have an obsolete alias key, remove it now
// otherwise create/open the alias key and set it's
// channel property to the correct value.
//
if (bKill) { #ifdef DEBUG
AuxDebugEx (3, DEBUGLINE TEXT ("Deleting key[%d] '%s'\r\n"), ii, sz); #endif
RegDeleteKey (hKey, sz); } else { #ifdef DEBUG
AuxDebugEx (3, DEBUGLINE TEXT ("Reusing key[%d] '%s'\r\n"), ii, pms->a[ii].pi->szKey); #endif
if (RegOpenKeyEx (hKey, sz, 0, KEY_ALL_ACCESS, &hKeyA)) break;
cb = (lstrlen(pms->a[ii].pi->szKey) + 1) * sizeof(TCHAR); RegSetValueEx (hKeyA, NULL, 0, REG_SZ, (LPBYTE)(pms->a[ii].pi->szKey), cb);
RegSetValueEx (hKeyA, cszChannels, 0, REG_DWORD, (LPBYTE)&pms->a[ii].dwMask, sizeof(DWORD));
RegCloseKey (hKeyA); }
}
// if we have channels that have not yet been written.
// do that now
//
for (kk = 0; ii < NUMELMS(pms->a); ++ii) { // if this alias has any assigned channels, create
// a key and give it a channels value
//
if (pms->a[ii].pi && (!ii || (pms->a[ii].pi->szKey[0] && pms->a[ii].dwMask))) { #ifdef DEBUG
AuxDebugEx (3, DEBUGLINE TEXT ("Creating key[%d] '%s'\r\n"), ii, pms->a[ii].pi->szKey); #endif
// find an unused keyname;
//
for ( ; kk < NUMELMS(pms->a); ++kk) { wsprintf (sz, csz02d, kk); if (RegOpenKey (hKey, sz, &hKeyA)) break; RegCloseKey (hKeyA); }
// create a key with that name
//
if (RegCreateKey (hKey, sz, &hKeyA)) break;
cb = (lstrlen(pms->a[ii].pi->szKey) + 1) * sizeof(TCHAR); RegSetValueEx (hKeyA, NULL, 0, REG_SZ, (LPBYTE)(pms->a[ii].pi->szKey),cb);
#ifdef DEBUG
AuxDebugEx (3, DEBUGLINE TEXT ("Setting Channel Value %08X\r\n"), pms->a[ii].dwMask); #endif
RegSetValueEx (hKeyA, cszChannels, 0, REG_DWORD, (LPBYTE)&pms->a[ii].dwMask, sizeof(DWORD));
RegCloseKey (hKeyA); } }
RegCloseKey (hKey); }
// if no HWND supplied, we are in the runonce, so we dont
// want to kick mapper just because a scheme has changed
//
if (hWnd) KickMapper (hWnd); return; }
/*+ DeleteSchemeFromReg
* *-=================================================================*/
STATICFN void DeleteSchemeFromReg ( HKEY hkSchemes, LPTSTR pszName) { TCHAR sz[MAX_ALIAS]; HKEY hKey; UINT ii;
#ifdef DEBUG
AuxDebugEx (4, DEBUGLINE TEXT ("DeletingSchemeFromReg(%08X,'%s')\r\n"), hkSchemes,pszName); #endif
SHRegDeleteKey(hkSchemes, pszName); /*
// if we cannot open this key as a child of the 'schemes' key
// we are done.
//
if (RegOpenKey (hkSchemes, pszName, &hKey)) return;
// Before we can delete a key, we must delete its children
//
for (ii = 0; !RegEnumKey (hKey, ii, sz, sizeof(sz)/sizeof(TCHAR)); ++ii) { // if we have an obsolete alias key, remove it now
// otherwise create/open the alias key and set it's
// channel property to the correct value.
//
AuxDebugEx (3, DEBUGLINE TEXT ("Deleting key[%d] '%s'\r\n"), ii, sz); RegDeleteKey (hKey, sz); }
RegCloseKey (hKey);
// now delete this key
//
RegDeleteKey (hkSchemes, pszName); return; */ }
/*+
* *-=================================================================*/
STATICFN void LoadChannelsIntoList ( HWND hWnd, UINT uId, UINT uIdLabel, PMSCHEME pms) { HWND hWndT = GetDlgItem (hWnd, uId); RECT rc; UINT ii; UINT nChan; int nTabs;
assert (pms);
// empty the list
//
SetWindowRedraw (hWndT, FALSE); ListBox_ResetContent (hWndT);
// calculate the width of the tabstop
// so that the second column lines up under the indicated
// label
//
GetWindowRect (GetDlgItem(hWnd, uIdLabel), &rc); nTabs = rc.left; GetWindowRect (hWnd, &rc); nTabs = MulDiv(nTabs - rc.left, 4, LOWORD(GetDialogBaseUnits())); ListBox_SetTabStops (hWndT, 1, &nTabs);
// fill the list with channel data
//
for (nChan = 0; nChan < NUM_CHANNEL; ++nChan) { static CONST TCHAR cszDtabS[] = TEXT ("%d\t%s"); TCHAR sz[MAX_ALIAS + 10];
for (ii = 0; ii < NUMELMS(pms->a); ++ii) if (pms->a[ii].dwMask & (1 << nChan)) break; assert (ii < NUMELMS(pms->a));
wsprintf (sz, cszDtabS, nChan+1, pms->a[ii].pi ? pms->a[ii].pi->szFriendly : pms->szNone); if (nChan == (UINT)NUM_CHANNEL-1) SetWindowRedraw (hWndT, TRUE); ListBox_InsertString (hWndT, nChan, sz);
if (pms->dwChanMask & (1 << nChan)) ListBox_SetSel (hWndT, TRUE, nChan); } }
/*+
* *-=================================================================*/
/*+ ChannelMaskToEdit
* * convert a bit mask to a string containing list of set bits * and bit ranges. Then SetWindowText the result into the given * edit control. * * This function loads prefix text from resource strings. * * For Example: ChannelMaskToEdit(....0x0000F0F) would set the text * 'Channels 1-4,9-12'. * *-=================================================================*/
STATICFN void ChannelMaskToEdit ( HWND hWnd, UINT uId, DWORD dwMask) { HWND hWndT = GetDlgItem (hWnd, uId); TCHAR sz[NUM_CHANNEL * 4 + MAX_ALIAS];
if (!dwMask) LoadString (ghInstance, IDS_NOCHAN, sz, NUMELMS(sz)); else { LPTSTR psz; LPTSTR pszT; int ii; int iSpan; DWORD dwLast; DWORD dwBit;
LoadString (ghInstance, (dwMask & (dwMask-1)) ? IDS_CHANPLURAL : IDS_CHANSINGULAR, sz, NUMELMS(sz));
pszT = psz = sz + lstrlen(sz);
for (ii = 0, dwBit = 1, dwLast = 0, iSpan = 0; ii <= 32; dwLast = dwMask & dwBit, ++ii, dwBit += dwBit) { if ((dwMask & dwBit) ^ (dwLast + dwLast)) { static CONST TCHAR cszCommaD[] = TEXT (",%d"); static CONST TCHAR cszDashD[] = TEXT ("-%d");
if ( ! dwLast) psz += wsprintf (psz, cszCommaD, ii+1); else if (iSpan) psz += wsprintf (psz, cszDashD, ii); iSpan = 0; } else ++iSpan; }
*pszT = TEXT (' '); }
SetWindowText (hWndT, sz); }
/*+ MidiChangeCommands
* *-=================================================================*/
BOOL WINAPI MidiChangeCommands ( HWND hWnd, UINT wId, HWND hWndCtl, UINT wNotify) { PMCLOCAL pmcl = GetDlgData(hWnd); PMSCHEME pms = &pmcl->ms;
#ifdef DEBUG
AuxDebugEx (5, DEBUGLINE TEXT ("MidiChangeCommands(%08X,%d,%08X,%d)\r\n"), hWnd, wId, hWndCtl, wNotify); #endif
switch (wId) { case ID_APPLY: return TRUE;
case IDOK: { int ix; HWND hWndT = GetDlgItem (hWnd, IDC_INSTRUMENTS);
ix = ComboBox_GetCurSel (hWndT); if (ix >= 0) { BOOL bFound = FALSE; PINSTRUM piSel; BOOL bFoundFirst = FALSE;
piSel = (LPVOID)ComboBox_GetItemData (hWndT, ix); assert (!IsBadWritePtr(piSel, sizeof(*piSel)));
// has the <none> item been selected? in this
// case, set stuff up so that we will not try
// to add none to the scheme, but we will clear
// all bits from other channels that are set
// to none.
//
if ( ! piSel || ! piSel->szKey[0]) piSel = NULL, bFound = TRUE;
// turn channels on for this instrument and off for
// other instruments in this scheme.
//
for (ix = 0; ix < (int)NUMELMS(pms->a); ++ix) { if (pms->a[ix].pi != piSel) pms->a[ix].dwMask &= ~pms->dwChanMask; else if (! pms->a[ix].pi) { if (! bFoundFirst) { pms->a[ix].dwMask |= pms->dwChanMask; bFound = TRUE; bFoundFirst = TRUE; } } else { pms->a[ix].dwMask |= pms->dwChanMask; bFound = TRUE; } }
// if this instrument was not already in the scheme,
// find an empty slot and add it to the scheme.
//
if (!bFound) { for (ix = 0; ix < (int)NUMELMS(pms->a); ++ix) { if ( ! pms->a[ix].dwMask) { pms->a[ix].dwMask = pms->dwChanMask; pms->a[ix].pi = piSel; bFound = TRUE; break; } } }
assert2 (bFound, TEXT ("no room to add instrument to scheme")); } EndDialog (hWnd, IDOK); break; }
case IDCANCEL: EndDialog (hWnd, IDCANCEL); break;
//
//case ID_INIT:
// break;
}
return FALSE; }
/*+ SaveAsDlgProc
* *-=================================================================*/
const static DWORD aSaveAsHelpIds[] = { // Context Help IDs
IDE_SCHEMENAME, IDH_MIDI_SAVEDLG_SCHEMENAME,
0, 0 };
INT_PTR CALLBACK SaveAsDlgProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK: { LPTSTR pszName = GetDlgData (hWnd); assert (pszName); GetDlgItemText (hWnd, IDE_SCHEMENAME, pszName, MAX_ALIAS); } // fall through
case IDCANCEL: EndDialog (hWnd, GET_WM_COMMAND_ID(wParam, lParam)); break; } break; case WM_CLOSE: SendMessage (hWnd, WM_COMMAND, IDCANCEL, 0); break;
case WM_INITDIALOG: { LPTSTR pszName = (LPVOID) lParam; assert (pszName); SetDlgData (hWnd, pszName); SetDlgItemText (hWnd, IDE_SCHEMENAME, pszName); break; } case WM_CONTEXTMENU: WinHelp ((HWND) wParam, NULL, HELP_CONTEXTMENU, (UINT_PTR) (LPTSTR) aSaveAsHelpIds); return TRUE;
case WM_HELP: { LPHELPINFO lphi = (LPVOID) lParam; WinHelp (lphi->hItemHandle, NULL, HELP_WM_HELP, (UINT_PTR) (LPTSTR) aSaveAsHelpIds); return TRUE; } }
return FALSE; }
/*+ GetNewSchemeName
* *-=================================================================*/
STATICFN BOOL WINAPI GetNewSchemeName ( HWND hWnd, HKEY hkSchemes, LPTSTR pszName) { TCHAR szNew[MAX_ALIAS]; UINT_PTR uBtn;
lstrcpyn (szNew, pszName, ARRAYSIZE(szNew));
uBtn = DialogBoxParam (ghInstance, MAKEINTRESOURCE(IDD_SAVENAME), hWnd, SaveAsDlgProc, (LPARAM)szNew); if (IDOK == uBtn) { if (ChildKeyExists (hkSchemes, szNew)) uBtn = Confirm (hWnd, IDS_QUERY_OVERSCHEME, szNew); else lstrcpy (pszName, szNew); }
return (IDOK == uBtn || IDYES == uBtn); }
/*+ MidiChangeDlgProc
* *-=================================================================*/
const static DWORD aChngInstrHelpIds[] = { // Context Help IDs
IDC_INSTRUMENTS, IDH_ADDMIDI_INSTRUMENT, IDC_TEXT_1, IDH_ADDMIDI_CHANNEL, IDE_SHOW_CHANNELS, IDH_ADDMIDI_CHANNEL,
0, 0 };
INT_PTR CALLBACK MidiChangeDlgProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_COMMAND: HANDLE_WM_COMMAND (hWnd, wParam, lParam, MidiChangeCommands); break; case WM_NOTIFY: ForwardBillNotify(hWnd, (NMHDR FAR *)lParam); break; case WM_CLOSE: SendMessage (hWnd, WM_COMMAND, IDCANCEL, 0); break;
case WM_INITDIALOG: { PMCLOCAL pmcl = (LPVOID) lParam; PMSCHEME pms = &pmcl->ms;
SetDlgData (hWnd, pmcl);
LoadInstrumentsIntoCombo (hWnd, IDC_INSTRUMENTS, NULL, &pmcl->mcm); ChannelMaskToEdit (hWnd, IDE_SHOW_CHANNELS, pms->dwChanMask); break; }
//case WM_DESTROY:
// break;
case WM_CONTEXTMENU: WinHelp ((HWND) wParam, NULL, HELP_CONTEXTMENU, (UINT_PTR) (LPTSTR) aChngInstrHelpIds); return TRUE;
case WM_HELP: { LPHELPINFO lphi = (LPVOID) lParam; WinHelp (lphi->hItemHandle, NULL, HELP_WM_HELP, (UINT_PTR) (LPTSTR) aChngInstrHelpIds); return TRUE; } }
return FALSE; }
/*+ MidiConfigCommands
* *-=================================================================*/
BOOL WINAPI MidiConfigCommands ( HWND hWnd, UINT wId, HWND hWndCtl, UINT wNotify) { PMCLOCAL pmcl = GetDlgData(hWnd); PMSCHEME pms = &pmcl->ms;
#ifdef DEBUG
AuxDebugEx (5, DEBUGLINE TEXT ("MidiConfigCommands(%08X,%d,%08X,%d)\r\n"), hWnd, wId, hWndCtl, wNotify); #endif
switch (wId) { case IDB_CHANGE: { UINT_PTR uRet; int ii; HWND hWndList = GetDlgItem (hWnd, IDL_CHANNELS);
#ifdef DEBUG
AuxDebugEx (2, DEBUGLINE TEXT ("Launching Change Dialog\r\n")); #endif
pms->dwChanMask = 0; for (ii = 0; ii < NUM_CHANNEL; ++ii) if (ListBox_GetSel (hWndList, ii)) pms->dwChanMask |= (1 << ii);
uRet = DialogBoxParam (ghInstance, MAKEINTRESOURCE(IDD_MIDICHANGE), hWnd, MidiChangeDlgProc, (LPARAM)pmcl); if (uRet == IDOK) { LoadChannelsIntoList (hWnd, IDL_CHANNELS, IDC_TEXT_1, pms); pms->bDirty = TRUE; } break; }
case IDB_DELETE: if (IsSzEqual(pmcl->szScheme, pmcl->szDefault)) { break; } if (Confirm (hWnd, IDS_QUERY_DELETESCHEME, pmcl->szScheme) == IDYES) { HWND hWndCtl = GetDlgItem (hWnd, IDC_SCHEMES); int ix = ComboBox_FindStringExact (hWndCtl, -1, pmcl->szScheme); assert (ix >= 0);
DeleteSchemeFromReg (pms->hkSchemes, pmcl->szScheme);
ComboBox_DeleteString (hWndCtl, ix); ComboBox_SetCurSel (hWndCtl, 0); SimulateNotify (hWnd, IDC_SCHEMES, CBN_SELCHANGE); } break;
case IDB_SAVE_AS: if (GetNewSchemeName (hWnd, pms->hkSchemes, pmcl->szScheme)) { SaveSchemeToReg (&pmcl->mcm, pms, pmcl->szScheme, hWnd);
LoadSchemesIntoCombo (hWnd, IDC_SCHEMES, pmcl->szScheme, pms); } SimulateNotify (hWnd, IDC_SCHEMES, CBN_SELCHANGE); break;
case IDC_SCHEMES: if (wNotify == CBN_SELCHANGE) { int ix;
ix = ComboBox_GetCurSel (hWndCtl); if (ix >= 0) ComboBox_GetLBText (hWndCtl, ix, pmcl->szScheme);
LoadSchemeFromReg (&pmcl->mcm, pms, pmcl->szScheme);
pms->dwChanMask = 0; LoadChannelsIntoList (hWnd, IDL_CHANNELS, IDC_TEXT_1, pms);
EnableWindow (GetDlgItem (hWnd, IDB_DELETE), !IsSzEqual(pmcl->szDefault, pmcl->szScheme)); } break;
case IDL_CHANNELS: if (wNotify == LBN_SELCHANGE) { int ix;
ix = ListBox_GetSelCount (hWndCtl); EnableWindow (GetDlgItem (hWnd, IDB_CHANGE), (ix > 0)); } break;
case IDOK: { SaveSchemeToReg (&pmcl->mcm, pms, pmcl->szScheme, hWnd);
EndDialog (hWnd, IDOK); break; }
case IDCANCEL: EndDialog (hWnd, IDCANCEL); break; }
return FALSE; }
/*+ MidiConfigDlgProc
* *-=================================================================*/
const static DWORD aMidiConfigHelpIds[] = { // Context Help IDs
IDC_GROUPBOX, IDH_COMM_GROUPBOX, IDC_SCHEMES, IDH_MIDI_CFGDLG_SCHEME, IDB_SAVE_AS, IDH_MIDI_CFGDLG_SAVEAS, IDB_DELETE, IDH_MIDI_CFGDLG_DELETE, IDC_GROUPBOX_2, IDH_COMM_GROUPBOX, IDL_CHANNELS, IDH_MIDI_INSTRUMENTS, IDB_CHANGE, IDH_MIDI_CFGDLG_CHANGE, IDC_TEXT_1, IDH_MIDI_INSTRUMENTS, IDC_TEXT_2, IDH_MIDI_INSTRUMENTS, IDC_TEXT_3, NO_HELP,
0, 0 };
INT_PTR CALLBACK MidiConfigDlgProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_COMMAND: HANDLE_WM_COMMAND (hWnd, wParam, lParam, MidiConfigCommands); break; case WM_NOTIFY: ForwardBillNotify(hWnd, (NMHDR FAR *)lParam); break;
case WM_CLOSE: SendMessage (hWnd, WM_COMMAND, IDCANCEL, 0); break;
case WM_INITDIALOG: { PMCLOCAL pmcl = (LPVOID) lParam; assert (pmcl);
SetDlgData (hWnd, pmcl); LoadString (ghInstance, IDS_NONE, pmcl->ms.szNone, NUMELMS(pmcl->ms.szNone));
LoadSchemesIntoCombo (hWnd, IDC_SCHEMES, pmcl->szScheme, &pmcl->ms); SimulateNotify (hWnd, IDC_SCHEMES, CBN_SELCHANGE);
EnableWindow (GetDlgItem(hWnd, IDB_CHANGE), FALSE); break; }
case WM_CONTEXTMENU: WinHelp ((HWND) wParam, NULL, HELP_CONTEXTMENU, (UINT_PTR) (LPTSTR) aMidiConfigHelpIds); return TRUE;
case WM_HELP: { LPHELPINFO lphi = (LPVOID) lParam; WinHelp (lphi->hItemHandle, NULL, HELP_WM_HELP, (UINT_PTR) (LPTSTR) aMidiConfigHelpIds); return TRUE; } }
return FALSE; }
STATICFN void WINAPI PickMidiInstrument( LPTSTR pszKey) { HKEY hKeyMR, hKeyDriver; UINT cDevs; UINT ii, jj; DWORD cbSize, dwType; LPMIDIOUTCAPS pmoc; MMRESULT mmr; PWSTR pszDevIntDev, pszDevIntKey; UINT aTech[] = { MOD_SWSYNTH, MOD_WAVETABLE, MOD_SYNTH, MOD_FMSYNTH, MOD_SQSYNTH, MOD_MIDIPORT}; UINT cTech = sizeof(aTech)/sizeof(aTech[0]); TCHAR szKey[MAX_ALIAS]; TCHAR szPname[MAXPNAMELEN]; TCHAR szPnameTarget[MAXPNAMELEN]; LONG lr;
szPname[0] = 0; cDevs = midiOutGetNumDevs();
if (0 == cDevs) { return; }
pmoc = (LPMIDIOUTCAPS)LocalAlloc (LPTR, cDevs * sizeof(MIDIOUTCAPS));
if (NULL == pmoc) { return; }
for (ii = cDevs; ii; ii--) { mmr = midiOutGetDevCaps(ii - 1, &(pmoc[ii - 1]), sizeof(MIDIOUTCAPS));
if (MMSYSERR_NOERROR != mmr) { LocalFree ((HLOCAL)pmoc); return; } }
for (ii = 0; ii < cTech; ii++) { for (jj = cDevs; jj; jj--) { if (pmoc[jj - 1].wTechnology == aTech[ii]) { lstrcpy(szPname, pmoc[jj - 1].szPname); break; } }
if (jj) { // Broke out of inner loop, found match
break; } }
LocalFree ((HLOCAL)pmoc);
if (0 == jj) { // This should never happen...
return; }
jj--;
mmr = midiOutMessage (HMIDIOUT_INDEX(jj), DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)(PULONG)&cbSize, 0L);
if (MMSYSERR_NOERROR != mmr) { return; }
pszDevIntDev = (PWSTR)LocalAlloc (LPTR, cbSize);
if (NULL == pszDevIntDev) { return; }
mmr = midiOutMessage (HMIDIOUT_INDEX(jj), DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)pszDevIntDev, (DWORD)cbSize);
if (MMSYSERR_NOERROR != mmr) { LocalFree ((HLOCAL)pszDevIntDev); return; }
lr = RegOpenKey(HKEY_LOCAL_MACHINE, cszDriversRoot, &hKeyMR);
if (ERROR_SUCCESS != lr) { LocalFree ((HLOCAL)pszDevIntDev); return; }
for (ii = 0; ; ) { lr = RegEnumKey(hKeyMR, ii++, szKey, sizeof(szKey)/sizeof(szKey[0]));
if (ERROR_SUCCESS != lr) { RegCloseKey(hKeyMR); LocalFree ((HLOCAL)pszDevIntDev); return; }
lr = RegOpenKey(hKeyMR, szKey, &hKeyDriver);
if (ERROR_SUCCESS != lr) { RegCloseKey(hKeyMR); LocalFree ((HLOCAL)pszDevIntDev); return; }
cbSize = sizeof(szPnameTarget);
lr = RegQueryValueEx( hKeyDriver, cszActive, NULL, &dwType, (LPSTR)szPnameTarget, &cbSize);
if (ERROR_SUCCESS != lr) { RegCloseKey(hKeyDriver); RegCloseKey(hKeyMR); LocalFree ((HLOCAL)pszDevIntDev); return; }
if (TEXT('1') != szPnameTarget[0]) { RegCloseKey(hKeyDriver); continue; }
cbSize = sizeof(szPnameTarget);
lr = RegQueryValueEx( hKeyDriver, cszDescription, NULL, &dwType, (LPSTR)szPnameTarget, &cbSize);
if (ERROR_SUCCESS != lr) { RegCloseKey(hKeyDriver); RegCloseKey(hKeyMR); LocalFree ((HLOCAL)pszDevIntDev); return; }
if (0 != lstrcmp(szPnameTarget, szPname)) { RegCloseKey(hKeyDriver); continue; }
cbSize = 0;
lr = RegQueryValueExW ( hKeyDriver, L"DeviceInterface", NULL, &dwType, (LPSTR)NULL, &cbSize);
if (ERROR_SUCCESS != lr) { RegCloseKey(hKeyDriver); RegCloseKey(hKeyMR); LocalFree ((HLOCAL)pszDevIntDev); return; }
pszDevIntKey = (PWSTR) LocalAlloc (LPTR, cbSize);
if (NULL == pszDevIntKey) { RegCloseKey(hKeyDriver); RegCloseKey(hKeyMR); LocalFree ((HLOCAL)pszDevIntDev); return; }
lr = RegQueryValueExW ( hKeyDriver, L"DeviceInterface", NULL, &dwType, (LPSTR)pszDevIntKey, &cbSize);
RegCloseKey(hKeyDriver);
if (ERROR_SUCCESS != lr) { LocalFree ((HLOCAL)pszDevIntKey); RegCloseKey(hKeyMR); LocalFree ((HLOCAL)pszDevIntDev); return; }
if (0 == lstrcmpiW(pszDevIntKey, pszDevIntDev)) { LocalFree ((HLOCAL)pszDevIntKey); RegCloseKey(hKeyMR); LocalFree ((HLOCAL)pszDevIntDev); lstrcpy(pszKey, szKey); return; }
LocalFree ((HLOCAL)pszDevIntKey); } }
/*+ SaveLocal
* *-=================================================================*/
STATICFN void WINAPI SaveLocal ( PMCLOCAL pmcl, BOOL bUserSetting, HWND hWnd) // optional window to report errors: NULL - no reports
{ HKEY hKey = NULL; UINT cb;
#ifdef DEBUG
AuxDebugEx (2, DEBUGLINE TEXT ("SaveLocal(%08X,%X) %s\r\n"), pmcl, hWnd, pmcl->pszReason ? pmcl->pszReason : TEXT ("")); #endif
if ((RegCreateKey (HKEY_CURRENT_USER, cszMidiMapRoot, &hKey) == ERROR_SUCCESS) && hKey) { cb = (lstrlen(pmcl->szScheme) + 1) * sizeof(TCHAR); RegSetValueEx (hKey, cszCurrentScheme, 0, REG_SZ, (LPBYTE)pmcl->szScheme, cb);
//assert (pmcl->piSingle);
if ((pmcl->piSingle) && (pmcl->piSingle->bActive)) { #ifdef DEBUG
AuxDebugEx (2, DEBUGLINE TEXT ("Setting CurrentInstrument Key to %08X '%s'\r\n"), pmcl->piSingle, pmcl->piSingle->szKey); #endif
cb = (lstrlen(pmcl->piSingle->szKey) + 1) * sizeof(TCHAR); RegSetValueEx (hKey, cszCurrentInstrument, 0, REG_SZ, (LPBYTE)(pmcl->piSingle->szKey), cb); } else { // Assume No Match
TCHAR szKey[MAX_ALIAS]; LONG lr;
szKey[0] = 0;
RegSetValueEx (hKey, cszCurrentInstrument, 0, REG_SZ, (LPBYTE)cszEmpty, 0); PickMidiInstrument(szKey);
cb = (lstrlen(szKey) + 1) * sizeof(TCHAR); lr = RegSetValueEx (hKey, cszCurrentInstrument, 0, REG_SZ, (LPBYTE)(szKey), cb); }
RegSetValueEx (hKey, cszUseScheme, 0, REG_DWORD, (LPBYTE)&pmcl->bUseScheme, sizeof(pmcl->bUseScheme));
if (bUserSetting) pmcl->bAutoScheme = FALSE;
RegSetValueEx (hKey, cszAutoScheme, 0, REG_DWORD, (LPBYTE)&pmcl->bAutoScheme, sizeof(pmcl->bAutoScheme));
RegSetValueEx (hKey, cszRunOnceCount, 0, REG_DWORD, (LPBYTE)&pmcl->dwRunCount, sizeof(pmcl->dwRunCount));
if (pmcl->pszReason) { cb = (lstrlen(pmcl->pszReason) + 1) * sizeof(TCHAR); RegSetValueEx (hKey, cszDriverList, 0, REG_SZ, (LPBYTE)pmcl->pszReason, cb); } else RegSetValueEx (hKey, cszDriverList, 0, REG_SZ, (LPBYTE)cszEmpty, 0);
RegCloseKey (hKey);
// Don't Kick mapper unless we have a window
if (hWnd) KickMapper (hWnd); } }
/*+ InitLocal
* *-=================================================================*/
STATICFN void WINAPI InitLocal ( PMCLOCAL pmcl, LPARAM lParam, BOOL bDriverAsAlias) // driver as alias mode used only for scheme init
{ HKEY hKey;
LoadString (ghInstance, IDS_DEFAULT_SCHEME_NAME, pmcl->szDefault, NUMELMS(pmcl->szDefault));
// NOTE : Comment below regarding RunOnceSchemeInit is in reference
// to an obsolete RunOnce initialization.
//
// we allow driver as alias (szFriendly) only for InitLocal when called
// from RunOnceSchemeInit. this works because in this case we have
// no UI so we dont need the friendly names for anything.
//
assert (!bDriverAsAlias || lParam == 0); LoadInstruments (&pmcl->mcm, bDriverAsAlias);
#ifdef DEBUG
if (mmdebug_OutputLevel >= 3) DumpInstruments (&pmcl->mcm); #endif
if (RegCreateKey (HKEY_CURRENT_USER, cszMidiMapRoot, &hKey) == ERROR_SUCCESS) { DWORD cb; DWORD dwType; TCHAR szSingle[MAX_ALIAS];
cb = sizeof(pmcl->szScheme); if (RegQueryValueEx (hKey, cszCurrentScheme, NULL, &dwType, (LPBYTE)pmcl->szScheme, &cb)) pmcl->szScheme[0] = 0;
pmcl->piSingle = NULL; cb = sizeof(szSingle); if (!RegQueryValueEx (hKey, cszCurrentInstrument, NULL, &dwType, (LPBYTE)szSingle, &cb)) pmcl->piSingle = FindInstrumentFromKey (&pmcl->mcm, szSingle);
cb = sizeof(pmcl->bUseScheme); if (RegQueryValueEx (hKey, cszUseScheme, NULL, &dwType, (LPBYTE)&pmcl->bUseScheme, &cb)) pmcl->bUseScheme = 0;
cb = sizeof(pmcl->bAutoScheme); if (RegQueryValueEx (hKey, cszAutoScheme, NULL, &dwType, (LPBYTE)&pmcl->bAutoScheme, &cb)) pmcl->bAutoScheme = TRUE;
cb = sizeof(pmcl->dwRunCount); if (RegQueryValueEx (hKey, cszRunOnceCount, NULL, &dwType, (LPBYTE)&pmcl->dwRunCount, &cb)) pmcl->dwRunCount = 0;
pmcl->pszReason = NULL;
RegCloseKey (hKey); }
pmcl->ppsp = (LPVOID)lParam; }
/*+ FixupHinderedIDFs
* *-=================================================================*/
VOID WINAPI FixupHinderedIDFs ( PMCLOCAL pmcl, LPTSTR pszTemp, // ptr to temp memory
UINT cchTemp) // size of temp memory
{ HKEY hkHind; // hinderedMidiList root
LPTSTR pszDriver = pszTemp; // max size is short filename
UINT cch; LPTSTR pszIDF = (LPVOID)(pszTemp + MAX_PATH); UINT cbSize; DWORD iEnum; DWORD dwType;
#ifdef DEBUG
AuxDebugEx (3, DEBUGLINE TEXT ("FixupHinderedIDFs(%08x)\r\n"), pmcl); #endif
assert (pszTemp); assert (cchTemp > MAX_PATH + MAX_PATH + 64);
// the midi key should have already been opened.
//
assert (pmcl->mcm.hkMidi);
if (RegCreateKey (HKEY_LOCAL_MACHINE, cszHinderedMidiList, &hkHind)) return;
// enumerate the known hindered driver list looking for
// drivers that need to have their IDF's set
//
for (iEnum = 0, cch = MAX_PATH, cbSize = (MAX_PATH + 64) * sizeof(TCHAR); ! RegEnumValue (hkHind, iEnum, pszDriver, &cch, NULL, &dwType, (LPBYTE)pszIDF, &cbSize); ++iEnum, cch = MAX_PATH, cbSize = (MAX_PATH + 64) * sizeof(TCHAR)) { UINT ii;
#ifdef DEBUG
AuxDebugEx (3, DEBUGLINE TEXT ("enum[%d] pszDriver='%s' pszIDF='%s'\r\n"), iEnum, pszDriver, pszIDF); #endif
// just to be careful. ignore any registry entry that
// does not have string data
//
assert (dwType == REG_SZ); if (dwType != REG_SZ) continue;
// scan through the list of drivers looking for one that is
// internal, and has the same driver name as one of our known
// list of hindered drivers. if we find one, force its
// IDF to be the given IDF
//
for (ii = 0; ii < pmcl->mcm.nInstr; ++ii) { PINSTRUM pi = pmcl->mcm.api[ii]; HKEY hkSub;
if (!pi || !pi->szKey[0] || pi->bExternal || !IsSzEqual (pi->szFriendly, pszDriver)) continue;
#ifdef DEBUG
AuxDebugEx (2, DEBUGLINE TEXT ("forcing driver '%s' to use IDF '%s'\r\n"), pi->szKey, pszIDF); #endif
if ( ! RegOpenKeyEx (pmcl->mcm.hkMidi, pi->szKey, 0, KEY_ALL_ACCESS, &hkSub)) { RegSetValueEx (hkSub, cszDefinition, 0, REG_SZ, (LPBYTE)pszIDF, cbSize); RegCloseKey (hkSub); } } }
RegCloseKey (hkHind); return; }
STDAPI_(void) HandleSynthAboutBox(HWND hWnd) { HWND hTree = GetDlgItem(hWnd, IDL_INSTRUMENTS); HTREEITEM hItem = TreeView_GetSelection(hTree); TV_ITEM ti; PINSTRUM pi;
memset(&ti, 0, sizeof(ti)); ti.mask = TVIF_PARAM; ti.hItem = hItem; TreeView_GetItem (hTree, &ti); pi = (LPVOID)ti.lParam;
if (pi) { UINT uWaveID;
if (GetWaveID(&uWaveID) != (MMRESULT)MMSYSERR_ERROR) { WAVEOUTCAPS woc;
if (waveOutGetDevCaps(uWaveID, &woc, sizeof(woc)) == MMSYSERR_NOERROR) { RolandProp(hWnd, ghInstance, woc.szPname); } } } }
/*+ MidiCplCommands
* *-=================================================================*/
BOOL WINAPI MidiCplCommands ( HWND hWnd, UINT wId, HWND hWndCtl, UINT wNotify) { PMCLOCAL pmcl = GetDlgData(hWnd);
#ifdef DEBUG
AuxDebugEx (3, DEBUGLINE TEXT ("MidiCplCommands(%08X,%X,%08X,%d)\r\n"), hWnd, wId, hWndCtl, wNotify); #endif
assert (pmcl); if (!pmcl) return FALSE;
switch (wId) { case IDB_CONFIGURE: { UINT_PTR uRet; TCHAR szOld[MAX_ALIAS];
#ifdef DEBUG
AuxDebugEx (2, DEBUGLINE TEXT ("Launching Config Dialog\r\n")); #endif
lstrcpy (szOld, pmcl->szScheme); uRet = DialogBoxParam (ghInstance, MAKEINTRESOURCE(IDD_MIDICONFIG), hWnd, MidiConfigDlgProc, (LPARAM)pmcl); if (uRet != IDOK) lstrcpy (pmcl->szScheme, szOld); else PropSheet_Changed(GetParent(hWnd), hWnd);
LoadSchemesIntoCombo (hWnd, IDC_SCHEMES, pmcl->szScheme, &pmcl->ms); } break;
case IDC_ABOUTSYNTH: { HandleSynthAboutBox(hWnd); } break;
case IDB_ADDWIZ: #ifdef DEBUG
AuxDebugEx (2, DEBUGLINE TEXT ("Launching Midi Wizard\r\n")); #endif
MidiInstrumentsWizard (hWnd, &pmcl->mcm, NULL);
LoadInstruments (&pmcl->mcm, FALSE); #ifdef DEBUG
if (mmdebug_OutputLevel >= 3) DumpInstruments (&pmcl->mcm); #endif
if (pmcl->bDlgType2) { LoadInstrumentsIntoTree (hWnd, IDL_INSTRUMENTS, IDC_INSTRUMENTS, pmcl->piSingle, pmcl); } else { LoadInstrumentsIntoCombo (hWnd, IDC_INSTRUMENTS, pmcl->piSingle, &pmcl->mcm); } MMExtPropSheetCallback(MM_EPS_BLIND_TREECHANGE, 0,0,0); break;
case IDC_SCHEMES: if (wNotify == CBN_SELCHANGE) { int ix;
ix = ComboBox_GetCurSel (hWndCtl); if (ix >= 0) ComboBox_GetLBText (hWndCtl, ix, pmcl->szScheme); PropSheet_Changed(GetParent(hWnd), hWnd); } break;
case IDC_INSTRUMENTS: if (wNotify == CBN_SELCHANGE) { int ix;
assert (!pmcl->bDlgType2);
ix = ComboBox_GetCurSel (hWndCtl); if (ix >= 0) { pmcl->piSingle = (LPVOID)ComboBox_GetItemData (hWndCtl, ix); } PropSheet_Changed(GetParent(hWnd), hWnd); } break;
case IDC_RADIO_CUSTOM: case IDC_RADIO_SINGLE: { BOOL bUseScheme = pmcl->bUseScheme; pmcl->bUseScheme = IsDlgButtonChecked (hWnd, IDC_RADIO_CUSTOM); if (bUseScheme != pmcl->bUseScheme) PropSheet_Changed(GetParent(hWnd), hWnd);
if (pmcl->bDlgType2) { HWND hWndCtl; EnableWindow(GetDlgItem (hWnd, IDL_INSTRUMENTS), !pmcl->bUseScheme); if (hWndCtl = GetDlgItem (hWnd, IDB_DETAILS)) EnableWindow(hWndCtl, !pmcl->bUseScheme); } EnableWindow(GetDlgItem (hWnd, IDC_INSTRUMENTS), !pmcl->bUseScheme); EnableWindow(GetDlgItem (hWnd, IDC_SCHEMES), pmcl->bUseScheme); EnableWindow(GetDlgItem (hWnd, IDC_SCHEMESLABEL), pmcl->bUseScheme); EnableWindow(GetDlgItem (hWnd, IDB_CONFIGURE), pmcl->bUseScheme); } break;
#if 1 //def DETAILS_FROM_MAIN_CPL
case IDB_DETAILS: assert (pmcl->bDlgType2); if (pmcl->bDlgType2) { TCHAR szSingle[MAX_PATH]; int ix;
ix = ComboBox_GetCurSel (hWndCtl); if (ix >= 0) pmcl->piSingle = (LPVOID)ComboBox_GetItemData (hWndCtl, ix);
szSingle[0] = 0; if (pmcl->piSingle) lstrcpy (szSingle, pmcl->piSingle->szKey);
if (ShowDetails (hWnd, pmcl)) { LoadInstruments (&pmcl->mcm, FALSE); pmcl->piSingle = FindInstrumentFromKey (&pmcl->mcm, szSingle);
LoadInstrumentsIntoTree (hWnd, IDL_INSTRUMENTS, IDC_INSTRUMENTS, pmcl->piSingle, pmcl); } } break; #endif
case ID_INIT: LoadInstruments (&pmcl->mcm, FALSE); #ifdef DEBUG
if (mmdebug_OutputLevel >= 3) DumpInstruments (&pmcl->mcm); #endif
if (pmcl->bDlgType2) { LoadInstrumentsIntoTree (hWnd, IDL_INSTRUMENTS, IDC_INSTRUMENTS, pmcl->piSingle, pmcl); } else { LoadInstrumentsIntoCombo (hWnd, IDC_INSTRUMENTS, pmcl->piSingle, &pmcl->mcm); } break;
case ID_APPLY: pmcl->bUseScheme = IsDlgButtonChecked (hWnd, IDC_RADIO_CUSTOM); SaveLocal (pmcl, TRUE, hWnd); break;
case IDOK: pmcl->bUseScheme = IsDlgButtonChecked (hWnd, IDC_RADIO_CUSTOM); break;
case IDCANCEL: break;
//
//case ID_INIT:
// break;
}
return FALSE; }
/*+ HandleInstrumentsSelChange
* *-=================================================================*/
STATICFN BOOL WINAPI HandleInstrumentsSelChange ( HWND hWnd, LPNMHDR lpnm) { PMCLOCAL pmcl = GetDlgData(hWnd); LPNM_TREEVIEW pntv = (LPVOID)lpnm; LPTV_ITEM pti = &pntv->itemNew; TV_ITEM ti; PINSTRUM pi; TCHAR szSingle[MAX_ALIAS]; BOOL bChange = FALSE;
if (!pmcl || pmcl->bIgnoreSelChange) return FALSE;
// setup ti to get text & # of children
// from the IDF filename entry.
//
ti.mask = TVIF_TEXT | TVIF_PARAM; ti.pszText = szSingle; ti.cchTextMax = NUMELMS(szSingle); ti.hItem = pti->hItem;
TreeView_GetItem (lpnm->hwndFrom, &ti); pi = (LPVOID)ti.lParam; // FindInstrument (&pmcl->mcm, szSingle);
#ifdef DEBUG
AuxDebugEx (2, DEBUGLINE TEXT ("HandInstSelChg(%X,...) %X %X Init=%d\r\n"), hWnd, pmcl->piSingle, pi, !pmcl->bPastInit); #endif
SetDlgItemText (hWnd, IDC_INSTRUMENTS, szSingle); if (pmcl->piSingle != pi) { EnableWindow(GetDlgItem(hWnd,IDC_ABOUTSYNTH),pi->fGSSynth); bChange = TRUE; pmcl->piSingle = pi; }
return (bChange && pmcl->bPastInit); }
/*+ MidiCplDlgProc
* *-=================================================================*/
const static DWORD aKeyWordIds[] = { // Context Help IDs
IDC_GROUPBOX, IDH_COMM_GROUPBOX, IDC_RADIO_SINGLE, IDH_MIDI_SINGLE_INST_BUTTON, IDC_INSTRUMENTS, IDH_MIDI_SINGLE_INST, IDL_INSTRUMENTS, IDH_MIDI_SINGLE_INST_LIST, IDC_RADIO_CUSTOM, IDH_MIDI_CUST_CONFIG, IDC_SCHEMESLABEL, IDH_MIDI_SCHEME, IDC_SCHEMES, IDH_MIDI_SCHEME, IDC_ABOUTSYNTH, IDH_ABOUT, //IDB_DETAILS, IDH_MIDI_SINGLE_INST_PROP,
IDB_CONFIGURE, IDH_MIDI_CONFIG_SCHEME, IDB_ADDWIZ, IDH_MIDI_ADD_NEW,
0, 0 };
INT_PTR CALLBACK MidiCplDlgProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { #ifdef DEBUG
AuxDebugEx (5, DEBUGLINE TEXT ("MidiCplDlgProc(%08X,%X,%08X,%08X)\r\n"), hWnd, uMsg, wParam, lParam); #endif
switch (uMsg) { case WM_COMMAND: HANDLE_WM_COMMAND (hWnd, wParam, lParam, MidiCplCommands); break; case WM_NOTIFY: { LPNMHDR lpnm = (LPVOID)lParam; if (lpnm->idFrom == (UINT)IDL_INSTRUMENTS && lpnm->code == TVN_SELCHANGED) { if (HandleInstrumentsSelChange (hWnd, lpnm)) PropSheet_Changed(GetParent(hWnd), hWnd); } else ForwardBillNotify(hWnd, (NMHDR FAR *)lParam); } break; case WM_INITDIALOG: { PMCLOCAL pmcl; pmcl = (LPVOID)LocalAlloc(LPTR, sizeof(*pmcl)); SetDlgData (hWnd, pmcl); if (!pmcl) { break; } pmcl->bPastInit = FALSE;
InitLocal (pmcl, lParam, FALSE); EnableWindow (GetDlgItem (hWnd, IDB_ADDWIZ), pmcl->mcm.bHasExternal & AccessServiceController()); EnableWindow(GetDlgItem(hWnd, IDC_ABOUTSYNTH), FALSE);
if (GetDlgItem(hWnd, IDL_INSTRUMENTS)) { pmcl->bDlgType2 = TRUE; LoadInstrumentsIntoTree (hWnd, IDL_INSTRUMENTS, IDC_INSTRUMENTS, pmcl->piSingle, pmcl); } else { pmcl->bDlgType2 = FALSE; LoadInstrumentsIntoCombo (hWnd, IDC_INSTRUMENTS, pmcl->piSingle, &pmcl->mcm); }
CheckRadioButton (hWnd, IDC_RADIO_SINGLE, IDC_RADIO_CUSTOM, pmcl->bUseScheme ? IDC_RADIO_CUSTOM : IDC_RADIO_SINGLE);
LoadSchemesIntoCombo (hWnd, IDC_SCHEMES, pmcl->szScheme, &pmcl->ms);
if (pmcl->mcm.nInstr > 1) { if (pmcl->bDlgType2) { HWND hWndCtl;
EnableWindow(GetDlgItem (hWnd, IDL_INSTRUMENTS), !pmcl->bUseScheme); if (hWndCtl = GetDlgItem (hWnd, IDB_DETAILS)) EnableWindow (hWndCtl, !pmcl->bUseScheme); } EnableWindow(GetDlgItem (hWnd, IDC_INSTRUMENTS), !pmcl->bUseScheme); EnableWindow(GetDlgItem (hWnd, IDC_SCHEMES), pmcl->bUseScheme); EnableWindow(GetDlgItem (hWnd, IDC_SCHEMESLABEL), pmcl->bUseScheme); EnableWindow(GetDlgItem (hWnd, IDB_CONFIGURE), pmcl->bUseScheme); } else { UINT aid[] = { IDL_INSTRUMENTS, IDC_INSTRUMENTS, IDC_SCHEMES, IDC_RADIO_SINGLE, IDC_RADIO_CUSTOM, IDB_CONFIGURE, IDB_DETAILS, IDB_ADDWIZ }; UINT ii;
for (ii = 0; ii < NUMELMS(aid); ++ii) { HWND hWndCtl = GetDlgItem (hWnd, aid[ii]); if (hWndCtl) EnableWindow (hWndCtl, FALSE); } } pmcl->bPastInit = TRUE; break; }
case WM_DESTROY: { PMCLOCAL pmcl = GetDlgData(hWnd);
#ifdef DEBUG
AuxDebugEx (5, DEBUGLINE TEXT ("MidiCPL - begin WM_DESTROY\r\n")); #endif
if (pmcl) { if (pmcl->mcm.hkMidi) RegCloseKey (pmcl->mcm.hkMidi); if (pmcl->ms.hkSchemes) RegCloseKey (pmcl->ms.hkSchemes);
FreeInstruments (&pmcl->mcm); SetDlgData (hWnd, 0); LocalFree ((HLOCAL)(UINT_PTR)(DWORD_PTR)pmcl); } #ifdef DEBUG
AuxDebugEx (5, DEBUGLINE TEXT ("MidiCPL - done with WM_DESTROY\r\n")); #endif
break; }
//case WM_DROPFILES:
// break;
case WM_CONTEXTMENU: WinHelp ((HWND) wParam, NULL, HELP_CONTEXTMENU, (UINT_PTR) (LPTSTR) aKeyWordIds); return TRUE;
case WM_HELP: { LPHELPINFO lphi = (LPVOID) lParam; WinHelp (lphi->hItemHandle, NULL, HELP_WM_HELP, (UINT_PTR) (LPTSTR) aKeyWordIds); return TRUE; }
#if 0
default: if (uMsg == wHelpMessage) { WinHelp (hWnd, gszWindowsHlp, HELP_CONTEXT, ID_SND_HELP); return TRUE; } break; #endif
}
return FALSE; }
/*+ MidiClassCommands
* *-=================================================================*/
BOOL WINAPI MidiClassCommands ( HWND hWnd, UINT wId, HWND hWndCtl, UINT wNotify) { PMCLOCAL pmcl = GetDlgData(hWnd);
if (!pmcl) return FALSE;
#ifdef DEBUG
AuxDebugEx (5, DEBUGLINE TEXT ("MidiClassCommands(%08X,%d,%08X,%d)\r\n"), hWnd, wId, hWndCtl, wNotify); #endif
switch (wId) { case IDB_ADDWIZ: MidiInstrumentsWizard (hWnd, &pmcl->mcm, NULL); LoadInstruments (&pmcl->mcm, FALSE); LoadInstrumentsIntoTree (hWnd, IDL_INSTRUMENTS, 0, NULL, pmcl);
// flog the parent property sheet to let it know that we have
// made changes to the advanced midi page structures
//
{ PMPSARGS pmpsa = (LPVOID)pmcl->ppsp->lParam; if (pmpsa && pmpsa->lpfnMMExtPSCallback) pmpsa->lpfnMMExtPSCallback (MM_EPS_TREECHANGE, 0, 0, pmpsa->lParam); } break;
//case ID_APPLY:
// return TRUE;
//
//case IDCANCEL:
// break;
}
return FALSE; }
/*+ MidiClassDlgProc
* *-=================================================================*/
const static DWORD aMidiClassHelpIds[] = { // Context Help IDs
IDB_ADDWIZ, IDH_MIDI_ADD_NEW, IDC_CLASS_ICON, NO_HELP, IDC_CLASS_LABEL, NO_HELP, IDL_INSTRUMENTS, IDH_MMCPL_DEVPROP_INST_LIST,
0, 0 };
INT_PTR CALLBACK MidiClassDlgProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_COMMAND: HANDLE_WM_COMMAND (hWnd, wParam, lParam, MidiClassCommands); break; case WM_NOTIFY: ForwardBillNotify (hWnd, (NMHDR FAR *)lParam); break; case WM_INITDIALOG: { PMCLOCAL pmcl; TCHAR sz[MAX_ALIAS]; pmcl = (LPVOID)LocalAlloc(LPTR, sizeof(*pmcl)); SetDlgData (hWnd, pmcl); if (!pmcl) { break; }
InitLocal (pmcl, lParam, FALSE);
#ifdef DEBUG
AuxDebugEx (5, DEBUGLINE TEXT ("midiClass.WM_INITDLG ppsp=%08X\r\n"), pmcl->ppsp); #endif
//AuxDebugDump (8, pmcl->ppsp, sizeof(*pmcl->ppsp));
LoadString (ghInstance, IDS_MIDI_DEV_AND_INST, sz, NUMELMS(sz)); SetDlgItemText (hWnd, IDC_CLASS_LABEL, sz); Static_SetIcon(GetDlgItem (hWnd, IDC_CLASS_ICON), LoadIcon (ghInstance, MAKEINTRESOURCE(IDI_INSTRUMENT)));
LoadInstrumentsIntoTree (hWnd, IDL_INSTRUMENTS, 0, NULL, pmcl); EnableWindow (GetDlgItem (hWnd, IDB_ADDWIZ), pmcl->mcm.bHasExternal & AccessServiceController()); break; }
case WM_DESTROY: { PMCLOCAL pmcl = GetDlgData(hWnd);
if (pmcl) { if (pmcl->mcm.hkMidi) RegCloseKey (pmcl->mcm.hkMidi); if (pmcl->ms.hkSchemes) RegCloseKey (pmcl->ms.hkSchemes);
FreeInstruments (&pmcl->mcm); LocalFree ((HLOCAL)(UINT_PTR)(DWORD_PTR)pmcl); } break; } case WM_CONTEXTMENU: WinHelp ((HWND) wParam, NULL, HELP_CONTEXTMENU, (UINT_PTR) (LPTSTR) aMidiClassHelpIds); return TRUE;
case WM_HELP: { LPHELPINFO lphi = (LPVOID) lParam; WinHelp (lphi->hItemHandle, NULL, HELP_WM_HELP, (UINT_PTR) (LPTSTR) aMidiClassHelpIds); return TRUE; } }
return FALSE; }
/*+ PropPageCallback
* * add a property page * *-=================================================================*/
UINT CALLBACK PropPageCallback ( HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp) { if (uMsg == PSPCB_RELEASE) { //LocalFree ((HLOCAL)(UINT)(DWORD)ppsp->pszTitle);
LocalFree ((HLOCAL)ppsp->lParam); } return 1; }
/*+ AddPropPage
* * add a property page * *-=================================================================*/
STATICFN HPROPSHEETPAGE WINAPI AddPropPage ( LPCTSTR pszTitle, LPFNMMEXTPROPSHEETCALLBACK lpfnAddPropSheetPage, DLGPROC fnDlgProc, UINT idTemplate, LPARAM lParam) { PROPSHEETPAGE psp; PMPSARGS pmpsa; UINT cbSize;
cbSize = sizeof(MPSARGS) + lstrlen (pszTitle) * sizeof(TCHAR); if (pmpsa = (PVOID) LocalAlloc (LPTR, cbSize)) { HPROPSHEETPAGE hpsp;
lstrcpy (pmpsa->szTitle, pszTitle); pmpsa->lpfnMMExtPSCallback = lpfnAddPropSheetPage; pmpsa->lParam = lParam;
psp.dwSize = sizeof(psp); psp.dwFlags = PSP_USETITLE | PSP_USECALLBACK; psp.hInstance = ghInstance; psp.pszTemplate = MAKEINTRESOURCE(idTemplate); psp.pszIcon = NULL; psp.pszTitle = pmpsa->szTitle; psp.pfnDlgProc = fnDlgProc; psp.lParam = (LPARAM)pmpsa; psp.pfnCallback = PropPageCallback; psp.pcRefParent = NULL;
if (hpsp = CreatePropertySheetPage (&psp)) { if ( ! lpfnAddPropSheetPage || lpfnAddPropSheetPage (MM_EPS_ADDSHEET, (DWORD_PTR)hpsp, 0, lParam)) {
return hpsp; } DestroyPropertySheetPage (hpsp); LocalFree ((HLOCAL) pmpsa); } } return NULL; }
/*+ AddInstrumentPages
* * add a midi page to a property sheet. Invoked from Advanced tab * of Muitimedia control panel when class midi is selected from * the list. * *-=================================================================*/
BOOL CALLBACK AddInstrumentPages ( LPCTSTR pszTitle, LPFNMMEXTPROPSHEETCALLBACK lpfnAddPropSheetPage, LPARAM lParam) { HPROPSHEETPAGE hpsp; TCHAR sz[MAX_ALIAS];
#ifdef DEBUG
AuxDebugEx (3, DEBUGLINE TEXT ("AddInstrumentPages(%08X,%08X,%08X)\r\n"), pszTitle, lpfnAddPropSheetPage, lParam); #endif
LoadString (ghInstance, IDS_GENERAL, sz, NUMELMS(sz)); hpsp = AddPropPage (sz, lpfnAddPropSheetPage, MidiInstrumentDlgProc, IDD_INSTRUMENT_GEN, lParam); if ( ! hpsp) return FALSE;
LoadString (ghInstance, IDS_MIDIDETAILS, sz, NUMELMS(sz)); hpsp = AddPropPage (sz, lpfnAddPropSheetPage, MidiInstrumentDlgProc, IDD_INSTRUMENT_DETAIL, lParam);
return (hpsp != NULL); }
/*+ AddDevicePages
* * add a midi page to a property sheet. Invoked from Advanced tab * of Multimedia control panel when class midi is selected from * the list. * *-=================================================================*/
BOOL CALLBACK AddDevicePages ( LPCTSTR pszTitle, LPFNMMEXTPROPSHEETCALLBACK lpfnAddPropSheetPage, LPARAM lParam) { HPROPSHEETPAGE hpsp; TCHAR sz[MAX_ALIAS];
#ifdef DEBUG
AuxDebugEx (3, DEBUGLINE TEXT ("AddInstrumentPages(%08X,%08X,%08X)\r\n"), pszTitle, lpfnAddPropSheetPage, lParam); #endif
LoadString (ghInstance, IDS_MIDIDETAILS, sz, NUMELMS(sz)); hpsp = AddPropPage (sz, lpfnAddPropSheetPage, MidiInstrumentDlgProc, IDD_DEVICE_DETAIL, lParam);
return (hpsp != NULL); }
/*+ ShowDetails
* * Show Instrument or device details sheet and allow edits * return TRUE if changes were made * *-=================================================================*/
struct _show_details_args { PMCLOCAL pmcl; BOOL bChanged; PROPSHEETHEADER psh; HPROPSHEETPAGE hpsp[2]; };
BOOL CALLBACK fnPropCallback ( DWORD dwFunc, DWORD_PTR dwParam1, DWORD_PTR dwParam2, DWORD_PTR dwInstance) { struct _show_details_args * psda = (LPVOID)dwInstance;
assert (psda); if (!psda) return FALSE;
switch (dwFunc) { case MM_EPS_GETNODEDESC: *(LPTSTR)dwParam1 = 0; if (psda->pmcl->piSingle) lstrcpyn ((LPTSTR)dwParam1, psda->pmcl->piSingle->szFriendly, (int)(dwParam2/sizeof(TCHAR))); break;
case MM_EPS_GETNODEID: *(LPTSTR)dwParam1 = 0; if (psda->pmcl->piSingle) { lstrcpy ((LPTSTR)dwParam1, cszMidiSlash); lstrcat ((LPTSTR)dwParam1, psda->pmcl->piSingle->szKey); } break;
case MM_EPS_ADDSHEET: if (psda->psh.nPages >= NUMELMS(psda->hpsp)-1) return FALSE; psda->psh.phpage[psda->psh.nPages++] = (HPROPSHEETPAGE)dwParam1; break;
case MM_EPS_TREECHANGE: psda->bChanged = TRUE; break;
default: return FALSE; }
return TRUE; }
BOOL WINAPI ShowDetails ( HWND hWnd, PMCLOCAL pmcl) { struct _show_details_args sda; TCHAR szTitle[MAX_ALIAS]; HPROPSHEETPAGE hpsp; UINT idDlg;
idDlg = IDD_DEVICE_DETAIL; if (pmcl->piSingle && pmcl->piSingle->piParent) idDlg = IDD_INSTRUMENT_DETAIL;
ZeroMemory (&sda, sizeof(sda)); sda.pmcl = pmcl; sda.psh.dwSize = sizeof(sda.psh); sda.psh.dwFlags = PSH_PROPTITLE; sda.psh.hwndParent = hWnd; sda.psh.hInstance = ghInstance; sda.psh.pszCaption = MAKEINTRESOURCE (IDS_MMPROP); sda.psh.nPages = 0; sda.psh.nStartPage = 0; sda.psh.phpage = sda.hpsp;
LoadString (ghInstance, IDS_MIDIDETAILS, szTitle, NUMELMS(szTitle)); hpsp = AddPropPage (szTitle, fnPropCallback, MidiInstrumentDlgProc, idDlg, (LPARAM)&sda); if (hpsp) sda.psh.nPages = 1;
PropertySheet (&sda.psh); return sda.bChanged; }
/*+ AddMidiPages
* * add a midi page to a property sheet. Invoked from Advanced tab * of Muitimedia control panel when class midi is selected from * the list. * *-=================================================================*/
BOOL CALLBACK AddMidiPages ( LPCTSTR pszTitle, LPFNMMEXTPROPSHEETCALLBACK lpfnAddPropSheetPage, LPARAM lParam) { HPROPSHEETPAGE hpsp; TCHAR sz[MAX_ALIAS];
LoadString (ghInstance, IDS_GENERAL, sz, NUMELMS(sz)); hpsp = AddPropPage (sz, lpfnAddPropSheetPage, MidiClassDlgProc, IDD_MIDICLASS_GEN, lParam); return (hpsp != NULL); }
/*+ AddSimpleMidiPages
* * add a midi page to a MM control panel. * *-=================================================================*/
BOOL CALLBACK AddSimpleMidiPages ( LPTSTR pszTitle, LPFNMMEXTPROPSHEETCALLBACK lpfnAddPropSheetPage, LPARAM lParam) { HPROPSHEETPAGE hpsp; //static CONST TCHAR sz[13] = TEXT (" ");
//UINT cch = lstrlen (pszTitle);
DebugSetOutputLevel (GetProfileInt(TEXT ("Debug"), TEXT ("midiprop"), 0));
// pad my tab to 12 spaces so it looks nice with the
// other simple tabls (as per request of vijr)
//
//if (cch < NUMELMS(sz)-2)
//{
// lstrcpy (sz + NUMELMS(sz)/2 - cch/2, pszTitle);
// pszTitle = sz;
// pszTitle[lstrlen(pszTitle)] = TEXT (' ');
//}
hpsp = AddPropPage (pszTitle, lpfnAddPropSheetPage, MidiCplDlgProc, IDD_CPL_MIDI2, lParam); return (hpsp != NULL); }
/*
*************************************************************** * BOOL PASCAL LoadDesc(LPCTSTR pszFile, LPCTSTR pszDesc) * This function gets the description string from the executable * file specified. We first try to get the string from the version info * If that fails then we try to get the string from the exehdr. * If that fails we return a NULL string. * Return TRUE on success, else FALSE. *************************************************************** */
BOOL PASCAL LoadDesc(LPCTSTR pszFile, LPTSTR pszDesc) { LPTSTR psz; static TCHAR szProfile[MAXSTR]; UINT cchSize; HANDLE hFind; WIN32_FIND_DATA wfd; DPF (TEXT ("LoadDesc: %s\r\n"), pszFile);
// Make sure file exists
hFind = FindFirstFile (pszFile, &wfd); if (hFind == INVALID_HANDLE_VALUE) return(FALSE); FindClose (hFind);
// Get User Friendly name from Version Info
if (GetVerDesc (wfd.cFileName, pszDesc)) return TRUE;
//
// As a last resort, look at the description in the Executable Header
//
cchSize = sizeof(szProfile)/sizeof(TCHAR); if ((! GetExeDesc (wfd.cFileName, szProfile, cchSize)) || (lstrlen (szProfile) < 3)) { *pszDesc = 0; return(FALSE); } else { // There is EXEHDR information Parse according to driver spec
psz = szProfile; while (*psz && *psz++ != TEXT (':')) { ; // skip type information
} if (!(*psz)) psz = szProfile; lstrcpy (pszDesc, psz); return(TRUE); } }
/* BOOL FAR PASCAL GetExeDesc(szFile, szBuff, cchBuff)
* * Function will return the an executable's description * * szFile - Path Name a new exe * pszBuf - Buffer to place returned info * cchBuf - Size of buffer (in characters * * returns: TRUE if successful, FALSE otherwise. */
STATIC BOOL FAR PASCAL GetExeDesc( LPTSTR szFile, LPTSTR pszBuff, int cchBuff) { DWORD dwSig; WORD wSig; HANDLE hFile; DWORD offset; BYTE cbLen; DWORD cbRead; IMAGE_DOS_HEADER doshdr; // Original EXE Header
// Open File
hFile = CreateFile (szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return FALSE;
// Get Original Dos Header
if ((! ReadFile (hFile, (LPVOID)&doshdr, sizeof(doshdr), &cbRead, NULL)) || (cbRead != sizeof(doshdr)) || // Read Error
(doshdr.e_magic != IMAGE_DOS_SIGNATURE)) // Invalid DOS Header
{ goto error; /* Abort("Not an exe",h); */ }
// Seek to new header
offset = doshdr.e_lfanew; SetFilePointer (hFile, offset, NULL, FILE_BEGIN); // Read in signature
if ((! ReadFile (hFile, (LPVOID)&dwSig, sizeof(dwSig), &cbRead, NULL)) || (cbRead != sizeof(dwSig))) // Read Error
{ goto error; /* Abort("Not an exe",h); */ } wSig = LOWORD (dwSig);
if (dwSig == IMAGE_NT_SIGNATURE) { DPF (TEXT ("GetExeDesc: NT Portable Executable Format\r\n"));
// NOTE - The NT Portatble Executable Format does not store
// the executable's user friendly name.
goto error; } else if (wSig == IMAGE_OS2_SIGNATURE) { IMAGE_OS2_HEADER winhdr; // New Windows/OS2 header
TCHAR szInfo[256];
DPF (TEXT ("GetExeDesc: Windows or OS2 Executable Format\r\n"));
// Seek to Windows Header
offset = doshdr.e_lfanew; SetFilePointer (hFile, offset, NULL, FILE_BEGIN);
// Read Windows Header
if ((! ReadFile (hFile, (LPVOID)&winhdr, sizeof(winhdr), &cbRead, NULL)) || (cbRead != sizeof(winhdr)) || // Read Error
(winhdr.ne_magic != IMAGE_OS2_SIGNATURE)) // Invalid Windows Header
{ goto error; }
// Seek to module name which is the first entry in the non-resident name table
offset = winhdr.ne_nrestab; SetFilePointer (hFile, offset, NULL, FILE_BEGIN);
// Get Size of Module Name
if ((! ReadFile (hFile, (LPVOID)&cbLen, sizeof(BYTE), &cbRead, NULL)) || (cbRead != sizeof(BYTE))) { goto error; }
cchBuff--; // leave room for a \0
if (cbLen > (BYTE)cchBuff) cbLen = (BYTE)cchBuff;
// Read Module Name
if ((! ReadFile (hFile, (LPVOID)szInfo, cbLen, &cbRead, NULL)) || (cbRead != cbLen)) { goto error; } szInfo[cbLen] = 0;
// Copy to Buffer
lstrcpy (pszBuff, szInfo); } else if (wSig == IMAGE_VXD_SIGNATURE) { IMAGE_VXD_HEADER vxdhdr; // New Windows/OS2 VXD Header
TCHAR szInfo[256];
DPF (TEXT ("GetExeDesc: Windows or OS2 VXD Executable Format\r\n"));
// Seek to VXD Header
offset = doshdr.e_lfanew; SetFilePointer (hFile, offset, NULL, FILE_BEGIN);
// Read VXD Header
if ((! ReadFile (hFile, (LPVOID)&vxdhdr, sizeof(vxdhdr), &cbRead, NULL)) || (cbRead != sizeof(vxdhdr)) || // Read Error
(vxdhdr.e32_magic != IMAGE_VXD_SIGNATURE)) // Invalid VXD Header
{ goto error; }
// Seek to module name which is the first entry in the non-resident name table
offset = vxdhdr.e32_nrestab; SetFilePointer (hFile, offset, NULL, FILE_BEGIN);
// Get Size of Module Name
if ((! ReadFile (hFile, (LPVOID)&cbLen, sizeof(BYTE), &cbRead, NULL)) || (cbRead != sizeof(BYTE))) { goto error; }
cchBuff--; // leave room for a \0
if (cbLen > (BYTE)cchBuff) cbLen = (BYTE)cchBuff;
// Read Module Name
if ((! ReadFile (hFile, (LPVOID)szInfo, cbLen, &cbRead, NULL)) || (cbRead != cbLen)) { goto error; } szInfo[cbLen] = 0;
// Copy to Buffer
lstrcpy (pszBuff, szInfo); } else { DPF (TEXT ("GetExeDesc: Unknown Executable\r\n")); goto error; /* Abort("Not an exe",h); */ }
CloseHandle (hFile); return TRUE;
error: CloseHandle (hFile); return FALSE; }
/*
*************************************************************** * STATIC INT_PTR GetVerDesc * Loads the version DLL and uses it to get Version Description string * from the specified file. *************************************************************** */
STATIC INT_PTR PASCAL GetVerDesc (LPCTSTR pstrFile, LPTSTR pstrDesc) { DWORD_PTR dwVerInfoSize; DWORD dwVerHnd; INT_PTR bRetCode;
bRetCode = FALSE;
DPF( TEXT ("Getting VERSION string for %s \r\n"), pstrFile);
dwVerInfoSize = GetFileVersionInfoSize (pstrFile, &dwVerHnd);
if (dwVerInfoSize) { LPBYTE lpVffInfo; // Pointer to block to hold info
// Get a block big enough to hold version info
if (lpVffInfo = (LPBYTE) GlobalAllocPtr(GMEM_MOVEABLE, dwVerInfoSize)) {
// Get the File Version first
if (GetFileVersionInfo (pstrFile, 0L, dwVerInfoSize, lpVffInfo)) { static SZCODE cszFileDescr[] = TEXT ("\\StringFileInfo\\040904E4\\FileDescription"); TCHAR szBuf[MAX_PATH]; LPTSTR lpVersion; WORD wVersionLen;
// Now try to get the FileDescription
// First try this for the "Translation" entry, and then
// try the American english translation.
// Keep track of the string length for easy updating.
// 040904E4 represents the language ID and the four
// least significant digits represent the codepage for
// which the data is formatted. The language ID is
// composed of two parts: the low ten bits represent
// the major language and the high six bits represent
// the sub language.
lstrcpy(szBuf, cszFileDescr); wVersionLen = 0; lpVersion = NULL;
// Look for the corresponding string.
bRetCode = VerQueryValue((LPVOID)lpVffInfo, (LPTSTR)szBuf, (void FAR* FAR*)&lpVersion, (UINT FAR *) &wVersionLen);
if (bRetCode && wVersionLen > 2 && lpVersion) { lstrcpy (pstrDesc, lpVersion); } else bRetCode = FALSE;
// Let go of the memory
GlobalFreePtr(lpVffInfo); } } } else bRetCode = FALSE; return bRetCode; }
LONG SHRegDeleteKey(HKEY hKey, LPCTSTR lpSubKey) { LONG lResult; HKEY hkSubKey; DWORD dwIndex; TCHAR szSubKeyName[MAX_PATH + 1]; DWORD cchSubKeyName = ARRAYSIZE(szSubKeyName); TCHAR szClass[MAX_PATH]; DWORD cchClass = ARRAYSIZE(szClass); DWORD dwDummy1, dwDummy2, dwDummy3, dwDummy4, dwDummy5, dwDummy6; FILETIME ft;
// Open the subkey so we can enumerate any children
lResult = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_ALL_ACCESS, &hkSubKey); if (ERROR_SUCCESS == lResult) { // I can't just call RegEnumKey with an ever-increasing index, because
// I'm deleting the subkeys as I go, which alters the indices of the
// remaining subkeys in an implementation-dependent way. In order to
// be safe, I have to count backwards while deleting the subkeys.
// Find out how many subkeys there are
lResult = RegQueryInfoKey(hkSubKey, szClass, &cchClass, NULL, &dwIndex, // The # of subkeys -- all we need
&dwDummy1, &dwDummy2, &dwDummy3, &dwDummy4, &dwDummy5, &dwDummy6, &ft);
if (ERROR_SUCCESS == lResult) { // dwIndex is now the count of subkeys, but it needs to be
// zero-based for RegEnumKey, so I'll pre-decrement, rather
// than post-decrement.
while (ERROR_SUCCESS == RegEnumKey(hkSubKey, --dwIndex, szSubKeyName, cchSubKeyName)) { SHRegDeleteKey(hkSubKey, szSubKeyName); } }
RegCloseKey(hkSubKey);
lResult = RegDeleteKey(hKey, lpSubKey); } return lResult; } // End SHRegDeleteKey
/* DeviceIDFromDriverName
* * Query MMSYSTEM to find the given device. Return its base device ID. * Return -1 if we cannot find the driver */ static UINT DeviceIDFromDriverName( PTSTR pstrDriverName) { UINT idxDev; UINT cPorts; DWORD cPort; PTSTR pstrDriver; MMRESULT mmr;
if (NULL == (pstrDriver = LocalAlloc(LPTR, MAX_ALIAS*sizeof(TCHAR)))) { AuxDebugEx(3, DEBUGLINE TEXT("DN->ID: LocalAlloc() failed.\r\n")); return (UINT)-1; }
// Walk through the base device ID of each driver. Use MMSYSTEM's
// driver query messages to find out how many ports & the driver name
//
cPorts = midiOutGetNumDevs(); for (idxDev = 0; idxDev < cPorts; idxDev++) { if (MMSYSERR_NOERROR != (mmr = midiOutMessage(HMIDIOUT_INDEX(idxDev), DRV_QUERYNUMPORTS, (DWORD_PTR)(LPDWORD)&cPort, 0))) { // Something is wrong with this driver. Skip it
//
AuxDebugEx(3, DEBUGLINE TEXT("DN->ID: DRV_QUERYNUMPORTS(%u)->%u\r\n"), (UINT)idxDev, (UINT)mmr); continue; }
if (MMSYSERR_NOERROR != (mmr = midiOutMessage(HMIDIOUT_INDEX(idxDev), DRV_QUERYDRVENTRY, (DWORD_PTR)(LPTSTR)pstrDriver, MAX_ALIAS))) { AuxDebugEx(3, DEBUGLINE TEXT("DN->ID: DRV_QUERYDRVENTRY(%u)->%u\r\n"), (UINT)idxDev, (UINT)mmr); continue; }
if (!_tcscmp(pstrDriver, pstrDriverName)) break; }
if (idxDev >= cPorts) { AuxDebugEx(3, DEBUGLINE TEXT("DN->ID: No match for [%s]\r\n"), (LPTSTR)pstrDriverName); idxDev = (UINT)-1; } else AuxDebugEx(3, DEBUGLINE TEXT("DN->ID: [%s] at %d\r\n"), (LPTSTR)pstrDriverName, (int)idxDev);
LocalFree(pstrDriver); return (int)idxDev; }
|