/*----------------------------------------------------------------------- | nt50.c - NT5.0 specific code for VSLinkA/RocketPort Windows Install Program. This compiles into a DLL library which is installed(via INF) into the SYSTEM directory. The INF file also hooks us into the system as a property page associated with the device. Also, our co-installer DLL calls into us as well to perform configuration tasks(initial install, un-install). The .NumDevices option is used to save the number of Devices in our configuration. Under NT50, we don't use it as such. This setup dll only concerns itself with 1 device, and lets NT5.0 OS handle the list of devices. So NumDevices always gets set to 1 under NT5.0 even if we have more than one device which our driver is controlling. 11-24-98 - add some code toward clean up of files after uninstall, kpb. Copyright 1998. Comtrol(TM) Corporation. |-----------------------------------------------------------------------*/ #include "precomp.h" #include #define D_Level 0x40 static int write_config(int clear_it); static int FindPortNodes(void); static int read_config(void); static int get_pnp_devicedesc(TCHAR *name); static int nt5_get_pnp_dev_id(int *id); static void uninstall_device(void); int get_device_name(void); int do_nt50_install(void); BOOL WINAPI ClassInsProc( int func_num, // our function to carry out. LPVOID our_info); // points to our data struct static int get_pnp_setup_info(void); static int get_device_property(char *ret_name, int max_size); static int get_pnp_isa_address(void); static void test_config(void); // following can be turned on to provide a User Interface during the // install time of the driver. Only problem is that NT5.0 fires up // the driver first, and are ports //#define TRY_UI 1 #ifdef TRY_UI int DoCLassPropPages(HWND hwndOwner); int FillClassPropertySheets(PROPSHEETPAGE *psp, LPARAM our_params); BOOL WINAPI ClassSheet( IN HWND hDlg, IN UINT uMessage, IN WPARAM wParam, IN LPARAM lParam); #endif //#define DO_SHOWIT #ifdef DO_SHOWIT #define ShowMess(s) OutputDebugString(s); static void show_install_info(OUR_INFO *pi); static void show_debug_info(OUR_INFO *pi, ULONG dev_id, TCHAR *desc_str); static int DumpPnpTree(void); static void show_tree_node(DEVINST devInst, ULONG dev_id, TCHAR *desc_str); static void show_tree_node_reg(DEVINST devInst, TCHAR *key_name); static TCHAR *spdrp_names[] = { TEXT("DEVICEDESC"), TEXT("HARDWAREID"), TEXT("COMPATIBLEIDS"), TEXT("NTDEVICEPATHS"), TEXT("SERVICE"), TEXT("CONFIGURATION"), // x5 TEXT("CONFIGURATIONVECTOR"), TEXT("CLASS"), TEXT("CLASSGUID"), TEXT("DRIVER"), TEXT("CONFIGFLAGS"), // xA TEXT("MFG"), TEXT("FRIENDLYNAME"), TEXT("LOCATION_INFORMATION"), TEXT("PHYSICAL_DEVICE_OBJECT_NAME"), TEXT("CAPABILITIES"), TEXT("UI_NUMBER"), // x10 TEXT("UPPERFILTERS"), TEXT("LOWERFILTERS"), TEXT("BUSTYPEGUID"), // x13 TEXT("LEGACYBUSTYPE"), TEXT("BUSNUMBER"), TEXT("invalid")}; static TCHAR *cm_drp_names[] = { TEXT("DEVICEDESC"), // DeviceDesc REG_SZ property (RW) TEXT("HARDWAREID"), // HardwareID REG_MULTI_SZ property (RW) TEXT("COMPATIBLEIDS"), // CompatibleIDs REG_MULTI_SZ property (RW) TEXT("NTDEVICEPATHS"), // Unsupported, DO NOT USE TEXT("SERVICE"), // Service REG_SZ property (RW) TEXT("CONFIGURATION"), // Configuration REG_RESOURCE_LIST property (R) TEXT("CONFIGURATIONVECTOR"), // ConfigurationVector REG_RESOURCE_REQUIREMENTS_LIST property (R) TEXT("CLASS"), // Class REG_SZ property (RW) TEXT("CLASSGUID"), // ClassGUID REG_SZ property (RW) TEXT("DRIVER"), // Driver REG_SZ property (RW) TEXT("CONFIGFLAGS"), // ConfigFlags REG_DWORD property (RW) TEXT("MFG"), // Mfg REG_SZ property (RW) TEXT("FRIENDLYNAME"), // 0x0d FriendlyName REG_SZ property (RW) TEXT("LOCATION_INFORMATION"), // LocationInformation REG_SZ property (RW) TEXT("PHYSICAL_DEVICE_OBJECT_NAME"), // PhysicalDeviceObjectName REG_SZ property (R) TEXT("CAPABILITIES"), // 0x10 Capabilities REG_DWORD property (R) TEXT("UI_NUMBER"), // UiNumber REG_DWORD property (R) TEXT("UPPERFILTERS"), // UpperFilters REG_MULTI_SZ property (RW) TEXT("LOWERFILTERS"), // LowerFilters REG_MULTI_SZ property (RW) TEXT("BUSTYPEGUID"), // Bus Type Guid, GUID, (R) TEXT("LEGACYBUSTYPE"), // Legacy bus type, INTERFACE_TYPE, (R) TEXT("BUSNUMBER"), // x16 Bus Number, DWORD, (R) TEXT("invalid")}; // these are under Control\Class\Guid\Node static TCHAR *dev_node_key_names[] = { TEXT("ProviderName"), TEXT("MatchingDeviceId"), TEXT("DriverDesc"), TEXT("InfPath"), TEXT("InfSection"), TEXT("isa_board_index"), NULL}; static TCHAR glob_ourstr[4000]; /*---------------------------------------------------------- show_install_info - show all the driver install info. |------------------------------------------------------------*/ static void show_install_info(OUR_INFO *pi) { int i; //if (MessageBox( GetFocus(), TEXT("Want Info?"), TEXT("aclass"), MB_YESNO | MB_ICONINFORMATION ) == // IDYES) { ShowMess(TEXT("**SPDRP****")); glob_ourstr[0] = 0; for (i=0; i<(SPDRP_MAXIMUM_PROPERTY-1); i++) { show_debug_info(pi, i, spdrp_names[i]); } ShowMess(glob_ourstr); //MessageBox( GetFocus(), glob_ourstr, TEXT("aclass"), MB_OK | MB_ICONINFORMATION ); } } /*---------------------------------------------------------- show_debug_info - |------------------------------------------------------------*/ static void show_debug_info(OUR_INFO *pi, ULONG dev_id, TCHAR *desc_str) { static TCHAR tmpstr[500]; static TCHAR showstr[500]; TCHAR smstr[40]; ULONG RegType; ULONG ReqSize,i; unsigned char *b_ptr; int stat; showstr[0] = 0; RegType = 0; ReqSize = 0; stat = SetupDiGetDeviceRegistryProperty(pi->DeviceInfoSet, pi->DeviceInfoData, dev_id, &RegType, // reg data type (PBYTE)tmpstr, sizeof(tmpstr), &ReqSize); // size thing if (stat == FALSE) { stat = GetLastError(); if (stat == 13) { return; // don't display this } wsprintf(showstr, TEXT("Error:%d[%xH] ReqSize:%d"), stat, stat, ReqSize); } else if (RegType == REG_SZ) { wsprintf(showstr, TEXT("SZ:%s"), tmpstr); } else if (RegType == REG_DWORD) { wsprintf(showstr, TEXT("Dword:%xH"), *((ULONG *) tmpstr)); } else if (RegType == REG_EXPAND_SZ) { wsprintf(showstr, TEXT("EXP_SZ:%s"), tmpstr); } else if (RegType == REG_MULTI_SZ) { wsprintf(showstr, TEXT("MULTI_SZ:%s"), tmpstr); } else if (RegType == REG_BINARY) { lstrcpy(showstr, TEXT("BIN:")); b_ptr = (unsigned char *)tmpstr; for (i=0; i= 0x20) && (b_ptr[i] < 0x80)) wsprintf(smstr, TEXT("%c"), b_ptr[i]); else wsprintf(smstr, TEXT("<%x>"), b_ptr[i]); lstrcat(showstr, smstr); if (i > 200) break; } } else { wsprintf(showstr, TEXT("BadType:%xH"), RegType); } if (lstrlen(showstr) > 200) showstr[200] = 0; if (lstrlen(glob_ourstr) < 3700) { lstrcat(glob_ourstr, desc_str); lstrcat(glob_ourstr, TEXT(" - ")); lstrcat(glob_ourstr, showstr); lstrcat(glob_ourstr, TEXT("\n")); } } /*----------------------------------------------------------------------------- | DumpPnpTree - Dump the pnp tree devnodes. |-----------------------------------------------------------------------------*/ static int DumpPnpTree(void) { DEVINST devInst; DEVINST devInstNext; CONFIGRET cr; ULONG walkDone = 0; ULONG len; static CHAR buf[800]; HKEY hKey; int di,pi; ULONG val_type; #if DBG //DebugBreak(); #endif //cr = CM_Locate_DevNode(&devInst, NULL, 0); // Get Root DevNode // cr = CM_Locate_DevNode(&devInst, NULL, 0); if (cr != CR_SUCCESS) { return 1; // err } // Do a depth first search for the DevNode with a matching parameter while (!walkDone) { cr = CR_SUCCESS; glob_ourstr[0] = 0; lstrcat(glob_ourstr,TEXT("-CM_DRP-----")); for (di=CM_DRP_MIN; di= 0x20) && (b_ptr[i] < 0x80)) wsprintf(smstr, TEXT("%c"), b_ptr[i]); else wsprintf(smstr, TEXT("<%x>"), b_ptr[i]); lstrcat(showstr, smstr); if (i > 200) break; } //MessageBox( GetFocus(), showstr, desc_str, MB_OK | MB_ICONINFORMATION ); } else { wsprintf(showstr, TEXT("BadType:%xH"), RegType); //MessageBox( GetFocus(), tmpstr, desc_str, MB_OK | MB_ICONINFORMATION ); } if (lstrlen(showstr) > 200) showstr[200] = 0; if (lstrlen(glob_ourstr) < 3700) { lstrcat(glob_ourstr, desc_str); lstrcat(glob_ourstr, TEXT(" - ")); lstrcat(glob_ourstr, showstr); lstrcat(glob_ourstr, TEXT("\n")); } } /*---------------------------------------------------------- show_tree_node_reg - |------------------------------------------------------------*/ static void show_tree_node_reg(DEVINST devInst, TCHAR *key_name) { CONFIGRET cr; static TCHAR tmpstr[500]; static TCHAR showstr[500]; TCHAR smstr[40]; ULONG RegType; ULONG ReqSize,i; unsigned char *b_ptr; int stat; TCHAR *desc_str = key_name; HKEY hKey; showstr[0] = 0; cr = CM_Open_DevNode_Key( devInst, KEY_READ, // IN REGSAM samDesired, 0, // IN ULONG ulHardwareProfile, RegDisposition_OpenExisting, &hKey, //OUT PHKEY phkDevice, CM_REGISTRY_SOFTWARE); // IN ULONG ulFlags if (cr == CR_SUCCESS) { RegType = 0; ReqSize = 0; tmpstr[0] = 0; ReqSize = sizeof(tmpstr); cr = RegQueryValueEx(hKey, key_name, 0, &RegType, (PBYTE) tmpstr, &ReqSize); if (cr != ERROR_SUCCESS) { tmpstr[0] = 0; } RegCloseKey(hKey); } // if openreg else { tmpstr[0] = 0; ShowMess(TEXT("**Error Opening Key!\n")); } if (cr != CR_SUCCESS) { stat = GetLastError(); //if (stat == 997) //{ // return; // don't display this //} wsprintf(showstr, TEXT("Error:%d[%xH] ReqSize:%d"), stat, stat, ReqSize); //MessageBox( GetFocus(), showstr, desc_str, MB_OK | MB_ICONINFORMATION ); } else if (RegType == REG_SZ) { wsprintf(showstr, TEXT("SZ:%s"), tmpstr); //MessageBox( GetFocus(), showstr, desc_str, MB_OK | MB_ICONINFORMATION ); } else if (RegType == REG_DWORD) { wsprintf(showstr, TEXT("Dword:%xH"), *((ULONG *) tmpstr)); //MessageBox( GetFocus(), showstr, desc_str, MB_OK | MB_ICONINFORMATION ); } else if (RegType == REG_EXPAND_SZ) { wsprintf(showstr, TEXT("EXP_SZ:%s"), tmpstr); //MessageBox( GetFocus(), showstr, desc_str, MB_OK | MB_ICONINFORMATION ); } else if (RegType == REG_MULTI_SZ) { wsprintf(showstr, TEXT("MULTI_SZ:%s"), tmpstr); //MessageBox( GetFocus(), showstr, desc_str, MB_OK | MB_ICONINFORMATION ); } else if (RegType == REG_BINARY) { lstrcpy(showstr, TEXT("BIN:")); b_ptr = (unsigned char *)tmpstr; for (i=0; i= 0x20) && (b_ptr[i] < 0x80)) wsprintf(smstr, TEXT("%c"), b_ptr[i]); else wsprintf(smstr, TEXT("<%x>"), b_ptr[i]); lstrcat(showstr, smstr); if (i > 200) break; } //MessageBox( GetFocus(), showstr, desc_str, MB_OK | MB_ICONINFORMATION ); } else { wsprintf(showstr, TEXT("BadType:%xH"), RegType); //MessageBox( GetFocus(), tmpstr, desc_str, MB_OK | MB_ICONINFORMATION ); } if (lstrlen(showstr) > 200) showstr[200] = 0; if (lstrlen(glob_ourstr) < 3700) { lstrcat(glob_ourstr, desc_str); lstrcat(glob_ourstr, TEXT(" - ")); lstrcat(glob_ourstr, showstr); lstrcat(glob_ourstr, TEXT("\n")); } } #endif // we are a DLL, so we need a LibMain... /*---------------------------------------------------------- LibMain - |-------------------------------------------------------------*/ BOOL APIENTRY LibMain( HANDLE hDll, DWORD dwReason, LPVOID lpReserved ) { //DMess("LibMain"); switch( dwReason ) { case DLL_PROCESS_ATTACH: glob_hinst = hDll; DisableThreadLibraryCalls((struct HINSTANCE__ *) hDll); break; case DLL_PROCESS_DETACH: break; case DLL_THREAD_DETACH: break; case DLL_THREAD_ATTACH: default: break; } return TRUE; } /*---------------------------------------------------------- DevicePropPage - DLL Entry Point from NT5.0 PnP manager to add property sheets. Not the entry point for NT4.0, see nt40.c code WinMain(). Exported Entry-point for adding additional device manager property sheet pages. Registry specifies this routine under Control\Class\PortNode::EnumPropPage32="vssetup.dll,DevicePropPage" entry. This entry-point gets called only when the Device Manager asks for additional property pages. Arguments: LPVOID pinfo - points to PROPSHEETPAGE_REQUEST, see setupapi.h LPFNADDPROPSHEETPAGE pfnAdd - function ptr to call to add sheet. LPARAM lParam - add sheet functions private data handle. Return Value: TRUE on success FALSE if pages could not be added |------------------------------------------------------------*/ BOOL WINAPI DevicePropPage( LPVOID pinfo, // points to PROPSHEETPAGE_REQUEST, see setupapi.h LPFNADDPROPSHEETPAGE pfnAdd, // add sheet function LPARAM lParam) // add sheet function data handle? { PSP_PROPSHEETPAGE_REQUEST ppr = (PSP_PROPSHEETPAGE_REQUEST) pinfo; PROPSHEETPAGE psp[NUM_DRIVER_SHEETS]; HPROPSHEETPAGE hpage[NUM_DRIVER_SHEETS]; OUR_INFO *pi; int i; int stat; setup_init(); // build our main structs pi = glob_info; // temporary kludge, unless we don't need re-entrantancy // copy the important port handles pi->DeviceInfoSet = ppr->DeviceInfoSet; pi->DeviceInfoData = ppr->DeviceInfoData; #ifdef DO_SHOWIT if (MessageBox( GetFocus(), TEXT("Want Info?"), TEXT("aclass"), MB_YESNO | MB_ICONINFORMATION ) == IDYES) { show_install_info(pi); DumpPnpTree(); } #endif //glob_hwnd = hDlg; wi->NumDevices = 0; // get the name that NT associates with this device, so we can // store and retrieve config information based on this also. stat = get_device_name(); if (stat) { // something is seriously wrong if we can't get our device // name. This is something NT uses as a name. DbgPrintf(D_Error, (TEXT("err5f\n"))); } wi->NumDevices = 1; // for pnp, devices are independent get_pnp_setup_info(); // read in pnp info get_pnp_devicedesc(wi->dev[0].Name); // read in pnp description get_nt_config(wi); // get configured vslink device settings. if (wi->dev[0].ModelName[0] == 0) { #ifdef S_RK if ((wi->dev[0].HardwareId == PCI_DEVICE_RPLUS2) || (wi->dev[0].HardwareId == PCI_DEVICE_422RPLUS2) || (wi->dev[0].HardwareId == PCI_DEVICE_RPLUS4) || (wi->dev[0].HardwareId == PCI_DEVICE_RPLUS8)) { strcpy(wi->dev[0].ModelName, szRocketPortPlus); } else if ((wi->dev[0].HardwareId == ISA_DEVICE_RMODEM4) || (wi->dev[0].HardwareId == ISA_DEVICE_RMODEM8) || (wi->dev[0].HardwareId == PCI_DEVICE_RMODEM6) || (wi->dev[0].HardwareId == PCI_DEVICE_RMODEM4)) { strcpy(wi->dev[0].ModelName, szRocketModem); } else { strcpy(wi->dev[0].ModelName, szRocketPort); } //szRocketPort485 #endif #ifdef S_VS if (wi->dev[0].HardwareId == NET_DEVICE_VS2000) { strcpy(wi->dev[0].ModelName, szVS2000); } else if ((wi->dev[0].HardwareId == NET_DEVICE_RHUB8) || (wi->dev[0].HardwareId == NET_DEVICE_RHUB4)) { strcpy(wi->dev[0].ModelName, szSerialHub); } else // if (wi->dev[0].HardwareId == NET_DEVICE_VS1000) { strcpy(wi->dev[0].ModelName, szVS1000); } #endif } validate_config(1); //test_config(); // if 0 dev-nodes setup, add 1 for the user. if (wi->NumDevices == 0) { ++wi->NumDevices; validate_device(&wi->dev[0], 1); } copy_setup_init(); // make a copy of config data for change detection FillDriverPropertySheets(&psp[0], (LPARAM)pi); // allocate our "Setting" sheet for (i=0; iDeviceInfoSet = ci->DeviceInfoSet; pi->DeviceInfoData = ci->DeviceInfoData; //glob_hwnd = hDlg; wi->NumDevices = 1; // get the name that NT associates with this device, so we can // store and retrieve config information based on this also. stat = get_device_name(); { get_pnp_setup_info(); get_nt_config(wi); // get configured vslink device settings. //validate_config(); } if (stat) { // something is seriously wrong if we can't get our device // name. This is something NT uses as a name. DbgPrintf(D_Error,(TEXT("err5f\n"))); } // if 0 dev-nodes setup, add 1 for the user. if (wi->NumDevices == 0) { ++wi->NumDevices; validate_device(&wi->dev[0], 1); } copy_setup_init(); // make a copy of config data for change detection validate_config(1); // make sure port names are setup if ((func_num & 1) == 0) // normal { DoDriverPropPages(GetFocus()); // in nt40.c // force it to save things off(probably should disable // cancel button, instead of this kludge). do_nt50_install(); } else // quite { wi->ip.prompting_off = 1; // turn our_message() prompting off. do_nt50_install(); } #endif break; case 0x42: // UnInstall RocketPort Device time. case 0x82: // UnInstall VS Device time. DbgPrintf(D_Test, (TEXT("uninstall time\n"))); ci = (CLASS_OUR_INFO *) our_info; setup_init(); // build our main structs pi = glob_info; // temporary kludge, unless we don't need re-entrantancy // copy the important port handles pi->DeviceInfoSet = ci->DeviceInfoSet; pi->DeviceInfoData = ci->DeviceInfoData; wi->NumDevices = 1; // get the name that NT associates with this device, so we can // store and retrieve config information based on this also. stat = get_device_name(); if (stat == 0) { get_pnp_setup_info(); //get_nt_config(wi); // get configured vslink device settings. //validate_config(); uninstall_device(); } break; default: return 1; // error, bad func_num break; } // switch return 0; } /*----------------------------------------------------------------------------- | get_pnp_setup_info - |-----------------------------------------------------------------------------*/ static int get_pnp_setup_info(void) { static TCHAR tmpstr[600]; TCHAR *ptr; int stat; int Hardware_ID = 0; // grab the board type information. Tells us what type of // board we have stat = get_device_property(tmpstr, 580); if (stat != 0) return 1; DbgPrintf(D_Level, (TEXT("dev_prop:%s\n"), tmpstr) ); // Find out what the PnP manager thinks my NT Hardware ID is // "CtmPort0000" for RocketPort port, // "CtmVPort0000" for VS port, // "CtmRK1002" for isa-board rocketport, // "CtmRM1002" for isa-board rocketmodem, // "CtmVS1003" for VS1000 // for pci we are getting a multi-wstring, 400 bytes long with // "PCI\VEN_11FE&DEV_0003&SUBSYS00000...",0,"PCI\VEN.." stat = HdwIDStrToID(&Hardware_ID, tmpstr); if (stat) { DbgPrintf(D_Error, (TEXT("Err, Unknown pnpid:%s\n"), tmpstr)) } stat = id_to_num_ports(Hardware_ID); if ((Hardware_ID & 0xfff) == 0) // marked as pci wi->dev[0].IoAddress = 1; // indicate to setup prog it is a PCI board if (Hardware_ID & 0x1000) // marked as isa get_pnp_isa_address(); // correct number of ports setting if it doesn't match //if (wi->dev[0].NumPorts != stat) //{ // DbgPrintf(D_Level, (TEXT("Correct NumPorts!\n"))); wi->dev[0].NumPorts = stat; //} wi->dev[0].HardwareId = Hardware_ID; // check for HubDevice, ModemDevice, etc. if (IsHubDevice(Hardware_ID)) wi->dev[0].HubDevice = 1; if (IsModemDevice(Hardware_ID)) wi->dev[0].ModemDevice = 1; DbgPrintf(D_Level, (TEXT("Num Ports:%d\n"),stat)); return 0; } /*----------------------------------------------------------------------------- | get_device_property - return "rckt1003", or whatever, see INF file for selections. For PCI this returns a long multi-sz string. |-----------------------------------------------------------------------------*/ static int get_device_property(char *ret_name, int max_size) { int stat, i,j; ULONG RegType; ULONG ReqSize; ret_name[0] = 0; stat = SetupDiGetDeviceRegistryProperty(glob_info->DeviceInfoSet, glob_info->DeviceInfoData, SPDRP_HARDWAREID, &RegType, // reg data type (PBYTE)ret_name, max_size, &ReqSize); // size thing if (stat == FALSE) { return 1; // err } if ((RegType != REG_MULTI_SZ) && (RegType != REG_SZ)) { return 2; // err // error } return 0; // ok } /*----------------------------------------------------------------------------- | our_nt50_exit - return 1 if not allowing to exit. return 0 if ok to exit. |-----------------------------------------------------------------------------*/ int our_nt50_exit(void) { int stat; OUR_INFO *pi; DWORD DataSize; DWORD DataType; DWORD dstat; DWORD Val; HKEY hkey; pi = glob_info; // temporary kludge, unless we don't need re-entrantancy { stat = do_nt50_install(); if (wi->NeedReset) our_message(&wi->ip,RcStr((MSGSTR+4)), MB_OK); write_config(1); // clear out msports claims write_config(0); // reclaim any new changed port names } return 0; } /*----------------------------------------------------------------------------- | get_device_name - return name in wi->ip.szNt50DevObjName[], ret 0 on success. Pnp puts config data into a registry node associated with the device. We put a lot of our config information into a related registry node. This related node is derived by and index saved and read from the pnp-node. So the first device added we assign a index of 0, and get a derived name of "Device0". The 2nd device we add to the system sees the first, and saves an index value of 1, to get a associated device name of "Device1". The driver actually writes these index values out to the registry, not the setup program. This is because the driver fires up before setup has a chance to run. |-----------------------------------------------------------------------------*/ int get_device_name(void) { int i; int stat; i = 0; stat = nt5_get_pnp_dev_id(&i); if (stat) { DbgPrintf(D_Test,(TEXT("failed to get pnp id\n"))) } wsprintf(wi->ip.szNt50DevObjName, "Device%d", i); DbgPrintf(D_Test,(TEXT("pnp idstr:%s\n"), wi->ip.szNt50DevObjName)) return 0; // ok } /*----------------------------------------------------------------------------- | nt5_get_pnp_dev_id - Get pnp device ID. Pnp can have devices come and go dynamically, so a simple list of devices does not work. This is because we are no longer in charge of the master list. We just get called from ths OS, which handles half of the installation. This approximates a simple list of devices by reading a unique "Device#" number which the driver creates and stores in the software key: Driver: Upon startup, reads Pnp_Software_Reg_Area\CtmNodeID if (not exist) { derive unique device id number by enumerating Service\Rocketport\Parameters\"Device#" key entries. Add this key entry and also save number off as CtmNodeID. } Read in its device configuration from Service\Rocketport\Parameters\"Device#" key. Setup Config Program: Upon startup, reads Pnp_Software_Reg_Area\CtmNodeID for its "Device#" to use in reading reg config area: Service\Rocketport\Parameters\"Device#" key entries. Note on pnp registr areas: Hardware key is something like: HKLM\CurrentControlSet\Enum\Root\MultiPortSerial\0000 ; ISA or net device or HKLM\CurrentControlSet\Enum\VEN_11FE&DEV......\0000 ; PCI device or (vs driver bus enumerated port entry): HKLM\CurrentControlSet\Enum\CtmvPort\RDevice\10&Port000 ; enumerated port Software key is something like: HKLM\CurrentControlSet\Control\Class\{50906CB8-....}\0000 ; MPS or for a port: HKLM\CurrentControlSet\Control\Class\{4D36E978-....}\0000 ; PORTS The hardware key is a reg. tree structure which reflects the hardware configuration. The software key is more of a flat reg. structure which reflects the devices in the system. Software area uses GUID names to catagorize and name types of hardware. The Hardware keys are hidden by default in the NT5 registry. Use a tool called PNPREG.EXE /U to Unlock this area, then regedit will see beyond enum. PNPREG /L will lock(hide) it. The hardware key contains a link to the software key. |-----------------------------------------------------------------------------*/ static int nt5_get_pnp_dev_id(int *id) { HKEY hkey; int stat; DWORD id_dword; stat = nt5_open_dev_key(&hkey); if (stat) { *id = 0; return 1; } stat = reg_get_dword(hkey, "", "CtmNodeId", &id_dword); reg_close_key(hkey); if (stat) { // it should have been there, the driver should set this up to // a unique index value. But if not, we use 0. *id = 0; return 2; } // return the unique index value which is used to derive the // registry configuration area "Device#". *id = (int) id_dword; return 0; } /*----------------------------------------------------------------------------- | nt5_open_dev_key - |-----------------------------------------------------------------------------*/ int nt5_open_dev_key(HKEY *hkey) { CONFIGRET cr; cr = CM_Open_DevNode_Key( glob_info->DeviceInfoData->DevInst, KEY_ALL_ACCESS, 0, RegDisposition_OpenExisting, hkey, CM_REGISTRY_SOFTWARE); // _SOFTWARE worked!(under CLASS) //CM_REGISTRY_HARDWARE); // _HARDWARE no open! //CM_REGISTRY_CONFIG); // _CONFIG wrote under HardwareConfig if (cr != CR_SUCCESS) { DbgPrintf(D_Error,(TEXT("nt50 pnp reg open fail:%d\n"), GetLastError())); *hkey = NULL; return 1; } return 0; } #if DBG /*----------------------------------------------------------------------------- | read_config - Save the config for the device Just a test. |-----------------------------------------------------------------------------*/ static int read_config(void) { int stat; DWORD DataSize; DWORD DataType; DWORD Err; DWORD Val; HKEY hkey; DEVINST devInst; CONFIGRET cr; static char *szNumPorts = {"NumPorts"}; static char *szTestVal = {"TestVal"}; stat = 0; DbgPrintf(D_Test,(TEXT("read config\n"))); if((hkey = SetupDiOpenDevRegKey(glob_info->DeviceInfoSet, glob_info->DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, //DIREG_DRV, KEY_READ)) == INVALID_HANDLE_VALUE) { DbgPrintf(D_Error,(TEXT("DI open fail:%xH\n"), GetLastError())); stat = 1; } if (stat == 0) { DataSize = sizeof(DWORD); // max size of return str Err = RegQueryValueEx(hkey, szNumPorts, NULL, &DataType, (BYTE *) &Val, &DataSize); if (Err != ERROR_SUCCESS) { DbgPrintf(D_Error,(TEXT("OpenDevReg fail\n"))); Val = 0; } DbgPrintf(D_Test,(TEXT("NumPorts=%d\n"), Val)); RegCloseKey(hkey); } DbgPrintf(D_Test,(TEXT("write config\n"))); stat = 0; if((hkey = SetupDiOpenDevRegKey(glob_info->DeviceInfoSet, glob_info->DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, //DIREG_DRV, //KEY_ALL_ACCESS)) == INVALID_HANDLE_VALUE) { KEY_WRITE)) == INVALID_HANDLE_VALUE) { DbgPrintf(D_Error,(TEXT("DI write open fail:%xH\n"), GetLastError())); stat = 1; } if (stat == 0) { stat = reg_set_dword(hkey, "", szTestVal, 0x1234); if (stat) { DbgPrintf(D_Error,(TEXT("write val fail\n"))); } RegCloseKey(hkey); } devInst = glob_info->DeviceInfoData->DevInst; if (devInst == 0) { DbgPrintf(D_Error,(TEXT("err6g\n"))); return 1; // err } cr = CM_Open_DevNode_Key( devInst, KEY_READ, // IN REGSAM samDesired, 0, // IN ULONG ulHardwareProfile, RegDisposition_OpenExisting, &hkey, //OUT PHKEY phkDevice, //CM_REGISTRY_SOFTWARE); // _SOFTWARE worked!(under CLASS) CM_REGISTRY_HARDWARE); // _HARDWARE no open! //CM_REGISTRY_CONFIG); // _CONFIG wrote under HardwareConfig if (cr == CR_SUCCESS) { DataSize = sizeof(DWORD); // max size of return str Err = RegQueryValueEx(hkey, szNumPorts, NULL, &DataType, (BYTE *) &Val, &DataSize); if (Err != ERROR_SUCCESS) { DbgPrintf(D_Error,(TEXT("Reg query fail\n"))); Val = 0; } DbgPrintf(D_Test,(TEXT("cr NumPorts=%d\n"), Val)); RegCloseKey(hkey); } else { DbgPrintf(D_Error,(TEXT("CM open fail:%d\n"), GetLastError())); } cr = CM_Open_DevNode_Key( devInst, //KEY_ALL_ACCESS, KEY_WRITE, 0, RegDisposition_OpenExisting, &hkey, //CM_REGISTRY_SOFTWARE); // _SOFTWARE worked!(under CLASS) CM_REGISTRY_HARDWARE); // _HARDWARE no open! //CM_REGISTRY_CONFIG); // _CONFIG wrote under HardwareConfig if (cr == CR_SUCCESS) { stat = reg_set_dword(hkey, "", szTestVal, 0x1234); if (stat) { DbgPrintf(D_Error,(TEXT("write val fail\n"))); } else { DbgPrintf(D_Test,(TEXT("write val ok\n"))); } RegCloseKey(hkey); } else { DbgPrintf(D_Error,(TEXT("CM write open fail:%d\n"), GetLastError())); } return 0; } #endif /*----------------------------------------------------------------------------- | get_pnp_devicedesc - |-----------------------------------------------------------------------------*/ static int get_pnp_devicedesc(TCHAR *name) { CONFIGRET cr; DWORD len; // Get the Device name len = 60; cr = CM_Get_DevNode_Registry_Property(glob_info->DeviceInfoData->DevInst, CM_DRP_DEVICEDESC, NULL, (PBYTE)name, &len, 0); if (cr != CR_SUCCESS) { DbgPrintf(D_Error,(TEXT("err, no fr.name.\n"))); return 2; // err } DbgPrintf(D_Test, (TEXT("get friendlyname:%s\n"), name)); return 0; // ok } #if 0 /*----------------------------------------------------------------------------- | set_pnp_devicedesc - |-----------------------------------------------------------------------------*/ static int set_pnp_devicedesc(TCHAR *name) { CONFIGRET cr; // Set the Device name cr = CM_Set_DevNode_Registry_Property( glob_info->DeviceInfoData->DevInst, CM_DRP_DEVICEDESC, (PBYTE)name, (lstrlen(name) + 1) * sizeof(TCHAR), 0); if (cr != CR_SUCCESS) { DbgPrintf(D_Error,(TEXT("err3d\n"))); return 2; // err } return 0; // ok } #endif /*----------------------------------------------------------------------------- | write_config - Save the config for the device - Set pnp port names so they match our configuration. Also, try to keep MSPORTS.DLL com-port name database in sync with our stuff by detecting when our pnp comport name changes, and calling msports routines to free and claim port names. We call this routine once with clear_it SET, then call it again with it clear. This is because we must clear ALL port claims from msports.dll (which holds a database in services\serial reg area) prior to re-claiming new port names. This is because if we overlap, we run into trouble. |-----------------------------------------------------------------------------*/ static int write_config(int clear_it) { DEVINST devInst; Device_Config *dev; Port_Config *port; int i,pi, str_i, stat; CONFIGRET cr; ULONG len; TCHAR buf[120]; TCHAR curname[40]; HKEY hKey; int port_index = 0; int port_i; ULONG val_type; HCOMDB hPort = NULL; FindPortNodes(); // fill in all port->hPnpNode for(i=0; iNumDevices; i++) // Loop through all possible boards { dev = &wi->dev[i]; for(pi=0; piNumPorts; pi++) // Loop through all ports { port = &dev->ports[pi]; if (port->hPnpNode != 0) // have a DEVINST handle for it. { devInst = (DEVINST) port->hPnpNode; if (!clear_it) { len = sizeof(buf); #ifdef S_RK wsprintf(buf, "Comtrol RocketPort %d (%s)", port_index, port->Name); #else wsprintf(buf, "Comtrol VS Port %d (%s)", port_index, port->Name); #endif cr = CM_Set_DevNode_Registry_Property(devInst, CM_DRP_FRIENDLYNAME, (PBYTE)buf, (lstrlen(buf) + 1) * sizeof(TCHAR), 0); if (cr != CR_SUCCESS) { DbgPrintf(D_Error,(TEXT("err7d\n"))); } } cr = CM_Open_DevNode_Key( devInst, KEY_ALL_ACCESS, // IN REGSAM samDesired, 0, // IN ULONG ulHardwareProfile, RegDisposition_OpenExisting, &hKey, //OUT PHKEY phkDevice, CM_REGISTRY_HARDWARE); // IN ULONG ulFlags wsprintf(buf, "%s", port->Name); if (cr == CR_SUCCESS) { curname[0] = 0; len = sizeof(curname); cr = RegQueryValueEx(hKey, TEXT("PortName"), 0, &val_type, (PBYTE) curname, &len); if (cr != CR_SUCCESS) { DbgPrintf(D_Error,(TEXT("error reading portname\n"))); } if (_tcsicmp(curname, buf) != 0) // it's changed! { DbgPrintf(D_Test,(TEXT("com name from:%s, to %s\n"), curname, buf)); if (hPort == NULL) cr = ComDBOpen(&hPort); if (hPort == NULL) { DbgPrintf(D_Error,(TEXT("err dbcom 1d\n"))); } else { if (clear_it) { // clear out name port_i = ExtractNameNum(curname); if ((port_i > 0) && (port_i < 256)) { ComDBReleasePort(hPort, port_i); DbgPrintf(D_Test,(TEXT("Free Old:%d\n"), port_i)); } } else { port_i = ExtractNameNum(buf); if ((port_i > 0) && (port_i < 256)) { ComDBClaimPort(hPort, port_i, 1 /* force*/, NULL); DbgPrintf(D_Test,(TEXT("Claim New:%d\n"), port_i)); } } } if (!clear_it) { RegSetValueEx(hKey, "PortName", 0, REG_SZ, (PBYTE) buf, (lstrlen(buf) + 1) * sizeof(TCHAR) ); } } // not matched, com-port name changed RegCloseKey(hKey); } // opened dev node key else { DbgPrintf(D_Error,(TEXT("err7e\n"))); } } // if (port->hPnpNode != 0) else { DbgPrintf(D_Level,(TEXT("Bad Pnp Name Find\n"))); } ++port_index; } // for(pi=0; piNumPorts; pi++) } // for(i=0; iNumDevices; i++) if (hPort != NULL) ComDBClose(hPort); return 0; } /*------------------------------------------------------------------------ | uninstall_device - |------------------------------------------------------------------------*/ static void uninstall_device(void) { #ifdef DO_SHOWIT if (MessageBox( GetFocus(), TEXT("UNINSTALL, Want Info?"), TEXT("aclass"), MB_YESNO | MB_ICONINFORMATION ) == IDYES) { show_install_info(glob_info); DumpPnpTree(); } #endif clear_nt_device(wi); //if (this_is_last_device) // remove_driver(1); } /*----------------------------------------------------------------------------- | FindPortNodes - Find the pnp tree devnodes which hold our port names. Put the handle into our port config struct for easy access. We start the search at our device node. |-----------------------------------------------------------------------------*/ static int FindPortNodes(void) { DEVINST devInst; DEVINST devInstNext; CONFIGRET cr; ULONG walkDone = 0; ULONG len; CHAR buf[120]; HKEY hKey; int di,pi; int port_index; Device_Config *dev; Port_Config *port; ULONG val_type; // clear out all stale pnpnode handles before re-creating this list for(di=0; diNumDevices; di++) // Loop through all possible boards { dev = &wi->dev[di]; for(pi=0; piNumPorts; pi++) // Loop through all ports { dev->ports[pi].hPnpNode = 0; } } #if 0 // Get Root DevNode // cr = CM_Locate_DevNode(&devInst, NULL, 0); if (cr != CR_SUCCESS) { return 1; // err } #endif devInst = glob_info->DeviceInfoData->DevInst; if (devInst == 0) { DbgPrintf(D_Error,(TEXT("err6g\n"))); return 1; // err } DbgPrintf(D_Level, (TEXT("search nodes\n"))); cr = CM_Get_Child(&devInstNext, devInst, 0); while (cr == CR_SUCCESS) { devInst = devInstNext; // Get the DriverName value // buf[0] = 0; len = sizeof(buf); cr = CM_Get_DevNode_Registry_Property(devInst, CM_DRP_CLASS, NULL, buf, &len, 0); if (cr == CR_SUCCESS && strcmp("Ports", buf) == 0) { // grab the "MatchingDeviceId" cr = CM_Open_DevNode_Key( devInst, KEY_READ, // IN REGSAM samDesired, 0, // IN ULONG ulHardwareProfile, RegDisposition_OpenExisting, &hKey, //OUT PHKEY phkDevice, CM_REGISTRY_SOFTWARE); // IN ULONG ulFlags if (cr == CR_SUCCESS) { buf[0] = 0; len = sizeof(buf); cr = RegQueryValueEx(hKey, TEXT("MatchingDeviceId"), 0, &val_type, (PBYTE) buf, &len); if (cr != ERROR_SUCCESS) { buf[0] = 0; } #ifdef S_RK if (strstr(buf, "ctmport") != NULL) // found it #else if (strstr(buf, "ctmvport") != NULL) // found it #endif { int k, dev_num; k = sscanf(&buf[8], "%d", &dev_num); if (k==1) { port_index = 0; // found a vs port node, so save a reference to this node // in our config struct for simple reference. //save_pnp_node(j, devInst); for(di=0; diNumDevices; di++) // Loop through all possible boards { dev = &wi->dev[di]; for(pi=0; piNumPorts; pi++) // Loop through all ports { port = &dev->ports[pi]; if (port_index == dev_num) // found our matching index { port->hPnpNode = (HANDLE) devInst; } ++port_index; } // for pi } // for di } // if scanf } // if strstr "ctmvport" RegCloseKey(hKey); } // if openreg } // if "Ports" // Get next child cr = CM_Get_Sibling(&devInstNext, devInst, 0); } // while (!cr_success) return 2; // done; } /*----------------------------------------------------------------------------- | do_nt50_install - |-----------------------------------------------------------------------------*/ int do_nt50_install(void) { int stat = 0; int do_remove = 0; int do_modem_inf = 0; static int in_here = 0; if (in_here) // problem hitting OK button twice(sets off two of these) return 2; in_here = 1; if (wi->nt_reg_flags & 4) // initial install, no setupversion string found { if (setup_utils_exist()) { setup_make_progman_group(1); // 1=with prompt } wi->nt_reg_flags &= ~4; } if (!wi->ChangesMade) send_to_driver(0); // evaluate if anything changed stat = send_to_driver(1); stat = set_nt_config(wi); in_here = 0; if (stat) return 1; // error return 0; // ok } /*---------------------------------------------------------------------------- | get_pnp_isa_address - |-----------------------------------------------------------------------------*/ static int get_pnp_isa_address(void) { int IoBase; LOG_CONF LogConfig; RES_DES ResDes; IO_RESOURCE IoResource; //IRQ_RESOURCE IrqResource; CONFIGRET cr; int status; status = CM_Get_First_Log_Conf(&LogConfig, (DEVINST)(glob_info->DeviceInfoData->DevInst), ALLOC_LOG_CONF); //if (status != CR_SUCCESS) // mess(&wi->ip, "No ALLOC lc %xH\n",status); if (status != CR_SUCCESS) return 1; // get the Io base port status = CM_Get_Next_Res_Des(&ResDes, LogConfig, ResType_IO, NULL, 0); if (status != CR_SUCCESS) { return 2; } cr = CM_Get_Res_Des_Data(ResDes, &IoResource, sizeof(IO_RESOURCE), 0); CM_Free_Res_Des_Handle(ResDes); if(cr != CR_SUCCESS) { return 3; } IoBase = (int)IoResource.IO_Header.IOD_Alloc_Base; //mess(&wi->ip, "OK 1c, Base:%xH\n", IoBase); if ((IoBase < 0x400) && (IoBase >= 0x100)) wi->dev[0].IoAddress = IoBase; else wi->dev[0].IoAddress = 0; return 0; } #if 0 /*---------------------------------------------------------------------------- | test_config - See what we can do concerning the allocated IO resources. |-----------------------------------------------------------------------------*/ static void test_config(void) { int IoBase; LOG_CONF LogConfig; RES_DES ResDes; IO_RESOURCE IoResource; //IRQ_RESOURCE IrqResource; CONFIGRET cr; int status; //glob_ourstr[0] = 0; //lstrcat(glob_ourstr, "Test Config:\n"); // mess(&wi->ip, "Test Config"); status = CM_Get_First_Log_Conf(&LogConfig, (DEVINST)(glob_info->DeviceInfoData->DevInst), BOOT_LOG_CONF); if (status != CR_SUCCESS) mess(&wi->ip, "No BOOT lc %xH\n",status); else mess(&wi->ip, "Got BOOT lc\n"); status = CM_Get_First_Log_Conf(&LogConfig, (DEVINST)(glob_info->DeviceInfoData->DevInst), FORCED_LOG_CONF); if (status != CR_SUCCESS) mess(&wi->ip, "No FORCED lc %xH\n",status); else mess(&wi->ip, "Got FORCED lc\n"); status = CM_Get_First_Log_Conf(&LogConfig, (DEVINST)(glob_info->DeviceInfoData->DevInst), BASIC_LOG_CONF); if (status != CR_SUCCESS) mess(&wi->ip, "No BASIC lc %xH\n",status); else mess(&wi->ip, "Got BASIC lc\n"); status = CM_Get_First_Log_Conf(&LogConfig, (DEVINST)(glob_info->DeviceInfoData->DevInst), FORCED_LOG_CONF); if (status != CR_SUCCESS) mess(&wi->ip, "No FORCED lc %xH\n",status); else mess(&wi->ip, "Got FORCED lc\n"); status = CM_Get_First_Log_Conf(&LogConfig, (DEVINST)(glob_info->DeviceInfoData->DevInst), ALLOC_LOG_CONF); if (status != CR_SUCCESS) mess(&wi->ip, "No ALLOC lc %xH\n",status); else mess(&wi->ip, "Got ALLOC lc\n"); if (status != CR_SUCCESS) return; // // First, get the Io base port // status = CM_Get_Next_Res_Des(&ResDes, LogConfig, ResType_IO, NULL, 0); if (status != CR_SUCCESS) { mess(&wi->ip, "Error 1b\n"); return; } mess(&wi->ip, "OK 1b\n"); cr = CM_Get_Res_Des_Data(ResDes, &IoResource, sizeof(IO_RESOURCE), 0); CM_Free_Res_Des_Handle(ResDes); if(cr != CR_SUCCESS) { mess(&wi->ip, "Error 1c\n"); return; } IoBase = (int)IoResource.IO_Header.IOD_Alloc_Base; mess(&wi->ip, "OK 1c, Base:%xH\n", IoBase); //OldIrq = IrqResource.IRQ_Header.IRQD_Alloc_Num; #if 0 // We don't want to popup the configuration UI if the 'quiet install' flag is // set _and_ we already have a forced config (pre-install support). if (CM_Get_First_Log_Conf(&ForcedLogConf, glob_info->DeviceInfoData->DevInst, FORCED_LOG_CONF) == CR_SUCCESS) { CM_Free_Log_Conf_Handle(ForcedLogConf); DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); if (SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams)) { if(FirstTime && (DeviceInstallParams.Flags & DI_QUIETINSTALL)) { DisplayPropSheet = FALSE; } } } #endif } #endif #ifdef TRY_UI #define MAX_NUM_CLASS_SHEETS 3 PROPSHEETPAGE class_psp[MAX_NUM_CLASS_SHEETS]; int num_class_pages = 0; /*------------------------------------------------------------------------ | DoCLassPropPages - |------------------------------------------------------------------------*/ int DoCLassPropPages(HWND hwndOwner, SP_PROPSHEETPAGE_REQUEST *propreq) { PROPSHEETPAGE *psp; PROPSHEETHEADER psh; OUR_INFO * our_params; INT stat; //SP_PROPSHEETPAGE_REQUEST propreq; //typedef struct _SP_PROPSHEETPAGE_REQUEST { //DWORD cbSize; //DWORD PageRequested; //HDEVINFO DeviceInfoSet; //PSP_DEVINFO_DATA DeviceInfoData; //Fill out the PROPSHEETPAGE data structure for the Background Color //sheet // our_params = glob_info; // temporary kludge, unless we don't need re-entrantancy psp = &class_psp[0]; //Fill out the PROPSHEETPAGE data structure for the Client Area Shape //sheet FillClassPropertySheets(&psp[0], (LPARAM)our_params); ++num_class_pages; //Fill out the PROPSHEETHEADER //stat = DevicePropPage( // (LPVOID) propreq, // points to PROPSHEETPAGE_REQUEST, see setupapi.h // (LPFNADDPROPSHEETPAGE) ClassAddPropPage, // add sheet function // 0) // add sheet function data handle? memset(&psh, 0, sizeof(PROPSHEETHEADER)); // add fix 11-24-98 psh.dwSize = sizeof(PROPSHEETHEADER); //psh.dwFlags = PSH_USEICONID | PSH_PROPSHEETPAGE; psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW; psh.hwndParent = hwndOwner; psh.hInstance = glob_hinst; psh.pszIcon = TEXT(""); psh.nPages = num_class_pages; psh.ppsp = (LPCPROPSHEETPAGE) &psp; //And finally display the dialog with the two property sheets. stat = PropertySheet(&psh); //BOOL WINAPI DevicePropPage( // LPVOID pinfo, // points to PROPSHEETPAGE_REQUEST, see setupapi.h // LPFNADDPROPSHEETPAGE pfnAdd, // add sheet function // LPARAM lParam) // add sheet function data handle? return 0; } /*------------------------------------------------------------------------ | ClassAddPropPage - Call back function to add a prop page. |------------------------------------------------------------------------*/ BOOL WINAPI ClassAddPropPage(HPROPSHEETPAGE hpage, LPARAM lparam) { PropSheet_AddPage(lparam, hpage); } /*------------------------------------------------------------------------ | FillClassPropertySheets - Setup pages for driver level property sheets. |------------------------------------------------------------------------*/ int FillClassPropertySheets(PROPSHEETPAGE *psp, LPARAM our_params) { INT pi; static TCHAR titlestr[40]; memset(psp, 0, sizeof(*psp) * NUM_CLASS_SHEETS); pi = 0; psp[pi].dwSize = sizeof(PROPSHEETPAGE); psp[pi].dwFlags = PSP_USETITLE | PSP_HASHELP | PSH_NOAPPLYNOW; psp[pi].hInstance = glob_hinst; // psp[pi].pszTemplate = MAKEINTRESOURCE(IDD_CLASS_DLG); psp[pi].pszTemplate = MAKEINTRESOURCE(IDD_DRIVER_OPTIONS); psp[pi].pfnDlgProc = ClassSheet; load_str( glob_hinst, (TITLESTR+3), titlestr, CharSizeOf(titlestr) ); psp[pi].pszTitle = TEXT("Setup"); psp[pi].lParam = (LPARAM)our_params; psp[pi].pfnCallback = NULL; ++pi; return 0; } /*---------------------------------------------------------- ClassSheet - Dlg window procedure for add on Advanced sheet. |-------------------------------------------------------------*/ BOOL WINAPI ClassSheet( IN HWND hDlg, IN UINT uMessage, IN WPARAM wParam, IN LPARAM lParam) { ////OUR_INFO *OurProps = (OUR_INFO *)GetWindowLong(hDlg, DWL_USER); switch(uMessage) { case WM_INITDIALOG : ////OurProps = (OUR_INFO *)((LPPROPSHEETPAGE)lParam)->lParam; ////SetWindowLong(hDlg, DWL_USER, (LONG)OurProps); #ifdef NT50 glob_hwnd = hDlg; #endif stat = DevicePropPage( (LPVOID) propreq, // points to PROPSHEETPAGE_REQUEST, see setupapi.h (LPFNADDPROPSHEETPAGE) ClassAddPropPage, // add sheet function 0) // add sheet function data handle? //set_field(hDlg, IDC_VERBOSE); return TRUE; // No need for us to set the focus. case WM_COMMAND: return FALSE; case WM_PAINT: return FALSE; case WM_CONTEXTMENU: // right-click //context_menu(); break; case WM_HELP: // question mark thing //our_context_help(lParam); return FALSE; case WM_NOTIFY : switch (((NMHDR *)lParam)->code) { case PSN_KILLACTIVE : // we're losing focus to another page... // make sure we update the Global485 variable here. //get_field(hDlg, IDC_GLOBAL485); SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR); return FALSE; // allow focus change break; case PSN_HELP : //our_help(&wi->ip, WIN_NT); break; case PSN_QUERYCANCEL : // the DWL_MSGRESULT field must be *FALSE* to tell QueryCancel // that an exit is acceptable. The function result must be // *TRUE* to acknowledge that we handled the message. SetWindowLong(hDlg, DWL_MSGRESULT, FALSE); // allow cancel return TRUE; break; case PSN_APPLY : SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR); return TRUE; default : return FALSE; } // switch ->code break; // case wmnotify default : return FALSE; } // switch(uMessage) } #endif