/** FILE: pp_lpt.c ********** Module Header ******************************* * * Control panel applet for configuring LPT ports. This file contains * the dialog and utility functions for managing the UI for setting LPT * port parameters * @@BEGIN_DDKSPLIT * History: * jsenior - 7/10/98 - created @@END_DDKSPLIT * * Copyright (C) 1990-1995 Microsoft Corporation * *************************************************************************/ //========================================================================== // Include files //========================================================================== #include "ports.h" #include "pp_lpt.h" #include TCHAR m_szFilterResourceMethod[] = TEXT("FilterResourceMethod"); TCHAR m_szParEnableLegacyZip[] = TEXT("ParEnableLegacyZip"); TCHAR m_szParEnableLegacyZipRegPath[] = TEXT("SYSTEM\\CurrentControlSet\\Services\\Parport\\Parameters"); const DWORD LptHelpIDs[]= { IDC_STATIC, IDH_NOHELP, //Filter resource method text - help not needed IDC_FILTERMETHOD_TRYNOT, idh_devmgr_portset_trynot, //first radio button IDC_FILTERMETHOD_NEVER, idh_devmgr_portset_never, //second radio button IDC_FILTERMETHOD_ACCEPTANY, idh_devmgr_portset_acceptany, //third radio button IDC_LPTNUMTEXT, idh_devmgr_portset_portnum, //Port number text PP_LPT_PORT_NUMBER, idh_devmgr_portset_LPTchoice, //the list box for port number IDC_LPT_ENABLE_LEGACY, idh_devmgr_enable_legacy, //Enable legacy detection checkbox 0, 0 }; #define NUM_FILTER_RESOURCE_METHODS 3 DWORD FilterResourceMethods[NUM_FILTER_RESOURCE_METHODS] = { 0, // Try not to use an interrupt 1, // Never use an interrupt 2 // Accept any interrupt given to the port }; // C Runtime // @@BEGIN_DDKSPLIT // // Prototype for IsUserAdmin (in pp.c) // BOOL IsUserAdmin(VOID); // @@END_DDKSPLIT void InformDriverOfChanges(BOOL NeedReboot, IN PLPT_PROP_PARAMS LptPropParams); void LptPortOnHelp(HWND ParentHwnd, LPHELPINFO HelpInfo); BOOL LptPortOnContextMenu(HWND HwndControl, WORD Xpos, WORD Ypos); BOOL LptPortOnInitDialog( HWND ParentHwnd, HWND FocusHwnd, LPARAM Lparam); ULONG LptFillPortSettings( IN HWND ParentHwnd, IN PLPT_PROP_PARAMS LptPropPageData); ULONG LptFillPortNameCb( HWND ParentHwnd, PLPT_PROP_PARAMS LptPropPageData); void LptInitializeControls( IN HWND ParentHwnd, IN PLPT_PROP_PARAMS LptPropPageData); ULONG LptSetFilterResourceMethod( HWND ParentHwnd, PLPT_PROP_PARAMS LptPropPageData); ULONG LptSavePortSettings( IN HWND ParentHwnd, IN PLPT_PROP_PARAMS LptPropParams); BOOL LptPortOnNotify( HWND ParentHwnd, LPNMHDR NmHdr); void LptPortOnCommand( HWND ParentHwnd, int ControlId, HWND ControlHwnd, UINT NotifyCode); UINT LptEnactPortNameChanges( IN HWND ParentHwnd, IN PLPT_PROP_PARAMS LptPropParams, IN HKEY hDeviceKey, IN UINT NewLptNum); void LptEnumerateUsedPorts( IN HWND ParentHwnd, IN PBYTE Buffer, IN DWORD BufferSize); void LptInitPropParams(IN OUT PLPT_PROP_PARAMS Params, IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData); HPROPSHEETPAGE LptInitSettingsPage(PROPSHEETPAGE * psp, OUT PLPT_PROP_PARAMS Params); INT_PTR APIENTRY LptPortSettingsDlgProc(IN HWND hDlg, IN UINT uMessage, IN WPARAM wParam, IN LPARAM lParam); UINT CALLBACK LptPortSettingsDlgCallback(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp); /*++ Routine Description: ParallelPortPropPageProvider Entry-point for adding additional device manager property sheet pages. Registry specifies this routine under Control\Class\PortNode::EnumPropPage32="msports.dll,thisproc" entry. This entry-point gets called only when the Device Manager asks for additional property pages. Arguments: Info - points to PROPSHEETPAGE_REQUEST, see setupapi.h AddFunc - 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 --*/ BOOL APIENTRY ParallelPortPropPageProvider(LPVOID Info, LPFNADDPROPSHEETPAGE AddFunc, LPARAM Lparam) { PSP_PROPSHEETPAGE_REQUEST pprPropPageRequest; PROPSHEETPAGE psp; HPROPSHEETPAGE hpsp; PLPT_PROP_PARAMS params = NULL; pprPropPageRequest = (PSP_PROPSHEETPAGE_REQUEST) Info; // @@BEGIN_DDKSPLIT // // Only administrators are allowed to see this page // if (!IsUserAdmin()) { return FALSE; } // @@END_DDKSPLIT // // Allocate and zero out memory for the struct that will contain // page specific data // params = (PLPT_PROP_PARAMS) LocalAlloc(LPTR, sizeof(LPT_PROP_PARAMS)); if (!params) { ErrMemDlg(GetFocus()); return FALSE; } if (pprPropPageRequest->PageRequested == SPPSR_ENUM_ADV_DEVICE_PROPERTIES) { LptInitPropParams(params, pprPropPageRequest->DeviceInfoSet, pprPropPageRequest->DeviceInfoData); hpsp = LptInitSettingsPage(&psp, params); if (!hpsp) { return FALSE; } if (!(*AddFunc)(hpsp, Lparam)) { DestroyPropertySheetPage(hpsp); return FALSE; } } return TRUE; } // ParallelPortPropPageProvider /*++ Routine Description: LptPortSettingsDlgProc The windows control function for the Port Settings properties window Arguments: hDlg, uMessage, wParam, lParam: standard windows DlgProc parameters Return Value: BOOL: FALSE if function fails, TRUE if function passes --*/ INT_PTR APIENTRY LptPortSettingsDlgProc(IN HWND hDlg, IN UINT uMessage, IN WPARAM wParam, IN LPARAM lParam) { switch(uMessage) { case WM_COMMAND: LptPortOnCommand(hDlg, (int) LOWORD(wParam), (HWND)lParam, (UINT)HIWORD(wParam)); break; case WM_CONTEXTMENU: return LptPortOnContextMenu((HWND)wParam, LOWORD(lParam), HIWORD(lParam)); case WM_HELP: LptPortOnHelp(hDlg, (LPHELPINFO) lParam); break; case WM_INITDIALOG: return LptPortOnInitDialog(hDlg, (HWND)wParam, lParam); case WM_NOTIFY: return LptPortOnNotify(hDlg, (NMHDR *)lParam); } return FALSE; } // PortSettingsDialogProc void LptInitPropParams(IN OUT PLPT_PROP_PARAMS Params, IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData) { BOOL bResult; DWORD requiredSize = 0; SP_DEVINFO_LIST_DETAIL_DATA detailData; ZeroMemory(Params, sizeof(LPT_PROP_PARAMS)); Params->DeviceInfoSet = DeviceInfoSet; Params->DeviceInfoData = DeviceInfoData; Params->ChangesEnabled = TRUE; // // Get the device ID first: if the device path is larger then // MAX_PATH, we will try again with a bigger buffer // bResult = SetupDiGetDeviceInstanceId(DeviceInfoSet, DeviceInfoData, NULL, MAX_PATH, &requiredSize); // // See if we are being invoked locally or over the network. If over the net, // then disable all possible changes. // detailData.cbSize = sizeof(SP_DEVINFO_LIST_DETAIL_DATA); if (SetupDiGetDeviceInfoListDetail(DeviceInfoSet, &detailData) && detailData.RemoteMachineHandle != NULL) { Params->ChangesEnabled = FALSE; } } // LptInitPropParams HPROPSHEETPAGE LptInitSettingsPage(PROPSHEETPAGE * psp, OUT PLPT_PROP_PARAMS Params) { // // Add the Port Settings property page // psp->dwSize = sizeof(PROPSHEETPAGE); psp->dwFlags = PSP_USECALLBACK; // | PSP_HASHELP; psp->hInstance = g_hInst; psp->pszTemplate = MAKEINTRESOURCE(DLG_PP_LPT_PORTSETTINGS); // // following points to the dlg window proc // psp->pfnDlgProc = LptPortSettingsDlgProc; psp->lParam = (LPARAM) Params; // // following points to some control callback of the dlg window proc // psp->pfnCallback = LptPortSettingsDlgCallback; // // allocate our "Ports Setting" sheet // return CreatePropertySheetPage(psp); } UINT CALLBACK LptPortSettingsDlgCallback(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp) { PLPT_PROP_PARAMS params; switch (uMsg) { case PSPCB_CREATE: return TRUE; // return TRUE to continue with creation of page case PSPCB_RELEASE: params = (PLPT_PROP_PARAMS) ppsp->lParam; LocalFree(params); return 0; // return value ignored default: break; } return TRUE; } BOOL LptPortOnInitDialog( HWND ParentHwnd, HWND FocusHwnd, LPARAM Lparam ) { PLPT_PROP_PARAMS lptPropParams; lptPropParams = (PLPT_PROP_PARAMS) ((LPPROPSHEETPAGE)Lparam)->lParam; // // Save value away SetWindowLongPtr(ParentHwnd, DWLP_USER, (ULONG_PTR) lptPropParams); // // Initialize the dialog box parameters // LptFillPortSettings(ParentHwnd, lptPropParams); // // Set up the dialog box with these initialized parameters // LptInitializeControls(ParentHwnd, lptPropParams); return TRUE; } /*++ Routine Description: LptFillPortSettings Gets the settings out of the registry ready for initializing the dialog box with. Arguments: LptPropPageData: the data to fill in ParentHwnd: address of the window Return Value: ULONG: returns error messages --*/ ULONG LptFillPortSettings( IN HWND ParentHwnd, IN PLPT_PROP_PARAMS LptPropPageData ) { HKEY hKey; DWORD dwPortNameSize, dwError; TCHAR szCharBuffer[81]; DWORD dwSize, dwData, dwMethod; // // Open the device key for the source device instance, and retrieve its // "PortName" value. // hKey = SetupDiOpenDevRegKey(LptPropPageData->DeviceInfoSet, LptPropPageData->DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_ALL_ACCESS); if (INVALID_HANDLE_VALUE == hKey) { return GetLastError(); } dwPortNameSize = sizeof(LptPropPageData->szLptName); dwError = RegQueryValueEx(hKey, m_szPortName, // "PortName" NULL, NULL, (PBYTE)LptPropPageData->szLptName, &dwPortNameSize); if(ERROR_SUCCESS != dwError) { RegCloseKey(hKey); return dwError; } // // create "lpt#:" // lstrcpy(szCharBuffer, LptPropPageData->szLptName); lstrcat(szCharBuffer, m_szColon); dwSize = sizeof(LptPropPageData->FilterResourceMethod); dwError = RegQueryValueEx(hKey, m_szFilterResourceMethod, NULL, NULL, (LPBYTE)(&LptPropPageData->FilterResourceMethod), &dwSize); if (dwError != ERROR_SUCCESS) { // // value does not exist. Create our own: // Get Filter Resource Method information // LptPropPageData->FilterResourceMethod = FilterResourceMethods[RESOURCE_METHOD_DEFAULT_IDX]; dwError = RegSetValueEx(hKey, m_szFilterResourceMethod, 0, REG_DWORD, (LPBYTE)(&LptPropPageData->FilterResourceMethod), sizeof(LptPropPageData->FilterResourceMethod)); } RegCloseKey(hKey); dwError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, m_szParEnableLegacyZipRegPath, 0, KEY_ALL_ACCESS, &hKey); if (dwError != ERROR_SUCCESS) { // // Don't have access maybe? // LptPropPageData->ParEnableLegacyZip = ENABLELEGACYZIPDEFAULT; return dwError; } dwSize = sizeof(LptPropPageData->ParEnableLegacyZip); dwError = RegQueryValueEx(hKey, TEXT("ParEnableLegacyZip"), NULL, NULL, (LPBYTE)(&LptPropPageData->ParEnableLegacyZip), &dwSize); if (dwError != ERROR_SUCCESS) { // // value does not exist. Create our own // LptPropPageData->ParEnableLegacyZip = ENABLELEGACYZIPDEFAULT; dwError = RegSetValueEx(hKey, m_szParEnableLegacyZip, 0, REG_DWORD, (LPBYTE)(&LptPropPageData->ParEnableLegacyZip), sizeof(LptPropPageData->ParEnableLegacyZip)); } RegCloseKey(hKey); return dwError; } // LptFillPortSettings /*++ Routine Description: LptInitializeControls Initializes all of the controls that represent Fifo Arguments: ParentHwnd - handle to the dialog LptPropPageData - Contains all of the initial values Return Value: None --*/ void LptInitializeControls( IN HWND ParentHwnd, IN PLPT_PROP_PARAMS LptPropPageData ) { TCHAR szCurrentValue[40]; HWND hwnd; int i, periodIdx; LptFillPortNameCb(ParentHwnd, LptPropPageData); LptSetFilterResourceMethod(ParentHwnd, LptPropPageData); // // Set the state of the Enable Legacy Detection checkbox // if (LptPropPageData->ParEnableLegacyZip) { CheckDlgButton(ParentHwnd, IDC_LPT_ENABLE_LEGACY, BST_CHECKED); } else { CheckDlgButton(ParentHwnd, IDC_LPT_ENABLE_LEGACY, BST_UNCHECKED); } if (!LptPropPageData->ChangesEnabled) { // EnableWindow(GetDlgItem(ParentHwnd, IDC_FIFO), FALSE); } } // LptInitializeControls /*++ Routine Description: LptSetFilterResourceMethod Checks the appropriate resource method to use Arguments: LptPropPageData: where to get the data from ParentHwnd: address of the window Return Value: ULONG: returns error messages --*/ ULONG LptSetFilterResourceMethod( HWND ParentHwnd, PLPT_PROP_PARAMS LptPropPageData ) { switch (LptPropPageData->FilterResourceMethod) { case FILTERMETHOD_TRYNOT: CheckRadioButton( ParentHwnd, // handle to dialog box IDC_FILTERMETHOD_TRYNOT, // first button in group IDC_FILTERMETHOD_ACCEPTANY, // last button in group IDC_FILTERMETHOD_TRYNOT // selected ); break; case FILTERMETHOD_ACCEPTANY: CheckRadioButton( ParentHwnd, // handle to dialog box IDC_FILTERMETHOD_TRYNOT, // first button in group IDC_FILTERMETHOD_ACCEPTANY, // last button in group IDC_FILTERMETHOD_ACCEPTANY // selected ); break; case FILTERMETHOD_NEVER: CheckRadioButton( ParentHwnd, // handle to dialog box IDC_FILTERMETHOD_TRYNOT, // first button in group IDC_FILTERMETHOD_ACCEPTANY, // last button in group IDC_FILTERMETHOD_NEVER // selected ); break; default: CheckRadioButton( ParentHwnd, // handle to dialog box IDC_FILTERMETHOD_TRYNOT, // first button in group IDC_FILTERMETHOD_ACCEPTANY, // last button in group IDC_FILTERMETHOD_NEVER // selected ); break; } return 0; } /*++ Routine Description: LptFillPortNameCb fill in the Port Name combo box selection with a list of possible un-used portnames Arguments: LptPropPageData: where to get the data from hDlg: address of the window Return Value: ULONG: returns error messages --*/ ULONG LptFillPortNameCb( HWND ParentHwnd, PLPT_PROP_PARAMS LptPropPageData ) { BYTE portUsage[MAX_LPT_PORT]; DWORD tmp, portsReported; int i, nEntries; int nCurPortNum; TCHAR szLpt[40]; TCHAR szInUse[40]; HWND portHwnd; portHwnd = GetDlgItem(ParentHwnd, PP_LPT_PORT_NUMBER); // // Check if our LptName is blank. If it is, disable the lpt port selector // if (_tcscmp(LptPropPageData->szLptName, TEXT("")) == 0) { EnableWindow(portHwnd, FALSE); EnableWindow(GetDlgItem(ParentHwnd, IDC_LPTNUMTEXT), FALSE); return 0; } // // assumes szLptPort filled in... // nCurPortNum = myatoi(&LptPropPageData->szLptName[3]); if (!LoadString(g_hInst, IDS_IN_USE, szInUse, CharSizeOf(szInUse))) { wcscpy(szInUse, _T(" (in use)")); } // // first tally up which ports NOT to offer in list box // ZeroMemory(portUsage, MAX_LPT_PORT); // Find out which ports not to offer LptEnumerateUsedPorts(ParentHwnd, portUsage, MAX_LPT_PORT); for(i = MIN_LPT-1; i < MAX_LPT_PORT; i++) { wsprintf(szLpt, TEXT("LPT%d"), i+1); if (portUsage[i] && _tcscmp(szLpt, LptPropPageData->szLptName)) { wcscat(szLpt, szInUse); } ComboBox_AddString(portHwnd, szLpt); } ComboBox_SetCurSel(portHwnd, nCurPortNum-1); return 0; } // FillPortNamesCb void LptPortOnCommand( HWND ParentHwnd, int ControlId, HWND ControlHwnd, UINT NotifyCode ) { PLPT_PROP_PARAMS params = (PLPT_PROP_PARAMS) GetWindowLongPtr(ParentHwnd, DWLP_USER); if (NotifyCode == CBN_SELCHANGE) { PropSheet_Changed(GetParent(ParentHwnd), ParentHwnd); } else { switch (ControlId) { // // Because this is a prop sheet, we should never get this. // All notifications for ctrols outside of the sheet come through // WM_NOTIFY // case IDOK: case IDCANCEL: EndDialog(ParentHwnd, 0); return; } } } // LptPortOnCommand BOOL LptPortOnNotify( HWND ParentHwnd, LPNMHDR NmHdr ) { PLPT_PROP_PARAMS params = (PLPT_PROP_PARAMS) GetWindowLongPtr(ParentHwnd, DWLP_USER); switch (NmHdr->code) { // // Sent when the user clicks on Apply OR OK !! // case PSN_APPLY: // // Write out the lpt port options to the registry // LptSavePortSettings(ParentHwnd, params); SetWindowLongPtr(ParentHwnd, DWLP_MSGRESULT, PSNRET_NOERROR); return TRUE; default: return FALSE; } } // LptPortOnNotify /*++ Routine Description: LptSavePortSettings saves the advanced box settings back to the registry, if any were changed Arguments: AdvancedData: holds the current settings and the location of of the device in the registry ParentHwnd: address of the window Return Value: ULONG: returns error messages --*/ ULONG LptSavePortSettings( IN HWND ParentHwnd, IN PLPT_PROP_PARAMS LptPropParams ) { HKEY hKey; DWORD dwSize, dwData; UINT i = CB_ERR, curLptNum, newLptNum = CB_ERR; UINT uiTryNotChecked, uiNeverChecked, uiAcceptAnyChecked; DWORD curFilterResourceMethod; DWORD newFilterResourceMethod = 0; DWORD curParEnableLegacyZip, newParEnableLegacyZip; ULONG error = ERROR_SUCCESS; SP_DEVINSTALL_PARAMS spDevInstall; // // Grab all of the new settings // // Filter resource method curFilterResourceMethod = newFilterResourceMethod = LptPropParams->FilterResourceMethod; if (BST_CHECKED == IsDlgButtonChecked(ParentHwnd, IDC_FILTERMETHOD_TRYNOT)) newFilterResourceMethod = 0; else if (BST_CHECKED == IsDlgButtonChecked(ParentHwnd, IDC_FILTERMETHOD_NEVER)) newFilterResourceMethod = 1; else if (BST_CHECKED == IsDlgButtonChecked(ParentHwnd, IDC_FILTERMETHOD_ACCEPTANY)) newFilterResourceMethod = 2; // LPT port number curLptNum = myatoi(LptPropParams->szLptName + wcslen(m_szLPT)); newLptNum = ComboBox_GetCurSel(GetDlgItem(ParentHwnd, PP_LPT_PORT_NUMBER)); if (newLptNum == CB_ERR) { newLptNum = curLptNum; } else { newLptNum++; } // Legacy device detection curParEnableLegacyZip = LptPropParams->ParEnableLegacyZip; if (BST_CHECKED == IsDlgButtonChecked(ParentHwnd, IDC_LPT_ENABLE_LEGACY)) { newParEnableLegacyZip = 0x1; } else { newParEnableLegacyZip = 0x0; } // // See if they changed anything // if ((curLptNum == newLptNum) && (curFilterResourceMethod == newFilterResourceMethod) && (curParEnableLegacyZip == newParEnableLegacyZip)) { // // They didn't change anything. Just exit. // return ERROR_SUCCESS; } // // Open the device key for the source device instance // hKey = SetupDiOpenDevRegKey(LptPropParams->DeviceInfoSet, LptPropParams->DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_ALL_ACCESS); if (INVALID_HANDLE_VALUE == hKey) { // // Not much we can do, just exit gracefully // return ERROR_SUCCESS; } // Check the LPT port name for changes if (newLptNum != curLptNum) { LptEnactPortNameChanges(ParentHwnd, LptPropParams, hKey, newLptNum); } // Check the Filter resource method for changes if (curFilterResourceMethod != newFilterResourceMethod) { // // They changed the Filter Resource Method // dwData = newFilterResourceMethod; dwSize = sizeof(dwData); RegSetValueEx(hKey, m_szFilterResourceMethod, 0, REG_DWORD, (CONST BYTE *)(&dwData), dwSize); } RegCloseKey(hKey); if (curParEnableLegacyZip != newParEnableLegacyZip) { // // Open the services path and set the new value for Legacy Parallel device // detection. // DWORD disposition = 0; error = RegCreateKeyEx(HKEY_LOCAL_MACHINE, m_szParEnableLegacyZipRegPath, 0, (TCHAR *) NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, (LPSECURITY_ATTRIBUTES) NULL, &hKey, &disposition); if (error == ERROR_SUCCESS) { error = RegSetValueEx(hKey, m_szParEnableLegacyZip, 0, REG_DWORD, (LPBYTE)(&newParEnableLegacyZip), sizeof(newParEnableLegacyZip)); RegCloseKey(hKey); if (error != ERROR_SUCCESS) { goto ParEnableLegacyZipSetParamFailed; } if (newParEnableLegacyZip == 0) { // // We want a reboot when disabling this thing, because the parallel // enumerator won't get rid of legacy devices. // InformDriverOfChanges(TRUE, LptPropParams); } else { InformDriverOfChanges(FALSE, LptPropParams); } } else { ParEnableLegacyZipSetParamFailed: MyMessageBox(ParentHwnd, IDS_LPT_LEGACY_FAILED, IDS_LPT_PROPERTIES, MB_OK); // // Don't want to overload the user by telling them they have to // reboot. Since we were unable to set things correctly, just // rebuild the stack. // InformDriverOfChanges(FALSE, LptPropParams); } } else { InformDriverOfChanges(FALSE, LptPropParams); } return error; } // LptSaveAdvancedSettings UINT LptEnactPortNameChanges( IN HWND ParentHwnd, IN PLPT_PROP_PARAMS LptPropParams, IN HKEY hDeviceKey, IN UINT NewLptNum) { HANDLE hLpt; DWORD dwError, dwNewLptNameLen; UINT curLptNum; BYTE portUsage[MAX_LPT_PORT]; TCHAR charBuffer[LINE_LEN], friendlyNameFormat[LINE_LEN], deviceDesc[LINE_LEN], buffer[BUFFER_SIZE], szNewLptName[20]; // // Check if we're trying to rename the port to the same name. // wsprintf(szNewLptName,_T("\\DosDevices\\LPT%d"),NewLptNum); if (wcscmp(szNewLptName, LptPropParams->szLptName) == 0) { return ERROR_SUCCESS; } // // Check if a valid port number has been passed in // if (MAX_LPT_PORT < NewLptNum) { // // Get out of here - exceeding array bounds // This should never happen in the property page since it is a hardcoded // selection box. The user can't simply type a number. // MyMessageBox(ParentHwnd, IDS_LPT_NUM_ERROR, IDS_LPT_PROPERTIES, MB_OK | MB_ICONINFORMATION); return ERROR_SUCCESS; } // // Get an array of used ports // LptEnumerateUsedPorts(ParentHwnd, portUsage, MAX_LPT_PORT); if (portUsage[NewLptNum-1]) { // // Port name is taken by another port. Check if user wants system to // get into inconsistent state. // if (IDNO == MyMessageBox(ParentHwnd, IDS_LPT_PORT_INUSE, IDS_LPT_PROPERTIES, MB_YESNO | MB_ICONINFORMATION)) { return ERROR_SUCCESS; } } curLptNum = myatoi(LptPropParams->szLptName + wcslen(m_szLPT)); // // Make sure that the port has not been opened by another application // wsprintf(buffer, L"\\\\.\\%ws", LptPropParams->szLptName); hLpt = CreateFile(buffer, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // // If the file handle is invalid, then the Lpt port is open, warn the user // if (hLpt == INVALID_HANDLE_VALUE && MyMessageBox(ParentHwnd, IDS_PORT_OPEN, IDS_LPT_PROPERTIES, MB_YESNO | MB_ICONINFORMATION) == IDNO) { return GetLastError(); } CloseHandle(hLpt); wsprintf(szNewLptName, _T("LPT%d"), NewLptNum); // // Open the device key for the source device instance, and write its // new "PortName" value. // hDeviceKey = SetupDiOpenDevRegKey(LptPropParams->DeviceInfoSet, LptPropParams->DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_ALL_ACCESS); if (INVALID_HANDLE_VALUE == hDeviceKey) { return GetLastError(); } dwNewLptNameLen = ByteCountOf(wcslen(szNewLptName) + 1); dwError = RegSetValueEx(hDeviceKey, m_szPortName, 0, REG_SZ, (PBYTE) szNewLptName, dwNewLptNameLen); if (ERROR_SUCCESS == dwError) { wcscpy(LptPropParams->szLptName, szNewLptName); } else { return dwError; } // Now generate a string, to be used for the device's friendly name, that // incorporates both the INF-specified device description, and the port // name. For example, // // ECP Printer Port (LPT1) // if (LoadString(g_hInst, IDS_FRIENDLY_FORMAT, friendlyNameFormat, CharSizeOf(friendlyNameFormat)) && SetupDiGetDeviceRegistryProperty(LptPropParams->DeviceInfoSet, LptPropParams->DeviceInfoData, SPDRP_DEVICEDESC, NULL, (PBYTE)deviceDesc, sizeof(deviceDesc), NULL)) { wsprintf(charBuffer, friendlyNameFormat, deviceDesc, szNewLptName); } else { // // Simply use LPT port name. // lstrcpy(charBuffer, szNewLptName); } SetupDiSetDeviceRegistryProperty(LptPropParams->DeviceInfoSet, LptPropParams->DeviceInfoData, SPDRP_FRIENDLYNAME, (PBYTE)charBuffer, ByteCountOf(lstrlen(charBuffer) + 1) ); return ERROR_SUCCESS; } // LptEnactPortNameChanges void InformDriverOfChanges(BOOL NeedReboot, IN PLPT_PROP_PARAMS LptPropParams) { SP_DEVINSTALL_PARAMS spDevInstall; // // Now broadcast this change to the device manager // ZeroMemory(&spDevInstall, sizeof(SP_DEVINSTALL_PARAMS)); spDevInstall.cbSize = sizeof(SP_DEVINSTALL_PARAMS); if (SetupDiGetDeviceInstallParams(LptPropParams->DeviceInfoSet, LptPropParams->DeviceInfoData, &spDevInstall)) { if (NeedReboot) { spDevInstall.Flags |= DI_PROPERTIES_CHANGE | DI_NEEDREBOOT; } else { spDevInstall.FlagsEx |= DI_FLAGSEX_PROPCHANGE_PENDING; } SetupDiSetDeviceInstallParams(LptPropParams->DeviceInfoSet, LptPropParams->DeviceInfoData, &spDevInstall); } } // // Takes a Buffer of bytes and marks out which port names are taken // void LptEnumerateUsedPorts( IN HWND ParentHwnd, IN PBYTE Buffer, IN DWORD BufferSize) { HKEY hParallelMap; TCHAR szParallel[BUFFER_SIZE]; DWORD dwParallelSize, dwLptSize, dwEnum, dwType, dwResult, dwPortNum; TCHAR szLpt[BUFFER_SIZE]; PTCHAR szParPortNum; ZeroMemory(Buffer, BufferSize); // // // if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, m_szRegParallelMap, 0, KEY_ALL_ACCESS, &hParallelMap) == ERROR_SUCCESS) { dwEnum = 0; do { dwParallelSize = CharSizeOf(szParallel); dwLptSize = sizeof(szLpt); dwResult = RegEnumValue(hParallelMap, dwEnum++, szParallel, &dwParallelSize, NULL, &dwType, (LPBYTE)szLpt, &dwLptSize); if (dwResult != ERROR_SUCCESS || dwType != REG_SZ) { continue; } szParPortNum = _tcsspnp(szLpt,_T("\\DosDevices\\LPT")); if (szParPortNum) { // // Find out if this is an actual port and not simply a // device attached to the port // if (_tcscspn(szParPortNum,_T(".")) == _tcslen(szParPortNum)) { dwPortNum = myatoi(szParPortNum); if (dwPortNum-1 < BufferSize) { Buffer[dwPortNum-1] = TRUE; } } } } while (dwResult == ERROR_SUCCESS); RegCloseKey(hParallelMap); } } // LptEnumerateUsedPorts BOOL LptPortOnContextMenu(HWND HwndControl, WORD Xpos, WORD Ypos) { WinHelp(HwndControl, _T("devmgr.hlp"), HELP_CONTEXTMENU, (ULONG_PTR) LptHelpIDs); return FALSE; } void LptPortOnHelp(HWND ParentHwnd, LPHELPINFO HelpInfo) { if (HelpInfo->iContextType == HELPINFO_WINDOW) { WinHelp((HWND) HelpInfo->hItemHandle, _T("devmgr.hlp"), HELP_WM_HELP, (ULONG_PTR) LptHelpIDs); } }