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