mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1079 lines
40 KiB
1079 lines
40 KiB
/*
|
|
* SETUP.C
|
|
*
|
|
* Copyright (C) 1990 Microsoft Corporation.
|
|
*
|
|
* Edit setups dialog box and support functions.
|
|
*/
|
|
/* Revision history:
|
|
March 92 Ported to 16/32 common code by Laurie Griffiths (LaurieGr)
|
|
*/
|
|
|
|
#include "preclude.h"
|
|
#include <windows.h>
|
|
#include <string.h>
|
|
#include <mmsystem.h>
|
|
#include <port1632.h>
|
|
#include "hack.h"
|
|
#include "midimap.h"
|
|
#include "midi.h"
|
|
#include <cphelp.h>
|
|
#include "extern.h"
|
|
#include "stdio.h"
|
|
#include "stdarg.h"
|
|
|
|
#if defined(WIN32)
|
|
#define _based(x)
|
|
#endif //WIN32
|
|
|
|
BOOL FAR PASCAL _loadds FSetupEnumPortsFunc(LPSTR, LPSTR, UINT, HWND, LPSTR);
|
|
|
|
#define PAL_SHOW 0 // show active line
|
|
#define PAL_HIDE 1 // hide active line
|
|
|
|
#define PSF_REDRAW 0x0001 // redraw where line used to be
|
|
#define PSF_SHOWIFHIDDEN 0x0002 // show line if hidden
|
|
|
|
#define BTN3S_UNCHECK 0 // uncheck a 3-state button
|
|
#define BTN3S_CHECK 1 // check a 3-state button
|
|
#define BTN3S_GRAY 2 // gray a 3-state button
|
|
|
|
#define DEF_SETUP_ROWS 16 // number of default setup rows
|
|
|
|
static HGLOBAL hSetup; // Setup handle
|
|
static HWND hPortList, // invalid port list box ctrl handle
|
|
hPortCombo, // port combo-box ctrl handle
|
|
hPatchCombo; // patch combo-box ctrl handle
|
|
static UINT nPorts; // number of ports available
|
|
static int nPatches, // number of user-defined patchmaps
|
|
iOldPos, // old position of active edit line
|
|
xArrowOffset; // arrow control positional offset
|
|
static SZCODE aszNull[] = "";
|
|
static SZCODE aszSetupNumFormat[] = "%3d";
|
|
|
|
#if DBG
|
|
void FAR cdecl dprintf(LPSTR szFormat, ...)
|
|
{
|
|
|
|
char ach[128];
|
|
va_list va;
|
|
int s,d;
|
|
|
|
va_start(va, szFormat);
|
|
s = vsprintf (ach, szFormat, va);
|
|
va_end(va);
|
|
#if 0
|
|
lstrcat(ach,"\n");
|
|
s++;
|
|
#endif
|
|
for (d=sizeof(ach)-1; s>=0; s--)
|
|
{
|
|
if ((ach[d--] = ach[s]) == '\n')
|
|
ach[d--] = '\r';
|
|
}
|
|
|
|
OutputDebugString("MIDI: ");
|
|
OutputDebugString(ach+d+1);
|
|
}
|
|
#else
|
|
#define dprintf if (0) ((int (*)(char *, ...)) 0)
|
|
#endif //DBG
|
|
|
|
static BOOL NEAR PASCAL FHasInvalidPort(
|
|
void)
|
|
{
|
|
SETUP FAR* lpSetup;
|
|
WORD wNumDevs;
|
|
int i;
|
|
|
|
wNumDevs = (WORD)midiOutGetNumDevs();
|
|
// dprintf("numDevs = %d\n", wNumDevs);
|
|
lpSetup = (SETUP FAR*)GlobalLock(hSetup);
|
|
for (i = 0; i < 16; i++)
|
|
{ // dprintf("device id[%d]=%d\n",i,lpSetup->channels[i].wDeviceID);
|
|
if ((lpSetup->channels[i].wDeviceID != LOWORD(MIDI_MAPPER)) &&
|
|
(lpSetup->channels[i].wDeviceID >= wNumDevs))
|
|
break;
|
|
}
|
|
|
|
GlobalUnlock(hSetup);
|
|
return (i < 16);
|
|
} /* FHasInvalidPort */
|
|
|
|
static int PASCAL ISetupSave(
|
|
HWND hdlg,
|
|
BOOL bQuery)
|
|
{
|
|
SETUP FAR* lpSetup;
|
|
MMAPERR mmaperr;
|
|
int iRet = 0; // choose a value not IDCANCEL or IDYES
|
|
|
|
if (bQuery)
|
|
if ((iRet = QuerySave()) != IDYES)
|
|
return iRet;
|
|
if (FHasInvalidPort())
|
|
if (!InvalidPortMsgBox(hdlg))
|
|
return IDCANCEL;
|
|
lpSetup = (SETUP FAR*)GlobalLock(hSetup);
|
|
mmaperr = mapWrite(MMAP_SETUP, lpSetup);
|
|
GlobalUnlock(hSetup);
|
|
if (mmaperr != MMAPERR_SUCCESS) {
|
|
VShowError(hdlg, mmaperr);
|
|
return IDCANCEL;
|
|
}
|
|
Modify(FALSE);
|
|
if (fNew)
|
|
fNew = FALSE;
|
|
return iRet;
|
|
} /* ISetupSave */
|
|
|
|
/*
|
|
* VSetupEditMsg
|
|
*
|
|
* This function deals with EN_UPDATE and EN_ACTIVATE messages sent
|
|
* to the channel number edit control through the WM_COMMAND message.
|
|
*/
|
|
|
|
static void PASCAL VSetupEditMsg(
|
|
HWND hdlg,
|
|
WORD NotifCode)
|
|
{
|
|
SETUP FAR* lpSetup;
|
|
int i;
|
|
LPWORD lpwChan;
|
|
WORD wChan;
|
|
BOOL bTranslate;
|
|
|
|
switch (NotifCode) {
|
|
case EN_UPDATE:
|
|
lpSetup = (SETUP FAR*)GlobalLock(hSetup);
|
|
lpwChan = &lpSetup->channels[iVertPos + iCurPos].wChannel;
|
|
i = GetDlgItemInt(hdlg, ID_SETUPEDIT, &bTranslate, FALSE);
|
|
if (i > 0 && i <= 16) {
|
|
if (*lpwChan != (BYTE)(i - 1)) {
|
|
*lpwChan = (BYTE)(i - 1);
|
|
Modify(TRUE);
|
|
}
|
|
} else {
|
|
char aszMessage[256];
|
|
char aszTitle[32];
|
|
|
|
// may want to experiment with EM_UNDO here.
|
|
LoadString(hLibInst, IDS_INVALIDDESTINATION, aszMessage, sizeof(aszMessage));
|
|
LoadString(hLibInst, IDS_USERERROR, aszTitle, sizeof(aszTitle));
|
|
MessageBox(hdlg, aszMessage, aszTitle, MB_ICONEXCLAMATION | MB_OK);
|
|
SetDlgItemInt(hdlg, ID_SETUPEDIT,
|
|
*lpwChan + 1, FALSE);
|
|
}
|
|
GlobalUnlock(hSetup);
|
|
break;
|
|
case EN_ACTIVATE:
|
|
lpSetup = (SETUP FAR*)GlobalLock(hSetup);
|
|
wChan = lpSetup->channels[iVertPos + iCurPos].wChannel;
|
|
GlobalUnlock(hSetup);
|
|
SetDlgItemInt(hdlg, ID_SETUPEDIT, wChan + 1, FALSE);
|
|
break;
|
|
}
|
|
} /* VSetupEditMsg */
|
|
|
|
/*
|
|
* VSetupActiveChan
|
|
*
|
|
* This function controls the checked/unchecked/grayed state of the 'Active'
|
|
* button for a specific channel. If the function is being grayed, it will
|
|
* be disabled as well.
|
|
*/
|
|
|
|
static void NEAR PASCAL VSetupActiveChan(
|
|
int iPos,
|
|
LPDWORD lpdwFlags,
|
|
UINT uCheck)
|
|
{
|
|
HWND hCheck;
|
|
BOOL fEnable;
|
|
|
|
if (lpdwFlags)
|
|
if (uCheck == BTN3S_CHECK)
|
|
*lpdwFlags |= MMAP_ACTIVE;
|
|
else
|
|
*lpdwFlags &= ~MMAP_ACTIVE;
|
|
hCheck = GetDlgItem(hWnd, ID_SETUPCHECK + iPos);
|
|
if ((UINT)SendMessage(hCheck, BM_GETCHECK, (WPARAM)0, (LPARAM)0) != uCheck)
|
|
SendMessage(hCheck, BM_SETCHECK, (WPARAM)uCheck, (LPARAM)0);
|
|
fEnable = (uCheck != BTN3S_GRAY);
|
|
if (fEnable != IsWindowEnabled(hCheck))
|
|
EnableWindow(hCheck, fEnable);
|
|
} /* VSetupActiveChan */
|
|
|
|
/*
|
|
* VSetupComboMsg
|
|
*
|
|
* This function deals with the CBN_ACTIVATE and CBN_SELCHANGE messages sent
|
|
* to the port or patch combo boxes through the WM_COMMAND message.
|
|
*/
|
|
|
|
static void NEAR PASCAL VSetupComboMsg(
|
|
HWND hdlg,
|
|
UINT id,
|
|
WORD NotifCode)
|
|
{
|
|
HWND hCombo = GetDlgItem(hdlg, id);
|
|
SETUP FAR* lpSetup;
|
|
CHANNEL FAR* lpChannel;
|
|
UINT uIdx;
|
|
char szBuf[MAXPNAMELEN];
|
|
|
|
if (NotifCode != CBN_ACTIVATE && NotifCode != CBN_SELCHANGE)
|
|
return;
|
|
lpSetup = (SETUP FAR*)GlobalLock(hSetup);
|
|
lpChannel = &lpSetup->channels[iVertPos + iCurPos];
|
|
switch (NotifCode) {
|
|
case CBN_ACTIVATE:
|
|
uIdx = MMAP_ID_NOPORT;
|
|
// if its a port combo box message
|
|
if (id == ID_SETUPPORTCOMBO)
|
|
if (lpChannel->wDeviceID != MMAP_ID_NOPORT)
|
|
uIdx = lpChannel->wDeviceID;
|
|
else
|
|
uIdx = nPorts;
|
|
// otherwise its a patch combo box message
|
|
else if (lpChannel->dFlags & MMAP_PATCHMAP)
|
|
uIdx = ComboLookup(hCombo, lpChannel->aszPatchName);
|
|
else
|
|
uIdx = nPatches;
|
|
SendMessage(hCombo, CB_SETCURSEL, (WPARAM)uIdx, (LPARAM)0);
|
|
break;
|
|
case CBN_SELCHANGE:
|
|
GetWindowText(hCombo, szBuf, MAXPNAMELEN);
|
|
// if we're dealing with a port combo message
|
|
if (id == ID_SETUPPORTCOMBO) {
|
|
// get the index of the newly selected port
|
|
uIdx = (UINT)SendMessage(hCombo,
|
|
CB_GETCURSEL, (WPARAM)NULL, (LPARAM)0);
|
|
// if it's the same as old index, we don't care
|
|
if (uIdx == lpChannel->wDeviceID)
|
|
break;
|
|
// if it's the last port index, it's the[none] entry
|
|
if (uIdx == (UINT)nPorts) {
|
|
// set id to bogus port value
|
|
lpChannel->wDeviceID = MMAP_ID_NOPORT;
|
|
// deactivate the channel
|
|
VSetupActiveChan(iCurPos, &lpChannel->dFlags,
|
|
BTN3S_GRAY);
|
|
} else {
|
|
// ok so it's not the[none] entry
|
|
// if it used to be[none], activate channel
|
|
if (lpChannel->wDeviceID == MMAP_ID_NOPORT)
|
|
VSetupActiveChan(iCurPos,
|
|
&lpChannel->dFlags,
|
|
BTN3S_CHECK);
|
|
// set the id to the new index
|
|
lpChannel->wDeviceID = (WORD)uIdx;
|
|
}
|
|
Modify(TRUE);
|
|
} else {
|
|
if (!lstrcmpi(szBuf, lpChannel->aszPatchName))
|
|
break;
|
|
lstrcpy(lpChannel->aszPatchName, szBuf);
|
|
if (!lstrcmpi(szBuf, szNone))
|
|
lpChannel->dFlags &= ~MMAP_PATCHMAP;
|
|
else
|
|
lpChannel->dFlags |= MMAP_PATCHMAP;
|
|
Modify(TRUE);
|
|
}
|
|
break;
|
|
}
|
|
GlobalUnlock(hSetup);
|
|
} /* VSetupComboMsg */
|
|
|
|
static void NEAR PASCAL VSetupActiveLine(
|
|
UINT uCase,
|
|
UINT uFlags)
|
|
{
|
|
static const UINT uDefFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
|
|
|
|
switch (uCase) {
|
|
case PAL_SHOW:
|
|
if (!fHidden)
|
|
return;
|
|
uFlags |= SWP_SHOWWINDOW;
|
|
fHidden = FALSE;
|
|
break;
|
|
case PAL_HIDE:
|
|
if (fHidden)
|
|
return;
|
|
uFlags |= SWP_HIDEWINDOW;
|
|
fHidden = TRUE;
|
|
break;
|
|
}
|
|
uFlags |= uDefFlags;
|
|
SetWindowPos(hEdit, NULL, 0L, 0L, 0L, 0L, uFlags);
|
|
SetWindowPos(hArrow, NULL, 0L, 0L, 0L, 0L, uFlags);
|
|
SetWindowPos(hPortCombo, NULL, 0L, 0L, 0L, 0L, uFlags);
|
|
SetWindowPos(hPatchCombo, NULL, 0L, 0L, 0L, 0L, uFlags);
|
|
if (uCase == PAL_SHOW)
|
|
SetFocus(hEdit);
|
|
} /* VSetupActiveLine */
|
|
|
|
static void NEAR PASCAL VSetupSetFocus(
|
|
HWND hdlg,
|
|
UINT uFlags,
|
|
int xPos)
|
|
{
|
|
HWND hOldCheck;
|
|
HWND hNewCheck;
|
|
RECT rc;
|
|
DWORD dwFlags;
|
|
int yPos = rcBox.top + iCurPos * yChar;
|
|
|
|
// change tabstop flag on new checkbox
|
|
hNewCheck = GetDlgItem(hdlg, ID_SETUPCHECK + iCurPos);
|
|
dwFlags = (DWORD)GetWindowLong(hNewCheck, GWL_STYLE);
|
|
dwFlags |= WS_TABSTOP;
|
|
SetWindowLong(hNewCheck, GWL_STYLE, dwFlags);
|
|
// set mnemonic on new window
|
|
SetWindowText(hNewCheck, aszSourceMnumonic);
|
|
// take the tabstop away from the old checkbox if it exists
|
|
if (iOldPos > -1) {
|
|
hOldCheck = GetDlgItem(hdlg, ID_SETUPCHECK + iOldPos);
|
|
dwFlags = (DWORD)GetWindowLong(hOldCheck, GWL_STYLE);
|
|
dwFlags &= ~(DWORD)WS_TABSTOP;
|
|
SetWindowLong(hOldCheck, GWL_STYLE, dwFlags);
|
|
// take away mnemonic from old window
|
|
SetWindowText(hOldCheck, aszNull);
|
|
}
|
|
iOldPos = iCurPos;
|
|
GetWindowRect(hEdit, &rc);
|
|
SetWindowPos(hEdit, NULL, rgxPos[1], yPos, 0L, 0L,
|
|
SWP_NOZORDER | SWP_NOSIZE);
|
|
VSetupEditMsg(hdlg, EN_ACTIVATE);
|
|
// UpdateWindow(hEdit);
|
|
SetWindowPos(hArrow, NULL, rgxPos[1] + xArrowOffset, yPos, 0L,
|
|
0L, SWP_NOZORDER | SWP_NOSIZE);
|
|
SetWindowPos(hPortCombo, NULL, rgxPos[2], yPos, 0L, 0L,
|
|
SWP_NOZORDER | SWP_NOSIZE);
|
|
VSetupComboMsg(hdlg, ID_SETUPPORTCOMBO, CBN_ACTIVATE);
|
|
SetWindowPos(hPatchCombo, NULL, rgxPos[3], yPos, 0L, 0L,
|
|
SWP_NOZORDER | SWP_NOSIZE);
|
|
VSetupComboMsg(hdlg, ID_SETUPPATCHCOMBO, CBN_ACTIVATE);
|
|
if ((fHidden) && (uFlags & PSF_SHOWIFHIDDEN)) {
|
|
VSetupActiveLine(PAL_SHOW, 0L);
|
|
UpdateWindow(hArrow);
|
|
UpdateWindow(hPortCombo);
|
|
UpdateWindow(hPatchCombo);
|
|
}
|
|
// ValidateRect(hdlg, NULL);
|
|
if (uFlags & PSF_REDRAW && rc.right) {
|
|
ScreenToClient(hdlg, (LPPOINT)&rc);
|
|
ScreenToClient(hdlg, (LPPOINT)&rc + 1);
|
|
rc.right = rcBox.right + 1;
|
|
InvalidateRect(hdlg, &rc, FALSE);
|
|
UpdateWindow(hdlg);
|
|
}
|
|
if (!xPos)
|
|
return;
|
|
if (xPos < rgxPos[2]) {
|
|
SetFocus(hEdit);
|
|
#if defined(WIN16)
|
|
SendMessage(hEdit, EM_SETSEL, (WPARAM)NULL, MAKELPARAM(0, 32767));
|
|
#else
|
|
SendMessage(hEdit, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
|
|
#endif //WIN16
|
|
} else if (xPos < rgxPos[3])
|
|
SetFocus(hPortCombo);
|
|
else if (xPos < rgxPos[4])
|
|
SetFocus(hPatchCombo);
|
|
} /* VSetupSetFocus */
|
|
|
|
/*
|
|
* VSetupSize
|
|
*/
|
|
static
|
|
void PASCAL VSetupSize(
|
|
HWND hdlg,
|
|
BOOL fMaximize)
|
|
{
|
|
RECT rcOK;
|
|
RECT rc3S;
|
|
RECT rcWnd;
|
|
LONG lDBU;
|
|
UINT xBU;
|
|
UINT yBU;
|
|
int xButton;
|
|
int xCenter;
|
|
int yTopMar;
|
|
int yBotMar;
|
|
int yLeftOver;
|
|
int yMiniBotMar;
|
|
int i;
|
|
|
|
lDBU = GetDialogBaseUnits();
|
|
xBU = LOWORD(lDBU);
|
|
yBU = HIWORD(lDBU);
|
|
// get the rectangle of the OK button
|
|
GetClientRect(GetDlgItem(hdlg, IDOK), &rcOK);
|
|
// get x-extent of button
|
|
xButton = rcOK.right - rcOK.left;
|
|
// top margin is 2 characters
|
|
yTopMar = (16 * yBU) / 8 - 6; // cookie land
|
|
// bottom margin is 2 * minimum bottom margin dialog units +
|
|
// height of button in pixels
|
|
yBotMar = (VERTMARGIN * 2 *yBU) / 8 + rcOK.bottom - rcOK.top;
|
|
if (fMaximize) {
|
|
// get the rectangle of a 3-state button
|
|
GetClientRect(GetDlgItem(hdlg, ID_SETUPCHECK), &rc3S);
|
|
SetWindowPos(hdlg, NULL, 0L, 0L,
|
|
rcBox.right - rcBox.left +
|
|
(rc3S.right - rc3S.left) +
|
|
(HORZMARGIN * 3 * xBU) / 4 +
|
|
(GetSystemMetrics(SM_CXDLGFRAME) + 1) * 2,
|
|
(DEF_SETUP_ROWS * 10 * yBU) / 8 +
|
|
yTopMar + yBotMar +
|
|
GetSystemMetrics(SM_CYCAPTION) +
|
|
(GetSystemMetrics(SM_CYDLGFRAME) + 1) * 2,
|
|
SWP_NOZORDER | SWP_NOMOVE);
|
|
}
|
|
// get the x and y extents of the client rectangle
|
|
GetClientRect(hdlg, &rcWnd);
|
|
xClient = rcWnd.right - rcWnd.left;
|
|
yClient = rcWnd.bottom - rcWnd.top;
|
|
// yChar is the height of one row in pixels - 1
|
|
yChar = (10 * yBU) / 8 - 1;
|
|
// xChar is the average width of a character
|
|
xChar = xBU;
|
|
// yBox is the room we actually have to display setup rows
|
|
yBox = yClient - yTopMar - yBotMar;
|
|
// nLines is the number of setup rows we can display
|
|
nLines = min(16, yBox / yChar);
|
|
// yLeftOver is how many pixels are left over
|
|
yLeftOver = yBox - nLines * yChar;
|
|
// add half the leftovers to the top margin
|
|
yTopMar += yLeftOver / 2;
|
|
// calculate scroll bar maximum and position
|
|
iVertMax = max(0, 16 - nLines);
|
|
iVertPos = min(iVertMax, iVertPos);
|
|
// rcBox is the box of rows and columns inside the client area
|
|
SetRect(&rcBox,
|
|
rcBox.left,
|
|
yTopMar,
|
|
rcBox.right,
|
|
yTopMar + nLines * yChar);
|
|
// xCenter is used to center the OK and CANCEL buttons horizontally
|
|
xCenter = (rcBox.right - rcBox.left - xButton * 3) / 4;
|
|
// yMiniBotMar is the spacing above and below the button
|
|
yMiniBotMar = (VERTMARGIN * yBU) / 8 + yLeftOver / 4;
|
|
SetWindowPos(GetDlgItem(hdlg, IDOK), NULL, rcBox.left + xCenter,
|
|
rcBox.bottom + yMiniBotMar, 0L, 0L,
|
|
SWP_NOSIZE | SWP_NOZORDER);
|
|
SetWindowPos(GetDlgItem(hdlg, IDCANCEL), NULL,
|
|
rcBox.left + xButton + xCenter * 2,
|
|
rcBox.bottom + yMiniBotMar, 0L, 0L,
|
|
SWP_NOSIZE | SWP_NOZORDER);
|
|
SetWindowPos(GetDlgItem(hdlg, IDH_DLG_MIDI_SETUPEDIT), NULL,
|
|
rcBox.left + xButton * 2 + xCenter * 3,
|
|
rcBox.bottom + yMiniBotMar, 0L, 0L,
|
|
SWP_NOSIZE | SWP_NOZORDER);
|
|
// this loop could be optimized
|
|
// then again, so could the u.s. judicial system
|
|
for (i = 0; i < 16; i++, yTopMar += yChar) {
|
|
HWND hCheck;
|
|
|
|
hCheck = GetDlgItem(hdlg, ID_SETUPCHECK + i);
|
|
if (i < nLines) {
|
|
SetWindowPos(hCheck, NULL,
|
|
rcBox.right + (HORZMARGIN * xBU) / 4,
|
|
yTopMar + 3, 0L, 0L,
|
|
SWP_NOSIZE | SWP_NOZORDER);
|
|
ShowWindow(hCheck, SW_SHOWNORMAL);
|
|
} else
|
|
ShowWindow(hCheck, SW_HIDE);
|
|
}
|
|
if (iCurPos >= 0 && iCurPos < nLines)
|
|
VSetupSetFocus(hdlg, PSF_SHOWIFHIDDEN, 1);
|
|
else
|
|
VSetupActiveLine(PAL_HIDE, SWP_NOREDRAW);
|
|
} /* VSetupSize */
|
|
|
|
static MMAPERR PASCAL MmaperrInitNew(void)
|
|
{
|
|
SETUP FAR* lpSetup;
|
|
WORD wChan;
|
|
|
|
if ((hSetup = GlobalAlloc(GHND, (DWORD)sizeof(SETUP))) == NULL)
|
|
return MMAPERR_MEMORY;
|
|
lpSetup = (SETUP FAR*)GlobalLock(hSetup);
|
|
lstrcpy(lpSetup->aszSetupName, szCurrent);
|
|
lstrcpy(lpSetup->aszSetupDescription, szCurDesc);
|
|
for (wChan = 0; wChan < 16; wChan++) {
|
|
lpSetup->channels[wChan].wChannel = wChan;
|
|
lpSetup->channels[wChan].wDeviceID = MMAP_ID_NOPORT;
|
|
lstrcpy(lpSetup->channels[wChan].aszPatchName, szNone);
|
|
}
|
|
GlobalUnlock(hSetup);
|
|
return MMAPERR_SUCCESS;
|
|
} /* MmaperrInitNew */
|
|
|
|
/*
|
|
* VSetupEnumPorts
|
|
*
|
|
* Enumerate available port names and throw them in a combo box.
|
|
*/
|
|
|
|
static void PASCAL VSetupEnumPorts(
|
|
void)
|
|
{
|
|
MIDIOUTCAPS moCaps;
|
|
UINT i;
|
|
|
|
nPorts = midiOutGetNumDevs();
|
|
for (i = 0; i < nPorts; i++) {
|
|
midiOutGetDevCaps(i, &moCaps, sizeof(MIDIOUTCAPS));
|
|
SendMessage(hPortCombo, CB_ADDSTRING, (WPARAM)NULL,
|
|
(LPARAM)(LPSTR)moCaps.szPname);
|
|
}
|
|
} /* VSetupEnumPorts */
|
|
|
|
/*
|
|
* MmaperrEnumPatches
|
|
*
|
|
* This function calls mapEnumerate to enumerate all the user-defined
|
|
* patchmaps into a combo box.
|
|
*/
|
|
static MMAPERR NEAR PASCAL MmaperrEnumPatches(void)
|
|
{
|
|
MMAPERR mmaperr;
|
|
|
|
mmaperr = mapEnumerate(MMAP_PATCH, EnumFunc, MMENUM_BASIC, hPatchCombo, NULL);
|
|
if (mmaperr != MMAPERR_SUCCESS)
|
|
return mmaperr;
|
|
nPatches = (int)(LONG)SendMessage(hPatchCombo, CB_GETCOUNT, (WPARAM)NULL, (LPARAM)0);
|
|
SendMessage(hPatchCombo, CB_ADDSTRING, (WPARAM)NULL, (LPARAM)(LPSTR)szNone);
|
|
return MMAPERR_SUCCESS;
|
|
} /* MmaperrEnumPatches */
|
|
|
|
static BOOL NEAR PASCAL FInitSetup(
|
|
HWND hdlg)
|
|
{
|
|
SETUP FAR* lpSetup;
|
|
LONG lDBU;
|
|
UINT xBU;
|
|
UINT yBU;
|
|
UINT xWidth; // width of current column
|
|
UINT xEdit; // width of edit controls
|
|
UINT yEdit; // height of edit/arrow controls
|
|
UINT xCombo; // width of combo boxes
|
|
UINT yCombo; // height of combo boxes
|
|
UINT wCheck;
|
|
char szCaption[80];
|
|
char szCaptionFormat[80];
|
|
MMAPERR mmaperr;
|
|
int i;
|
|
|
|
if (!fNew) {
|
|
if ((hSetup = GlobalAlloc(GHND, sizeof(SETUP))) == NULL) {
|
|
mmaperr = MMAPERR_MEMORY;
|
|
exit00: VShowError(hdlg, mmaperr);
|
|
return FALSE;
|
|
}
|
|
} else if ((mmaperr = MmaperrInitNew()) != MMAPERR_SUCCESS)
|
|
goto exit00;
|
|
fHidden = FALSE;
|
|
iVertPos = 0;
|
|
iCurPos = 0;
|
|
nLines = 0; // necessary?
|
|
nPatches = 0;
|
|
nPorts = 0;
|
|
hPortList = GetDlgItem(hdlg, ID_SETUPPORTLIST);
|
|
hEdit = GetDlgItem(hdlg, ID_SETUPEDIT);
|
|
hArrow = GetDlgItem(hdlg, ID_SETUPARROW);
|
|
hPortCombo = GetDlgItem(hdlg, ID_SETUPPORTCOMBO);
|
|
hPatchCombo = GetDlgItem(hdlg, ID_SETUPPATCHCOMBO);
|
|
if (fReadOnly)
|
|
{
|
|
EnableWindow(GetDlgItem(hdlg,IDOK),FALSE);
|
|
SendMessage(hdlg, DM_SETDEFID, (WPARAM)IDCANCEL, (LPARAM)0);
|
|
}
|
|
lDBU = GetDialogBaseUnits();
|
|
xBU = LOWORD(lDBU);
|
|
yBU = HIWORD(lDBU);
|
|
xEdit = (40 * xBU) / 4; // 10 chars wide
|
|
yEdit = (10 * yBU) / 8; // 10 is a magic cookie
|
|
xCombo = (64 * xBU) / 4; // 16 characters long
|
|
yCombo = (46 * yBU) / 8; // 46 is a magic cookie
|
|
rcBox.left = (HORZMARGIN * xBU) / 4;
|
|
rcBox.right = rcBox.left;
|
|
rgxPos[0] = rcBox.right;
|
|
rcBox.right += xEdit;
|
|
rgxPos[1] = rcBox.right;
|
|
xWidth = xEdit;
|
|
SetWindowPos(hEdit, NULL, 0L, 0L, xWidth, yEdit,
|
|
SWP_NOZORDER | SWP_NOMOVE);
|
|
// set global arrow control offset to proper position
|
|
rcBox.right += xArrowOffset = xWidth - 1;
|
|
// width of dst channel arrow control
|
|
xWidth = (10 * xBU) / 4;
|
|
SetWindowPos(hArrow, NULL, 0L, 0L, xWidth, yEdit,
|
|
SWP_NOZORDER | SWP_NOMOVE);
|
|
rcBox.right += xWidth - 1;
|
|
rgxPos[2] = rcBox.right;
|
|
xWidth = (80 * xBU) / 4; // 20 characters long
|
|
SetWindowPos(hPortCombo, NULL, 0L, 0L, xWidth,
|
|
yCombo, SWP_NOZORDER | SWP_NOMOVE);
|
|
rcBox.right += xWidth - 1;
|
|
rgxPos[3] = rcBox.right;
|
|
xWidth = xCombo;
|
|
SetWindowPos(hPatchCombo, NULL, 0L, 0L, xWidth,
|
|
yCombo, SWP_NOZORDER | SWP_NOMOVE);
|
|
rcBox.right += xWidth - 1;
|
|
rgxPos[4] = rcBox.right;
|
|
if (!nPorts)
|
|
VSetupEnumPorts();
|
|
lpSetup = (SETUP FAR*)GlobalLock(hSetup);
|
|
if (!nPatches)
|
|
if ((mmaperr = MmaperrEnumPatches()) != MMAPERR_SUCCESS) {
|
|
exit01: GlobalUnlock(hSetup);
|
|
GlobalFree(hSetup);
|
|
goto exit00;
|
|
}
|
|
if (!fNew) {
|
|
mmaperr = mapReadSetup(szCurrent, lpSetup);
|
|
if (mmaperr == MMAPERR_INVALIDPORT) {
|
|
if (!InvalidPortMsgBox(hdlg)) {
|
|
GlobalUnlock(hSetup);
|
|
GlobalFree(hSetup);
|
|
return FALSE;
|
|
}
|
|
mmaperr = mapEnumerate( MMAP_PORTS
|
|
, FSetupEnumPortsFunc
|
|
, MMENUM_BASIC
|
|
, NULL
|
|
, (LPSTR)szCurrent
|
|
);
|
|
}
|
|
if (mmaperr != MMAPERR_SUCCESS){
|
|
goto exit01;
|
|
}
|
|
if (lstrcmp(lpSetup->aszSetupDescription, szCurDesc)) {
|
|
lstrcpy(lpSetup->aszSetupDescription, szCurDesc);
|
|
fNew = TRUE;
|
|
}
|
|
}
|
|
SendMessage(hPortCombo, CB_ADDSTRING, (WPARAM)NULL, (LPARAM)(LPSTR)szNone);
|
|
for (i = 0; i < 16; i++) {
|
|
// check a 3-state button if the channel is active, or gray
|
|
// it if the channel is not mapped to a port
|
|
if (lpSetup->channels[i].wDeviceID == MMAP_ID_NOPORT)
|
|
wCheck = BTN3S_GRAY;
|
|
else if (lpSetup->channels[i].dFlags & MMAP_ACTIVE)
|
|
wCheck = BTN3S_CHECK;
|
|
else
|
|
continue;
|
|
VSetupActiveChan(i, 0L, wCheck);
|
|
}
|
|
GlobalUnlock(hSetup);
|
|
|
|
LoadString(hLibInst, IDS_SETUPS ,szCaptionFormat, sizeof(szCaptionFormat));
|
|
wsprintf(szCaption, szCaptionFormat, (LPSTR)szCurrent);
|
|
SetWindowText(hWnd, szCaption);
|
|
|
|
SendMessage(GetDlgItem(hdlg, ID_SETUPDESTMNEM),
|
|
WM_SETFONT, (WPARAM)hFont, (LPARAM)0);
|
|
SendMessage(GetDlgItem(hdlg, ID_SETUPPORTMNEM),
|
|
WM_SETFONT, (WPARAM)hFont, (LPARAM)0);
|
|
SendMessage(GetDlgItem(hdlg, ID_SETUPPATCHMNEM),
|
|
WM_SETFONT, (WPARAM)hFont, (LPARAM)0);
|
|
VSetupSize(hdlg, TRUE);
|
|
SetWindowPos(GetDlgItem(hdlg, ID_SETUPDESTMNEM), NULL,
|
|
rgxPos[1], yChar, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER);
|
|
SetWindowPos(GetDlgItem(hdlg, ID_SETUPPORTMNEM), NULL,
|
|
rgxPos[2], yChar, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER);
|
|
SetWindowPos(GetDlgItem(hdlg, ID_SETUPPATCHMNEM), NULL,
|
|
rgxPos[3], yChar, 0L, 0L, SWP_NOSIZE | SWP_NOZORDER);
|
|
Modify(fNew);
|
|
return TRUE;
|
|
} /* FInitSetup */
|
|
|
|
static void PASCAL VSetupButtonDown(
|
|
HWND hdlg,
|
|
LONG lParam)
|
|
{
|
|
int x = LOWORD(lParam);
|
|
int y = HIWORD(lParam);
|
|
int iPos;
|
|
UINT uFlags;
|
|
|
|
if (x < rcBox.left || x > rcBox.right)
|
|
return;
|
|
if (y < rcBox.top || y > rcBox.bottom)
|
|
return;
|
|
if ((iPos = min(nLines - 1, (y - rcBox.top) / yChar)) == iCurPos)
|
|
return;
|
|
if (iCurPos >= 0 && iCurPos < nLines) {
|
|
uFlags = PSF_REDRAW;
|
|
SendMessage(hPortCombo, CB_SHOWDROPDOWN, (WPARAM)FALSE, (LPARAM)0);
|
|
SendMessage(hPatchCombo, CB_SHOWDROPDOWN, (WPARAM)FALSE, (LPARAM)0);
|
|
UpdateWindow(hdlg);
|
|
} else
|
|
uFlags = PSF_SHOWIFHIDDEN;
|
|
iCurPos = iPos;
|
|
VSetupSetFocus(hdlg, uFlags, x);
|
|
} /* VSetupButtonDown */
|
|
|
|
static void PASCAL VSetupPaint(
|
|
HWND hdlg)
|
|
{
|
|
HPEN hPen; // previous pen to restore
|
|
SETUP FAR* lpSetup;
|
|
CHANNEL FAR* lpChannel;
|
|
PAINTSTRUCT ps; // from BeginPaint
|
|
RECT rcText;
|
|
UINT uDev;
|
|
int i; // loop counter
|
|
int iVert;
|
|
int nBegin; // first row to repaint
|
|
int nEnd; // last row to repaint
|
|
int iLeft; // left of invalid area
|
|
int iTop; // top of invalid area
|
|
int iBottom; // bottom of invalid area
|
|
char szBuf[MAXPNAMELEN];
|
|
// uses GLOBAL hFont - Lord knows why.
|
|
// uses GLOBAL rcBox = clipping rectangle???
|
|
|
|
BeginPaint(hdlg, &ps);
|
|
if (!ps.rcPaint.bottom) { // bottom==0 => area must be empty
|
|
exit00: EndPaint(hdlg, &ps);
|
|
return;
|
|
}
|
|
hPen = SelectObject(ps.hdc, GetStockObject(BLACK_PEN));
|
|
hFont = SelectObject(ps.hdc, hFont);
|
|
SetTextColor(ps.hdc, GetSysColor(COLOR_WINDOWTEXT));
|
|
SetBkMode(ps.hdc, TRANSPARENT);
|
|
if (ps.rcPaint.top < rcBox.top) { // need to paint top headings?
|
|
iVert = yChar;
|
|
TextOut(ps.hdc, 11, iVert, aszSourceChannel, lstrlen(aszSourceChannel));
|
|
SetRect(&rcText, rcBox.right + 2, yChar, 0, 0);
|
|
DrawText(ps.hdc, aszActive, -1, &rcText,
|
|
DT_LEFT | DT_NOCLIP);
|
|
}
|
|
// calculate top and bottom y coordinates of invalid area
|
|
iTop = max(ps.rcPaint.top, rcBox.top);
|
|
// if top is below the box, forget about painting
|
|
if (iTop > rcBox.bottom) {
|
|
exit01: hFont = SelectObject(ps.hdc, hFont); // restore
|
|
hPen = SelectObject(ps.hdc, hPen); // restore
|
|
goto exit00;
|
|
}
|
|
iBottom = min(ps.rcPaint.bottom, rcBox.bottom);
|
|
// calculate left x coordinate of invalid area
|
|
iLeft = max(ps.rcPaint.left, rcBox.left);
|
|
// calculate beginning and ending data row to be repainted
|
|
nBegin = max(0, (iTop - rcBox.top) / yChar);
|
|
nEnd = min(nLines, (iBottom - rcBox.top) / yChar);
|
|
// draw vertical lines of the box
|
|
for (i = 0; i < 5; i++) {
|
|
MMoveTo(ps.hdc, rgxPos[i], iTop);
|
|
LineTo(ps.hdc, rgxPos[i], iBottom + 1);
|
|
}
|
|
// vertical position of first line we have to draw
|
|
iVert = rcBox.top + nBegin * yChar;
|
|
// lock the map
|
|
lpSetup = (SETUP FAR*)GlobalLock(hSetup);
|
|
// set up an optimization pointer
|
|
lpChannel = &lpSetup->channels[iVertPos + nBegin];
|
|
for (i = nBegin; i <= nEnd; i++, iVert += yChar, lpChannel++) {
|
|
MMoveTo(ps.hdc, iLeft, iVert);
|
|
LineTo(ps.hdc, rcBox.right, iVert);
|
|
if (i == nLines)
|
|
break;
|
|
if (iLeft < rgxPos[1]) {
|
|
wsprintf(szBuf, aszSetupNumFormat, iVertPos + i + 1);
|
|
TextOut(ps.hdc, rgxPos[0] + xChar, iVert + 2,
|
|
szBuf, 3);
|
|
}
|
|
if (iLeft < rgxPos[2]) {
|
|
wsprintf(szBuf, aszSetupNumFormat, lpChannel->wChannel + 1);
|
|
TextOut(ps.hdc, rgxPos[1] + 2 * xChar, iVert + 2,
|
|
szBuf, 3);
|
|
}
|
|
if (i == iCurPos)
|
|
continue;
|
|
if (iLeft < rgxPos[3]) {
|
|
*szBuf = 0;
|
|
uDev = lpChannel->wDeviceID;
|
|
if (uDev == MMAP_ID_NOPORT)
|
|
uDev = nPorts;
|
|
if (uDev <= nPorts) {
|
|
RECT sTextRect;
|
|
TEXTMETRIC sTM;
|
|
|
|
SendMessage(hPortCombo, CB_GETLBTEXT,
|
|
uDev, (LPARAM)(LPSTR)szBuf);
|
|
|
|
GetTextMetrics(ps.hdc,(LPTEXTMETRIC)&sTM);
|
|
SetRect((LPRECT)&sTextRect,rgxPos[2]+2,iVert+2,rgxPos[3]-2,iVert+2+sTM.tmHeight);
|
|
DrawText(ps.hdc, szBuf, -1,(LPRECT)&sTextRect ,DT_NOPREFIX|DT_LEFT|DT_SINGLELINE);
|
|
}
|
|
}
|
|
if (iLeft < rgxPos[4]) {
|
|
RECT rc;
|
|
SetRect(&rc, rgxPos[3]+2, iVert, rgxPos[4]-2, iVert+yChar);
|
|
DrawText(ps.hdc,
|
|
lpChannel->aszPatchName,
|
|
lstrlen(lpChannel->aszPatchName),
|
|
&rc,
|
|
DT_LEFT|DT_SINGLELINE|DT_VCENTER
|
|
);
|
|
// was:
|
|
// TextOut(ps.hdc, rgxPos[3] + 2, iVert + 2, lpChannel->aszPatchName,
|
|
// lstrlen(lpChannel->aszPatchName));
|
|
}
|
|
}
|
|
GlobalUnlock(hSetup);
|
|
goto exit01;
|
|
} /* VSetupPaint */
|
|
|
|
static void PASCAL VSetupArrowScroll(
|
|
HWND hdlg,
|
|
WORD ScrollCode)
|
|
{
|
|
SETUP FAR* lpSetup;
|
|
WORD wChan;
|
|
|
|
lpSetup = (SETUP FAR*)GlobalLock(hSetup);
|
|
wChan = lpSetup->channels[iVertPos + iCurPos].wChannel;
|
|
GlobalUnlock(hSetup);
|
|
switch (ScrollCode) {
|
|
case SB_LINEDOWN:
|
|
if (!wChan--)
|
|
wChan = 15;
|
|
break;
|
|
case SB_LINEUP:
|
|
if (++wChan > 15)
|
|
wChan = 0;
|
|
break;
|
|
}
|
|
SetDlgItemInt(hWnd, ID_SETUPEDIT, wChan + 1, FALSE);
|
|
} /* VSetupArrowScroll */
|
|
|
|
/*
|
|
* VSetupCheckMsg
|
|
*/
|
|
static void PASCAL VSetupCheckMsg(
|
|
WORD id,
|
|
WORD NotifCode)
|
|
{
|
|
SETUP FAR* lpSetup;
|
|
CHANNEL FAR* lpChannel;
|
|
|
|
if (NotifCode != BN_CLICKED)
|
|
return;
|
|
lpSetup = (SETUP FAR*)GlobalLock(hSetup);
|
|
lpChannel = &lpSetup->channels[iVertPos + id - ID_SETUPCHECK];
|
|
if (lpChannel->wDeviceID != MMAP_ID_NOPORT) {
|
|
VSetupActiveChan( id - ID_SETUPCHECK
|
|
, &lpChannel->dFlags
|
|
, (lpChannel->dFlags & MMAP_ACTIVE)
|
|
? BTN3S_UNCHECK
|
|
: BTN3S_CHECK
|
|
);
|
|
Modify(TRUE);
|
|
}
|
|
GlobalUnlock(hSetup);
|
|
} /* VSetupCheckMsg */
|
|
|
|
BOOL FAR PASCAL _loadds SetupBox(
|
|
HWND hdlg,
|
|
UINT uMessage,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
int iRet;
|
|
HWND hwndCheckBox;
|
|
|
|
switch (uMessage) {
|
|
case WM_INITDIALOG:
|
|
hWnd = hdlg;
|
|
iOldPos = -1;
|
|
SetFocus(GetDlgItem(hdlg, ID_SETUPEDIT));
|
|
if (!FInitSetup(hdlg))
|
|
EndDialog(hdlg, FALSE);
|
|
SetFocus(hEdit);
|
|
PlaceWindow(hWnd);
|
|
return FALSE;
|
|
case WM_COMMAND:
|
|
{ WORD id = LOWORD(wParam);
|
|
#if defined(WIN16)
|
|
WORD NotifCode = HIWORD(lParam);
|
|
HWND hwnd = LOWORD(lParam);
|
|
#else
|
|
WORD NotifCode = HIWORD(wParam);
|
|
HWND hwnd = (HWND)lParam;
|
|
#endif //WIN16
|
|
|
|
switch (id) {
|
|
case IDH_DLG_MIDI_SETUPEDIT:
|
|
goto DoHelp;
|
|
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
if (NotifCode != BN_CLICKED)
|
|
break;
|
|
if (!fReadOnly && ((id == IDOK) && fModified)) {
|
|
iRet = ISetupSave(hdlg, TRUE);
|
|
if (iRet == IDCANCEL)
|
|
break;
|
|
iRet = (iRet == IDYES);
|
|
} else
|
|
iRet = FALSE;
|
|
GlobalFree(hSetup);
|
|
EndDialog(hdlg, iRet);
|
|
break;
|
|
|
|
case ID_SETUPGHOSTEDITFIRST:
|
|
|
|
/* assume the user back-tabbed before the first
|
|
* control on the current row, so jump to the
|
|
* previous row (if iCurPos > 0) or the last row
|
|
* (if iCurPos == 0)
|
|
*/
|
|
|
|
if (NotifCode != EN_SETFOCUS)
|
|
break;
|
|
if (iCurPos < 0)
|
|
/* do nothing */ ;
|
|
else
|
|
if (iCurPos > 0)
|
|
iCurPos--;
|
|
else
|
|
iCurPos = nLines - 1;
|
|
VSetupSetFocus(hdlg, PSF_REDRAW, 0);
|
|
hwndCheckBox = GetDlgItem(hdlg, ID_SETUPCHECK + iOldPos);
|
|
if (IsWindowEnabled(hwndCheckBox))
|
|
SetFocus(hwndCheckBox);
|
|
else
|
|
SetFocus(hPatchCombo);
|
|
break;
|
|
|
|
case ID_SETUPGHOSTEDITLAST:
|
|
|
|
/* assume the user forward-tabbed beyond the last
|
|
* control on the current row, so jump to the
|
|
* next row (if iCurPos < nLines - 1) or the first row
|
|
* (if iCurPos == nLines - 1)
|
|
*/
|
|
|
|
if (NotifCode != EN_SETFOCUS)
|
|
break;
|
|
if (iCurPos < 0)
|
|
/* do nothing */ ;
|
|
else
|
|
if (iCurPos < nLines - 1)
|
|
iCurPos++;
|
|
else
|
|
iCurPos = 0;
|
|
VSetupSetFocus(hdlg, PSF_REDRAW, 0);
|
|
SetFocus(hEdit);
|
|
#if defined(WIN16)
|
|
SendMessage(hEdit, EM_SETSEL, (WPARAM)NULL, MAKELPARAM(0, 32767));
|
|
#else
|
|
SendMessage(hEdit, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
|
|
#endif //WIN16
|
|
break;
|
|
|
|
case ID_SETUPEDIT:
|
|
VSetupEditMsg(hdlg, NotifCode);
|
|
break;
|
|
case ID_SETUPPORTCOMBO:
|
|
case ID_SETUPPATCHCOMBO:
|
|
VSetupComboMsg(hdlg, id, NotifCode);
|
|
break;
|
|
default:
|
|
if ((id >= ID_SETUPCHECK) &&
|
|
(id < ID_SETUPCHECK + 16))
|
|
VSetupCheckMsg(id, NotifCode);
|
|
else
|
|
return FALSE;
|
|
}
|
|
break;
|
|
} /* end of WM_COMMAND */
|
|
case WM_PAINT:
|
|
VSetupPaint(hdlg);
|
|
break;
|
|
case WM_LBUTTONDOWN:
|
|
VSetupButtonDown(hdlg, (LONG)lParam);
|
|
break;
|
|
case WM_VSCROLL:
|
|
// if (HIWORD(lParam)) // in DOS this is the window ID - I don't see why we need the test
|
|
// and in NT we don't have that ID anyway
|
|
VSetupArrowScroll(hdlg, LOWORD(wParam));
|
|
// LOWORD(wParam) is scroll code. See cpArrow:
|
|
// actually the whole of wParam is.
|
|
break;
|
|
case WM_CHAR:
|
|
if ((LONG)lParam == 14)
|
|
if (iCurPos == 15)
|
|
iCurPos = 0;
|
|
else
|
|
iCurPos++;
|
|
else if ((LONG)lParam == 16)
|
|
if (!iCurPos)
|
|
iCurPos = 15;
|
|
else
|
|
iCurPos--;
|
|
else
|
|
return FALSE;
|
|
VSetupSetFocus(hdlg, 0L, 0L);
|
|
break;
|
|
case WM_CLOSE:
|
|
PostMessage(hdlg, WM_COMMAND, (WPARAM)IDOK, (LPARAM)0);
|
|
break;
|
|
|
|
default:
|
|
if (uMessage == uHelpMessage) {
|
|
DoHelp:
|
|
WinHelp(hWnd, szMidiHlp, HELP_CONTEXT,
|
|
IDH_DLG_MIDI_SETUPEDIT);
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
break;
|
|
}
|
|
return TRUE;
|
|
} /* SetupBox */
|
|
|
|
/*
|
|
* FSetupEnumPortsFunc
|
|
*
|
|
* This function receives port information for each channel in a setup,
|
|
* determines if the port is not available in the current environment, and
|
|
* if so adds it to a listbox of invalid port names.
|
|
*
|
|
* The types and parameters are weird because it is being forced into the straightjacket
|
|
* of an enumfunc.
|
|
*/
|
|
|
|
BOOL FAR PASCAL _loadds FSetupEnumPortsFunc(
|
|
LPSTR lpChannel,
|
|
LPSTR lpPort,
|
|
UINT uCase, // unused
|
|
HWND hCombo, //unused
|
|
LPSTR DeviceID)
|
|
{
|
|
SETUP FAR* lpSetup;
|
|
INT Idx;
|
|
|
|
if (DeviceID == (LPSTR)MMAP_ID_NOPORT) {
|
|
Idx = ComboLookup(hPortCombo, lpPort);
|
|
if (Idx == CB_ERR) {
|
|
SendMessage(hPortCombo, CB_ADDSTRING, (WPARAM)NULL,
|
|
(LPARAM)lpPort);
|
|
Idx = nPorts++;
|
|
}
|
|
lpSetup = (SETUP FAR*)GlobalLock(hSetup);
|
|
lpSetup->channels[(WORD)(DWORD_PTR)lpChannel - 1].wDeviceID = (WORD)Idx;
|
|
GlobalUnlock(hSetup);
|
|
}
|
|
return TRUE;
|
|
} /* FSetupEnumPortsFunc */
|
|
|