1985 lines
57 KiB
C
1985 lines
57 KiB
C
/*****************************************************************************
|
|
*
|
|
* Copyright (c) 1998-1999 Microsoft Corporation
|
|
*
|
|
* @doc
|
|
* @module IRCLASS.C
|
|
* @comm
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* Date: 1/26/1998 (created)
|
|
*
|
|
* Contents: CoClassInstaller and Property Pages for IRSIR
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include <objbase.h>
|
|
#include <windows.h>
|
|
#include <tchar.h>
|
|
#include <cfgmgr32.h>
|
|
#include <setupapi.h>
|
|
#include <regstr.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
#include <stddef.h>
|
|
#include <stdarg.h>
|
|
|
|
#include "irclass.h"
|
|
|
|
//
|
|
// Instantiate device class GUIDs (we need infrared class GUID).
|
|
//
|
|
#include <initguid.h>
|
|
#include <devguid.h>
|
|
|
|
HANDLE ghDllInst = NULL;
|
|
|
|
TCHAR gszTitle[40];
|
|
TCHAR gszOutOfMemory[512];
|
|
TCHAR gszHelpFile[40];
|
|
|
|
TCHAR *BaudTable[] = {
|
|
TEXT("2400"),
|
|
TEXT("9600"),
|
|
TEXT("19200"),
|
|
TEXT("38400"),
|
|
TEXT("57600"),
|
|
TEXT("115200")
|
|
};
|
|
|
|
#define NUM_BAUD_RATES (sizeof(BaudTable)/sizeof(TCHAR*))
|
|
#define DEFAULT_MAX_CONNECT_RATE BaudTable[NUM_BAUD_RATES-1]
|
|
|
|
TCHAR szHelpFile[] = TEXT("INFRARED.HLP");
|
|
|
|
#define IDH_DEVICE_MAXIMUM_CONNECT_RATE 1201
|
|
#define IDH_DEVICE_COMMUNICATIONS_PORT 1202
|
|
|
|
const DWORD HelpIDs[] =
|
|
{
|
|
IDC_MAX_CONNECT, IDH_DEVICE_MAXIMUM_CONNECT_RATE,
|
|
IDC_RATE_TEXT, IDH_DEVICE_MAXIMUM_CONNECT_RATE,
|
|
IDC_PORT, IDH_DEVICE_COMMUNICATIONS_PORT,
|
|
IDC_SELECT_PORT_TEXT, IDH_DEVICE_COMMUNICATIONS_PORT,
|
|
IDC_PORT_TEXT, IDH_DEVICE_COMMUNICATIONS_PORT,
|
|
IDC_DEVICE_DESC, -1,
|
|
IDC_PORT_BOX, -1,
|
|
IDC_IRDA_ICON, -1,
|
|
0, 0
|
|
};
|
|
|
|
void InitStrings(HINSTANCE hInst)
|
|
/*++
|
|
|
|
Routine Description: InitStrings
|
|
|
|
Loads default strings from resource table
|
|
|
|
Arguments:
|
|
hInst - DLL Instance
|
|
|
|
Return Value: NONE
|
|
|
|
--*/
|
|
{
|
|
LoadString(hInst, IDS_TITLE, gszTitle, sizeof(gszTitle)/sizeof(gszTitle[0]));
|
|
LoadString(hInst, IDS_MEM_ERROR, gszOutOfMemory, sizeof(gszOutOfMemory)/sizeof(gszOutOfMemory[0]));
|
|
}
|
|
|
|
//==========================================================================
|
|
// Dll Entry Point
|
|
//==========================================================================
|
|
BOOL APIENTRY LibMain( HANDLE hDll, DWORD dwReason, LPVOID lpReserved )
|
|
{
|
|
switch ( dwReason )
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
ghDllInst = hDll;
|
|
InitStrings(ghDllInst);
|
|
DisableThreadLibraryCalls(ghDllInst);
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
break;
|
|
|
|
case DLL_THREAD_DETACH:
|
|
break;
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int MyLoadString(HINSTANCE hInst, UINT uID, LPTSTR *ppBuffer)
|
|
/*++
|
|
|
|
Routine Description: MyLoadString
|
|
|
|
LoadString wrapper which allocs properly sized buffer and loads
|
|
string from resource table
|
|
|
|
Arguments:
|
|
hInst - DLL Instanace
|
|
uID - Resource ID
|
|
ppBuffer - returns allocated buffer containing string.
|
|
|
|
Return Value:
|
|
ERROR_SUCCESS on success
|
|
ERROR_* on failure.
|
|
|
|
--*/
|
|
{
|
|
UINT Length = 8;
|
|
int LoadResult = 0;
|
|
HLOCAL hLocal = NULL;
|
|
|
|
do
|
|
{
|
|
Length <<= 1;
|
|
|
|
if (hLocal)
|
|
{
|
|
LocalFree(hLocal);
|
|
}
|
|
|
|
hLocal = LocalAlloc(LMEM_FIXED, Length*sizeof(TCHAR));
|
|
|
|
if (hLocal)
|
|
{
|
|
LoadResult = LoadString(hInst, uID, (LPTSTR)hLocal, Length);
|
|
}
|
|
else
|
|
{
|
|
MessageBox(GetFocus(), OUT_OF_MEMORY_MB);
|
|
}
|
|
} while ( (UINT)LoadResult==Length-1 && Length<4096 && hLocal);
|
|
|
|
if (LoadResult==0 && hLocal)
|
|
{
|
|
LocalFree(hLocal);
|
|
hLocal = NULL;
|
|
}
|
|
|
|
*ppBuffer = (LPTSTR)hLocal;
|
|
|
|
return LoadResult;
|
|
}
|
|
|
|
int MyMessageBox(HWND hWnd, UINT uText, UINT uCaption, UINT uType)
|
|
/*++
|
|
|
|
Routine Description: MyMessageBox
|
|
|
|
MessageBox wrapper which takes string resource IDs as parameters
|
|
|
|
Arguments:
|
|
hWnd - Parent window
|
|
uText - Message box body text ID
|
|
uCaption - Message box caption ID
|
|
uType - As in MessageBox()
|
|
|
|
Return Value:
|
|
Result of MessageBox call
|
|
|
|
--*/
|
|
{
|
|
LPTSTR szText=NULL, szCaption=NULL;
|
|
int Result = 0;
|
|
|
|
MyLoadString(ghDllInst, uText, &szText);
|
|
|
|
if (szText != NULL) {
|
|
|
|
MyLoadString(ghDllInst, uCaption, &szCaption);
|
|
|
|
if (szCaption != NULL) {
|
|
|
|
Result = MessageBox(hWnd, szText, szCaption, uType);
|
|
|
|
LocalFree(szCaption);
|
|
}
|
|
LocalFree(szText);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
LONG
|
|
MyRegQueryValueEx(
|
|
IN HKEY hKey,
|
|
IN LPCTSTR Value,
|
|
IN LPDWORD lpdwReserved,
|
|
IN LPDWORD lpdwType,
|
|
OUT LPBYTE *lpbpData,
|
|
OUT LPDWORD lpcbLength)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RegQueryValueEx wrapper which automatically queries data size and
|
|
LocalAllocs a buffer.
|
|
|
|
Arguments:
|
|
|
|
hKey - handle of open key
|
|
Value - text name of value
|
|
lpdwReserved - Must be NULL
|
|
lpdwType - Returns type of value queried
|
|
lpbpData - Returns alloced buffer containing query data
|
|
lpcbLength - Returns length of data returned/size of buffer alloced.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS
|
|
ERROR_OUTOFMEMORY on failure to alloc buffer
|
|
result of RegQueryValueEx call
|
|
|
|
--*/
|
|
{
|
|
LONG Result;
|
|
|
|
*lpcbLength = 0;
|
|
|
|
Result = RegQueryValueEx(hKey,
|
|
Value,
|
|
lpdwReserved,
|
|
lpdwType,
|
|
NULL,
|
|
lpcbLength);
|
|
if (Result==ERROR_SUCCESS)
|
|
{
|
|
*lpbpData = LocalAlloc(LMEM_FIXED, *lpcbLength);
|
|
|
|
if (!*lpbpData)
|
|
{
|
|
Result = ERROR_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
Result = RegQueryValueEx(hKey,
|
|
Value,
|
|
lpdwReserved,
|
|
lpdwType,
|
|
*lpbpData,
|
|
lpcbLength);
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
LPTSTR GetDIFString(IN DI_FUNCTION Func)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a DI_FUNCTION value, returns a text representation.
|
|
|
|
Arguments:
|
|
|
|
Func - DI_FUNCTON value
|
|
|
|
Return Value:
|
|
|
|
Text string if value is known. Hex representation if not.
|
|
|
|
--*/
|
|
{
|
|
static TCHAR buf[32];
|
|
#define MakeCase(d) case d: return TEXT(#d)
|
|
switch (Func)
|
|
{
|
|
MakeCase(DIF_SELECTDEVICE);
|
|
MakeCase(DIF_INSTALLDEVICE);
|
|
MakeCase(DIF_ASSIGNRESOURCES);
|
|
MakeCase(DIF_PROPERTIES);
|
|
MakeCase(DIF_REMOVE);
|
|
MakeCase(DIF_FIRSTTIMESETUP);
|
|
MakeCase(DIF_FOUNDDEVICE);
|
|
MakeCase(DIF_SELECTCLASSDRIVERS);
|
|
MakeCase(DIF_VALIDATECLASSDRIVERS);
|
|
MakeCase(DIF_INSTALLCLASSDRIVERS);
|
|
MakeCase(DIF_CALCDISKSPACE);
|
|
MakeCase(DIF_DESTROYPRIVATEDATA);
|
|
MakeCase(DIF_VALIDATEDRIVER);
|
|
MakeCase(DIF_MOVEDEVICE);
|
|
MakeCase(DIF_DETECT);
|
|
MakeCase(DIF_INSTALLWIZARD);
|
|
MakeCase(DIF_DESTROYWIZARDDATA);
|
|
MakeCase(DIF_PROPERTYCHANGE);
|
|
MakeCase(DIF_ENABLECLASS);
|
|
MakeCase(DIF_DETECTVERIFY);
|
|
MakeCase(DIF_INSTALLDEVICEFILES);
|
|
MakeCase(DIF_UNREMOVE);
|
|
MakeCase(DIF_SELECTBESTCOMPATDRV);
|
|
MakeCase(DIF_ALLOW_INSTALL);
|
|
MakeCase(DIF_REGISTERDEVICE);
|
|
MakeCase(DIF_INSTALLINTERFACES);
|
|
MakeCase(DIF_DETECTCANCEL);
|
|
MakeCase(DIF_REGISTER_COINSTALLERS);
|
|
MakeCase(DIF_NEWDEVICEWIZARD_FINISHINSTALL);
|
|
default:
|
|
wsprintf(buf, TEXT("%x"), Func);
|
|
return buf;
|
|
}
|
|
}
|
|
|
|
void EnumValues(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function mainly for debugging purposes which will print to debugger
|
|
a list of values found in the device's Class/{GUID}/Instance key.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - As passed in to IrSIRClassCoInstaller
|
|
DeviceInfoData - As passed in to IrSIRClassCoInstaller
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
HKEY hKey;
|
|
DWORD i, dwReserved = 0, dwType;
|
|
TCHAR Value[MAX_PATH];
|
|
TCHAR Data[MAX_PATH];
|
|
DWORD ValueLength = sizeof(Value)/sizeof(TCHAR);
|
|
DWORD DataLength = sizeof(Data);
|
|
TCHAR buf[100];
|
|
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DEV,
|
|
KEY_READ);
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:EnumValues:SetupDiOpenDevRegKey failed\n"));
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
|
|
for (i=0,
|
|
dwType=REG_SZ;
|
|
RegEnumValue(hKey,
|
|
i,
|
|
Value,
|
|
&ValueLength,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)Data,
|
|
&DataLength
|
|
)==ERROR_SUCCESS;
|
|
i++, dwType=REG_SZ
|
|
)
|
|
{
|
|
#if DBG
|
|
if (dwType==REG_SZ)
|
|
{
|
|
wsprintf(buf, TEXT("Value(%d):%s Data:%s\n"), i, Value, Data);
|
|
OutputDebugString(buf);
|
|
}
|
|
#endif
|
|
|
|
ValueLength = sizeof(Value)/sizeof(TCHAR);
|
|
DataLength = sizeof(Data);
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
LONG
|
|
EnumSerialDevices(
|
|
IN PPROPPAGEPARAMS pPropParams,
|
|
IN HWND hDlg,
|
|
OUT PULONG pNumFound
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function which fills in the IDC_PORT control of the dialiog box with
|
|
valid COM names.
|
|
|
|
Arguments:
|
|
|
|
pPropParams - Context data
|
|
hDlg - Dialog box containing IDC_PORT
|
|
pNumFound - Count of COM names added to IDC_PORT
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS or failure code
|
|
|
|
--*/
|
|
{
|
|
LRESULT lResult;
|
|
LONG Result = ERROR_SUCCESS, tmpResult;
|
|
HKEY hKey = INVALID_HANDLE_VALUE;
|
|
HKEY hkSerialComm = INVALID_HANDLE_VALUE;
|
|
TCHAR Buf[100];
|
|
LPTSTR CurrentPort = NULL;
|
|
DWORD dwLength, dwType, dwDisposition;
|
|
HDEVINFO hPorts;
|
|
SP_DEVINFO_DATA PortData;
|
|
|
|
*pNumFound = 0;
|
|
|
|
hKey = SetupDiOpenDevRegKey(pPropParams->DeviceInfoSet,
|
|
pPropParams->DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DRV,
|
|
KEY_ALL_ACCESS);
|
|
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:EnumSerial:SetupDiOpenDevRegKey failed\n"));
|
|
#endif
|
|
Result = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
// Read the current port. If it's empty, we'll start with an empty value.
|
|
// Failure is ok.
|
|
|
|
(void)MyRegQueryValueEx(hKey,
|
|
TEXT("Port"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE*)&CurrentPort,
|
|
&dwLength);
|
|
|
|
Result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hkSerialComm);
|
|
}
|
|
|
|
if (Result != ERROR_SUCCESS)
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:RegOpenKeyEx on SERIALCOMM failed\n"));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
DWORD i, dwReserved = 0, dwType;
|
|
TCHAR Value[MAX_PATH];
|
|
TCHAR Data[MAX_PATH];
|
|
DWORD ValueLength = sizeof(Value)/sizeof(TCHAR);
|
|
DWORD DataLength = sizeof(Data);
|
|
|
|
|
|
for (i=0,
|
|
dwType=REG_SZ;
|
|
RegEnumValue(hkSerialComm,
|
|
i,
|
|
Value,
|
|
&ValueLength,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)Data,
|
|
&DataLength
|
|
)==ERROR_SUCCESS;
|
|
i++, dwType=REG_SZ
|
|
)
|
|
{
|
|
if (dwType==REG_SZ)
|
|
{
|
|
(*pNumFound)++;
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_PORT,
|
|
LB_ADDSTRING,
|
|
0,
|
|
(LPARAM)Data);
|
|
|
|
}
|
|
|
|
ValueLength = sizeof(Value)/sizeof(TCHAR);
|
|
DataLength = sizeof(Data);
|
|
}
|
|
|
|
lResult = SendDlgItemMessage(hDlg,
|
|
IDC_PORT,
|
|
LB_FINDSTRINGEXACT,
|
|
0,
|
|
(LPARAM)CurrentPort);
|
|
if (lResult==LB_ERR)
|
|
{
|
|
i = 0;
|
|
pPropParams->PortInitialValue = -1;
|
|
}
|
|
else
|
|
{
|
|
i = (DWORD)lResult;
|
|
pPropParams->PortInitialValue = i;
|
|
}
|
|
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_PORT,
|
|
LB_SETCURSEL,
|
|
i,
|
|
0);
|
|
}
|
|
|
|
if (CurrentPort)
|
|
{
|
|
LocalFree(CurrentPort);
|
|
}
|
|
|
|
if (hkSerialComm!=INVALID_HANDLE_VALUE)
|
|
{
|
|
RegCloseKey(hkSerialComm);
|
|
}
|
|
|
|
if (hKey!=INVALID_HANDLE_VALUE)
|
|
{
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
BOOL
|
|
IsPortValueSet(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData
|
|
)
|
|
{
|
|
HKEY hKey = INVALID_HANDLE_VALUE;
|
|
BOOL bResult = FALSE;
|
|
LPTSTR CurrentPort = NULL;
|
|
DWORD dwLength;
|
|
LONG Result;
|
|
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DRV,
|
|
KEY_ALL_ACCESS);
|
|
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
{
|
|
// Read the current port. If it's empty, we'll start with an empty value.
|
|
// Failure is ok.
|
|
|
|
Result = MyRegQueryValueEx(hKey,
|
|
TEXT("Port"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE*)&CurrentPort,
|
|
&dwLength);
|
|
|
|
if (Result == ERROR_SUCCESS && CurrentPort!=NULL)
|
|
{
|
|
bResult = TRUE;
|
|
LocalFree(CurrentPort);
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
LONG
|
|
InitMaxConnect(
|
|
IN PPROPPAGEPARAMS pPropParams,
|
|
IN HWND hDlg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function which fills in the IDC_MAX_CONNECT control of the dialiog box with
|
|
valid baud rates for this device.
|
|
|
|
Arguments:
|
|
pPropParams - Context data
|
|
hDlg - Dialog box containing IDC_MAX_CONNECT
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS or failure code
|
|
|
|
--*/
|
|
{
|
|
LRESULT lResult;
|
|
LONG Result = ERROR_SUCCESS;
|
|
HKEY hKey = INVALID_HANDLE_VALUE;
|
|
TCHAR Buf[100];
|
|
LPTSTR CurrentMaxConnectRate = NULL;
|
|
LPTSTR MaxConnectList = NULL;
|
|
DWORD dwLength;
|
|
LONG i;
|
|
|
|
hKey = SetupDiOpenDevRegKey(pPropParams->DeviceInfoSet,
|
|
pPropParams->DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DRV,
|
|
KEY_ALL_ACCESS);
|
|
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:InitMaxConnect:SetupDiOpenDevRegKey failed\n"));
|
|
#endif
|
|
Result = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
LONG TmpResult;
|
|
|
|
// Read the MaxConnectRate. If it doesn't exist, we'll use the BaudTable instead.
|
|
|
|
TmpResult = MyRegQueryValueEx(
|
|
hKey,
|
|
TEXT("MaxConnectList"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE*)&MaxConnectList,
|
|
&dwLength);
|
|
|
|
if (TmpResult == ERROR_SUCCESS)
|
|
{
|
|
i = 0;
|
|
|
|
|
|
// Parse the MULTI_SZ, and add each string to IDC_MAX_CONNECT
|
|
// We assume the values are ordered.
|
|
|
|
while (MaxConnectList[i])
|
|
{
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_MAX_CONNECT,
|
|
LB_ADDSTRING,
|
|
0,
|
|
(LPARAM)&MaxConnectList[i]);
|
|
|
|
while (MaxConnectList[i]) i++;
|
|
|
|
i++; // advance past the null
|
|
|
|
if ((unsigned)i>=dwLength)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Key not found, use default baud table.
|
|
|
|
for (i=NUM_BAUD_RATES-1; i>=0; i--)
|
|
{
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_MAX_CONNECT,
|
|
LB_ADDSTRING,
|
|
0,
|
|
(LPARAM)BaudTable[i]);
|
|
}
|
|
}
|
|
|
|
TmpResult = MyRegQueryValueEx(
|
|
hKey,
|
|
TEXT("MaxConnectRate"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE*)&CurrentMaxConnectRate,
|
|
&dwLength);
|
|
|
|
lResult = SendDlgItemMessage(
|
|
hDlg,
|
|
IDC_MAX_CONNECT,
|
|
LB_FINDSTRINGEXACT,
|
|
0,
|
|
(LPARAM)CurrentMaxConnectRate);
|
|
|
|
|
|
if (lResult==LB_ERR)
|
|
{
|
|
i = 0;
|
|
pPropParams->MaxConnectInitialValue = -1;
|
|
}
|
|
else
|
|
{
|
|
i = (LONG)lResult;
|
|
pPropParams->MaxConnectInitialValue = i;
|
|
}
|
|
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_MAX_CONNECT,
|
|
LB_SETCURSEL,
|
|
i,
|
|
0);
|
|
}
|
|
|
|
if (CurrentMaxConnectRate)
|
|
{
|
|
LocalFree(CurrentMaxConnectRate);
|
|
}
|
|
|
|
if (MaxConnectList)
|
|
{
|
|
LocalFree(MaxConnectList);
|
|
}
|
|
|
|
if (hKey!=INVALID_HANDLE_VALUE)
|
|
{
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
BOOL
|
|
EnablePortSelection(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN HWND hDlg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function determines whether the dialog box should have a port
|
|
selection entry, and if so enables the appropriate controls:
|
|
IDC_PORT_BOX, IDC_PORT_TEXT, IDC_PORT.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - As passed in to IrSIRClassCoInstaller
|
|
DeviceInfoData - As passed in to IrSIRClassCoInstaller
|
|
hDlg - Dialog box containing IDC_PORT and associated controls
|
|
|
|
Return Value:
|
|
|
|
TRUE if PortSelection was enabled.
|
|
|
|
--*/
|
|
{
|
|
LONG Result = ERROR_SUCCESS;
|
|
HKEY hKey = INVALID_HANDLE_VALUE;
|
|
TCHAR Buf[100];
|
|
TCHAR SerialBased[16] = TEXT("");
|
|
DWORD dwLength;
|
|
LONG i;
|
|
BOOL bSerialBased = FALSE;
|
|
|
|
hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DRV,
|
|
KEY_ALL_ACCESS);
|
|
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:EnablePortSelection:SetupDiOpenDevRegKey failed\n"));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Read the MaxConnectRate. If it's empty, we'll start with an empty value.
|
|
|
|
dwLength = sizeof(SerialBased);
|
|
|
|
Result = RegQueryValueEx(hKey,
|
|
TEXT("SerialBased"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)SerialBased,
|
|
&dwLength);
|
|
|
|
bSerialBased = (Result==ERROR_SUCCESS) ? _ttol(SerialBased) : TRUE;
|
|
|
|
if (bSerialBased)
|
|
{
|
|
DWORD ControlsToShow[] = { IDC_PORT_BOX, IDC_PORT_TEXT, IDC_PORT };
|
|
|
|
for (i=0; i<sizeof(ControlsToShow)/sizeof(ControlsToShow[0]); i++)
|
|
{
|
|
ShowWindow(GetDlgItem(hDlg, ControlsToShow[i]),
|
|
SW_SHOWNA);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hKey!=INVALID_HANDLE_VALUE)
|
|
{
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return bSerialBased;
|
|
}
|
|
|
|
LONG
|
|
InitDescription(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN HWND hDlg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function to fill the IDC_DEVICE_DESC box with an appropriate description
|
|
of the device being configured.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - As passed in to IrSIRClassCoInstaller
|
|
DeviceInfoData - As passed in to IrSIRClassCoInstaller
|
|
hDlg - Dialog box containing IDC_DEVICE_DESC
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS or failure code
|
|
|
|
--*/
|
|
{
|
|
LONG Result = ERROR_SUCCESS;
|
|
TCHAR Description[LINE_LEN] = TEXT("Failed to retrive description");
|
|
DWORD dwLength;
|
|
|
|
if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_DEVICEDESC,
|
|
NULL,
|
|
(LPBYTE)Description,
|
|
sizeof(Description),
|
|
&dwLength))
|
|
{
|
|
Result = GetLastError();
|
|
#if DBG
|
|
{
|
|
TCHAR buf[100];
|
|
wsprintf(buf, TEXT("IrSIRCoClassInstaller:InitDescription:SetupDiGetDeviceRegistryProperty failed (0x%08x)\n"), Result);
|
|
OutputDebugString(buf);
|
|
}
|
|
#endif
|
|
}
|
|
// Display it
|
|
SetDlgItemText(hDlg, IDC_DEVICE_DESC, Description);
|
|
|
|
return Result;
|
|
}
|
|
|
|
LONG
|
|
WriteRegistrySettings(
|
|
IN HWND hDlg,
|
|
IN PPROPPAGEPARAMS pPropParams
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function to write Port and MaxConnectRate values to the devnode key.
|
|
This also ensures that the miniport is restarted to pick up these changes.
|
|
It usually means someone has changed a value in the device manager.
|
|
|
|
Arguments:
|
|
|
|
hDlg - Dialog box containing IDC_PORT and associated controls
|
|
pPropParams - Local context data for this devnode
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS or failure code
|
|
|
|
--*/
|
|
{
|
|
TCHAR szPort[16], szMaxConnectRate[16];
|
|
HKEY hKey;
|
|
LRESULT lResult;
|
|
DWORD i;
|
|
LONG Result = ERROR_SUCCESS;
|
|
BOOL PropertiesChanged = FALSE;
|
|
TCHAR buf[100];
|
|
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:WriteRegistrySettings\n"));
|
|
#endif
|
|
//
|
|
// Write out the com port options to the registry. These options
|
|
// are read by the NDIS miniport via NdisReadConfiguration()
|
|
//
|
|
if (pPropParams->SerialBased)
|
|
{
|
|
lResult = SendDlgItemMessage(hDlg,
|
|
IDC_PORT,
|
|
LB_GETCURSEL,
|
|
0, 0);
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_PORT,
|
|
LB_GETTEXT,
|
|
(UINT)lResult, (LPARAM)szPort);
|
|
|
|
if ((unsigned)lResult!=pPropParams->PortInitialValue)
|
|
{
|
|
PropertiesChanged = TRUE;
|
|
}
|
|
}
|
|
|
|
if (pPropParams->FirstTimeInstall)
|
|
{
|
|
lstrcpy(szMaxConnectRate, DEFAULT_MAX_CONNECT_RATE);
|
|
}
|
|
else
|
|
{
|
|
lResult = SendDlgItemMessage(hDlg,
|
|
IDC_MAX_CONNECT,
|
|
LB_GETCURSEL,
|
|
0, 0);
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_MAX_CONNECT,
|
|
LB_GETTEXT,
|
|
(UINT)lResult, (LPARAM)szMaxConnectRate);
|
|
if ((unsigned)lResult!=pPropParams->MaxConnectInitialValue)
|
|
{
|
|
PropertiesChanged = TRUE;
|
|
}
|
|
}
|
|
|
|
hKey = SetupDiOpenDevRegKey(pPropParams->DeviceInfoSet,
|
|
pPropParams->DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DRV,
|
|
KEY_ALL_ACCESS);
|
|
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:WriteRegistrySettings:SetupDiOpenDevRegKey failed\n"));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if (pPropParams->SerialBased)
|
|
{
|
|
TCHAR szLocation[128], *pszLocationFmt;
|
|
|
|
|
|
Result = RegSetValueEx(hKey,
|
|
TEXT("Port"),
|
|
0,
|
|
REG_SZ,
|
|
(LPBYTE)szPort,
|
|
lstrlen(szPort)*sizeof(szPort[0]));
|
|
#if 0
|
|
if(MyLoadString(ghDllInst, IDS_LOCATION_FORMAT, &pszLocationFmt))
|
|
{
|
|
wsprintf(szLocation, pszLocationFmt, szPort);
|
|
LocalFree(pszLocationFmt);
|
|
}
|
|
else
|
|
{
|
|
szLocation[0] = 0;
|
|
}
|
|
#else
|
|
lstrcpy(szLocation,szPort);
|
|
#endif
|
|
SetupDiSetDeviceRegistryProperty(pPropParams->DeviceInfoSet,
|
|
pPropParams->DeviceInfoData,
|
|
SPDRP_LOCATION_INFORMATION,
|
|
(LPBYTE)szLocation,
|
|
(lstrlen(szLocation)+1)*sizeof(TCHAR));
|
|
}
|
|
|
|
if (Result==ERROR_SUCCESS)
|
|
{
|
|
Result = RegSetValueEx(hKey,
|
|
TEXT("MaxConnectRate"),
|
|
0,
|
|
REG_SZ,
|
|
(LPBYTE)szMaxConnectRate,
|
|
lstrlen(szMaxConnectRate)*sizeof(szMaxConnectRate[0]));
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
|
|
if (Result==ERROR_SUCCESS && PropertiesChanged)
|
|
{
|
|
if (pPropParams->FirstTimeInstall)
|
|
{
|
|
// On a first time install, NT may not look for the PROPCHANGE_PENDING bit.
|
|
// Instead we will notify that the driver needs to be restarted ourselves,
|
|
// so that the changes we're writing get picked up.
|
|
SP_DEVINSTALL_PARAMS DevInstallParams;
|
|
SP_PROPCHANGE_PARAMS PropChangeParams;
|
|
|
|
ZeroMemory(&PropChangeParams, sizeof(SP_PROPCHANGE_PARAMS));
|
|
|
|
PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
|
|
PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
|
|
PropChangeParams.StateChange = DICS_PROPCHANGE;
|
|
PropChangeParams.Scope = DICS_FLAG_GLOBAL;
|
|
|
|
if (SetupDiSetClassInstallParams(pPropParams->DeviceInfoSet,
|
|
pPropParams->DeviceInfoData,
|
|
(PSP_CLASSINSTALL_HEADER)&PropChangeParams,
|
|
sizeof(SP_PROPCHANGE_PARAMS))
|
|
)
|
|
{
|
|
|
|
DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
|
|
if(SetupDiGetDeviceInstallParams(pPropParams->DeviceInfoSet,
|
|
pPropParams->DeviceInfoData,
|
|
&DevInstallParams))
|
|
{
|
|
DevInstallParams.Flags |= DI_CLASSINSTALLPARAMS;
|
|
|
|
SetupDiSetDeviceInstallParams(pPropParams->DeviceInfoSet,
|
|
pPropParams->DeviceInfoData,
|
|
&DevInstallParams);
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:WriteRegistrySettings:SetupDiGetDeviceInstallParams failed 1\n"));
|
|
#endif
|
|
}
|
|
|
|
SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
|
|
pPropParams->DeviceInfoSet,
|
|
pPropParams->DeviceInfoData);
|
|
|
|
if(SetupDiGetDeviceInstallParams(pPropParams->DeviceInfoSet,
|
|
pPropParams->DeviceInfoData,
|
|
&DevInstallParams))
|
|
{
|
|
DevInstallParams.Flags |= DI_PROPERTIES_CHANGE;
|
|
|
|
SetupDiSetDeviceInstallParams(pPropParams->DeviceInfoSet,
|
|
pPropParams->DeviceInfoData,
|
|
&DevInstallParams);
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:WriteRegistrySettings:SetupDiGetDeviceInstallParams failed 2\n"));
|
|
#endif
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:WriteRegistrySettings:SetupDiSetClassInstallParams failed \n"));
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// This is the case where the user has changed settings in the property
|
|
// sheet. Life is much easier.
|
|
SP_DEVINSTALL_PARAMS DevInstallParams;
|
|
//
|
|
// The changes are written, notify the world to reset the driver.
|
|
//
|
|
|
|
DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
if(SetupDiGetDeviceInstallParams(pPropParams->DeviceInfoSet,
|
|
pPropParams->DeviceInfoData,
|
|
&DevInstallParams))
|
|
{
|
|
LONG ChangeResult;
|
|
DevInstallParams.FlagsEx |= DI_FLAGSEX_PROPCHANGE_PENDING;
|
|
|
|
ChangeResult =
|
|
SetupDiSetDeviceInstallParams(pPropParams->DeviceInfoSet,
|
|
pPropParams->DeviceInfoData,
|
|
&DevInstallParams);
|
|
#if DBG
|
|
{
|
|
wsprintf(buf, TEXT("SetupDiSetDeviceInstallParams(DI_FLAGSEX_PROPCHANGE_PENDING)==%d %x\n"), ChangeResult, GetLastError());
|
|
OutputDebugString(buf);
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:WriteRegistrySettings:SetupDiGetDeviceInstallParams failed 2\n"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
#if DBG
|
|
{
|
|
wsprintf(buf, TEXT("IrSIRCoClassInstaller:Result==%x FirstTimeInstall==%d Changed==%d\n"),
|
|
Result, pPropParams->FirstTimeInstall, PropertiesChanged);
|
|
OutputDebugString(buf);
|
|
}
|
|
#endif
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
INT_PTR APIENTRY PortDlgProc(IN HWND hDlg,
|
|
IN UINT uMessage,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The windows control function for the IrDA Settings properties window
|
|
|
|
Arguments:
|
|
|
|
hDlg, uMessage, wParam, lParam: standard windows DlgProc parameters
|
|
|
|
Return Value:
|
|
|
|
BOOL: FALSE if function fails, TRUE if function passes
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
TCHAR CharBuffer[LINE_LEN];
|
|
PPROPPAGEPARAMS pPropParams;
|
|
TCHAR buf[100];
|
|
|
|
pPropParams = (PPROPPAGEPARAMS)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
switch (uMessage)
|
|
{
|
|
case WM_INITDIALOG:
|
|
|
|
//
|
|
// lParam points to one of two possible objects. If we're a property
|
|
// page, it points to the PropSheetPage structure. If we're a regular
|
|
// dialog box, it points to the PROPPAGEPARAMS structure. We can
|
|
// verify which because the first field of PROPPAGEPARAMS is a signature.
|
|
//
|
|
// In either case, once we figure out which, we store the value into
|
|
// DWL_USER so we only have to do this once.
|
|
//
|
|
pPropParams = (PPROPPAGEPARAMS)lParam;
|
|
if (pPropParams->Signature!=PPParamsSignature)
|
|
{
|
|
pPropParams = (PPROPPAGEPARAMS)((LPPROPSHEETPAGE)lParam)->lParam;
|
|
if (pPropParams->Signature!=PPParamsSignature)
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IRCLASS.DLL: PortDlgProc Signature not found!\n"));
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
}
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LPARAM)pPropParams);
|
|
|
|
|
|
|
|
if (!pPropParams->FirstTimeInstall)
|
|
{
|
|
InitMaxConnect(pPropParams, hDlg);
|
|
|
|
pPropParams->SerialBased = EnablePortSelection(pPropParams->DeviceInfoSet,
|
|
pPropParams->DeviceInfoData,
|
|
hDlg);
|
|
if (pPropParams->SerialBased)
|
|
{
|
|
EnumSerialDevices(pPropParams, hDlg, &i);
|
|
}
|
|
|
|
InitDescription(pPropParams->DeviceInfoSet,
|
|
pPropParams->DeviceInfoData,
|
|
hDlg);
|
|
}
|
|
else
|
|
{
|
|
pPropParams->SerialBased = TRUE;
|
|
EnumSerialDevices(pPropParams, hDlg, &i);
|
|
|
|
if (i > 0) {
|
|
//
|
|
// there were some port availible
|
|
//
|
|
// Enable next and cancel wizard buttons. BACK is not valid here,
|
|
// since the device is already installed at this point. Cancel
|
|
// will cause the device to be removed.
|
|
//
|
|
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT);
|
|
}
|
|
EnableWindow(GetDlgItem(GetParent(hDlg), IDCANCEL), TRUE);
|
|
}
|
|
|
|
return TRUE; // No need for us to set the focus.
|
|
|
|
case WM_COMMAND:
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case LBN_SELCHANGE:
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:PropertySheet Changed\n"));
|
|
#endif
|
|
PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
}
|
|
return TRUE;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
//
|
|
// Because this is a prop sheet, we should never get this.
|
|
// All notifications for ctrols outside of the sheet come through
|
|
// WM_NOTIFY
|
|
//
|
|
case IDCANCEL:
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
|
|
EndDialog(hDlg, uMessage);
|
|
return TRUE;
|
|
case IDOK:
|
|
{
|
|
WriteRegistrySettings(hDlg, pPropParams);
|
|
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
|
|
EndDialog(hDlg, uMessage);
|
|
return TRUE;
|
|
}
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
case WM_NOTIFY:
|
|
|
|
switch (((NMHDR *)lParam)->code)
|
|
{
|
|
//
|
|
// Sent when the user clicks on Apply OR OK !!
|
|
//
|
|
case PSN_WIZNEXT:
|
|
if (!pPropParams->FirstTimeInstall)
|
|
{
|
|
break;
|
|
}
|
|
case PSN_APPLY:
|
|
{
|
|
WriteRegistrySettings(hDlg, pPropParams);
|
|
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
|
|
return TRUE;
|
|
}
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
//
|
|
// free the description of the com ports. If any msgs are processed
|
|
// after WM_DESTROY, do not reference pPropParams!!! To enforce this,
|
|
// set the DWL_USER stored long to 0
|
|
//
|
|
LocalFree(pPropParams);
|
|
SetWindowLongPtr(hDlg, DWLP_USER, 0);
|
|
|
|
case WM_HELP:
|
|
if (lParam)
|
|
{
|
|
return WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle,
|
|
(LPCTSTR)szHelpFile,
|
|
HELP_WM_HELP,
|
|
(ULONG_PTR)HelpIDs);
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
case WM_CONTEXTMENU:
|
|
return WinHelp((HWND)wParam,
|
|
(LPCTSTR)szHelpFile,
|
|
HELP_CONTEXTMENU,
|
|
(ULONG_PTR)HelpIDs);
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
} /* PortDialogProc */
|
|
|
|
|
|
void PortSelectionDlg(
|
|
HDEVINFO DeviceInfoSet,
|
|
PSP_DEVINFO_DATA DeviceInfoData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
PropSheet setup for devnode configuration.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - As passed in to IrSIRClassCoInstaller
|
|
DeviceInfoData - As passed in to IrSIRClassCoInstaller
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
HKEY hKey = 0;
|
|
PPROPPAGEPARAMS pPropParams = NULL;
|
|
PROPSHEETHEADER PropHeader;
|
|
PROPSHEETPAGE PropSheetPage;
|
|
TCHAR buf[100];
|
|
LPTSTR Title=NULL;
|
|
LPTSTR SubTitle=NULL;
|
|
|
|
|
|
|
|
SP_NEWDEVICEWIZARD_DATA WizData;
|
|
|
|
WizData.ClassInstallHeader.cbSize = sizeof(WizData.ClassInstallHeader);
|
|
|
|
if (!SetupDiGetClassInstallParams(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
(PSP_CLASSINSTALL_HEADER)&WizData,
|
|
sizeof(WizData),
|
|
NULL)
|
|
|| WizData.ClassInstallHeader.InstallFunction!=DIF_NEWDEVICEWIZARD_FINISHINSTALL)
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller: Failed to get ClassInstall params\n"));
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller: PortSelectionDlg\n"));
|
|
#endif
|
|
|
|
pPropParams = LocalAlloc(LMEM_FIXED, sizeof(PROPPAGEPARAMS));
|
|
if (!pPropParams)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pPropParams->Signature = PPParamsSignature;
|
|
pPropParams->DeviceInfoSet = DeviceInfoSet;
|
|
pPropParams->DeviceInfoData = DeviceInfoData;
|
|
pPropParams->FirstTimeInstall = TRUE;
|
|
|
|
if (WizData.NumDynamicPages < MAX_INSTALLWIZARD_DYNAPAGES)
|
|
{
|
|
//
|
|
// Setup the advanced properties window information
|
|
//
|
|
BOOLEAN bResult;
|
|
DWORD RequiredSize = 0;
|
|
DWORD dwTotalSize = 0;
|
|
LONG lResult;
|
|
|
|
memset(&PropSheetPage, 0, sizeof(PropSheetPage));
|
|
//
|
|
// Add the Port Settings property page
|
|
//
|
|
PropSheetPage.dwSize = sizeof(PROPSHEETPAGE);
|
|
PropSheetPage.dwFlags = PSP_DEFAULT; //PSP_USECALLBACK; // | PSP_HASHELP;
|
|
PropSheetPage.hInstance = ghDllInst;
|
|
PropSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_INSTALL_PORT_SELECT);
|
|
|
|
//
|
|
// following points to the dlg window proc
|
|
//
|
|
PropSheetPage.hIcon = NULL;
|
|
PropSheetPage.pfnDlgProc = PortDlgProc;
|
|
PropSheetPage.lParam = (LPARAM)pPropParams;
|
|
|
|
//
|
|
// following points to some control callback of the dlg window proc
|
|
//
|
|
PropSheetPage.pfnCallback = NULL;
|
|
|
|
PropSheetPage.pcRefParent = NULL;
|
|
|
|
if ( 0 != MyLoadString(ghDllInst, IDS_SELECT_PORT_TITLE, &Title)) {
|
|
|
|
// We don't use these, but if we wanted to...
|
|
PropSheetPage.dwFlags |= PSP_USEHEADERTITLE;
|
|
PropSheetPage.pszHeaderTitle = Title;
|
|
|
|
}
|
|
|
|
if (0 != MyLoadString(ghDllInst, IDS_SELECT_PORT_SUBTITLE, &SubTitle)) {
|
|
|
|
PropSheetPage.dwFlags |= PSP_USEHEADERSUBTITLE;
|
|
PropSheetPage.pszHeaderSubTitle = SubTitle;
|
|
|
|
}
|
|
|
|
WizData.DynamicPages[WizData.NumDynamicPages] = CreatePropertySheetPage(&PropSheetPage);
|
|
if (WizData.DynamicPages[WizData.NumDynamicPages])
|
|
{
|
|
WizData.NumDynamicPages++;
|
|
}
|
|
|
|
SetupDiSetClassInstallParams(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
(PSP_CLASSINSTALL_HEADER)&WizData,
|
|
sizeof(WizData));
|
|
|
|
if (Title != NULL) {
|
|
|
|
LocalFree(Title);
|
|
}
|
|
|
|
if (SubTitle != NULL) {
|
|
|
|
LocalFree(SubTitle);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
LocalFree(pPropParams);
|
|
}
|
|
} /* PortSelectionDlg */
|
|
|
|
|
|
VOID
|
|
DestroyPrivateData(PCOINSTALLER_PRIVATE_DATA pPrivateData)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function to dealloc/destroy context data
|
|
|
|
Arguments:
|
|
|
|
pPrivateData - Context buffer to dealloc/destroy
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
if (pPrivateData)
|
|
{
|
|
if (pPrivateData->hInf!=INVALID_HANDLE_VALUE)
|
|
{
|
|
SetupCloseInfFile(pPrivateData->hInf);
|
|
}
|
|
LocalFree(pPrivateData);
|
|
pPrivateData = NULL;
|
|
}
|
|
}
|
|
|
|
PCOINSTALLER_PRIVATE_DATA
|
|
CreatePrivateData(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocs and initailizes private context data buffer
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - As passed in to IrSIRClassCoInstaller
|
|
DeviceInfoData - As passed in to IrSIRClassCoInstaller
|
|
|
|
Return Value:
|
|
|
|
Pointer to alloced context data, or NULL if failure. Call GetLastError()
|
|
for extended error information.
|
|
|
|
--*/
|
|
{
|
|
PCOINSTALLER_PRIVATE_DATA pPrivateData;
|
|
BOOL Status = TRUE;
|
|
UINT ErrorLine;
|
|
TCHAR buf[100];
|
|
|
|
pPrivateData = LocalAlloc(LPTR, sizeof(COINSTALLER_PRIVATE_DATA));
|
|
|
|
if (!pPrivateData)
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller: Insufficient Memory\n"));
|
|
#endif
|
|
Status = FALSE;
|
|
}
|
|
else
|
|
{
|
|
pPrivateData->DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
|
|
Status = SetupDiGetSelectedDriver(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
&pPrivateData->DriverInfoData);
|
|
if (!Status)
|
|
{
|
|
#if DBG
|
|
wsprintf(buf, TEXT("IrSIRCoClassInstaller:SetupDiGetSelectedDriver failed (%d)\n"), GetLastError());
|
|
OutputDebugString(buf);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (Status)
|
|
{
|
|
pPrivateData->DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
|
|
Status = SetupDiGetDriverInfoDetail(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
&pPrivateData->DriverInfoData,
|
|
&pPrivateData->DriverInfoDetailData,
|
|
sizeof(SP_DRVINFO_DETAIL_DATA),
|
|
NULL);
|
|
|
|
if (!Status)
|
|
{
|
|
if (GetLastError()==ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
// We don't need the extended information. Ignore.
|
|
Status = TRUE;
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
wsprintf(buf, TEXT("IrSIRCoClassInstaller:SetupDiGetDriverInfoDetail failed (%d)\n"), GetLastError());
|
|
OutputDebugString(buf);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (Status)
|
|
{
|
|
pPrivateData->hInf = SetupOpenInfFile(pPrivateData->DriverInfoDetailData.InfFileName,
|
|
NULL,
|
|
INF_STYLE_WIN4,
|
|
&ErrorLine);
|
|
|
|
if (pPrivateData->hInf==INVALID_HANDLE_VALUE)
|
|
{
|
|
Status = FALSE;
|
|
#if DBG
|
|
wsprintf(buf, TEXT("IrSIRCoClassInstaller:SetupOpenInfFile failed (%d) ErrorLine==%d\n"), GetLastError(), ErrorLine);
|
|
OutputDebugString(buf);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (Status)
|
|
{
|
|
// Translate to the .NT name, if present.
|
|
Status = SetupDiGetActualSectionToInstall(pPrivateData->hInf,
|
|
pPrivateData->DriverInfoDetailData.SectionName,
|
|
pPrivateData->InfSectionWithExt,
|
|
LINE_LEN,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (!Status)
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:SetupDiGetActualSectionToInstall failed\n"));
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
if (!Status)
|
|
{
|
|
// We experienced some failure. Cleanup.
|
|
|
|
DestroyPrivateData(pPrivateData);
|
|
pPrivateData = NULL;
|
|
}
|
|
|
|
return pPrivateData;
|
|
}
|
|
|
|
DWORD
|
|
IrSIRClassCoInstaller(
|
|
IN DI_FUNCTION InstallFunction,
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
|
|
IN OUT PCOINSTALLER_CONTEXT_DATA pContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine acts as the class coinstaller for SIR devices. This is set up
|
|
to be called by the INF:
|
|
|
|
[MS_Devices]
|
|
; DisplayName Section DeviceID
|
|
; ----------- ------- --------
|
|
%*PNP0510.DevDesc% = PNP, *PNP0510
|
|
|
|
[PNP.NT.CoInstallers]
|
|
AddReg = IRSIR.CoInstallers.reg
|
|
|
|
[IRSIR.CoInstallers.reg]
|
|
HKR,,CoInstallers32,0x00010000,"IRCLASS.dll,IrSIRClassCoInstaller"
|
|
|
|
|
|
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:
|
|
|
|
ERROR_DI_DO_DEFAULT, ERROR_DI_POSTPROCESSING_REQUIRED, or error code
|
|
|
|
--*/
|
|
{
|
|
TCHAR buf[100];
|
|
DWORD Result = ERROR_SUCCESS;
|
|
LONG lResult;
|
|
PCOINSTALLER_PRIVATE_DATA pPrivateData;
|
|
INFCONTEXT InfContext;
|
|
|
|
#if DBG
|
|
wsprintf(buf, TEXT("IrSIRCoClassInstaller:InstallFunction(%s) PostProcessing:%d\n"), GetDIFString(InstallFunction), pContext->PostProcessing);
|
|
OutputDebugString(buf);
|
|
#endif
|
|
|
|
|
|
switch (InstallFunction)
|
|
{
|
|
case DIF_INSTALLDEVICE:
|
|
{
|
|
UINT ErrorLine;
|
|
|
|
// Private data for coinstallers is only kept across a single call,
|
|
// pre and post processing. The private data that we create here
|
|
// is not any good for any other DIF_ call.
|
|
pContext->PrivateData = CreatePrivateData(DeviceInfoSet,
|
|
DeviceInfoData);
|
|
|
|
if (!pContext->PrivateData)
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
pPrivateData = pContext->PrivateData;
|
|
|
|
{
|
|
// NOTE on the use of UPPERFILTERS and LOWERFILTERS
|
|
// A filter driver is a driver that is loaded as a shim above
|
|
// or below another driver, in this case SERIAL below IRSIR.
|
|
// It does special processing on IRPs and can give added
|
|
// functionality or is a means to avoid duplicate functionality
|
|
// in multiple drivers. UPPERFILTERS and LOWERFILTERS values
|
|
// are used by the PnP system to identify and load filter
|
|
// drivers. These values could be set via the INF in a .HW
|
|
// section, but setting them via the coinstaller may give you
|
|
// more control, i.e. you could remove one of several filter
|
|
// drivers from a list.
|
|
//
|
|
// If your driver isn't a filter driver, or doesn't use filter
|
|
// drivers, you won't need to clear these values as is done
|
|
// here.
|
|
|
|
|
|
// Always clear UpperFilters. If this is an upgrade from
|
|
// a post-1671, the IrDA device could have been installed as
|
|
// a serial port, with a serenum upper filter. This will
|
|
// blow up NDIS, so clear it.
|
|
//
|
|
// This is atypical behavior for a class coinstaller. Normally
|
|
// the upperfilter/lowerfilter values do not need to be touched.
|
|
|
|
// Note that it is possible to do this from the INF. This
|
|
// is here more for demo purpose.
|
|
|
|
SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_UPPERFILTERS,
|
|
NULL,
|
|
0);
|
|
}
|
|
|
|
if (SetupFindFirstLine(pPrivateData->hInf,
|
|
pPrivateData->InfSectionWithExt,
|
|
TEXT("LowerFilters"),
|
|
&InfContext))
|
|
{
|
|
TCHAR LowerFilters[LINE_LEN];
|
|
DWORD BytesNeeded;
|
|
if (!SetupGetMultiSzField(&InfContext, 1, LowerFilters, LINE_LEN, &BytesNeeded))
|
|
{
|
|
// Lowerfilters value was not found in the inf.
|
|
// This means we do not want a lowerfilters value in
|
|
// the registry. (Unique to IRSIR.SYS and NETIRSIR.INF)
|
|
|
|
// Setting lowerfilters here for demo purpose only.
|
|
// Normally done from INF, if necessary at all.
|
|
if (!SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_LOWERFILTERS,
|
|
NULL,
|
|
0)
|
|
)
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller: Failed to set lowerfilter\n"));
|
|
#endif
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// Setting lowerfilters here for demo purpose only.
|
|
// Normally done from INF, if necessary at all.
|
|
if (!SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_LOWERFILTERS,
|
|
(LPBYTE)LowerFilters,
|
|
((BytesNeeded<LINE_LEN) ?
|
|
BytesNeeded : LINE_LEN)*sizeof(TCHAR))
|
|
)
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller: Failed to set lowerfilter\n"));
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No lowerfilters value present. Clear it.
|
|
// Setting lowerfilters here for demo purpose only.
|
|
// Normally done from INF, if necessary at all.
|
|
if (!SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_LOWERFILTERS,
|
|
NULL,
|
|
0)
|
|
)
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller: Failed to set lowerfilter\n"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
DestroyPrivateData(pContext->PrivateData);
|
|
pContext->PrivateData = NULL;
|
|
break;
|
|
}
|
|
case DIF_NEWDEVICEWIZARD_FINISHINSTALL:
|
|
{
|
|
pContext->PrivateData = CreatePrivateData(DeviceInfoSet,
|
|
DeviceInfoData);
|
|
|
|
if (!pContext->PrivateData)
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
pPrivateData = pContext->PrivateData;
|
|
|
|
if (!SetupFindFirstLine(pPrivateData->hInf,
|
|
pPrivateData->InfSectionWithExt,
|
|
TEXT("PromptForPort"),
|
|
&InfContext))
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:failed to find PromptForPort in .INF\n"));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if (!SetupGetIntField(&InfContext, 1, &pPrivateData->PromptForPort))
|
|
{
|
|
#if DBG
|
|
OutputDebugString(TEXT("IrSIRCoClassInstaller:failed to read PromptForPort in .INF\n"));
|
|
#endif
|
|
|
|
// Default to true
|
|
pPrivateData->PromptForPort = TRUE;
|
|
}
|
|
|
|
// If we have a COM port we need to query the user, UNLESS
|
|
// this is an upgrade.
|
|
if (pPrivateData->PromptForPort && !IsPortValueSet(DeviceInfoSet, DeviceInfoData))
|
|
{
|
|
PortSelectionDlg(DeviceInfoSet, DeviceInfoData);
|
|
}
|
|
}
|
|
if (!pPrivateData->PromptForPort)
|
|
{
|
|
TCHAR *pszLocation;
|
|
if (MyLoadString(ghDllInst, IDS_INTERNAL_PORT, &pszLocation))
|
|
{
|
|
SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
SPDRP_LOCATION_INFORMATION,
|
|
(LPBYTE)pszLocation,
|
|
(1+lstrlen(pszLocation))*sizeof(TCHAR));
|
|
LocalFree(pszLocation);
|
|
}
|
|
|
|
}
|
|
|
|
DestroyPrivateData(pContext->PrivateData);
|
|
pContext->PrivateData = NULL;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
#if DBG
|
|
wsprintf(buf, TEXT("IrSIRCoClassInstaller:returning:0x%08x\n"), Result);
|
|
OutputDebugString(buf);
|
|
#endif
|
|
return Result;
|
|
}
|
|
|
|
|
|
BOOL APIENTRY IrSIRPortPropPageProvider(LPVOID pinfo,
|
|
LPFNADDPROPSHEETPAGE pfnAdd,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Entry-point for adding additional device manager property
|
|
sheet pages. This entry-point gets called only when the Device
|
|
Manager asks for additional property pages. The INF associated with
|
|
this causes it to be called by specifying it in an AddReg section:
|
|
|
|
[IRSIR.reg]
|
|
HKR, , EnumPropPages32, , "IRCLASS.dll,IrSIRPortPropPageProvider"
|
|
|
|
|
|
Arguments:
|
|
|
|
pinfo - points to PROPSHEETPAGE_REQUEST, see setupapi.h
|
|
pfnAdd - function ptr to call to add sheet.
|
|
lParam - add sheet functions private data handle.
|
|
|
|
Return Value:
|
|
|
|
BOOL: FALSE if pages could not be added, TRUE on success
|
|
|
|
--*/
|
|
{
|
|
PSP_PROPSHEETPAGE_REQUEST pprPropPageRequest;
|
|
HKEY hKey = 0;
|
|
PROPSHEETPAGE PropSheetPage;
|
|
HPROPSHEETPAGE hspPropSheetPage;
|
|
PPROPPAGEPARAMS pPropParams = NULL;
|
|
|
|
pPropParams = LocalAlloc(LMEM_FIXED, sizeof(PROPPAGEPARAMS));
|
|
if (!pPropParams)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pprPropPageRequest = (PSP_PROPSHEETPAGE_REQUEST) pinfo;
|
|
|
|
pPropParams->Signature = PPParamsSignature;
|
|
pPropParams->DeviceInfoSet = pprPropPageRequest->DeviceInfoSet;
|
|
pPropParams->DeviceInfoData = pprPropPageRequest->DeviceInfoData;
|
|
pPropParams->FirstTimeInstall = FALSE;
|
|
|
|
if (pprPropPageRequest->PageRequested == SPPSR_ENUM_ADV_DEVICE_PROPERTIES)
|
|
{
|
|
//
|
|
// Setup the advanced properties window information
|
|
//
|
|
BOOLEAN bResult;
|
|
DWORD RequiredSize = 0;
|
|
DWORD dwTotalSize = 0;
|
|
|
|
memset(&PropSheetPage, 0, sizeof(PropSheetPage));
|
|
//
|
|
// Add the Port Settings property page
|
|
//
|
|
PropSheetPage.dwSize = sizeof(PROPSHEETPAGE);
|
|
PropSheetPage.dwFlags = PSP_USECALLBACK; // | PSP_HASHELP;
|
|
PropSheetPage.hInstance = ghDllInst;
|
|
PropSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PP_IRDA_SETTINGS);
|
|
|
|
//
|
|
// following points to the dlg window proc
|
|
//
|
|
PropSheetPage.pfnDlgProc = PortDlgProc;
|
|
PropSheetPage.lParam = (LPARAM)pPropParams;
|
|
|
|
//
|
|
// following points to some control callback of the dlg window proc
|
|
//
|
|
PropSheetPage.pfnCallback = NULL;
|
|
|
|
//
|
|
// allocate our "Ports Setting" sheet
|
|
//
|
|
hspPropSheetPage = CreatePropertySheetPage(&PropSheetPage);
|
|
if (!hspPropSheetPage)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// add the thing in.
|
|
//
|
|
if (!pfnAdd(hspPropSheetPage, lParam))
|
|
{
|
|
DestroyPropertySheetPage(hspPropSheetPage);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LocalFree(pPropParams);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} /* IrSIRPortPropPageProvider */
|