mirror of https://github.com/lianthony/NT4.0
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.
4319 lines
135 KiB
4319 lines
135 KiB
/** FILE: ports.c ********** Module Header ********************************
|
|
*
|
|
* Control panel applet for configuring COM ports. This file contains
|
|
* the dialog and utility functions for managing the UI for setting COM
|
|
* port parameters
|
|
*
|
|
* History:
|
|
* 12:30 on Tues 23 Apr 1991 -by- Steve Cathcart [stevecat]
|
|
* Took base code from Win 3.1 source
|
|
* 10:30 on Tues 04 Feb 1992 -by- Steve Cathcart [stevecat]
|
|
* Updated code to latest Win 3.1 sources
|
|
* 16:30 on Fri 27 Mar 1992 -by- Steve Cathcart [stevecat]
|
|
* Changed to allow for unlimited number of NT COM ports
|
|
* 18:00 on Tue 06 Apr 1993 -by- Steve Cathcart [stevecat]
|
|
* Updated to work seamlessly with NT serial driver
|
|
* 19:00 on Wed 05 Jan 1994 -by- Steve Cathcart [stevecat]
|
|
* Allow setting COM1 - COM4 advanced parameters
|
|
*
|
|
* Copyright (C) 1990-1995 Microsoft Corporation
|
|
*
|
|
*************************************************************************/
|
|
//==========================================================================
|
|
// Include files
|
|
//==========================================================================
|
|
// C Runtime
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
// Application specific
|
|
#include "ports.h"
|
|
|
|
//==========================================================================
|
|
// Local Structures
|
|
//==========================================================================
|
|
typedef struct _GENERAL_PROP_PARAMS {
|
|
DWORD ComPortNumber;
|
|
BOOL FifoEnabled;
|
|
BOOL FifoChanged;
|
|
HDEVINFO DeviceInfoSet;
|
|
PSP_DEVINFO_DATA DeviceInfoData;
|
|
} GENERAL_PROP_PARAMS, *PGENERAL_PROP_PARAMS;
|
|
|
|
//==========================================================================
|
|
// Local Definitions
|
|
//==========================================================================
|
|
#define PORTS 4
|
|
#define MAXPORTS 32
|
|
#define KEYBZ 4096
|
|
|
|
#define DEF_BAUD 3 // 1200
|
|
#define DEF_WORD 4 // 8 bits
|
|
#define DEF_PARITY 2 // None
|
|
#define DEF_STOP 0 // 1
|
|
#define DEF_PORT 0 // Null Port
|
|
#define DEF_SHAKE 2 // None
|
|
#define PAR_EVEN 0
|
|
#define PAR_ODD 1
|
|
#define PAR_NONE 2
|
|
#define PAR_MARK 3
|
|
#define PAR_SPACE 4
|
|
#define STOP_1 0
|
|
#define STOP_15 1
|
|
#define STOP_2 2
|
|
#define FLOW_XON 0
|
|
#define FLOW_HARD 1
|
|
#define FLOW_NONE 2
|
|
|
|
#define CURRENT_SET 1 // TRUE if Registry key CurrentControlSet works
|
|
|
|
#define MAX_COM_PORT 256 // Maximum number of COM ports NT supports
|
|
#define MIN_COM 1 // Minimum new COM port number
|
|
#define MIN_SERIAL 10000 // Minimum new registry "Serial" value
|
|
|
|
|
|
//==========================================================================
|
|
// External Declarations
|
|
//==========================================================================
|
|
|
|
|
|
//==========================================================================
|
|
// Local Data Declarations
|
|
//==========================================================================
|
|
|
|
|
|
BOOL bNewPort = FALSE;
|
|
BOOL bResetTitle = FALSE;
|
|
BOOL bResetLB = FALSE;
|
|
|
|
|
|
#ifdef LATER
|
|
|
|
int errno;
|
|
TCHAR sz386Enh[] = TEXT( "386Enh" );
|
|
TCHAR szBase[] = TEXT( "Base" );
|
|
TCHAR szIrq[] = TEXT( "Irq" );
|
|
|
|
#endif // LATER
|
|
|
|
|
|
TCHAR m_szColon[] = TEXT( ":" );
|
|
TCHAR m_szComma[] = TEXT( "," );
|
|
TCHAR m_szCloseParen[] = TEXT( ")" );
|
|
TCHAR m_szPorts[] = TEXT( "Ports" );
|
|
TCHAR m_szCOM[] = TEXT( "COM" );
|
|
TCHAR m_szSERIAL[] = TEXT( "Serial" );
|
|
|
|
TCHAR m_szComPort[ 20 ];
|
|
TCHAR m_szSerialKey[ 40 ];
|
|
BOOL m_PortIsPnP;
|
|
|
|
//
|
|
// NT Registry keys to find COM port to Serial Device mapping
|
|
//
|
|
|
|
TCHAR m_szRegSerialMap[] = TEXT( "Hardware\\DeviceMap\\SerialComm" );
|
|
|
|
//
|
|
// Registry Serial Port Advanced I/O settings key and valuenames
|
|
//
|
|
|
|
TCHAR m_szRegSerial[] =
|
|
TEXT( "System\\CurrentControlSet\\Services\\Serial" );
|
|
|
|
TCHAR m_szRegSerialParam[] =
|
|
TEXT( "System\\CurrentControlSet\\Services\\Serial\\Parameters" );
|
|
|
|
TCHAR m_szRegSerialIO[] =
|
|
TEXT( "System\\CurrentControlSet\\Services\\Serial\\Parameters\\%s" );
|
|
|
|
TCHAR m_szParametersSerialIO[] =
|
|
TEXT( "Parameters\\%s" );
|
|
|
|
TCHAR m_szRegHwDesc[] =
|
|
TEXT( "Hardware\\Description\\System\\" );
|
|
|
|
TCHAR m_szRegResourceMap[] =
|
|
TEXT( "HARDWARE\\RESOURCEMAP\\LOADED SERIAL DRIVER RESOURCES\\Serial" );
|
|
|
|
TCHAR m_szSerialController[] = TEXT( "SerialController" );
|
|
TCHAR m_szConfigurationData[] = TEXT( "Configuration Data" );
|
|
TCHAR m_szIdentifier[] = TEXT( "Identifier" );
|
|
TCHAR m_szMultifunctionAdapter[] = TEXT( "MultifunctionAdapter" );
|
|
TCHAR m_szEisaAdapter[] = TEXT( "EisaAdapter" );
|
|
TCHAR m_szDeviceSerial[] = TEXT( "\\Device\\Serial" );
|
|
TCHAR m_szDeviceSerialSuffix[] = TEXT( ".Raw" );
|
|
|
|
TCHAR m_szRegPortAddress[] = TEXT( "PortAddress" );
|
|
TCHAR m_szRegPortIRQ[] = TEXT( "Interrupt" );
|
|
TCHAR m_szFIFO[] = TEXT( "ForceFifoEnable" );
|
|
TCHAR m_szDosDev[] = TEXT( "DosDevices" );
|
|
TCHAR m_szPnPDeviceId[] = TEXT( "PnPDeviceId" );
|
|
TCHAR m_szPortName[] = REGSTR_VAL_PORTNAME;
|
|
TCHAR m_szSetupApiDll[] = TEXT( "setupapi.dll" );
|
|
|
|
int m_nBaudRates[] = { 75, 110, 134, 150, 300, 600, 1200, 1800, 2400,
|
|
4800, 7200, 9600, 14400, 19200, 38400, 57600,
|
|
115200, 128000, 0 };
|
|
|
|
TCHAR m_sz9600[] = TEXT( "9600" );
|
|
|
|
TCHAR m_szDefParams[] = TEXT( "9600,n,8,1" );
|
|
|
|
short m_nDataBits[] = { 4, 5, 6, 7, 8, 0};
|
|
|
|
TCHAR *m_pszParitySuf[] = { TEXT( ",e" ),
|
|
TEXT( ",o" ),
|
|
TEXT( ",n" ),
|
|
TEXT( ",m" ),
|
|
TEXT( ",s" ) };
|
|
|
|
TCHAR *m_pszLenSuf[] = { TEXT( ",4" ),
|
|
TEXT( ",5" ),
|
|
TEXT( ",6" ),
|
|
TEXT( ",7" ),
|
|
TEXT( ",8" ) };
|
|
|
|
TCHAR *m_pszStopSuf[] = { TEXT( ",1" ),
|
|
TEXT( ",1.5" ),
|
|
TEXT( ",2 " ) };
|
|
|
|
TCHAR *m_pszFlowSuf[] = { TEXT( ",x" ),
|
|
TEXT( ",p" ),
|
|
TEXT( " " ) };
|
|
|
|
|
|
//==========================================================================
|
|
// Local Function Prototypes
|
|
//==========================================================================
|
|
|
|
BOOL AdvancedPortDlg( HWND hDlg, UINT message, DWORD wParam, LONG lParam );
|
|
BOOL CheckBaseIOSetting( LPTSTR );
|
|
BOOL CommDlg( HWND hDlg, UINT message, DWORD wParam, LONG lParam );
|
|
|
|
HDEVINFO
|
|
OpenPnPSerialDeviceInstance(
|
|
IN HWND hwndParent,
|
|
IN LPCTSTR SerialKeyName,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData
|
|
);
|
|
|
|
INT
|
|
DoPnPAdvancedPortDialog(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN HWND hwndParent,
|
|
IN BOOL FirstTime,
|
|
OUT PHKEY phPortKey OPTIONAL
|
|
);
|
|
|
|
DWORD
|
|
InstallPnPSerialPort(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData
|
|
);
|
|
|
|
BOOL
|
|
FindDuplicateDeviceInstance(
|
|
IN DEVINST DevInst,
|
|
OUT PINT ComPortNumber,
|
|
OUT PINT SerialDeviceId
|
|
);
|
|
|
|
BOOL
|
|
GetSerialPortDevInstConfig(
|
|
IN DEVINST DevInst,
|
|
IN ULONG LogConfigType,
|
|
OUT PIO_RESOURCE IoResource,
|
|
OUT PIRQ_RESOURCE IrqResource
|
|
);
|
|
|
|
BOOL
|
|
SearchForSerialControllerDup(
|
|
IN LPTSTR pszAdapter,
|
|
IN PDWORDLONG pIoBase,
|
|
IN ULONG Irq,
|
|
OUT PINT ComPortNumber
|
|
);
|
|
|
|
BOOL
|
|
GetPortValues(
|
|
IN PCM_FULL_RESOURCE_DESCRIPTOR pRes,
|
|
OUT PDWORDLONG pullPort,
|
|
OUT PULONG pulIrq
|
|
);
|
|
|
|
BOOL
|
|
SearchForResourceMapMatch(
|
|
IN PDWORDLONG pIoBase,
|
|
IN ULONG Irq,
|
|
OUT PINT SerialDeviceId
|
|
);
|
|
|
|
VOID
|
|
GetComPortForSerialDevice(
|
|
IN INT SerialDeviceId,
|
|
IN OUT PINT ComPortNumber
|
|
);
|
|
|
|
BOOL
|
|
CALLBACK
|
|
AddPropSheetPageProc(
|
|
IN HPROPSHEETPAGE hpage,
|
|
IN LPARAM lParam
|
|
);
|
|
|
|
BOOL
|
|
APIENTRY
|
|
GeneralAdvPortsDlg(
|
|
IN HWND hDlg,
|
|
IN UINT uMessage,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
);
|
|
|
|
|
|
//==========================================================================
|
|
// Functions
|
|
//==========================================================================
|
|
|
|
BOOL ChkCommSettings( HWND hDlg )
|
|
{
|
|
TCHAR szTest[ 133 ];
|
|
TCHAR *pszVerify;
|
|
|
|
SendDlgItemMessage( hDlg, PORT_BAUDRATE, WM_GETTEXT, 80, (LPARAM) szTest );
|
|
|
|
for( pszVerify = szTest; *pszVerify != TEXT( '\0' ); pszVerify++ )
|
|
{
|
|
if( ( *pszVerify < TEXT( '0' ) ) || ( *pszVerify > TEXT( '9' ) ) )
|
|
{
|
|
if( !LoadString( g_hInst, ERRORS, szTest, CharSizeOf( szTest ) ) )
|
|
ErrMemDlg( hDlg );
|
|
else
|
|
MessageBox( hDlg, szTest, g_szPortsApplet,
|
|
MB_OK | MB_ICONINFORMATION );
|
|
|
|
//
|
|
// ERROR EXIT
|
|
//
|
|
|
|
return( FALSE );
|
|
}
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOL CheckBaseIOSetting( LPTSTR lpszBaseIO )
|
|
{
|
|
LPTSTR lpch;
|
|
BOOL bRet = TRUE;
|
|
|
|
CharUpper( lpszBaseIO );
|
|
|
|
for( lpch = lpszBaseIO; *lpch; lpch++ )
|
|
if( ( *lpch < TEXT( '0' ) || *lpch > TEXT( '9' ) )
|
|
&& (*lpch < TEXT( 'A' ) || *lpch > TEXT( 'F' ) ) )
|
|
{
|
|
bRet = FALSE;
|
|
break;
|
|
}
|
|
|
|
return( bRet );
|
|
}
|
|
|
|
|
|
//
|
|
// Set dialog items to defaults from win.ini for given port
|
|
// Port is zero based, 0 = com1, 1 = com2, etc.
|
|
//
|
|
// void SetFromWin( HWND hDlg, int Port )
|
|
//
|
|
|
|
void SetFromWin( HWND hDlg )
|
|
{
|
|
TCHAR szParms[ 81 ]; // parms from win.ini for port
|
|
TCHAR *pszCur, *pszNext;
|
|
int nIndex;
|
|
int baud;
|
|
|
|
// m_szComPort[3] = (TCHAR) ( TEXT( '1' ) + Port );
|
|
|
|
GetProfileString( m_szPorts, m_szComPort, g_szNull, szParms, 81 );
|
|
|
|
StripBlanks( szParms );
|
|
|
|
pszCur = szParms;
|
|
|
|
//
|
|
// baud rate
|
|
//
|
|
|
|
pszNext = strscan( pszCur, m_szComma );
|
|
|
|
if( *pszNext )
|
|
*pszNext++ = 0;
|
|
|
|
//
|
|
// Find current Baud Rate selection
|
|
//
|
|
|
|
nIndex = (short) SendDlgItemMessage( hDlg, PORT_BAUDRATE,
|
|
CB_FINDSTRING,
|
|
(WPARAM) -1,
|
|
(LPARAM) pszCur );
|
|
|
|
nIndex = (nIndex == CB_ERR) ? 0 : nIndex;
|
|
|
|
SendDlgItemMessage( hDlg, PORT_BAUDRATE, CB_SETCURSEL, nIndex, 0L );
|
|
|
|
pszCur = pszNext;
|
|
|
|
//
|
|
// parity
|
|
//
|
|
|
|
pszNext = strscan( pszCur, m_szComma );
|
|
|
|
if( *pszNext )
|
|
*pszNext++ = 0;
|
|
|
|
StripBlanks( pszCur );
|
|
|
|
switch( *pszCur )
|
|
{
|
|
case TEXT( 'o' ):
|
|
nIndex = PAR_ODD;
|
|
break;
|
|
|
|
case TEXT( 'e' ):
|
|
nIndex = PAR_EVEN;
|
|
break;
|
|
|
|
case TEXT( 'n' ):
|
|
nIndex = PAR_NONE;
|
|
break;
|
|
|
|
case TEXT( 'm' ):
|
|
nIndex = PAR_MARK;
|
|
break;
|
|
|
|
case TEXT( 's' ):
|
|
nIndex = PAR_SPACE;
|
|
break;
|
|
|
|
default:
|
|
nIndex = DEF_PARITY;
|
|
break;
|
|
}
|
|
|
|
SendDlgItemMessage( hDlg, PORT_PARITY, CB_SETCURSEL, nIndex, 0L );
|
|
pszCur = pszNext;
|
|
|
|
//
|
|
// word length
|
|
//
|
|
|
|
pszNext = strscan( pszCur, m_szComma );
|
|
|
|
if( *pszNext )
|
|
*pszNext++ = 0;
|
|
|
|
StripBlanks( pszCur );
|
|
nIndex = ( *pszCur - TEXT( '4' ) );
|
|
|
|
if ( (nIndex >= 0) && (nIndex <= 4) )
|
|
SendDlgItemMessage( hDlg, PORT_DATABITS, CB_SETCURSEL, nIndex, 0L );
|
|
else
|
|
SendDlgItemMessage( hDlg, PORT_DATABITS, CB_SETCURSEL, DEF_WORD, 0L );
|
|
|
|
pszCur = pszNext;
|
|
|
|
//
|
|
// stop bits
|
|
//
|
|
|
|
pszNext = strscan( pszCur, m_szComma );
|
|
|
|
if( *pszNext )
|
|
*pszNext++ = 0;
|
|
|
|
StripBlanks( pszCur );
|
|
|
|
if( !lstrcmp( pszCur, TEXT( "1" ) ) )
|
|
SendDlgItemMessage( hDlg, PORT_STOPBITS, CB_SETCURSEL, STOP_1, 0L );
|
|
else if( !lstrcmp( pszCur, TEXT( "1.5" ) ) )
|
|
SendDlgItemMessage( hDlg, PORT_STOPBITS, CB_SETCURSEL, STOP_15, 0L );
|
|
else if( !lstrcmp( pszCur, TEXT( "2" ) ) )
|
|
SendDlgItemMessage( hDlg, PORT_STOPBITS, CB_SETCURSEL, STOP_2, 0L );
|
|
else
|
|
SendDlgItemMessage( hDlg, PORT_STOPBITS, CB_SETCURSEL, DEF_STOP, 0L );
|
|
|
|
pszCur = pszNext;
|
|
|
|
//
|
|
// handshaking: Hardware, xon/xoff, or none
|
|
//
|
|
|
|
pszNext = strscan( pszCur, m_szComma );
|
|
|
|
if( *pszNext )
|
|
*pszNext++ = 0;
|
|
|
|
StripBlanks( pszCur );
|
|
|
|
if( *pszCur == TEXT( 'p' ) )
|
|
SendDlgItemMessage( hDlg, PORT_FLOWCTL, CB_SETCURSEL, FLOW_HARD, 0L );
|
|
else if( *pszCur == TEXT( 'x' ) )
|
|
SendDlgItemMessage( hDlg, PORT_FLOWCTL, CB_SETCURSEL, FLOW_XON, 0L );
|
|
else
|
|
SendDlgItemMessage( hDlg, PORT_FLOWCTL, CB_SETCURSEL, FLOW_NONE, 0L );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// This routine reads off the settings from the dialog and writes them
|
|
// out to win.ini
|
|
//
|
|
// This routine was completely overhauled to work with the new 3.1 Dialog
|
|
// box. Modified by C. Stevens, Oct. 90
|
|
//
|
|
|
|
void CommPortsToWin( HWND hDlg )
|
|
{
|
|
TCHAR szBuild[ PATHMAX ];
|
|
int i;
|
|
|
|
//
|
|
// Get the baud rate
|
|
//
|
|
|
|
i = SendDlgItemMessage( hDlg, PORT_BAUDRATE, WM_GETTEXT, 18,
|
|
(LPARAM) szBuild );
|
|
|
|
if( i == 0 )
|
|
return;
|
|
|
|
//
|
|
// Get the parity setting
|
|
//
|
|
|
|
i = SendDlgItemMessage( hDlg, PORT_PARITY, CB_GETCURSEL, 0, 0L );
|
|
|
|
if( ( i == CB_ERR ) || ( i == CB_ERRSPACE ) )
|
|
return;
|
|
|
|
lstrcat( szBuild, m_pszParitySuf[ i ] );
|
|
|
|
//
|
|
// Get the word length
|
|
//
|
|
|
|
i = SendDlgItemMessage( hDlg, PORT_DATABITS, CB_GETCURSEL, 0, 0L );
|
|
|
|
if( ( i == CB_ERR ) || ( i == CB_ERRSPACE ) )
|
|
return;
|
|
|
|
lstrcat( szBuild, m_pszLenSuf[ i ] );
|
|
|
|
//
|
|
// Get the stop bits
|
|
//
|
|
|
|
i = SendDlgItemMessage( hDlg, PORT_STOPBITS, CB_GETCURSEL, 0, 0L );
|
|
|
|
if( ( i == CB_ERR ) || ( i == CB_ERRSPACE ) )
|
|
return;
|
|
|
|
lstrcat( szBuild, m_pszStopSuf[ i ] );
|
|
|
|
//
|
|
// Get the flow control
|
|
//
|
|
|
|
i = SendDlgItemMessage( hDlg, PORT_FLOWCTL, CB_GETCURSEL, 0, 0L );
|
|
|
|
if( ( i == CB_ERR ) || ( i == CB_ERRSPACE ) )
|
|
return;
|
|
|
|
lstrcat( szBuild, m_pszFlowSuf[ i ] );
|
|
|
|
//
|
|
// Write settings string to [ports] section in win.ini
|
|
//
|
|
|
|
WriteProfileString( m_szPorts, m_szComPort, szBuild );
|
|
|
|
SendWinIniChange( (LPTSTR) m_szPorts );
|
|
}
|
|
|
|
|
|
BOOL ShortCommDlg( HWND hDlg, UINT message, DWORD wParam, LONG lParam )
|
|
{
|
|
int i, j, nEntries;
|
|
DWORD dwSize, dwBufz;
|
|
DWORD dwType;
|
|
HKEY hkey, hkeySub;
|
|
TCHAR szSerial[ 40 ];
|
|
TCHAR szCom[ 40 ];
|
|
BOOL PortIsPnP;
|
|
HDEVINFO DeviceInfoSet;
|
|
SP_DEVINFO_DATA DeviceInfoData;
|
|
TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
|
|
DEVINST DevInst;
|
|
|
|
//
|
|
// 1 based array of all allowable COM ports
|
|
//
|
|
|
|
BOOL bPorts[ MAX_COM_PORT+1 ];
|
|
|
|
switch( message )
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
|
HourGlass( TRUE );
|
|
|
|
//
|
|
// Init globals
|
|
//
|
|
|
|
bResetTitle = FALSE;
|
|
bResetLB = FALSE;
|
|
|
|
bNewPort = FALSE;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Create a MERGED listing of COM ports between DeviceMap and
|
|
// Services node.
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Always clear BOOL array
|
|
//
|
|
|
|
for( i = 0; i <= MAX_COM_PORT; bPorts[ i++ ] = FALSE )
|
|
;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Get list of valid COM ports from DEVICEMAP in registry
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Reset list box before display.
|
|
//
|
|
|
|
SendDlgItemMessage( hDlg, PORT_LB, LB_RESETCONTENT, 0, 0L );
|
|
|
|
if( !RegOpenKeyEx( HKEY_LOCAL_MACHINE, m_szRegSerialMap,
|
|
0L, KEY_READ, &hkey ) )
|
|
{
|
|
dwBufz = sizeof( szSerial );
|
|
dwSize = sizeof( szCom );
|
|
nEntries = i = 0;
|
|
|
|
while( !RegEnumValue( hkey, i++, szSerial, &dwBufz,
|
|
NULL, &dwType, (LPBYTE) szCom, &dwSize ) )
|
|
{
|
|
if( dwType != REG_SZ )
|
|
continue;
|
|
|
|
//
|
|
// Append ":" char to end of szCom string
|
|
//
|
|
|
|
lstrcat( szCom, m_szColon );
|
|
|
|
//
|
|
// Get number of COM port (go past "COM" in string)
|
|
//
|
|
|
|
j = myatoi( &szCom[ 3 ] );
|
|
|
|
if( j <= MAX_COM_PORT )
|
|
bPorts[ j ] = TRUE;
|
|
else
|
|
continue;
|
|
|
|
//
|
|
// Put Port name string in ListBox
|
|
//
|
|
|
|
if( ( j = (int) SendDlgItemMessage( hDlg,
|
|
PORT_LB,
|
|
LB_INSERTSTRING,
|
|
(WPARAM)(LONG) -1,
|
|
(LPARAM) szCom))
|
|
>= 0 )
|
|
{
|
|
SendDlgItemMessage( hDlg, SERIAL_DBASE, LB_INSERTSTRING,
|
|
j, (LPARAM) szSerial );
|
|
|
|
//
|
|
// Set item data associated with this list entry to indicate
|
|
// it's not a PnP ISA device (this may be updated later).
|
|
//
|
|
SendDlgItemMessage( hDlg, SERIAL_DBASE, LB_SETITEMDATA,
|
|
j, (LPARAM) FALSE );
|
|
|
|
++nEntries;
|
|
}
|
|
|
|
dwSize = sizeof( szCom );
|
|
dwBufz = sizeof( szSerial );
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Get list of valid COM ports from Services Node in registry
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
hkey = NULL;
|
|
|
|
//
|
|
// Read Serial keys at Services Node
|
|
//
|
|
|
|
if( !RegOpenKeyEx( HKEY_LOCAL_MACHINE, // Root key
|
|
m_szRegSerialParam, // Subkey to open
|
|
0L, // Reserved
|
|
KEY_READ, // SAM
|
|
&hkey ) ) // return handle
|
|
{
|
|
//
|
|
// Enumerate all keys under Serial\Parameters
|
|
//
|
|
|
|
i = 0;
|
|
|
|
while( RegEnumKey (hkey, i++, szSerial, CharSizeOf( szSerial ) )
|
|
!= ERROR_NO_MORE_ITEMS )
|
|
{
|
|
hkeySub = NULL;
|
|
|
|
if( !RegOpenKeyEx( hkey, // Root key
|
|
szSerial, // Subkey to open
|
|
0L, // Reserved
|
|
KEY_READ, // SAM
|
|
&hkeySub ) ) // return handle
|
|
{
|
|
//
|
|
// Get DosDevices value for this Serial key
|
|
//
|
|
|
|
dwSize = sizeof( szCom );
|
|
|
|
if( !RegQueryValueEx( hkeySub, m_szDosDev, NULL, &dwType,
|
|
(LPBYTE) szCom, &dwSize ) )
|
|
{
|
|
if( dwType != REG_SZ )
|
|
goto TryNextSubKey;
|
|
|
|
//
|
|
// Check for the existence of a 'PnPDeviceId" value entry
|
|
// in this key. If present, this value indicates what the
|
|
// associated Plug&Play device instance is for this PnP ISA
|
|
// enumerated device.
|
|
//
|
|
dwSize = sizeof(DeviceInstanceId);
|
|
PortIsPnP = ((RegQueryValueEx(hkeySub,
|
|
m_szPnPDeviceId,
|
|
NULL,
|
|
&dwType,
|
|
(PBYTE)DeviceInstanceId,
|
|
&dwSize) == ERROR_SUCCESS)
|
|
&& (dwType == REG_SZ));
|
|
|
|
if(PortIsPnP)
|
|
{
|
|
//
|
|
// Check to see if this device is currently present.
|
|
//
|
|
if(CM_Locate_DevInst(&DevInst,
|
|
(DEVINSTID)DeviceInstanceId,
|
|
CM_LOCATE_DEVINST_NORMAL) != CR_SUCCESS) {
|
|
//
|
|
// Not present--skip this device.
|
|
//
|
|
goto TryNextSubKey;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Append ":" char to end of szCom string
|
|
//
|
|
|
|
lstrcat( szCom, m_szColon );
|
|
|
|
//
|
|
// Get number of COM port (go past "COM" in string)
|
|
//
|
|
|
|
j = myatoi( &szCom[ 3 ] );
|
|
|
|
if( j <= MAX_COM_PORT )
|
|
{
|
|
if( !bPorts[ j ] )
|
|
{
|
|
bPorts[ j ] = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We already found this port in the device map, but finding
|
|
// it under the serial key may have indicated that it's a
|
|
// PnP ISA modem. If so, then set the item data associated
|
|
// with this port to TRUE.
|
|
//
|
|
if(PortIsPnP)
|
|
{
|
|
//
|
|
// find this item in the serial list.
|
|
//
|
|
if( ( j = (int) SendDlgItemMessage (hDlg,
|
|
SERIAL_DBASE,
|
|
LB_FINDSTRINGEXACT,
|
|
(WPARAM) -1,
|
|
(LPARAM) szSerial ) )
|
|
>= 0 )
|
|
{
|
|
SendDlgItemMessage( hDlg, SERIAL_DBASE, LB_SETITEMDATA,
|
|
j, (LPARAM) TRUE );
|
|
}
|
|
}
|
|
|
|
goto TryNextSubKey; // nothing more to do with this port
|
|
}
|
|
}
|
|
else
|
|
{
|
|
goto TryNextSubKey;
|
|
}
|
|
|
|
//
|
|
// Put Port name string in ListBox
|
|
//
|
|
|
|
if( ( j = (int) SendDlgItemMessage (hDlg,
|
|
PORT_LB,
|
|
LB_INSERTSTRING,
|
|
(WPARAM) -1,
|
|
(LPARAM) szCom ) )
|
|
>= 0 )
|
|
{
|
|
SendDlgItemMessage( hDlg,
|
|
SERIAL_DBASE,
|
|
LB_INSERTSTRING,
|
|
j,
|
|
(LPARAM) szSerial );
|
|
//
|
|
// Set item data associated with this list entry to indicate
|
|
// whether or not it's a PnP ISA device.
|
|
//
|
|
SendDlgItemMessage( hDlg, SERIAL_DBASE, LB_SETITEMDATA,
|
|
j, (LPARAM) PortIsPnP );
|
|
|
|
++nEntries;
|
|
}
|
|
}
|
|
TryNextSubKey:
|
|
RegCloseKey( hkeySub );
|
|
}
|
|
}
|
|
RegCloseKey( hkey );
|
|
}
|
|
|
|
//
|
|
// By default, select the first item in the Listbox
|
|
//
|
|
|
|
SendDlgItemMessage( hDlg, PORT_LB, LB_SETCURSEL, 0, 0L );
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Check for Greying out ADD and DELETE buttons
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Check for registry access to the Services nodes for
|
|
// adding new ports.
|
|
//
|
|
|
|
if( (RegOpenKeyEx( HKEY_LOCAL_MACHINE, // Root key
|
|
m_szRegSerialParam, // Subkey to open
|
|
0L, // Reserved
|
|
KEY_READ | KEY_WRITE, // SAM
|
|
&hkey ) // return handle
|
|
!= ERROR_SUCCESS ) )
|
|
{
|
|
EnableWindow( GetDlgItem( hDlg, PORT_ADD ), FALSE );
|
|
EnableWindow( GetDlgItem( hDlg, PORT_DELETE ), FALSE );
|
|
RegCloseKey( hkey );
|
|
}
|
|
|
|
HourGlass( FALSE );
|
|
return TRUE;
|
|
|
|
|
|
case WM_COMMAND:
|
|
switch( LOWORD( wParam ) )
|
|
{
|
|
case IDD_HELP:
|
|
goto DoHelp;
|
|
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
EndDialog( hDlg, LOWORD( wParam ) );
|
|
break;
|
|
|
|
case PORT_LB:
|
|
//
|
|
// If user Double Clicks on listbox item, react as though they
|
|
// clicked on "Settings" button
|
|
//
|
|
|
|
if( HIWORD( wParam ) != LBN_DBLCLK )
|
|
break;
|
|
|
|
//
|
|
// fall through...
|
|
//
|
|
|
|
case PORT_SETTING:
|
|
i = SendDlgItemMessage( hDlg, PORT_LB, LB_GETCURSEL, 0, 0L );
|
|
|
|
if( i != LB_ERR )
|
|
{
|
|
//
|
|
// Set the global COM PORT string for later use
|
|
//
|
|
|
|
SendDlgItemMessage( hDlg, PORT_LB, LB_GETTEXT, i,
|
|
(LPARAM) m_szComPort );
|
|
|
|
SendDlgItemMessage( hDlg, SERIAL_DBASE, LB_GETTEXT, i,
|
|
(LPARAM) m_szSerialKey );
|
|
|
|
//
|
|
// Retrieve the item data associated with the serial key entry, to
|
|
// determine whether this port is a PnP ISA device.
|
|
//
|
|
m_PortIsPnP = SendDlgItemMessage( hDlg, SERIAL_DBASE, LB_GETITEMDATA, i, 0 );
|
|
if( m_PortIsPnP == LB_ERR )
|
|
{
|
|
m_PortIsPnP = FALSE;
|
|
}
|
|
|
|
if( DoDialogBoxParam( DLG_PORTS2, hDlg, (DLGPROC) CommDlg,
|
|
IDH_DLG_PORTS2, 0L ) == IDOK )
|
|
{
|
|
SetDlgItemText( hDlg, IDOK, g_szClose );
|
|
}
|
|
|
|
if( bResetLB )
|
|
{
|
|
//
|
|
// User changed COM Port Number, delete old, add new
|
|
//
|
|
|
|
SendDlgItemMessage( hDlg, PORT_LB, LB_DELETESTRING, i, 0L );
|
|
SendDlgItemMessage( hDlg, SERIAL_DBASE, LB_DELETESTRING,
|
|
i, 0L );
|
|
|
|
//
|
|
// Put New Port and Serial name strings in ListBoxes
|
|
//
|
|
|
|
if( ( j = (int) SendDlgItemMessage( hDlg,
|
|
PORT_LB,
|
|
LB_INSERTSTRING,
|
|
(WPARAM)(LONG)-1,
|
|
(LPARAM) m_szComPort) )
|
|
>= 0)
|
|
{
|
|
SendDlgItemMessage( hDlg, SERIAL_DBASE, LB_INSERTSTRING,
|
|
j, (LPARAM) m_szSerialKey );
|
|
|
|
SendDlgItemMessage( hDlg, SERIAL_DBASE, LB_SETITEMDATA,
|
|
j, (LPARAM) m_PortIsPnP );
|
|
}
|
|
|
|
j = (j > 0) ? j : 0;
|
|
|
|
//
|
|
// Select an item in the Listbox
|
|
//
|
|
|
|
SendDlgItemMessage( hDlg, PORT_LB, LB_SETCURSEL, j, 0L );
|
|
|
|
//
|
|
// Reset globals
|
|
//
|
|
|
|
bResetTitle = FALSE;
|
|
bResetLB = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PORT_ADD:
|
|
{
|
|
DWORD dwSave;
|
|
|
|
//
|
|
// Set global flag for Advanced Dialog
|
|
//
|
|
|
|
bNewPort = TRUE;
|
|
|
|
dwSave = g_dwContext;
|
|
g_dwContext = IDH_DLG_PORTS3;
|
|
|
|
//
|
|
// Setup some Advanced parameters for this port now
|
|
//
|
|
|
|
if( DialogBox( g_hInst, (LPTSTR) MAKEINTRESOURCE( DLG_PORTS3 ),
|
|
hDlg, (DLGPROC) AdvancedPortDlg ) == 1 )
|
|
{
|
|
SetDlgItemText( hDlg, IDOK, g_szClose );
|
|
|
|
//
|
|
// Add new port name to listbox
|
|
// Add new serial value to SERIAL_DBASE listbox
|
|
//
|
|
|
|
if( ( j = (int) SendDlgItemMessage( hDlg, PORT_LB, LB_ADDSTRING,
|
|
(WPARAM)(LONG)-1,
|
|
(LPARAM) m_szComPort)) >= 0)
|
|
{
|
|
SendDlgItemMessage( hDlg, SERIAL_DBASE, LB_INSERTSTRING,
|
|
j, (LPARAM) m_szSerialKey );
|
|
//
|
|
// Set item data associated with this list entry to indicate
|
|
// it's not a PnP ISA device.
|
|
//
|
|
SendDlgItemMessage( hDlg, SERIAL_DBASE, LB_SETITEMDATA,
|
|
j, (LPARAM) FALSE );
|
|
|
|
//
|
|
// Select an item in the Listbox
|
|
//
|
|
|
|
SendDlgItemMessage( hDlg, PORT_LB, LB_SETCURSEL, j, 0L );
|
|
|
|
SendWinIniChange( m_szPorts );
|
|
}
|
|
}
|
|
|
|
bNewPort = FALSE;
|
|
g_dwContext = dwSave;
|
|
|
|
break;
|
|
}
|
|
|
|
case PORT_DELETE:
|
|
{
|
|
LONG err1, err2;
|
|
/////////////////////////////////////////////////////////////////
|
|
// Check for registry access to both the DeviceMap and
|
|
// Services nodes
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
err1 = RegOpenKeyEx( HKEY_LOCAL_MACHINE, // Root key
|
|
m_szRegSerialMap, // Subkey to open
|
|
0L, // Reserved
|
|
KEY_READ | KEY_WRITE, // SAM
|
|
&hkey ); // return handle
|
|
|
|
if (err1 != ERROR_SUCCESS ) {
|
|
hkey = NULL;
|
|
}
|
|
|
|
err2 = RegOpenKeyEx( HKEY_LOCAL_MACHINE, // Root key
|
|
m_szRegSerialParam, // Subkey to open
|
|
0L, // Reserved
|
|
KEY_READ | KEY_WRITE, // SAM
|
|
&hkeySub ); // return handle
|
|
|
|
if ( err2 != ERROR_SUCCESS ) {
|
|
hkeySub = NULL;
|
|
}
|
|
|
|
// Could not open either key, assume that we don't have permission
|
|
if ((hkey == NULL && hkeySub == NULL) || err1 == ERROR_ACCESS_DENIED || err2 == ERROR_ACCESS_DENIED) {
|
|
|
|
MyMessageBox( hDlg, MYPORT+7, INITS+1,
|
|
MB_OKCANCEL | MB_ICONEXCLAMATION );
|
|
break;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Confirm deletion
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
i = MyMessageBox( hDlg, MYPORT+6, INITS+1,
|
|
MB_OKCANCEL | MB_ICONEXCLAMATION );
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Delete everything associated with COM port
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
if( i == IDOK )
|
|
{
|
|
SetDlgItemText( hDlg, IDOK, g_szClose );
|
|
|
|
//
|
|
// Get current selection
|
|
//
|
|
|
|
i = SendDlgItemMessage( hDlg, PORT_LB, LB_GETCURSEL, 0, 0L );
|
|
|
|
SendDlgItemMessage( hDlg, SERIAL_DBASE, LB_GETTEXT, i,
|
|
(LPARAM) szSerial );
|
|
|
|
SendDlgItemMessage( hDlg, PORT_LB, LB_GETTEXT, i,
|
|
(LPARAM) szCom );
|
|
|
|
//
|
|
// Retrieve the item data associated with the serial key entry, to
|
|
// determine whether this port is a PnP ISA device.
|
|
//
|
|
PortIsPnP = SendDlgItemMessage( hDlg, SERIAL_DBASE, LB_GETITEMDATA, i, 0 );
|
|
if( PortIsPnP == LB_ERR )
|
|
{
|
|
PortIsPnP = FALSE;
|
|
}
|
|
|
|
//
|
|
// Delete Registry entries for this COM port
|
|
//
|
|
// Delete Value entry in DeviceMap\SERIALCOMM key
|
|
// Delete entire key under Services\Serial\Parameters node
|
|
//
|
|
|
|
if (hkey != NULL) {
|
|
RegDeleteValue( hkey, szSerial );
|
|
RegCloseKey( hkey );
|
|
}
|
|
|
|
if (hkeySub != NULL) {
|
|
|
|
if (PortIsPnP) {
|
|
//
|
|
// This is a PnP ISA port, so we need to retrieve the corresponding
|
|
// device instance, and remove it.
|
|
//
|
|
DeviceInfoSet = OpenPnPSerialDeviceInstance(hDlg, szSerial, &DeviceInfoData);
|
|
if(DeviceInfoSet != INVALID_HANDLE_VALUE) {
|
|
SetupDiCallClassInstaller(DIF_REMOVE, DeviceInfoSet, &DeviceInfoData);
|
|
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
|
}
|
|
}
|
|
|
|
RegDeleteKey( hkeySub, szSerial );
|
|
RegCloseKey( hkeySub );
|
|
}
|
|
|
|
//
|
|
// Delete WIN.INI entry - write NULL string to [ports] section
|
|
//
|
|
|
|
WriteProfileString( m_szPorts, szCom, (LPTSTR) NULL );
|
|
|
|
//
|
|
// Delete ListBox items
|
|
//
|
|
|
|
SendDlgItemMessage( hDlg, PORT_LB, LB_DELETESTRING, i, 0L );
|
|
SendDlgItemMessage( hDlg, SERIAL_DBASE, LB_DELETESTRING, i, 0L );
|
|
|
|
//
|
|
// Selection next item in ListBox
|
|
//
|
|
|
|
j = SendDlgItemMessage( hDlg, PORT_LB, LB_GETCOUNT, 0, 0L );
|
|
|
|
j = (j > i) ? i : j;
|
|
|
|
//
|
|
// Select an item in the Listbox
|
|
//
|
|
|
|
SendDlgItemMessage( hDlg, PORT_LB, LB_SETCURSEL, j, 0L );
|
|
|
|
//
|
|
// Let the rest of the world know also
|
|
//
|
|
|
|
SendWinIniChange( m_szPorts );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
if( message == g_wHelpMessage )
|
|
{
|
|
DoHelp:
|
|
SysHelp( hDlg );
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
VOID SetCBFromRes( HWND hCB, DWORD wRes, DWORD wDef )
|
|
{
|
|
TCHAR szTemp[ 258 ], cSep;
|
|
LPTSTR pThis, pThat;
|
|
|
|
|
|
if( !LoadString( g_hInst, wRes, szTemp, CharSizeOf( szTemp ) ) )
|
|
return;
|
|
|
|
for( pThis = szTemp, cSep = *pThis++; pThis; pThis = pThat )
|
|
{
|
|
if( pThat = _tcschr( pThis, cSep ) )
|
|
*pThat++ = TEXT( '\0' );
|
|
|
|
SendMessage( hCB, CB_ADDSTRING, 0, (LPARAM) pThis );
|
|
}
|
|
|
|
SendMessage( hCB, CB_SETCURSEL, wDef, 0L );
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CommDlg
|
|
//
|
|
// This is the communications ports setup dialog. It just reads all the
|
|
// items, munges them all together into a string, and then writes it out
|
|
// to win.ini. This routine does not interact with the comm driver. It
|
|
// is the responsibility of each app that uses the comm ports to go first
|
|
// to win.ini, read the appropriate line, and then set up the comm port
|
|
// accordingly
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CommDlg(HWND hDlg, UINT message, DWORD wParam, LONG lParam)
|
|
{
|
|
TCHAR szTitle[ 81 ];
|
|
TCHAR szTitleFormat[ 81 ];
|
|
short nIndex;
|
|
HWND hParent;
|
|
DWORD dwMask;
|
|
HANDLE hComm;
|
|
COMMPROP cpComm;
|
|
|
|
switch( message )
|
|
{
|
|
case WM_INITDIALOG:
|
|
/* init to defaults */
|
|
|
|
// Get info about COM port from Serial driver
|
|
hComm = CreateFile( m_szComPort,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
if( ( hComm != INVALID_HANDLE_VALUE ) &&
|
|
GetCommProperties( hComm, &cpComm ) )
|
|
{
|
|
//
|
|
// Check baud rate bitmask and only display settable rates
|
|
//
|
|
|
|
for( dwMask = 1, nIndex = 0; m_nBaudRates[ nIndex ]; nIndex++ )
|
|
{
|
|
//
|
|
// BAUD_128K comes before 115200 in bitmask, special checks
|
|
//
|
|
|
|
if( ( cpComm.dwSettableBaud & dwMask ) == BAUD_128K )
|
|
{
|
|
//
|
|
// Check for BAUD_115200 first and put it in
|
|
// before this one
|
|
//
|
|
|
|
if( cpComm.dwSettableBaud & BAUD_115200 )
|
|
{
|
|
MyItoa( m_nBaudRates[ nIndex ], szTitle, 10 );
|
|
|
|
SendDlgItemMessage( hDlg, PORT_BAUDRATE, CB_ADDSTRING,
|
|
0, (LPARAM) szTitle );
|
|
}
|
|
|
|
//
|
|
// Now increment to 128K baud rate value
|
|
//
|
|
|
|
nIndex++;
|
|
|
|
MyItoa( m_nBaudRates[ nIndex ], szTitle, 10 );
|
|
|
|
SendDlgItemMessage( hDlg, PORT_BAUDRATE, CB_ADDSTRING,
|
|
0, (LPARAM) szTitle );
|
|
|
|
//
|
|
// Move mask over another bit since we have checked
|
|
// for the 115200 value
|
|
//
|
|
|
|
dwMask <<= 1;
|
|
}
|
|
else if( ( cpComm.dwSettableBaud & dwMask ) == BAUD_115200 )
|
|
{
|
|
MyItoa( m_nBaudRates[ nIndex - 1 ], szTitle, 10 );
|
|
|
|
SendDlgItemMessage( hDlg, PORT_BAUDRATE, CB_ADDSTRING,
|
|
0, (LPARAM) szTitle );
|
|
}
|
|
else if( cpComm.dwSettableBaud & dwMask )
|
|
{
|
|
MyItoa( m_nBaudRates[ nIndex ], szTitle, 10 );
|
|
|
|
SendDlgItemMessage( hDlg, PORT_BAUDRATE, CB_ADDSTRING,
|
|
0, (LPARAM) szTitle );
|
|
}
|
|
|
|
dwMask <<= 1;
|
|
}
|
|
CloseHandle( hComm );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Open failure, just list all of the baud rates
|
|
//
|
|
|
|
for( nIndex = 0; m_nBaudRates[nIndex]; nIndex++ )
|
|
{
|
|
MyItoa( m_nBaudRates[ nIndex ], szTitle, 10 );
|
|
|
|
SendDlgItemMessage( hDlg, PORT_BAUDRATE, CB_ADDSTRING, 0,
|
|
(LPARAM) szTitle );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set 9600 as default baud selection
|
|
//
|
|
|
|
nIndex = (short) SendDlgItemMessage( hDlg,
|
|
PORT_BAUDRATE,
|
|
CB_FINDSTRING,
|
|
(WPARAM) -1,
|
|
(LPARAM) m_sz9600 );
|
|
|
|
nIndex = (nIndex == CB_ERR) ? 0 : nIndex;
|
|
|
|
SendDlgItemMessage( hDlg, PORT_BAUDRATE, CB_SETCURSEL, nIndex, 0L );
|
|
|
|
for( nIndex = 0; m_nDataBits[ nIndex ]; nIndex++ )
|
|
{
|
|
MyItoa( m_nDataBits[ nIndex ], szTitle, 10 );
|
|
|
|
SendDlgItemMessage( hDlg, PORT_DATABITS, CB_ADDSTRING, 0,
|
|
(LPARAM) szTitle );
|
|
}
|
|
|
|
SendDlgItemMessage( hDlg, PORT_DATABITS, CB_SETCURSEL, DEF_WORD, 0L );
|
|
|
|
SetCBFromRes( GetDlgItem( hDlg, PORT_PARITY), MYPORT+1, DEF_PARITY );
|
|
SetCBFromRes( GetDlgItem( hDlg, PORT_STOPBITS), MYPORT+2, DEF_STOP );
|
|
SetCBFromRes( GetDlgItem( hDlg, PORT_FLOWCTL), MYPORT+3, DEF_SHAKE );
|
|
|
|
LoadString( g_hInst, MYPORT + 5, szTitleFormat,
|
|
CharSizeOf( szTitleFormat ) );
|
|
|
|
wsprintf( szTitle, szTitleFormat, m_szComPort );
|
|
|
|
SetWindowText( hDlg, szTitle );
|
|
|
|
SetFromWin( hDlg );
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Test code to determine if this is a "Serial" port or "Digiboard" port
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Test global m_szSerialKey string to determine if this is a Serial
|
|
// driver port or a 3rd party (i.e OEM) port. If it is a 3rd party
|
|
// port, we do not attempt to Setup Advanced parameters for it.
|
|
//
|
|
|
|
if( !_tcsstr( m_szSerialKey, m_szSERIAL ) )
|
|
EnableWindow( GetDlgItem( hDlg, PORT_ADVANCED ), FALSE );
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// center and make visible
|
|
//
|
|
|
|
ShowWindow( hDlg, SHOW_OPENWINDOW );
|
|
|
|
return( TRUE );
|
|
break;
|
|
|
|
|
|
case WM_COMMAND:
|
|
switch( LOWORD( wParam ) )
|
|
{
|
|
case IDD_HELP:
|
|
goto DoHelp;
|
|
|
|
case PORT_ADVANCED:
|
|
{
|
|
DWORD dwSave;
|
|
INT DialogReturnCode;
|
|
|
|
dwSave = g_dwContext;
|
|
g_dwContext = IDH_DLG_PORTS3;
|
|
|
|
//
|
|
// For PnP ISA devices (either serial cards or modems), we have to use
|
|
// our Win95-style configuration dialog, in order to be able to tie together
|
|
// the legacy registry information with the Plug&Play information.
|
|
//
|
|
if( m_PortIsPnP )
|
|
{
|
|
HDEVINFO DeviceInfoSet;
|
|
SP_DEVINFO_DATA DeviceInfoData;
|
|
|
|
DeviceInfoSet = OpenPnPSerialDeviceInstance(hDlg,
|
|
m_szSerialKey,
|
|
&DeviceInfoData
|
|
);
|
|
|
|
if(DeviceInfoSet == INVALID_HANDLE_VALUE) {
|
|
DialogReturnCode = 0;
|
|
} else {
|
|
DialogReturnCode = DoPnPAdvancedPortDialog(DeviceInfoSet,
|
|
&DeviceInfoData,
|
|
hDlg,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DialogReturnCode = DialogBox( g_hInst,
|
|
(LPTSTR) MAKEINTRESOURCE( DLG_PORTS3 ),
|
|
hDlg,
|
|
(DLGPROC) AdvancedPortDlg );
|
|
}
|
|
|
|
if( DialogReturnCode == 1 )
|
|
{
|
|
SetDlgItemText( hDlg, IDCANCEL, g_szClose );
|
|
|
|
hParent = GetParent( hDlg );
|
|
|
|
SetDlgItemText( hParent, IDOK, g_szClose );
|
|
|
|
//
|
|
// COM Port Number changed, change our title, tell parent also
|
|
//
|
|
|
|
if( bResetTitle )
|
|
{
|
|
LoadString( g_hInst, MYPORT + 5, szTitleFormat,
|
|
CharSizeOf( szTitleFormat ) );
|
|
|
|
wsprintf( szTitle, szTitleFormat, m_szComPort );
|
|
|
|
SetWindowText( hDlg, szTitle );
|
|
|
|
bResetTitle = FALSE;
|
|
|
|
//
|
|
// Tell parent dlg to reset when we get there
|
|
//
|
|
|
|
bResetLB = TRUE;
|
|
}
|
|
}
|
|
|
|
g_dwContext = dwSave;
|
|
|
|
break;
|
|
}
|
|
|
|
case IDOK:
|
|
if( ChkCommSettings( hDlg ) )
|
|
{
|
|
//
|
|
// change cursor to hourglass
|
|
//
|
|
|
|
HourGlass( TRUE );
|
|
|
|
//
|
|
// store changes to win.ini; broadcast changes to apps
|
|
//
|
|
|
|
CommPortsToWin( hDlg );
|
|
|
|
//
|
|
// change cursor back to arrow
|
|
//
|
|
|
|
HourGlass( FALSE );
|
|
}
|
|
else
|
|
{
|
|
SetFocus( GetDlgItem( hDlg, PORT_BAUDRATE ) );
|
|
SendDlgItemMessage( hDlg, PORT_BAUDRATE, EM_SETSEL, 0, 32767 );
|
|
break;
|
|
}
|
|
/* fall through */
|
|
|
|
case IDCANCEL:
|
|
EndDialog( hDlg, LOWORD( wParam ) );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if( message == g_wHelpMessage )
|
|
{
|
|
DoHelp:
|
|
SysHelp( hDlg );
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// AdvancedPortDlg
|
|
//
|
|
// Note: This dlg uses the global strings m_szComPort and m_szSerialKey.
|
|
// and sets the global BOOL bResetTitle.
|
|
//
|
|
// The global BOOL bNewPort is used to modify behavoir of this
|
|
// dialog slightly when creating new COM ports.
|
|
//
|
|
// DEFAULT values in Base I/O and IRQ controls are only valid for
|
|
// COM1 - COM4 if nothing currently exists for these ports. For all
|
|
// other COM ports, the DEFAULT selection basically means just leaving
|
|
// the current configured value for that port as it is.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define IRQMIN 2
|
|
#define IRQMAX 15
|
|
#define IRQDEF 2
|
|
#define BASEIODEF 1 /* A000 */
|
|
|
|
TCHAR *pszBaseIO[] = { TEXT( "03F8" ), TEXT( "02F8" ), TEXT( "03E8" ),
|
|
TEXT( "02E8" ), TEXT( "02E0" ), TEXT( "\0" ) };
|
|
|
|
BOOL AdvancedPortDlg( HWND hDlg, UINT nMsg, DWORD wParam, LONG lParam )
|
|
{
|
|
TCHAR szFormat[ 200 ];
|
|
TCHAR szBaseIO[ 8 ];
|
|
TCHAR szTitle[ 120 ];
|
|
TCHAR szDef[ 20 ];
|
|
TCHAR szCom[ 40 ];
|
|
TCHAR *pszTemp;
|
|
int nVal;
|
|
int nIndex;
|
|
DWORD dwSize, dwBaseIO, dwFIFO;
|
|
DWORD dwType, dwBaseIRQ;
|
|
BOOL bNone, bWroteToSerialKey;
|
|
HWND hParent;
|
|
int LastCom, NewCom;
|
|
int i, nEntries;
|
|
HKEY hkey;
|
|
|
|
static int nStartIndex;
|
|
static DWORD nFifo;
|
|
static int nPortNumber;
|
|
static TCHAR szStartString[ 10 ];
|
|
static HKEY hkeySerial = NULL;
|
|
static DWORD dwDisposition;
|
|
|
|
|
|
switch ( nMsg )
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
|
{
|
|
TCHAR szSerial[ 40 ];
|
|
int LastSerial, NewSerial;
|
|
|
|
HourGlass( TRUE );
|
|
|
|
dwDisposition = 0;
|
|
|
|
if( bNewPort )
|
|
{
|
|
//////////////////////////////////////////////////////////////////
|
|
// Determine new "Serial" and "Com" values
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
hParent = GetParent( hDlg );
|
|
|
|
//
|
|
// Determine the last "Serial" and "Com" values
|
|
//
|
|
|
|
nEntries = SendDlgItemMessage( hParent, PORT_LB, LB_GETCOUNT, 0, 0 );
|
|
|
|
//
|
|
// Since BIOS usually detects COM1 - COM2
|
|
// New "COMx" port value cannot be less than COM3
|
|
// [stevecat] - for Win NT 3.11 we allow this to be COM1 & COM2
|
|
//
|
|
|
|
NewCom = MIN_COM;
|
|
|
|
//
|
|
// New "Serialxx" value cannot be less than 10,000
|
|
//
|
|
|
|
NewSerial = MIN_SERIAL;
|
|
|
|
//
|
|
// Find last (largest) numbers for COM and SERIAL port numbers
|
|
//
|
|
|
|
for( i = 0; i < nEntries; i++ )
|
|
{
|
|
SendDlgItemMessage( hParent, PORT_LB, LB_GETTEXT,
|
|
i, (LPARAM) szCom );
|
|
|
|
//
|
|
// Get number of Last COM port (go past "COM" in string)
|
|
//
|
|
|
|
LastCom = myatoi( &szCom[ 3 ] );
|
|
|
|
NewCom = max( LastCom+1, NewCom );
|
|
|
|
SendDlgItemMessage( hParent, SERIAL_DBASE, LB_GETTEXT, i,
|
|
(LPARAM) szSerial );
|
|
|
|
//
|
|
// Get number of Last Serial entry (go past "Serial" in string)
|
|
//
|
|
|
|
LastSerial = myatoi( &szSerial[ 6 ] );
|
|
|
|
NewSerial = max( LastSerial+1, NewSerial );
|
|
}
|
|
|
|
//
|
|
// Use NewCom as the recommendation (only) for new COM port number
|
|
//
|
|
|
|
NewCom = (NewCom > MAX_COM_PORT) ? MIN_COM : NewCom;
|
|
|
|
//
|
|
// Setup new global registry SerialKey value
|
|
//
|
|
|
|
wsprintf( m_szSerialKey, TEXT( "%s%d" ), m_szSERIAL, NewSerial );
|
|
|
|
//
|
|
// Set up window title
|
|
//
|
|
|
|
LoadString( g_hInst, MYPORT + 9, szFormat, CharSizeOf( szFormat ) );
|
|
LoadString( g_hInst, MYPORT + 4, szCom, CharSizeOf( szCom ) );
|
|
|
|
wsprintf( szTitle, szFormat, szCom );
|
|
SetWindowText( hDlg, szTitle );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Determine current COM port number
|
|
//
|
|
// NOTE: m_szSerialKey and m_szComPort global vlaues are already set
|
|
//
|
|
// Get number of Last COM port (go past "COM" in string)
|
|
//
|
|
|
|
NewCom = myatoi( &m_szComPort[ 3 ] );
|
|
|
|
//
|
|
// Set up window title
|
|
//
|
|
|
|
LoadString( g_hInst, MYPORT + 9, szFormat, CharSizeOf( szFormat ) );
|
|
|
|
wsprintf( szTitle, szFormat, m_szComPort );
|
|
|
|
SetWindowText( hDlg, szTitle );
|
|
}
|
|
|
|
//
|
|
// Init values for "COM port number" combobox
|
|
//
|
|
|
|
for( i = MIN_COM; i <= MAX_COM_PORT; i++ )
|
|
{
|
|
wsprintf( szCom, TEXT( "%d" ), i );
|
|
SendDlgItemMessage( hDlg, PORT_NUMBER, CB_ADDSTRING, 0,
|
|
(LPARAM) szCom );
|
|
}
|
|
|
|
SendDlgItemMessage (hDlg, PORT_NUMBER, CB_SETCURSEL,
|
|
NewCom-MIN_COM, 0L);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Put selections for Port Base I/O address in combobox
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Limit length of edit boxes
|
|
//
|
|
|
|
SendDlgItemMessage( hDlg, PORT_BASEIO, CB_LIMITTEXT, 4, 0L );
|
|
|
|
//
|
|
// Fill combo box; add "(None)" and numbers
|
|
//
|
|
|
|
if( !bNewPort )
|
|
{
|
|
//
|
|
// "Default" not allowed for new ports
|
|
//
|
|
|
|
LoadString( g_hInst, MYPORT, szDef, CharSizeOf( szDef ) );
|
|
|
|
SendDlgItemMessage( hDlg, PORT_BASEIO, CB_ADDSTRING, 0,
|
|
(LPARAM) szDef );
|
|
}
|
|
|
|
for( nIndex = 0; *pszBaseIO[ nIndex ]; nIndex++ )
|
|
SendDlgItemMessage( hDlg, PORT_BASEIO, CB_ADDSTRING, 0,
|
|
(LPARAM) pszBaseIO[ nIndex ] );
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Put selections for Port IRQ level in combobox
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
if( !bNewPort )
|
|
{
|
|
//
|
|
// "Default" not allowed for new ports
|
|
//
|
|
|
|
SendDlgItemMessage( hDlg, PORT_IRQ, CB_ADDSTRING, 0,
|
|
(LPARAM) szDef );
|
|
}
|
|
|
|
for( nIndex = IRQMAX; nIndex >= IRQMIN; --nIndex )
|
|
{
|
|
wsprintf( szTitle, TEXT( "%d" ), nIndex );
|
|
SendDlgItemMessage( hDlg, PORT_IRQ, CB_ADDSTRING, 0,
|
|
(LPARAM) szTitle );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Get configured values for options from Registry
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Put initial values in edit boxes; note that szDef still
|
|
// contains "Default"
|
|
//
|
|
// NT: The NT serial driver doesn't support the EscapeCommFunction
|
|
// api. We try to get this value from the Registry.
|
|
//
|
|
// Make registry key for this Serial Port to get Advanced I/O
|
|
// settings. And save hkey around for later use on exit
|
|
//
|
|
|
|
hkeySerial = NULL;
|
|
wsprintf( szFormat, m_szRegSerialIO, m_szSerialKey );
|
|
|
|
//
|
|
// For New Ports this will create a new serial key entry
|
|
//
|
|
|
|
if( !RegCreateKeyEx( HKEY_LOCAL_MACHINE, // Root key
|
|
szFormat, // Subkey to open/create
|
|
0L, // Reserved
|
|
NULL, // Class string
|
|
0L, // Options
|
|
KEY_ALL_ACCESS, // SAM
|
|
NULL, // ptr to Security struct
|
|
&hkeySerial, // return handle
|
|
&dwDisposition ) ) // return disposition
|
|
{
|
|
//
|
|
// Try to get the configured Port Base I/O address from Registry
|
|
//
|
|
|
|
dwSize = sizeof( DWORD );
|
|
|
|
if( !RegQueryValueEx( hkeySerial, m_szRegPortAddress, NULL, &dwType,
|
|
(LPBYTE) &dwBaseIO, &dwSize ) )
|
|
{
|
|
if( dwType == REG_DWORD )
|
|
{
|
|
MyUltoa( dwBaseIO, szBaseIO, 16 );
|
|
SetDlgItemText( hDlg, PORT_BASEIO, szBaseIO );
|
|
}
|
|
else
|
|
goto SetDefaultIO;
|
|
}
|
|
else
|
|
{
|
|
SetDefaultIO:
|
|
if( bNewPort )
|
|
{
|
|
//
|
|
// Choose first item in combobox for new ports
|
|
//
|
|
|
|
SendDlgItemMessage( hDlg, PORT_BASEIO, CB_SETCURSEL, 0, 0 );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If this is port COM1, 2, 3 or 4 allow open to continue
|
|
// and set all controls for with default values.
|
|
//
|
|
|
|
if( NewCom <= 4 )
|
|
{
|
|
SetDlgItemText( hDlg, PORT_BASEIO, szDef );
|
|
goto SpecialCom1to4;
|
|
}
|
|
|
|
//
|
|
// Put up a message box error stating that the USER does
|
|
// not have the Advanced Serial I/O parameters configured
|
|
// in the registry and just continue for now.
|
|
//
|
|
|
|
RegCloseKey( hkeySerial );
|
|
|
|
if( dwDisposition == REG_CREATED_NEW_KEY )
|
|
{
|
|
RegDeleteKey( HKEY_LOCAL_MACHINE, szFormat );
|
|
}
|
|
|
|
MyMessageBox( hDlg, MYPORT+13, INITS+1,
|
|
MB_OK | MB_ICONINFORMATION );
|
|
|
|
HourGlass( FALSE );
|
|
EndDialog( hDlg, 0 );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
SpecialCom1to4:
|
|
|
|
//
|
|
// Try to get the configured Port IRQ Level from Registry
|
|
//
|
|
|
|
dwSize = sizeof( DWORD );
|
|
dwBaseIRQ = 0;
|
|
|
|
if( !RegQueryValueEx( hkeySerial, m_szRegPortIRQ, NULL, &dwType,
|
|
(LPBYTE) &dwBaseIRQ, &dwSize ) )
|
|
{
|
|
if( dwType != REG_DWORD )
|
|
dwBaseIRQ = 0;
|
|
}
|
|
|
|
//
|
|
// Try to get the configured FIFO state from Registry
|
|
//
|
|
dwSize = sizeof( DWORD );
|
|
dwFIFO = (DWORD)-1;
|
|
|
|
if( !RegQueryValueEx( hkeySerial, m_szFIFO, NULL, &dwType,
|
|
(LPBYTE) &dwFIFO, &dwSize ) )
|
|
{
|
|
if( dwType != REG_DWORD )
|
|
dwFIFO = (DWORD)-1;
|
|
}
|
|
|
|
if (dwFIFO == -1) {
|
|
HKEY hkeyDef;
|
|
|
|
if (RegOpenKey(HKEY_LOCAL_MACHINE, m_szRegSerial, &hkeyDef) == ERROR_SUCCESS) {
|
|
|
|
dwSize = sizeof( dwFIFO );
|
|
dwFIFO = 0;
|
|
|
|
if( !RegQueryValueEx( hkeyDef, m_szFIFO, NULL, &dwType,
|
|
(LPBYTE) &dwFIFO, &dwSize ) )
|
|
{
|
|
if( dwType != REG_DWORD )
|
|
dwFIFO = 0;
|
|
}
|
|
|
|
RegCloseKey(hkeyDef);
|
|
} else {
|
|
dwFIFO = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MyMessageBox( hDlg, (bNewPort) ? MYPORT+15 : MYPORT+14, INITS+1,
|
|
MB_OK | MB_ICONINFORMATION );
|
|
HourGlass( FALSE );
|
|
EndDialog( hDlg, 0 );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Make a PORT_IRQ and PORT_FIFO selection
|
|
//
|
|
|
|
SendDlgItemMessage( hDlg, PORT_IRQ, CB_SETCURSEL,
|
|
(dwBaseIRQ >= IRQMIN && dwBaseIRQ <= IRQMAX) ?
|
|
IRQMAX+1 - dwBaseIRQ : 0, 0L );
|
|
|
|
CheckDlgButton( hDlg, PORT_FIFO, dwFIFO );
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Store away the initial settings so we can warn the user if
|
|
// they need to reboot
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
nFifo = dwFIFO;
|
|
|
|
nPortNumber = NewCom;
|
|
|
|
nStartIndex = SendDlgItemMessage( hDlg,PORT_IRQ,CB_GETCURSEL, 0, 0L );
|
|
|
|
GetDlgItemText( hDlg, PORT_BASEIO, szStartString,
|
|
CharSizeOf( szStartString ) );
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Show the window and reset the cursor
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
ShowWindow( hDlg, SW_SHOW );
|
|
|
|
UpdateWindow( hDlg );
|
|
|
|
HourGlass( FALSE );
|
|
break;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch( LOWORD( wParam ) )
|
|
{
|
|
|
|
case IDD_HELP:
|
|
goto DoHelp;
|
|
|
|
case IDOK:
|
|
HourGlass( TRUE );
|
|
|
|
bWroteToSerialKey = FALSE;
|
|
|
|
//
|
|
// Check IRQ line is valid
|
|
//
|
|
|
|
nVal = (int) SendDlgItemMessage( hDlg, PORT_IRQ, CB_GETCURSEL,
|
|
0, 0L) ;
|
|
|
|
if( ( nVal == CB_ERR ) || ( nVal == CB_ERRSPACE ) )
|
|
nVal = nStartIndex;
|
|
|
|
//
|
|
// Check Base I/O Address is valid
|
|
//
|
|
|
|
i = GetDlgItemText( hDlg, PORT_BASEIO, szBaseIO,
|
|
CharSizeOf( szBaseIO ) );
|
|
|
|
LoadString( g_hInst, MYPORT, szDef, CharSizeOf( szDef ) );
|
|
|
|
if( i == 0 )
|
|
lstrcpy( szBaseIO, szStartString );
|
|
|
|
bNone = !_tcsnicmp( szDef, szBaseIO, CharSizeOf( szBaseIO ) - 1 );
|
|
|
|
if( !bNone && !CheckBaseIOSetting( szBaseIO ) )
|
|
{
|
|
LoadString( g_hInst, MYPORT + 11, szFormat,
|
|
CharSizeOf( szFormat ) );
|
|
|
|
GetWindowText( hDlg, szTitle, CharSizeOf( szTitle ) );
|
|
MessageBox( hDlg, szFormat, szTitle, MB_OK | MB_ICONINFORMATION );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get FIFO selection
|
|
//
|
|
|
|
dwFIFO = IsDlgButtonChecked( hDlg, PORT_FIFO );
|
|
|
|
//
|
|
// Get the COM port number from the edit box
|
|
//
|
|
|
|
i = GetDlgItemText( hDlg, PORT_NUMBER, szCom, CharSizeOf( szCom ) );
|
|
|
|
NewCom = (i == 0) ? nPortNumber : myatoi( szCom );
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// Check to see if we've changed anything. If so,
|
|
// - Output new values to registry
|
|
// - check and save the stuff in the parent dialog,
|
|
// - and issue a restart warning.
|
|
//
|
|
|
|
// ASSERT( hkeySerial != NULL );
|
|
|
|
if( bNewPort ||
|
|
nVal != nStartIndex ||
|
|
nPortNumber != NewCom ||
|
|
nFifo != dwFIFO ||
|
|
_tcsnicmp( szStartString, szBaseIO, CharSizeOf( szBaseIO ) - 1 ) )
|
|
{
|
|
//
|
|
// Output Base I/O to Registry
|
|
//
|
|
// If I write anything out to registry for this port
|
|
// I must also, always write the Port Address, IRQ and
|
|
// DosDevices name. For COM1-COM4 this means converting
|
|
// from the "default" value to the real default Base I/O
|
|
// address.
|
|
//
|
|
|
|
if( bNone )
|
|
{
|
|
//
|
|
// Convert "Default" value to a real I/O address for
|
|
// storage in registry - failsafe case uses COM1 I/O
|
|
//
|
|
|
|
if( ( NewCom > 0 ) && ( NewCom < 5 ) )
|
|
dwBaseIO = _tcstoul( pszBaseIO[ NewCom-1 ], &pszTemp, 16 );
|
|
else
|
|
dwBaseIO = _tcstoul( pszBaseIO[ 4] , &pszTemp, 16 );
|
|
}
|
|
else
|
|
{
|
|
dwBaseIO = _tcstoul( szBaseIO, &pszTemp, 16 );
|
|
}
|
|
|
|
dwSize = sizeof( DWORD );
|
|
|
|
if( RegSetValueEx( hkeySerial, m_szRegPortAddress, 0L,
|
|
REG_DWORD, (LPBYTE) &dwBaseIO, dwSize ) )
|
|
goto RegistryError;
|
|
|
|
bWroteToSerialKey = TRUE;
|
|
|
|
//
|
|
// Set FIFO value
|
|
//
|
|
|
|
dwSize = sizeof( DWORD );
|
|
|
|
if( RegSetValueEx( hkeySerial, m_szFIFO, 0L, REG_DWORD,
|
|
(LPBYTE) &dwFIFO, dwSize ) )
|
|
goto RegistryError;
|
|
|
|
//
|
|
// Create global string from new port (without ":")
|
|
//
|
|
|
|
wsprintf( m_szComPort, TEXT( "%s%d" ), m_szCOM, NewCom );
|
|
|
|
//
|
|
// Set "DosDevices" entry while we are here
|
|
//
|
|
|
|
if( RegSetValueEx( hkeySerial, m_szDosDev, 0L, REG_SZ,
|
|
(LPBYTE) m_szComPort,
|
|
ByteCountOf( lstrlen( m_szComPort ) + 1 ) ) )
|
|
{
|
|
//
|
|
// Append ":" char to end of m_szComPort string
|
|
//
|
|
|
|
lstrcat( m_szComPort, m_szColon );
|
|
|
|
goto RegistryError;
|
|
}
|
|
|
|
//
|
|
// Try to create registry Devicemap entry
|
|
//
|
|
|
|
if( RegCreateKey( HKEY_LOCAL_MACHINE, m_szRegSerialMap,
|
|
&hkey) == ERROR_SUCCESS )
|
|
{
|
|
if( RegSetValueEx( hkey, m_szSerialKey, 0L, REG_SZ,
|
|
(LPBYTE) m_szComPort,
|
|
ByteCountOf( lstrlen( m_szComPort ) + 1 ) )
|
|
!= ERROR_SUCCESS )
|
|
{
|
|
RegCloseKey( hkey );
|
|
goto ComCreateError;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ComCreateError:
|
|
//
|
|
// Append ":" char to end of m_szComPort string
|
|
//
|
|
|
|
lstrcat( m_szComPort, m_szColon );
|
|
|
|
MyMessageBox( hDlg, MYPORT+17, INITS+1,
|
|
MB_OK | MB_ICONINFORMATION );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Append ":" char to end of m_szComPort string
|
|
//
|
|
|
|
lstrcat( m_szComPort, m_szColon );
|
|
RegCloseKey( hkey );
|
|
|
|
//
|
|
// Output IRQ line to Registry
|
|
//
|
|
|
|
if( bNewPort || nVal > 0 )
|
|
{
|
|
//
|
|
// Since we don't display "Default" string at NewPort time
|
|
// the equation for IRQ is different
|
|
//
|
|
|
|
dwBaseIRQ = (bNewPort ? IRQMAX : IRQMAX+1) - nVal;
|
|
}
|
|
else if( nVal == 0 )
|
|
{
|
|
//
|
|
// Replace the Default setting with correct IRQ for port
|
|
//
|
|
|
|
switch( NewCom )
|
|
{
|
|
case 1:
|
|
case 3:
|
|
dwBaseIRQ = 4;
|
|
break;
|
|
|
|
case 2:
|
|
case 4:
|
|
dwBaseIRQ = 3;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Failsafe
|
|
//
|
|
|
|
dwBaseIRQ = 15;
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwSize = sizeof( DWORD );
|
|
|
|
if( RegSetValueEx( hkeySerial, m_szRegPortIRQ, 0L,
|
|
REG_DWORD, (LPBYTE) &dwBaseIRQ, dwSize ) )
|
|
{
|
|
RegistryError:
|
|
//
|
|
// ERROR - Cannot set Registry value
|
|
//
|
|
|
|
MyMessageBox( hDlg, MYPORT+18, INITS+1,
|
|
MB_OK | MB_ICONINFORMATION );
|
|
goto AdvancedFailure;
|
|
}
|
|
|
|
if( bNewPort )
|
|
{
|
|
//
|
|
// Write default Baud rate string to registry "9600,n,8,1"
|
|
//
|
|
|
|
WriteProfileString( m_szPorts, m_szComPort, m_szDefParams );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Check params in "Baud rate" dlg
|
|
//
|
|
|
|
hParent = GetParent( hDlg );
|
|
|
|
if( !ChkCommSettings( hParent ) )
|
|
{
|
|
SetFocus( hDlg );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Output normal comm settings to WIN.INI
|
|
//
|
|
|
|
CommPortsToWin( hParent );
|
|
|
|
//
|
|
// Change titlebar in parent dlg if COM Port Number changed
|
|
//
|
|
|
|
if( nPortNumber != NewCom )
|
|
bResetTitle = TRUE;
|
|
}
|
|
|
|
//
|
|
// Issue a restart warning
|
|
//
|
|
|
|
DialogBoxParam( g_hInst,
|
|
(LPTSTR) MAKEINTRESOURCE(DLG_RESTART),
|
|
hDlg,
|
|
(DLGPROC) RestartDlg,
|
|
MAKELONG(IDS_COMCHANGE, 0 ) );
|
|
}
|
|
|
|
RegCloseKey( hkeySerial );
|
|
|
|
//
|
|
// Delete the Serial Key entry I created at InitDlg time in the
|
|
// Services\Parameters\Serial registry node only if I really
|
|
// created it AND I did not write anything to it at ID_OK time.
|
|
//
|
|
// Note: This is for the brain dead serial driver that doesn't
|
|
// know how to ignore a key that has no value entries
|
|
// and instead reports bogus EventLog ERRORS.
|
|
//
|
|
|
|
if( ( dwDisposition == REG_CREATED_NEW_KEY ) && !bWroteToSerialKey )
|
|
{
|
|
if( !RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
m_szRegSerialParam,
|
|
0L,
|
|
KEY_ALL_ACCESS,
|
|
&hkey ) )
|
|
{
|
|
RegDeleteKey( hkey, m_szSerialKey );
|
|
RegCloseKey( hkey );
|
|
}
|
|
}
|
|
|
|
|
|
HourGlass( FALSE );
|
|
|
|
EndDialog( hDlg, 1 );
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
AdvancedFailure:
|
|
if( bNewPort )
|
|
{
|
|
//
|
|
// "Cancel" btn selected, delete Parameters entry
|
|
//
|
|
|
|
if( hkeySerial != NULL )
|
|
{
|
|
RegCloseKey( hkeySerial );
|
|
|
|
if( !RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
m_szRegSerialParam,
|
|
0L,
|
|
KEY_ALL_ACCESS,
|
|
&hkey ) )
|
|
{
|
|
RegDeleteKey( hkey, m_szSerialKey );
|
|
RegCloseKey( hkey );
|
|
}
|
|
}
|
|
}
|
|
else if( hkeySerial != NULL )
|
|
{
|
|
RegCloseKey( hkeySerial );
|
|
|
|
//
|
|
// Delete Parameters entry in other cases only if I initially
|
|
// created the key at InitDlg time.
|
|
//
|
|
|
|
if( dwDisposition == REG_CREATED_NEW_KEY )
|
|
{
|
|
if (!RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
m_szRegSerialParam,
|
|
0L,
|
|
KEY_ALL_ACCESS,
|
|
&hkey ) )
|
|
{
|
|
RegDeleteKey( hkey, m_szSerialKey );
|
|
RegCloseKey( hkey );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
HourGlass( FALSE );
|
|
|
|
EndDialog( hDlg, 0 );
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if( nMsg == g_wHelpMessage )
|
|
{
|
|
DoHelp:
|
|
SysHelp( hDlg );
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
PortsClassInstaller(
|
|
IN DI_FUNCTION InstallFunction,
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine acts as the class installer for Ports devices.
|
|
|
|
Arguments:
|
|
|
|
InstallFunction - Specifies the device installer function code indicating
|
|
the action being performed.
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set being
|
|
acted upon by this install action.
|
|
|
|
DeviceInfoData - Optionally, supplies the address of a device information
|
|
element being acted upon by this install action.
|
|
|
|
Return Value:
|
|
|
|
If this function successfully completed the requested action, the return
|
|
value is NO_ERROR.
|
|
|
|
If the default behavior is to be performed for the requested action, the
|
|
return value is ERROR_DI_DO_DEFAULT.
|
|
|
|
If an error occurred while attempting to perform the requested action, a
|
|
Win32 error code is returned.
|
|
|
|
--*/
|
|
{
|
|
SP_MOVEDEV_PARAMS MoveDevParams;
|
|
HKEY hDeviceKey;
|
|
TCHAR PortName[20];
|
|
DWORD PortNameSize, Err;
|
|
|
|
switch(InstallFunction) {
|
|
|
|
case DIF_INSTALLDEVICE :
|
|
|
|
return InstallPnPSerialPort(DeviceInfoSet, DeviceInfoData);
|
|
|
|
case DIF_MOVEDEVICE :
|
|
//
|
|
// In addition to doing the default action of calling
|
|
// SetupDiMoveDuplicateDevice, we need to retrieve the COM port
|
|
// number of the old device, and set it to be the COM port number
|
|
// of the new device (if the move is successful). In Win95, setupx
|
|
// had a hack inside of DiMoveDuplicateDevNode to do that, but it's
|
|
// really the class installer's job to do class-specific stuff like
|
|
// this.
|
|
//
|
|
MoveDevParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
|
|
if(!SetupDiGetClassInstallParams(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
(PSP_CLASSINSTALL_HEADER)&MoveDevParams,
|
|
sizeof(MoveDevParams),
|
|
NULL)) {
|
|
return GetLastError();
|
|
}
|
|
|
|
//
|
|
// Open the device key for the source device instance, and retrieve its
|
|
// "PortName" value.
|
|
//
|
|
if((hDeviceKey = SetupDiOpenDevRegKey(DeviceInfoSet,
|
|
&MoveDevParams.SourceDeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DEV,
|
|
KEY_READ)) == INVALID_HANDLE_VALUE) {
|
|
return GetLastError();
|
|
}
|
|
|
|
PortNameSize = sizeof(PortName);
|
|
Err = RegQueryValueEx(hDeviceKey,
|
|
m_szPortName,
|
|
NULL,
|
|
NULL,
|
|
(PBYTE)PortName,
|
|
&PortNameSize
|
|
);
|
|
|
|
RegCloseKey(hDeviceKey);
|
|
|
|
if(Err != ERROR_SUCCESS) {
|
|
return Err;
|
|
}
|
|
|
|
//
|
|
// Now call the default routine for moving devices.
|
|
//
|
|
if(!SetupDiMoveDuplicateDevice(DeviceInfoSet, DeviceInfoData)) {
|
|
return GetLastError();
|
|
}
|
|
|
|
//
|
|
// The device was successfully moved. Now open the destination device's key,
|
|
// and store the COM port name there. (Ignore failure here.)
|
|
//
|
|
if((hDeviceKey = SetupDiOpenDevRegKey(DeviceInfoSet,
|
|
&MoveDevParams.SourceDeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DEV,
|
|
KEY_READ)) != INVALID_HANDLE_VALUE) {
|
|
|
|
RegSetValueEx(hDeviceKey,
|
|
m_szPortName,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE)PortName,
|
|
ByteCountOf(lstrlen(PortName) + 1)
|
|
);
|
|
|
|
RegCloseKey(hDeviceKey);
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
default :
|
|
//
|
|
// Just do the default action.
|
|
//
|
|
return ERROR_DI_DO_DEFAULT;
|
|
}
|
|
}
|
|
|
|
|
|
HDEVINFO
|
|
OpenPnPSerialDeviceInstance(
|
|
IN HWND hwndParent,
|
|
IN LPCTSTR SerialKeyName,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a device information set, and opens the specified serial
|
|
device information element within that set.
|
|
|
|
Arguments:
|
|
|
|
hwndParent - supplies the handle of the window to be used as the parent for
|
|
any UI to be performed for the device information element.
|
|
|
|
SerialKeyName - supplies the name of the subkey under the serial driver's
|
|
Parameters subkey that contains information about this serial device
|
|
|
|
DeviceInfoData - supplies the address of a SP_DEVINFO_DATA structure that is
|
|
filled in upon return with the newly-opened device information element.
|
|
|
|
Return Value:
|
|
|
|
If successful, the return value is a handle to the newly-created device
|
|
information set. If failure, the return value is INVALID_HANDLE_VALUE.
|
|
|
|
--*/
|
|
{
|
|
HKEY hPortKey;
|
|
TCHAR CharBuffer[MAX_PATH];
|
|
DWORD CharBufferSize;
|
|
HDEVINFO DeviceInfoSet;
|
|
DWORD Err;
|
|
|
|
//
|
|
// CharBuffer is used to hold both a registry path and a device instance ID.
|
|
// Make sure our assumption about which string is larger remains correct.
|
|
//
|
|
#if MAX_DEVICE_ID_LEN > MAX_PATH
|
|
#error MAX_DEVICE_ID_LEN is greater than MAX_PATH. Update CharBuffer.
|
|
#endif
|
|
|
|
//
|
|
// Retrieve the PnP ISA device instance name associated with this port.
|
|
//
|
|
wsprintf(CharBuffer, m_szRegSerialIO, SerialKeyName);
|
|
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
CharBuffer,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hPortKey) != ERROR_SUCCESS) {
|
|
|
|
goto clean0;
|
|
}
|
|
|
|
CharBufferSize = sizeof(CharBuffer);
|
|
Err = RegQueryValueEx(hPortKey,
|
|
m_szPnPDeviceId,
|
|
NULL,
|
|
NULL,
|
|
(PBYTE)CharBuffer,
|
|
&CharBufferSize
|
|
);
|
|
|
|
RegCloseKey(hPortKey);
|
|
|
|
if(Err != ERROR_SUCCESS) {
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// We've retrieved the device instance ID, now open this as a device
|
|
// information element.
|
|
//
|
|
if((DeviceInfoSet = SetupDiCreateDeviceInfoList(NULL, hwndParent)) == INVALID_HANDLE_VALUE) {
|
|
goto clean0;
|
|
}
|
|
|
|
DeviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
|
|
if(SetupDiOpenDeviceInfo(DeviceInfoSet,
|
|
CharBuffer,
|
|
hwndParent,
|
|
0,
|
|
DeviceInfoData)) {
|
|
|
|
return DeviceInfoSet;
|
|
}
|
|
|
|
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
|
|
|
clean0:
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
|
|
INT
|
|
DoPnPAdvancedPortDialog(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN HWND hwndParent,
|
|
IN BOOL FirstTime,
|
|
OUT PHKEY phPortKey OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine displays the advanced configuration property sheet for a
|
|
PnP ISA serial port device. This contains a property page for resource
|
|
selection, and another page for miscellaneous settings (e.g., port number,
|
|
FIFO enable/disable).
|
|
|
|
NOTE: This routine uses the global variables m_szComPort (read-write) and
|
|
m_szSerialKey (read-only). It also set the global variable bResetTitle to
|
|
TRUE if the user changed the COM port number.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - supplies the handle of the device information set containing
|
|
the serial device to display a dialog for.
|
|
|
|
DeviceInfoData - supplies the device information element to be configured.
|
|
|
|
hwndParent - supplies the handle of the window to be used as the parent for
|
|
the configuration UI.
|
|
|
|
FirstTime - If TRUE, then property sheet comes up with resource selection UI
|
|
having focus instead of General.
|
|
|
|
phPortKey - Optionally, supplies the address of a variable that will be filled
|
|
in with a handle to the serial key (under services\serial\parameters) upon
|
|
succussful return from this routine. The caller must close this handle with
|
|
RegCloseKey(). If the routine fails, the variable will be set to
|
|
INVALID_HANDLE_VALUE.
|
|
|
|
Return Value:
|
|
|
|
If success (i.e., if the user changed something), the return value is 1.
|
|
If failure, the return value is 0, and GetLastError() returns the cause.
|
|
|
|
--*/
|
|
{
|
|
TCHAR CharBuffer[MAX_PATH];
|
|
DWORDLONG IoBase, OldIoBase;
|
|
DWORD dwIoBase;
|
|
ULONG Irq, OldIrq;
|
|
DWORD Err, RegDataType, RegDataSize, OldComPortNumber;
|
|
PROPSHEETPAGE PropPage;
|
|
PROPSHEETHEADER PropHeader;
|
|
SP_PROPSHEETPAGE_REQUEST PropPageRequest;
|
|
GENERAL_PROP_PARAMS GeneralPropParams;
|
|
HPROPSHEETPAGE hPages[2];
|
|
HINSTANCE hLib;
|
|
INT i, PropSheetReturn;
|
|
FARPROC PropSheetExtProc;
|
|
HKEY hPortKey, hKey;
|
|
DWORD RegDisposition;
|
|
BOOL GlobalFifoEnable;
|
|
IO_RESOURCE IoResource;
|
|
IRQ_RESOURCE IrqResource;
|
|
LOG_CONF ForcedLogConf;
|
|
BOOL DisplayPropSheet = TRUE;
|
|
SP_DEVINSTALL_PARAMS DeviceInstallParams;
|
|
|
|
//
|
|
// Retrieve the current settings for this device, so we'll know whether they changed.
|
|
//
|
|
if(GetSerialPortDevInstConfig((DEVINST)(DeviceInfoData->DevInst),
|
|
FORCED_LOG_CONF,
|
|
&IoResource,
|
|
&IrqResource)) {
|
|
|
|
OldIoBase = IoResource.IO_Header.IOD_Alloc_Base;
|
|
OldIrq = IrqResource.IRQ_Header.IRQD_Alloc_Num;
|
|
|
|
} else {
|
|
//
|
|
// IRQ of -1 means that we had no old settings
|
|
//
|
|
OldIrq = (ULONG)-1;
|
|
}
|
|
|
|
//
|
|
// Open the Services\Serial key.
|
|
//
|
|
if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
m_szRegSerial,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hKey)) != ERROR_SUCCESS) {
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Retrieve the state of the global 'ForceFifoEnable' setting.
|
|
//
|
|
RegDataSize = sizeof(GlobalFifoEnable);
|
|
if((RegQueryValueEx(hKey,
|
|
m_szFIFO,
|
|
NULL,
|
|
&RegDataType,
|
|
(PBYTE)&GlobalFifoEnable,
|
|
&RegDataSize) != ERROR_SUCCESS) ||
|
|
(RegDataType != REG_DWORD))
|
|
{
|
|
GlobalFifoEnable = TRUE; // default to TRUE for PnP ISA cards.
|
|
}
|
|
|
|
//
|
|
// Now open/create the Parameters\Serialxxx subkey.
|
|
//
|
|
wsprintf(CharBuffer, m_szParametersSerialIO, m_szSerialKey);
|
|
Err = RegCreateKeyEx(hKey,
|
|
CharBuffer,
|
|
0,
|
|
NULL,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hPortKey,
|
|
&RegDisposition
|
|
);
|
|
//
|
|
// Don't need the handle to the parameter key anymore.
|
|
//
|
|
RegCloseKey(hKey);
|
|
|
|
if(Err != ERROR_SUCCESS) {
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Initialize the property pages list, so we'll know which one we need to free
|
|
// later, if an error occurs.
|
|
//
|
|
ZeroMemory(hPages, sizeof(hPages));
|
|
|
|
//
|
|
// Create the first page (General)
|
|
//
|
|
GeneralPropParams.ComPortNumber = OldComPortNumber = myatoi(&m_szComPort[3]);
|
|
|
|
GeneralPropParams.FifoChanged = FALSE;
|
|
RegDataSize = sizeof(GeneralPropParams.FifoEnabled);
|
|
if((RegQueryValueEx(hPortKey,
|
|
m_szFIFO,
|
|
NULL,
|
|
&RegDataType,
|
|
(PBYTE)&(GeneralPropParams.FifoEnabled),
|
|
&RegDataSize) != ERROR_SUCCESS) ||
|
|
(RegDataType != REG_DWORD))
|
|
{
|
|
//
|
|
// Value isn't stored in the serial port's key, so use the global value.
|
|
//
|
|
GeneralPropParams.FifoEnabled = GlobalFifoEnable;
|
|
}
|
|
|
|
GeneralPropParams.DeviceInfoSet = DeviceInfoSet;
|
|
GeneralPropParams.DeviceInfoData = DeviceInfoData;
|
|
|
|
//
|
|
// We don't want to popup the configuration UI if the 'quiet install' flag is
|
|
// set _and_ we already have a forced config (pre-install support).
|
|
//
|
|
if(CM_Get_First_Log_Conf(&ForcedLogConf, DeviceInfoData->DevInst, FORCED_LOG_CONF) == CR_SUCCESS) {
|
|
|
|
CM_Free_Log_Conf_Handle(ForcedLogConf);
|
|
|
|
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
if(SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams)) {
|
|
if(FirstTime && (DeviceInstallParams.Flags & DI_QUIETINSTALL)) {
|
|
DisplayPropSheet = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(DisplayPropSheet) {
|
|
|
|
PropPage.dwSize = sizeof(PROPSHEETPAGE);
|
|
PropPage.dwFlags = PSP_DEFAULT;
|
|
PropPage.hInstance = g_hInst;
|
|
PropPage.pszTemplate = MAKEINTRESOURCE(DLG_ADVPORTS_GENERAL);
|
|
PropPage.pszIcon = NULL;
|
|
PropPage.pszTitle = NULL;
|
|
PropPage.pfnDlgProc = GeneralAdvPortsDlg;
|
|
PropPage.lParam = (LPARAM)&GeneralPropParams;
|
|
PropPage.pfnCallback = NULL;
|
|
|
|
if(!(hPages[0] = CreatePropertySheetPage(&PropPage))) {
|
|
//
|
|
// Failure most likely due to out-of-memory.
|
|
//
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean1;
|
|
}
|
|
|
|
//
|
|
// Now get the resource selection page from setupapi.dll
|
|
//
|
|
if(!(hLib = GetModuleHandle(m_szSetupApiDll)) ||
|
|
!(PropSheetExtProc = GetProcAddress(hLib, "ExtensionPropSheetPageProc"))) {
|
|
|
|
Err = GetLastError();
|
|
goto clean1;
|
|
}
|
|
|
|
PropPageRequest.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST);
|
|
PropPageRequest.PageRequested = SPPSR_SELECT_DEVICE_RESOURCES;
|
|
PropPageRequest.DeviceInfoSet = DeviceInfoSet;
|
|
PropPageRequest.DeviceInfoData = DeviceInfoData;
|
|
|
|
if(!PropSheetExtProc(&PropPageRequest, AddPropSheetPageProc, &hPages[1])) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean1;
|
|
}
|
|
|
|
//
|
|
// Create the property sheet.
|
|
//
|
|
LoadString(g_hInst,
|
|
MYPORT + 20,
|
|
CharBuffer,
|
|
CharSizeOf(CharBuffer)
|
|
);
|
|
|
|
PropHeader.dwSize = sizeof(PROPSHEETHEADER);
|
|
PropHeader.dwFlags = PSH_NOAPPLYNOW;
|
|
PropHeader.hwndParent = hwndParent;
|
|
PropHeader.hInstance = g_hInst;
|
|
PropHeader.pszIcon = NULL;
|
|
PropHeader.pszCaption = CharBuffer;
|
|
PropHeader.nPages = 2;
|
|
PropHeader.phpage = hPages;
|
|
PropHeader.nStartPage = FirstTime ? 1 : 0;
|
|
PropHeader.pfnCallback = NULL;
|
|
|
|
if((PropSheetReturn = PropertySheet(&PropHeader)) == -1) {
|
|
Err = ERROR_INVALID_DATA;
|
|
goto clean1;
|
|
}
|
|
|
|
//
|
|
// Since PropertySheet() was successful, we need to clear the page
|
|
// handles out of our array, because we don't need to destroy them
|
|
// anymore.
|
|
//
|
|
for(i = 0; i < (sizeof(hPages) / sizeof(hPages[0])); i++) {
|
|
hPages[i] = NULL;
|
|
}
|
|
|
|
if(!PropSheetReturn) {
|
|
Err = ERROR_CANCELLED;
|
|
goto clean1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The user selected resources for this device--retrieve those resources.
|
|
//
|
|
if(GetSerialPortDevInstConfig((DEVINST)(DeviceInfoData->DevInst),
|
|
FORCED_LOG_CONF,
|
|
&IoResource,
|
|
&IrqResource)) {
|
|
|
|
IoBase = IoResource.IO_Header.IOD_Alloc_Base;
|
|
Irq = IrqResource.IRQ_Header.IRQD_Alloc_Num;
|
|
|
|
} else {
|
|
Err = ERROR_INVALID_DATA; // just use a semi-applicable error code.
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Did any of the settings change?
|
|
//
|
|
if(FirstTime ||
|
|
(Irq != OldIrq) ||
|
|
(IoBase != OldIoBase) ||
|
|
(GeneralPropParams.ComPortNumber != OldComPortNumber) ||
|
|
(GeneralPropParams.FifoChanged))
|
|
{
|
|
//
|
|
// We have all the information we need--write out the settings to the serial
|
|
// key.
|
|
//
|
|
wsprintf(m_szComPort, TEXT("%s%d"), m_szCOM, GeneralPropParams.ComPortNumber);
|
|
|
|
if((Err = RegSetValueEx(hPortKey,
|
|
m_szDosDev,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE)m_szComPort,
|
|
ByteCountOf(lstrlen(m_szComPort) + 1))) != ERROR_SUCCESS) {
|
|
goto clean1;
|
|
}
|
|
|
|
//
|
|
// Also store the port name in a win95-compatible location (so that the modem class
|
|
// installer can use it, for instance).
|
|
//
|
|
if((hKey = SetupDiCreateDevRegKey(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DEV,
|
|
NULL,
|
|
NULL)) == INVALID_HANDLE_VALUE) {
|
|
Err = GetLastError();
|
|
goto clean1;
|
|
}
|
|
|
|
Err = RegSetValueEx(hKey,
|
|
m_szPortName,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE)m_szComPort,
|
|
ByteCountOf(lstrlen(m_szComPort) + 1)
|
|
);
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
if(Err != ERROR_SUCCESS) {
|
|
goto clean1;
|
|
}
|
|
|
|
if(GeneralPropParams.FifoChanged) {
|
|
|
|
if((Err = RegSetValueEx(hPortKey,
|
|
m_szFIFO,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&GeneralPropParams.FifoEnabled,
|
|
sizeof(GeneralPropParams.FifoEnabled))) != ERROR_SUCCESS) {
|
|
goto clean1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Io base is stored in registry a 32-bit, not 64-bit value.
|
|
//
|
|
dwIoBase = (DWORD)IoBase;
|
|
if((Err = RegSetValueEx(hPortKey,
|
|
m_szRegPortAddress,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&dwIoBase,
|
|
sizeof(dwIoBase))) != ERROR_SUCCESS) {
|
|
goto clean1;
|
|
}
|
|
|
|
if((Err = RegSetValueEx(hPortKey,
|
|
m_szRegPortIRQ,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&Irq,
|
|
sizeof(Irq))) != ERROR_SUCCESS) {
|
|
goto clean1;
|
|
}
|
|
|
|
//
|
|
// Create/Update DeviceMap entry (don't consider problems here a fatal error).
|
|
//
|
|
if(RegCreateKey(HKEY_LOCAL_MACHINE,
|
|
m_szRegSerialMap,
|
|
&hKey) == ERROR_SUCCESS) {
|
|
|
|
RegSetValueEx(hKey,
|
|
m_szSerialKey,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE)m_szComPort,
|
|
ByteCountOf(lstrlen(m_szComPort) + 1)
|
|
);
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
//
|
|
// Now generate a string, to be used for the device's friendly name, of the form:
|
|
//
|
|
// Communications Port (COM<x>)
|
|
//
|
|
if(LoadString(g_hInst, MYPORT + 19, CharBuffer, CharSizeOf(CharBuffer))) {
|
|
lstrcat(CharBuffer, m_szComPort);
|
|
lstrcat(CharBuffer, m_szCloseParen);
|
|
} else {
|
|
//
|
|
// Simply use COM port name.
|
|
//
|
|
lstrcpy(CharBuffer, m_szComPort);
|
|
}
|
|
|
|
SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_FRIENDLYNAME,
|
|
(PBYTE)CharBuffer,
|
|
ByteCountOf(lstrlen(CharBuffer) + 1)
|
|
);
|
|
|
|
if(FirstTime) {
|
|
//
|
|
// Write default Baud rate string to registry "9600,n,8,1"
|
|
//
|
|
WriteProfileString(m_szPorts, m_szComPort, m_szDefParams);
|
|
|
|
} else {
|
|
//
|
|
// Change titlebar in parent dlg if COM Port Number changed
|
|
//
|
|
if(GeneralPropParams.ComPortNumber != OldComPortNumber) {
|
|
bResetTitle = TRUE;
|
|
}
|
|
|
|
//
|
|
// Issue a restart warning
|
|
//
|
|
DialogBoxParam(g_hInst,
|
|
(LPTSTR)MAKEINTRESOURCE(DLG_RESTART),
|
|
hwndParent,
|
|
(DLGPROC)RestartDlg,
|
|
MAKELONG(IDS_COMCHANGE, 0)
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we get to here, then we've successfully written out all the necessary registry
|
|
// settings. Return the still-open handle of the serial device's parameter key, in
|
|
// case the caller needs to do some more.
|
|
//
|
|
if(phPortKey) {
|
|
*phPortKey = hPortKey;
|
|
} else {
|
|
RegCloseKey(hPortKey);
|
|
}
|
|
return 1;
|
|
|
|
clean1:
|
|
for(i = 0; i < (sizeof(hPages) / sizeof(hPages[0])); i++) {
|
|
if(hPages[i]) {
|
|
DestroyPropertySheetPage(hPages[i]);
|
|
}
|
|
}
|
|
RegCloseKey(hPortKey);
|
|
|
|
clean0:
|
|
if(phPortKey) {
|
|
*phPortKey = INVALID_HANDLE_VALUE;
|
|
}
|
|
SetLastError(Err);
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD
|
|
InstallPnPSerialPort(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the installation of a PnP ISA serial port device (may
|
|
actually be a modem card). This involves the following steps:
|
|
|
|
1. Select a COM port number and serial device name for this port
|
|
(This involves duplicate detection, since PnP ISA cards will
|
|
sometimes have a boot config, and thus be reported by ntdetect/ARC
|
|
firmware.)
|
|
2. Create a subkey under the serial driver's Parameters key, and
|
|
set it up just as if it was a manually-installed port.
|
|
3. Display the resource selection dialog, and allow the user to
|
|
configure the settings for the port.
|
|
4. Write out the settings to the serial port's key in legacy format
|
|
(i.e., the way serial.sys expects to see it).
|
|
5. Write out PnPDeviceId value to the serial port's key, which gives
|
|
the device instance name with which this port is associated.
|
|
6. Write out PortName value to the devnode key, so that modem class
|
|
installer can continue with installation (if this is really a
|
|
PnP ISA modem).
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set containing
|
|
the device being installed.
|
|
|
|
DeviceInfoData - Supplies the address of the device information element
|
|
being installed.
|
|
|
|
Return Value:
|
|
|
|
If successful, the return value is NO_ERROR, otherwise it is a Win32 error code.
|
|
|
|
--*/
|
|
{
|
|
HKEY hKey, hSubKey;
|
|
int PortList[MAX_COM_PORT+1]; // 1 based array of all allowable COM ports
|
|
TCHAR SerialName[40];
|
|
TCHAR ComPort[40];
|
|
DWORD SerialNameSize, ComPortSize, RegDataType;
|
|
int i, ComPortNumber, NewCom, DupSerial, NewSerial, HighestFreeCom;
|
|
TCHAR CharBuffer[MAX_PATH];
|
|
DWORD RegDisposition, Err;
|
|
SP_DEVINSTALL_PARAMS DeviceInstallParams;
|
|
HWND hwndParent;
|
|
BOOL HwDescHadComPort, DuplicateFound;
|
|
|
|
//
|
|
// CharBuffer is used to hold both a registry path and a device instance ID.
|
|
// Make sure our assumption about which string is larger remains correct.
|
|
//
|
|
#if MAX_DEVICE_ID_LEN > MAX_PATH
|
|
#error MAX_DEVICE_ID_LEN is greater than MAX_PATH. Update CharBuffer.
|
|
#endif
|
|
|
|
//
|
|
// First, do duplicate detection for this device. If it had a boot config, then
|
|
// it should already be in the hardware description tree. If we don't detect this
|
|
// condition, then we'll be adding an extra bogus COM port in the system.
|
|
//
|
|
DuplicateFound = FindDuplicateDeviceInstance((DEVINST)(DeviceInfoData->DevInst), &NewCom, &DupSerial);
|
|
|
|
//
|
|
// Now go and find an unused COM port number and serial port name. We have to
|
|
// merge two lists of serial port devices in order to make this determination--the
|
|
// device map list and the serial driver's Parameters list. (NOTE: the duplicate
|
|
// detection may have found a hardware description for this device, but no
|
|
// corresponding resource map entry. In this case, the hardware description may
|
|
// contain an identifier formatted as a COM port # (e.g., COM1). If so, then we'll
|
|
// try to use that name, unless it's already in use.)
|
|
//
|
|
FillMemory(PortList, sizeof(PortList), 0xFF); // use -1 as unused marker, since Serial0 is valid name
|
|
|
|
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
m_szRegSerialMap,
|
|
0,
|
|
KEY_READ,
|
|
&hKey) == ERROR_SUCCESS) {
|
|
|
|
SerialNameSize = sizeof(SerialName);
|
|
ComPortSize = sizeof(ComPort);
|
|
i = 0;
|
|
|
|
while(RegEnumValue(hKey,
|
|
i++,
|
|
SerialName,
|
|
&SerialNameSize,
|
|
NULL,
|
|
&RegDataType,
|
|
(LPBYTE)ComPort,
|
|
&ComPortSize) == ERROR_SUCCESS) {
|
|
|
|
if(RegDataType != REG_SZ) {
|
|
goto TryNextSerialValue;
|
|
}
|
|
|
|
//
|
|
// Get number of COM port (go past "COM" in string)
|
|
//
|
|
ComPortNumber = myatoi(&ComPort[3]);
|
|
|
|
if(ComPortNumber <= MAX_COM_PORT) {
|
|
//
|
|
// Store the serial port's number in this location in the ports array.
|
|
// (go past "Serial" in string).
|
|
//
|
|
PortList[ComPortNumber] = myatoi(&SerialName[6]);
|
|
|
|
//
|
|
// If this COM port number is the same as the one retrieved during our
|
|
// failed attempt at duplicate detection, then reset that value, since
|
|
// it's in use.
|
|
//
|
|
if(!DuplicateFound && (NewCom == ComPortNumber)) {
|
|
NewCom = -1;
|
|
}
|
|
}
|
|
|
|
TryNextSerialValue:
|
|
SerialNameSize = sizeof(SerialName);
|
|
ComPortSize = sizeof(ComPort);
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
m_szRegSerialParam,
|
|
0,
|
|
KEY_READ,
|
|
&hKey) == ERROR_SUCCESS) {
|
|
//
|
|
// Enumerate all keys under Serial\Parameters
|
|
//
|
|
i = 0;
|
|
|
|
while(RegEnumKey(hKey,
|
|
i++,
|
|
SerialName,
|
|
CharSizeOf(SerialName)) != ERROR_NO_MORE_ITEMS) {
|
|
|
|
if(RegOpenKeyEx(hKey,
|
|
SerialName,
|
|
0,
|
|
KEY_READ,
|
|
&hSubKey) == ERROR_SUCCESS) {
|
|
//
|
|
// Get DosDevices value for this Serial key
|
|
//
|
|
ComPortSize = sizeof(ComPort);
|
|
if(RegQueryValueEx(hSubKey,
|
|
m_szDosDev,
|
|
NULL,
|
|
&RegDataType,
|
|
(LPBYTE)ComPort,
|
|
&ComPortSize) == ERROR_SUCCESS) {
|
|
|
|
if(RegDataType != REG_SZ) {
|
|
goto TryNextSubKey;
|
|
}
|
|
|
|
//
|
|
// Get number of COM port (go past "COM" in string)
|
|
//
|
|
ComPortNumber = myatoi(&ComPort[3]);
|
|
|
|
if(ComPortNumber > MAX_COM_PORT) {
|
|
goto TryNextSubKey;
|
|
}
|
|
|
|
//
|
|
// Store the serial port's number in this location in the ports array.
|
|
// (go past "Serial" in string).
|
|
//
|
|
PortList[ComPortNumber] = myatoi(&SerialName[6]);
|
|
|
|
//
|
|
// If this COM port number is the same as the one retrieved during our
|
|
// failed attempt at duplicate detection, then reset that value, since
|
|
// it's in use.
|
|
//
|
|
if(!DuplicateFound && (NewCom == ComPortNumber)) {
|
|
NewCom = -1;
|
|
}
|
|
}
|
|
TryNextSubKey:
|
|
RegCloseKey(hSubKey);
|
|
}
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
//
|
|
// OK, now we have an array whose non-zero elements have indexes corresponding to COM port
|
|
// numbers that are taken. These elements specify the number of the corresponding serial
|
|
// name. Search through this list, and pick a number that is one greater than the existing
|
|
// highest number (above a certain threshold).
|
|
//
|
|
if(NewCom == -1) {
|
|
//
|
|
// We need to search for a COM port number to use.
|
|
//
|
|
HwDescHadComPort = FALSE;
|
|
NewCom = MIN_COM;
|
|
} else {
|
|
//
|
|
// We have a good COM port number--all we need is a unique serial port id.
|
|
//
|
|
HwDescHadComPort = TRUE;
|
|
}
|
|
NewSerial = MIN_SERIAL;
|
|
HighestFreeCom = 0;
|
|
|
|
for(i = 1; i <= MAX_COM_PORT; i++) {
|
|
if(PortList[i] != -1) {
|
|
if(!HwDescHadComPort) {
|
|
NewCom = max(i+1, NewCom);
|
|
}
|
|
NewSerial = max(PortList[i]+1, NewSerial);
|
|
} else {
|
|
//
|
|
// Remember the highest com port number that isn't taken, because it could be that
|
|
// 256 was taken, but 128 was free, for example.
|
|
//
|
|
HighestFreeCom = i;
|
|
}
|
|
}
|
|
|
|
if(NewCom > MAX_COM_PORT) {
|
|
//
|
|
// Did we find a hole along the way?
|
|
//
|
|
if(HighestFreeCom) {
|
|
NewCom = HighestFreeCom;
|
|
} else {
|
|
//
|
|
// All ports are taken! Fail the installation.
|
|
//
|
|
return ERROR_OUT_OF_STRUCTURES;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Generate the serial and COM port names based on the numbers we picked.
|
|
//
|
|
wsprintf(m_szSerialKey, TEXT("%s%d"), m_szSERIAL, NewSerial);
|
|
wsprintf(m_szComPort, TEXT("%s%d"), m_szCOM, NewCom);
|
|
|
|
//
|
|
// Now set the device instance's 'Service' registry property to "Serial"
|
|
//
|
|
if(!SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_SERVICE,
|
|
(PBYTE)m_szSERIAL,
|
|
sizeof(m_szSERIAL))) {
|
|
return GetLastError();
|
|
}
|
|
|
|
//
|
|
// Now generate a string, to be used for the device's friendly name, of the form:
|
|
//
|
|
// Communications Port (COM<x>)
|
|
//
|
|
if(LoadString(g_hInst, MYPORT + 19, CharBuffer, CharSizeOf(CharBuffer))) {
|
|
lstrcat(CharBuffer, m_szComPort);
|
|
lstrcat(CharBuffer, m_szCloseParen);
|
|
} else {
|
|
//
|
|
// Simply use COM port name.
|
|
//
|
|
lstrcpy(CharBuffer, m_szComPort);
|
|
}
|
|
|
|
SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_FRIENDLYNAME,
|
|
(PBYTE)CharBuffer,
|
|
ByteCountOf(lstrlen(CharBuffer) + 1)
|
|
);
|
|
|
|
//
|
|
// Retrieve the device install parameters, and set the DI_NEEDREBOOT flag. If this
|
|
// fails, it's no big deal, as the device installer should be able to figure it out
|
|
// on its own. (Also, retrieve the parent window handle for resource selection UI.)
|
|
//
|
|
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
if(SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams)) {
|
|
hwndParent = DeviceInstallParams.hwndParent;
|
|
DeviceInstallParams.Flags |= DI_NEEDREBOOT;
|
|
SetupDiSetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams);
|
|
} else {
|
|
hwndParent = NULL;
|
|
}
|
|
|
|
//
|
|
// Now do the installation for this device.
|
|
//
|
|
if(!SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData)) {
|
|
return GetLastError();
|
|
}
|
|
|
|
//
|
|
// Finally, popup the advanced configuration dialog for the user to pick the resources
|
|
// for this new port.
|
|
//
|
|
if(!DoPnPAdvancedPortDialog(DeviceInfoSet, DeviceInfoData, hwndParent, TRUE, &hKey)) {
|
|
Err = GetLastError();
|
|
goto RegistryError;
|
|
}
|
|
|
|
//
|
|
// Set "PnPDeviceId" entry
|
|
//
|
|
SetupDiGetDeviceInstanceId(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
CharBuffer,
|
|
sizeof(CharBuffer) / sizeof(TCHAR),
|
|
NULL
|
|
);
|
|
|
|
Err = RegSetValueEx(hKey,
|
|
m_szPnPDeviceId,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE)CharBuffer,
|
|
ByteCountOf(lstrlen(CharBuffer) + 1)
|
|
);
|
|
|
|
//
|
|
// Don't need the handle to the serial device's parameter key anymore.
|
|
//
|
|
RegCloseKey(hKey);
|
|
|
|
if(Err == ERROR_SUCCESS) {
|
|
//
|
|
// OK, we've successfully installed the serial device. Before returning success,
|
|
// we should try to clean up the existing serial device entry under the device map,
|
|
// in the case where we detected a duplicate. We picked a different name than the
|
|
// one we found there, so the old name is now a turd. This is not a failure if we
|
|
// can't delete this--it goes away on reboot anyway.
|
|
//
|
|
if(DuplicateFound &&
|
|
(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
m_szRegSerialMap,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hKey) == ERROR_SUCCESS)) {
|
|
|
|
wsprintf(m_szSerialKey, TEXT("%s%d"), m_szSERIAL, DupSerial);
|
|
RegDeleteValue(hKey, m_szSerialKey);
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Drop down into error handling.
|
|
//
|
|
|
|
RegistryError:
|
|
//
|
|
// Clean up the device instance. This behavior is taken from the clean-up code in
|
|
// SetupDiInstallDevice.
|
|
//
|
|
// Disable the device if the error wasn't a user cancel.
|
|
//
|
|
if(Err != ERROR_CANCELLED) {
|
|
|
|
DWORD ConfigFlags;
|
|
SP_DRVINFO_DATA DriverInfoData;
|
|
|
|
//
|
|
// The device is in an unknown state. Disable it by setting the
|
|
// CONFIGFLAG_DISABLED config flag.
|
|
//
|
|
if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_CONFIGFLAGS,
|
|
NULL,
|
|
(PBYTE)&ConfigFlags,
|
|
sizeof(ConfigFlags),
|
|
NULL))
|
|
{
|
|
//
|
|
// Couldn't retrieve ConfigFlags--default to zero.
|
|
//
|
|
ConfigFlags = 0;
|
|
}
|
|
|
|
ConfigFlags |= (CONFIGFLAG_DISABLED | CONFIGFLAG_REINSTALL);
|
|
|
|
SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_CONFIGFLAGS,
|
|
(PBYTE)&ConfigFlags,
|
|
sizeof(ConfigFlags)
|
|
);
|
|
|
|
//
|
|
// Delete the Driver= entry from the Dev Reg Key and delete the
|
|
// DrvRegKey
|
|
//
|
|
DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
|
|
if(SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, &DriverInfoData)) {
|
|
|
|
SetupDiDeleteDevRegKey(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
DICS_FLAG_GLOBAL | DICS_FLAG_CONFIGGENERAL,
|
|
0,
|
|
DIREG_DRV
|
|
);
|
|
|
|
SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_DRIVER,
|
|
NULL,
|
|
0
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clean up parameters key.
|
|
//
|
|
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
m_szRegSerialParam,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hKey) == ERROR_SUCCESS) {
|
|
|
|
RegDeleteKey(hKey, m_szSerialKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
|
|
BOOL
|
|
FindDuplicateDeviceInstance(
|
|
IN DEVINST DevInst,
|
|
OUT PINT ComPortNumber,
|
|
OUT PINT SerialDeviceId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to find a duplicate of the specified device instance.
|
|
To accomplish this, it employs the following algorithm:
|
|
|
|
for each SerialController under HKLM\HARDWARE\DESCRIPTION\System {
|
|
|
|
if the SerialController's base IO port and IRQ match our device's {
|
|
|
|
for each raw resource list under HKLM\HARDWARE\RESOURCEMAP\LOADED SERIAL DRIVER RESOURCES\Serial
|
|
|
|
if raw resource list's base IO port and IRQ match our device's {
|
|
|
|
return TRUE with serial device ID and COM port number (from HKLM\HARDWARE\DEVICEMAP\SERIALCOMM)
|
|
}
|
|
}
|
|
return FALSE with COM port # from hardware description identifier (if form "COM<x>") and -1 for serial device ID
|
|
}
|
|
}
|
|
return FALSE with -1 for COM port # and serial device ID
|
|
|
|
If it discovers that the COM port is already being controlled by serial.sys, then
|
|
it sets the device's alloc config to match the settings being used.
|
|
|
|
Arguments:
|
|
|
|
DevInst - Supplies a handle to the device instance for which a duplicate is to
|
|
be found.
|
|
|
|
ComPortNumber - Supplies the address of a variable that receives the COM port
|
|
number at which the duplicate was found. If a hardware description entry
|
|
was found, but no corresponding resource map entry was located, then
|
|
duplicate detection will fail, but this value may still be filled in with
|
|
the hardware description's "Identifier" com port value, if it is in the
|
|
proper format (i.e., COM<x>). If neither of these determinations can be
|
|
made, this value will be set to -1 upon return.
|
|
|
|
SerialDeviceId - Supplies the address of a variable that receives the serial
|
|
device ID of the duplicate, if found. If no duplicate is found, this
|
|
value will be set to -1 upon return.
|
|
|
|
Return Value:
|
|
|
|
If a duplicate is found, the return value is TRUE, otherwise it is FALSE.
|
|
|
|
--*/
|
|
{
|
|
LOG_CONF LogConf;
|
|
RES_DES ResDes;
|
|
IO_RESOURCE IoResource;
|
|
IRQ_RESOURCE IrqResource;
|
|
|
|
*ComPortNumber = -1;
|
|
*SerialDeviceId = -1;
|
|
|
|
if(!GetSerialPortDevInstConfig(DevInst,
|
|
BOOT_LOG_CONF,
|
|
&IoResource,
|
|
&IrqResource)) {
|
|
//
|
|
// The device instance doesn't have a boot config--there should never be a duplicate
|
|
// in this case.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Examine every SerialController device under HKLM\HARDWARE\DESCRIPTION\System (under
|
|
// either MultifunctionAdapter or EisaAdapter).
|
|
//
|
|
if(!SearchForSerialControllerDup(m_szMultifunctionAdapter,
|
|
&IoResource.IO_Header.IOD_Alloc_Base,
|
|
IrqResource.IRQ_Header.IRQD_Alloc_Num,
|
|
ComPortNumber) &&
|
|
!SearchForSerialControllerDup(m_szEisaAdapter,
|
|
&IoResource.IO_Header.IOD_Alloc_Base,
|
|
IrqResource.IRQ_Header.IRQD_Alloc_Num,
|
|
ComPortNumber)) {
|
|
//
|
|
// No matches found--no duplicates.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Now, search for a corresponding entry under the following key:
|
|
//
|
|
// HKLM\HARDWARE\RESOURCEMAP\LOADED SERIAL DRIVER RESOURCES\Serial
|
|
//
|
|
if(!SearchForResourceMapMatch(&IoResource.IO_Header.IOD_Alloc_Base,
|
|
IrqResource.IRQ_Header.IRQD_Alloc_Num,
|
|
SerialDeviceId)) {
|
|
//
|
|
// Couldn't find the serial device corresponding the hardware description entry.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// If we get to here, then serial.sys is already controlling this device. Write out
|
|
// an alloc config that reflects the settings being used (if there isn't already an
|
|
// alloc config).
|
|
//
|
|
if(CM_Get_First_Log_Conf(&LogConf, DevInst, ALLOC_LOG_CONF) == CR_SUCCESS) {
|
|
CM_Free_Log_Conf_Handle(LogConf);
|
|
} else {
|
|
|
|
if(CM_Add_Empty_Log_Conf(&LogConf, DevInst, LCPRI_BOOTCONFIG, ALLOC_LOG_CONF) == CR_SUCCESS) {
|
|
//
|
|
// First, add IO resource...
|
|
//
|
|
if(CM_Add_Res_Des(&ResDes, LogConf, ResType_IO, &IoResource, sizeof(IoResource), 0) == CR_SUCCESS) {
|
|
CM_Free_Res_Des_Handle(ResDes);
|
|
}
|
|
//
|
|
// then add the IRQ resource.
|
|
//
|
|
if(CM_Add_Res_Des(&ResDes, LogConf, ResType_IRQ, &IrqResource, sizeof(IrqResource), 0) == CR_SUCCESS) {
|
|
CM_Free_Res_Des_Handle(ResDes);
|
|
}
|
|
|
|
CM_Free_Log_Conf_Handle(LogConf);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Finally, retrieve the real COM port number associated with this serial device.
|
|
//
|
|
GetComPortForSerialDevice(*SerialDeviceId, ComPortNumber);
|
|
|
|
//
|
|
// By this point, we'd better have a good COM port number!
|
|
//
|
|
return (*ComPortNumber != -1);
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetSerialPortDevInstConfig(
|
|
IN DEVINST DevInst,
|
|
IN ULONG LogConfigType,
|
|
OUT PIO_RESOURCE IoResource,
|
|
OUT PIRQ_RESOURCE IrqResource
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves the base IO port and IRQ for the specified device instance
|
|
in a particular logconfig.
|
|
|
|
Arguments:
|
|
|
|
DevInst - Supplies the handle of a device instance to retrieve configuration for.
|
|
|
|
LogConfigType - Specifies the type of logconfig to retrieve. Must be either
|
|
ALLOC_LOG_CONF, BOOT_LOG_CONF, or FORCED_LOG_CONF.
|
|
|
|
IoResource - Supplies the address of an Io resource structure that receives the
|
|
Io resource retreived.
|
|
|
|
IrqResource - Supplies the address of an IRQ resource variable that receives the
|
|
IRQ resource retrieved.
|
|
|
|
Return Value:
|
|
|
|
If success, the return value is TRUE, otherwise it is FALSE.
|
|
|
|
--*/
|
|
{
|
|
LOG_CONF LogConfig;
|
|
RES_DES ResDes;
|
|
CONFIGRET cr;
|
|
BOOL Success;
|
|
|
|
if(CM_Get_First_Log_Conf(&LogConfig, DevInst, LogConfigType) != CR_SUCCESS) {
|
|
return FALSE;
|
|
}
|
|
|
|
Success = FALSE; // assume failure.
|
|
|
|
//
|
|
// First, get the Io base port
|
|
//
|
|
if(CM_Get_Next_Res_Des(&ResDes, LogConfig, ResType_IO, NULL, 0) != CR_SUCCESS) {
|
|
goto clean0;
|
|
}
|
|
|
|
cr = CM_Get_Res_Des_Data(ResDes, IoResource, sizeof(IO_RESOURCE), 0);
|
|
|
|
CM_Free_Res_Des_Handle(ResDes);
|
|
|
|
if(cr != CR_SUCCESS) {
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Now, get the IRQ
|
|
//
|
|
if(CM_Get_Next_Res_Des(&ResDes, LogConfig, ResType_IRQ, NULL, 0) != CR_SUCCESS) {
|
|
goto clean0;
|
|
}
|
|
|
|
if(CM_Get_Res_Des_Data(ResDes, IrqResource, sizeof(IRQ_RESOURCE), 0) == CR_SUCCESS) {
|
|
Success = TRUE;
|
|
}
|
|
|
|
CM_Free_Res_Des_Handle(ResDes);
|
|
|
|
clean0:
|
|
CM_Free_Log_Conf_Handle(LogConfig);
|
|
|
|
return Success;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SearchForSerialControllerDup(
|
|
IN LPTSTR pszAdapter,
|
|
IN PDWORDLONG pIoBase,
|
|
IN ULONG Irq,
|
|
OUT PINT ComPortNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine searches for serial controllers under adapters of the specified
|
|
type. For any such controllers it finds, it compares the IO Port base and
|
|
IRQ to the values specified, looking for a match.
|
|
|
|
Arguments:
|
|
|
|
pszAdapter - Supplies the name of the adapter under which controller are to be
|
|
searched for (e.g., MultifunctionAdapter).
|
|
|
|
pIoBase - Supplies the address of the quadword base address of the IO range
|
|
being searched for.
|
|
|
|
Irq - Supplies the IRQ being searched for.
|
|
|
|
ComPortNumber - Supplies the address of a variable that receives the COM port
|
|
number specified by the controller's Identifier value, or -1 if that value
|
|
is not of the form "COM<x>". If this function does not find a match, then
|
|
this value is not set.
|
|
|
|
Return Value:
|
|
|
|
If a match is found, this routine returns TRUE, otherwise it returns FALSE.
|
|
|
|
--*/
|
|
{
|
|
LONG RegStatus, RegStatus1;
|
|
TCHAR RegStr[MAX_PATH];
|
|
HKEY hAdapterKey, hAdapterInstanceKey, hControllerKey, hControllerInstanceKey;
|
|
ULONG ulAdapter, ulController;
|
|
PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
|
|
DWORD FullResourceDescriptorSize;
|
|
DWORD RegDataType, RegDataSize;
|
|
DWORDLONG CurIoPort;
|
|
ULONG CurIrq;
|
|
BOOL MatchFound, ContinueSearch;
|
|
|
|
//
|
|
// The adapter is always searched for under hardware\description\system
|
|
//
|
|
lstrcpy(RegStr, m_szRegHwDesc);
|
|
lstrcat(RegStr, pszAdapter);
|
|
|
|
//
|
|
// Open a key to the adapter
|
|
//
|
|
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegStr, 0, KEY_READ, &hAdapterKey) != ERROR_SUCCESS) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialize resource descriptor buffer variables. We start out with a size
|
|
// that should be large enough in most (all?) cases.
|
|
//
|
|
FullResourceDescriptor = NULL;
|
|
FullResourceDescriptorSize = 0x48;
|
|
|
|
//
|
|
// Look at each adapter ordinal instance
|
|
//
|
|
MatchFound = FALSE;
|
|
ContinueSearch = TRUE;
|
|
for(ulAdapter = 0; ContinueSearch; ulAdapter++) {
|
|
|
|
wsprintf(RegStr, TEXT("%d"), ulAdapter);
|
|
|
|
if (RegOpenKeyEx(hAdapterKey, RegStr, 0, KEY_READ, &hAdapterInstanceKey) == ERROR_SUCCESS) {
|
|
//
|
|
// attempt to open the specified controller key
|
|
//
|
|
if (RegOpenKeyEx(hAdapterInstanceKey, m_szSerialController,
|
|
0, KEY_READ, &hControllerKey) == ERROR_SUCCESS) {
|
|
//
|
|
// Look at each controller ordinal instance
|
|
//
|
|
RegStatus = ERROR_SUCCESS;
|
|
|
|
for(ulController = 0; ((RegStatus == ERROR_SUCCESS) && ContinueSearch); ulController++) {
|
|
|
|
wsprintf(RegStr, TEXT("%d"), ulController);
|
|
|
|
if ((RegStatus = RegOpenKeyEx(hControllerKey, RegStr, 0,
|
|
KEY_READ, &hControllerInstanceKey)) == ERROR_SUCCESS) {
|
|
//
|
|
// Retrieve the Configuration Data for this controller instance.
|
|
//
|
|
while (TRUE) {
|
|
|
|
if(!FullResourceDescriptor) {
|
|
if(!(FullResourceDescriptor =
|
|
(PCM_FULL_RESOURCE_DESCRIPTOR)LocalAlloc(LMEM_FIXED, FullResourceDescriptorSize)))
|
|
{
|
|
//
|
|
// Out of memory--abort the search.
|
|
//
|
|
ContinueSearch = FALSE;
|
|
goto NextControllerInstance;
|
|
}
|
|
}
|
|
|
|
if((RegStatus1 = RegQueryValueEx(hControllerInstanceKey,
|
|
m_szConfigurationData,
|
|
NULL,
|
|
&RegDataType,
|
|
(PBYTE)FullResourceDescriptor,
|
|
&FullResourceDescriptorSize)) == ERROR_SUCCESS) {
|
|
break;
|
|
}
|
|
|
|
if(RegStatus1 == ERROR_MORE_DATA) {
|
|
//
|
|
// The buffer wasn't big enough, free the current buffer, and try again with
|
|
// a bigger buffer.
|
|
//
|
|
LocalFree(FullResourceDescriptor);
|
|
FullResourceDescriptor = NULL;
|
|
} else {
|
|
//
|
|
// We failed for some reason other than buffer-too-small. Skip this key,
|
|
// and move on to the next one.
|
|
//
|
|
goto NextControllerInstance;
|
|
}
|
|
}
|
|
|
|
if(GetPortValues(FullResourceDescriptor, &CurIoPort, &CurIrq)) {
|
|
|
|
if((*pIoBase == CurIoPort) && (Irq == CurIrq)) {
|
|
//
|
|
// We've found a match!
|
|
//
|
|
MatchFound = TRUE;
|
|
ContinueSearch = FALSE;
|
|
//
|
|
// Check the value of 'Identifier' to see if its of the form
|
|
// "COM<x>", and if so, then retrieve the port number for return
|
|
// via the ComPortNumber output parameter.
|
|
//
|
|
RegDataSize = sizeof(RegStr);
|
|
if((RegQueryValueEx(hControllerInstanceKey,
|
|
m_szIdentifier,
|
|
NULL,
|
|
&RegDataType,
|
|
(PBYTE)RegStr,
|
|
&RegDataSize) == ERROR_SUCCESS) &&
|
|
(RegDataType = REG_SZ)) {
|
|
|
|
if(!_tcsnicmp(RegStr, m_szCOM, 3)) {
|
|
if((*ComPortNumber = myatoi(&RegStr[3])) > MAX_COM_PORT) {
|
|
*ComPortNumber = -1;
|
|
}
|
|
}
|
|
} else {
|
|
*ComPortNumber = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
NextControllerInstance:
|
|
RegCloseKey(hControllerInstanceKey);
|
|
}
|
|
}
|
|
RegCloseKey(hControllerKey);
|
|
}
|
|
RegCloseKey(hAdapterInstanceKey);
|
|
} else {
|
|
ContinueSearch = FALSE;
|
|
}
|
|
}
|
|
|
|
if(FullResourceDescriptor) {
|
|
LocalFree(FullResourceDescriptor);
|
|
}
|
|
|
|
RegCloseKey(hAdapterKey);
|
|
|
|
return MatchFound;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetPortValues(
|
|
IN PCM_FULL_RESOURCE_DESCRIPTOR pRes,
|
|
OUT PDWORDLONG pullPort,
|
|
OUT PULONG pulIrq
|
|
)
|
|
{
|
|
BOOL bFoundPort = FALSE, bFoundIrq = FALSE;
|
|
ULONG i;
|
|
|
|
*pullPort = 0;
|
|
*pulIrq = 0;
|
|
|
|
for (i = 0; i < pRes->PartialResourceList.Count; i++) {
|
|
|
|
if (pRes->PartialResourceList.PartialDescriptors[i].Type == CmResourceTypePort) {
|
|
|
|
if(bFoundPort) {
|
|
//
|
|
// Not expecting more than one IO
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
*pullPort = pRes->PartialResourceList.PartialDescriptors[i].u.Port.Start.QuadPart;
|
|
bFoundPort = TRUE;
|
|
|
|
} else if (pRes->PartialResourceList.PartialDescriptors[i].Type == CmResourceTypeInterrupt) {
|
|
|
|
if(bFoundIrq) {
|
|
//
|
|
// Not expecting more than one IRQ
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
*pulIrq = pRes->PartialResourceList.PartialDescriptors[i].u.Interrupt.Vector;
|
|
bFoundIrq = TRUE;
|
|
}
|
|
}
|
|
|
|
return (bFoundPort && bFoundIrq);
|
|
}
|
|
|
|
|
|
BOOL
|
|
SearchForResourceMapMatch(
|
|
IN PDWORDLONG pIoBase,
|
|
IN ULONG Irq,
|
|
OUT PINT SerialDeviceId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine searches under
|
|
|
|
HKLM\HARDWARE\RESOURCEMAP\LOADED SERIAL DRIVER RESOURCES\Serial
|
|
|
|
for a serial device whose resources match those specified.
|
|
|
|
Arguments:
|
|
|
|
pIoBase - Supplies the address of the quadword base address of the IO range
|
|
being searched for.
|
|
|
|
Irq - Supplies the IRQ being searched for.
|
|
|
|
SerialDeviceId - Supplies the address of a variable that receives the ID for
|
|
the serial device where the match was found. The ID is the value <x> in
|
|
the format of the value entry where the match is found:
|
|
|
|
\Device\Serial<x>.Raw : REG_RESOURCE_LIST : ...
|
|
|
|
Return Value:
|
|
|
|
If a match is found, this routine returns TRUE, otherwise it returns FALSE.
|
|
|
|
--*/
|
|
{
|
|
HKEY hKey;
|
|
TCHAR ValueName[MAX_PATH];
|
|
PCM_RESOURCE_LIST ResourceList = NULL;
|
|
DWORD ValueNameSize, ValueDataSize, i, RegDataType;
|
|
LONG RegErr;
|
|
BOOL Success;
|
|
PTSTR p, Suffix;
|
|
DWORDLONG CurIoBase;
|
|
ULONG CurIrq;
|
|
|
|
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
m_szRegResourceMap,
|
|
0,
|
|
KEY_READ,
|
|
&hKey) != ERROR_SUCCESS) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
Success = FALSE; // assume failure.
|
|
|
|
//
|
|
// Enumerate all value entries under this key.
|
|
//
|
|
// (Start out with a value data buffer that should always be large enough.)
|
|
//
|
|
ValueDataSize = 0x34;
|
|
|
|
//
|
|
// Compute a pointer to first character of serial device ID.
|
|
//
|
|
p = &(ValueName[CharSizeOf(m_szDeviceSerial) - 1]);
|
|
|
|
i = 0;
|
|
while(TRUE) {
|
|
|
|
if(!ResourceList) {
|
|
if(!(ResourceList = (PCM_RESOURCE_LIST)LocalAlloc(LMEM_FIXED, ValueDataSize))) {
|
|
goto clean0;
|
|
}
|
|
}
|
|
|
|
ValueNameSize = CharSizeOf(ValueName);
|
|
if((RegErr = RegEnumValue(hKey,
|
|
i,
|
|
ValueName,
|
|
&ValueNameSize,
|
|
NULL,
|
|
&RegDataType,
|
|
(PBYTE)ResourceList,
|
|
&ValueDataSize)) != ERROR_SUCCESS) {
|
|
|
|
if(RegErr == ERROR_MORE_DATA) {
|
|
//
|
|
// Our buffer wasn't big enough--free our current buffer and try
|
|
// again with the required size.
|
|
//
|
|
LocalFree(ResourceList);
|
|
ResourceList = NULL;
|
|
continue;
|
|
|
|
} else if(RegErr == ERROR_NO_MORE_ITEMS) {
|
|
//
|
|
// We've examined all the items--break out of the loop.
|
|
//
|
|
break;
|
|
} else {
|
|
//
|
|
// We failed for some other reason--skip this value and move on to
|
|
// the next.
|
|
//
|
|
goto ProcessNextValue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We've successfully retrieved a value--make sure the name is of the form
|
|
// "\Device\Serial<x>.Raw"
|
|
//
|
|
if(_tcsnicmp(ValueName, m_szDeviceSerial, CharSizeOf(m_szDeviceSerial) - 1)) {
|
|
goto ProcessNextValue;
|
|
}
|
|
|
|
//
|
|
// Search for the next period, and verify that remainder of string is ".Raw"
|
|
//
|
|
if(!(Suffix = _tcschr(p, TEXT('.'))) || lstrcmpi(Suffix, m_szDeviceSerialSuffix)) {
|
|
goto ProcessNextValue;
|
|
}
|
|
|
|
*Suffix = TEXT('\0');
|
|
|
|
//
|
|
// Make sure we have the right data type.
|
|
//
|
|
if((RegDataType != REG_RESOURCE_LIST) || !ResourceList->Count) {
|
|
goto ProcessNextValue;
|
|
}
|
|
|
|
//
|
|
// Now retrieve the Io base port and IRQ for this device.
|
|
//
|
|
if(!GetPortValues(&(ResourceList->List[0]), &CurIoBase, &CurIrq)) {
|
|
goto ProcessNextValue;
|
|
}
|
|
|
|
if((*pIoBase == CurIoBase) && (Irq == CurIrq)) {
|
|
//
|
|
// We've found a match!
|
|
//
|
|
Success = TRUE;
|
|
*SerialDeviceId = myatoi(p);
|
|
break;
|
|
}
|
|
|
|
ProcessNextValue:
|
|
i++;
|
|
}
|
|
|
|
LocalFree(ResourceList);
|
|
|
|
clean0:
|
|
RegCloseKey(hKey);
|
|
|
|
return Success;
|
|
}
|
|
|
|
|
|
VOID
|
|
GetComPortForSerialDevice(
|
|
IN INT SerialDeviceId,
|
|
IN OUT PINT ComPortNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves the COM port number associated with the specified
|
|
serial device ID.
|
|
|
|
Arguments:
|
|
|
|
SerialDeviceId - Supplies the ID of the serial port device whose COM port
|
|
number is to be retrieved.
|
|
|
|
ComPortNumber - Supplies the address of a variable that receives the COM
|
|
port number for the specified serial port device. If no port number
|
|
is found, this value is not modified.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
TCHAR SerialDeviceName[40];
|
|
TCHAR SerialParamPath[MAX_PATH];
|
|
TCHAR ComPortName[40];
|
|
HKEY hKey;
|
|
DWORD ComPortNameSize;
|
|
BOOL Success = FALSE;
|
|
|
|
wsprintf(SerialDeviceName, TEXT("%s%d"), m_szSERIAL, SerialDeviceId);
|
|
|
|
//
|
|
// First, look in HKLM\HARDWARE\DEVICEMAP\SERIALCOMM for a mapping.
|
|
//
|
|
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
m_szRegSerialMap,
|
|
0,
|
|
KEY_READ,
|
|
&hKey) == ERROR_SUCCESS) {
|
|
|
|
ComPortNameSize = sizeof(ComPortName);
|
|
if(RegQueryValueEx(hKey,
|
|
SerialDeviceName,
|
|
NULL,
|
|
NULL,
|
|
(PBYTE)ComPortName,
|
|
&ComPortNameSize) == ERROR_SUCCESS) {
|
|
|
|
*ComPortNumber = myatoi(&ComPortName[3]);
|
|
Success = TRUE;
|
|
}
|
|
RegCloseKey(hKey);
|
|
if(Success) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Well, that didn't work, try looking in the serial driver's parameter subkey for
|
|
// this device.
|
|
//
|
|
wsprintf(SerialParamPath, m_szRegSerialIO, SerialDeviceName);
|
|
|
|
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
SerialParamPath,
|
|
0,
|
|
KEY_READ,
|
|
&hKey) == ERROR_SUCCESS) {
|
|
|
|
ComPortNameSize = sizeof(ComPortName);
|
|
if(RegQueryValueEx(hKey,
|
|
m_szDosDev,
|
|
NULL,
|
|
NULL,
|
|
(PBYTE)ComPortName,
|
|
&ComPortNameSize) == ERROR_SUCCESS) {
|
|
|
|
*ComPortNumber = myatoi(&ComPortName[3]);
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
CALLBACK
|
|
AddPropSheetPageProc(
|
|
IN HPROPSHEETPAGE hpage,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
*((HPROPSHEETPAGE *)lParam) = hpage;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
APIENTRY
|
|
GeneralAdvPortsDlg(
|
|
IN HWND hDlg,
|
|
IN UINT uMessage,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
PGENERAL_PROP_PARAMS GeneralPropParams = (PGENERAL_PROP_PARAMS)GetWindowLong(hDlg, DWL_USER);
|
|
UINT i;
|
|
TCHAR CharBuffer[LINE_LEN];
|
|
|
|
switch(uMessage) {
|
|
|
|
case WM_INITDIALOG :
|
|
//
|
|
// on WM_INITDIALOG call, lParam points to the property sheet page.
|
|
// The lParam field in the property sheet page struct is set by,
|
|
// caller. When I created the property sheet, I passed in a pointer
|
|
// to a HWPROF_INFO struct. Save this in the user window long so I
|
|
// can access it on later messages.
|
|
//
|
|
GeneralPropParams = (PGENERAL_PROP_PARAMS)((LPPROPSHEETPAGE)lParam)->lParam;
|
|
SetWindowLong(hDlg, DWL_USER, (LONG)GeneralPropParams);
|
|
|
|
//
|
|
// Fill in COM port number drop-down listbox, and pre-select current number.
|
|
//
|
|
for(i = MIN_COM; i <= MAX_COM_PORT; i++ )
|
|
{
|
|
wsprintf(CharBuffer, TEXT("%d"), i);
|
|
SendDlgItemMessage(hDlg,
|
|
PORT_NUMBER,
|
|
CB_ADDSTRING,
|
|
0,
|
|
(LPARAM)CharBuffer
|
|
);
|
|
}
|
|
|
|
SendDlgItemMessage(hDlg,
|
|
PORT_NUMBER,
|
|
CB_SETCURSEL,
|
|
GeneralPropParams->ComPortNumber - MIN_COM,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Initialize the "FIFO Enabled" checkbox.
|
|
//
|
|
CheckDlgButton(hDlg, PORT_FIFO, GeneralPropParams->FifoEnabled);
|
|
|
|
//
|
|
// Retrieve the description of the device (try to use friendly name first,
|
|
// and fall back to stock
|
|
//
|
|
if(!SetupDiGetDeviceRegistryProperty(GeneralPropParams->DeviceInfoSet,
|
|
GeneralPropParams->DeviceInfoData,
|
|
SPDRP_FRIENDLYNAME,
|
|
NULL,
|
|
(PBYTE)CharBuffer,
|
|
sizeof(CharBuffer),
|
|
NULL))
|
|
{
|
|
if(!SetupDiGetDeviceRegistryProperty(GeneralPropParams->DeviceInfoSet,
|
|
GeneralPropParams->DeviceInfoData,
|
|
SPDRP_DEVICEDESC,
|
|
NULL,
|
|
(PBYTE)CharBuffer,
|
|
sizeof(CharBuffer),
|
|
NULL))
|
|
{
|
|
//
|
|
// This should never happen! Fall back to "COM<x>".
|
|
//
|
|
wsprintf(CharBuffer, TEXT( "%s%d" ), m_szCOM, GeneralPropParams->ComPortNumber);
|
|
|
|
}
|
|
}
|
|
|
|
SetDlgItemText(hDlg, IDC_DEVDESC, CharBuffer);
|
|
|
|
//
|
|
// No need for us to set the focus.
|
|
//
|
|
return TRUE;
|
|
|
|
case WM_COMMAND :
|
|
|
|
switch(LOWORD(wParam)) {
|
|
|
|
case PORT_FIFO :
|
|
GeneralPropParams->FifoChanged = TRUE;
|
|
return TRUE;
|
|
|
|
default :
|
|
return FALSE;
|
|
}
|
|
|
|
case WM_NOTIFY :
|
|
|
|
switch (((NMHDR *)lParam)->code) {
|
|
|
|
case PSN_APPLY :
|
|
//
|
|
// Retrieve the new values of COM port number and FIFO enabled flag.
|
|
//
|
|
GeneralPropParams->FifoEnabled = IsDlgButtonChecked(hDlg, PORT_FIFO);
|
|
if(GetDlgItemText(hDlg, PORT_NUMBER, CharBuffer, CharSizeOf(CharBuffer))) {
|
|
GeneralPropParams->ComPortNumber = myatoi(CharBuffer);
|
|
}
|
|
|
|
SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
|
|
return TRUE;
|
|
|
|
default :
|
|
return FALSE;
|
|
}
|
|
|
|
default :
|
|
return FALSE;
|
|
}
|
|
}
|
|
|