windows-nt/Source/XPSP1/NT/net/irda/irclass/irclass.c
2020-09-26 16:20:57 +08:00

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 */