/*++ Copyright (C) 1997-1999 Microsoft Corporation Module Name: api.cpp Abstract: This module implements Device Manager exported APIs. Author: William Hsieh (williamh) created Revision History: --*/ #include "devmgr.h" #include "devgenpg.h" #include "devdrvpg.h" #include "devpopg.h" #include "api.h" #include "printer.h" #include "tswizard.h" STDAPI_(BOOL) DeviceManager_ExecuteA( HWND hwndStub, HINSTANCE hAppInstance, LPCWSTR lpMachineName, int nCmdShow ) { try { CTString tstrMachineName(lpMachineName); return DeviceManager_Execute(hwndStub, hAppInstance, (LPCTSTR)tstrMachineName, nCmdShow ); } catch(CMemoryException* e) { e->Delete(); SetLastError(ERROR_NOT_ENOUGH_MEMORY); } return FALSE; } STDAPI_(BOOL) DeviceManager_ExecuteW( HWND hwndStub, HINSTANCE hAppInstance, LPCWSTR lpMachineName, int nCmdShow ) { try { CTString tstrMachineName(lpMachineName); return DeviceManager_Execute(hwndStub, hAppInstance, (LPCTSTR)tstrMachineName, nCmdShow ); } catch(CMemoryException* e) { e->Delete(); SetLastError(ERROR_NOT_ENOUGH_MEMORY); } return FALSE; } BOOL DeviceManager_Execute( HWND hwndStub, HINSTANCE hAppInstance, LPCTSTR lpMachineName, int nCmdShow ) { SHELLEXECUTEINFO sei; TCHAR MachineOptions[MAX_PATH]; TCHAR Parameters[MAX_PATH * 2]; if (lpMachineName) { wsprintf(MachineOptions, DEVMGR_MACHINENAME_OPTION, lpMachineName); } else { MachineOptions[0] = _T('\0'); } WCHAR* FilePart; DWORD Size; Size = SearchPath(NULL, DEVMGR_MSC_FILE, NULL, MAX_PATH, Parameters, &FilePart); if (!Size || Size >=MAX_PATH) { lstrcpy(Parameters, DEVMGR_MSC_FILE); } lstrcat(Parameters, MMC_COMMAND_LINE); lstrcat(Parameters, MachineOptions); memset(&sei, 0, sizeof(sei)); sei.cbSize = sizeof(sei); sei.hwnd = hwndStub; sei.nShow = nCmdShow; sei.hInstApp = hAppInstance; sei.lpFile = MMC_FILE; sei.lpParameters = Parameters; return ShellExecuteEx(&sei); } STDAPI_(BOOL) DeviceManagerPrintA( LPCSTR MachineName, LPCSTR FileName, int ReportType, DWORD ClassGuids, LPGUID ClassGuidList ) { BOOL Result; try { CTString strMachineName(MachineName); CTString strFileName(FileName); Result = DeviceManagerDoPrint(strMachineName, strFileName, ReportType, ClassGuids, ClassGuidList ); } catch (CMemoryException* e) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); Result = 0; } return Result; } STDAPI_(BOOL) DeviceManagerPrintW( LPCWSTR MachineName, LPCWSTR FileName, int ReportType, DWORD ClassGuids, LPGUID ClassGuidList ) { BOOL Result; try { CTString strMachineName(MachineName); CTString strFileName(FileName); Result = DeviceManagerDoPrint(strMachineName, strFileName, ReportType, ClassGuids, ClassGuidList ); } catch (CMemoryException* e) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); Result = FALSE; } return Result; } BOOL DeviceManagerDoPrint( LPCTSTR MachineName, LPCTSTR FileName, int ReportType, DWORD ClassGuids, LPGUID ClassGuidList ) { int PrintStatus = 0; if (!FileName || _T('\0') == *FileName) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } TCHAR FullPathName[MAX_PATH + 1]; LPTSTR FilePart; if (!GetFullPathName(FileName, ARRAYLEN(FullPathName), FullPathName, &FilePart)) { return FALSE; } CMachine TheMachine(MachineName); if (TheMachine.Initialize()) { CPrinter ThePrinter; if (ThePrinter.StartDoc(FullPathName)) { if (0 == ReportType) { // print system and resource summary PrintStatus = ThePrinter.PrintResourceSummary(TheMachine); } else if (1 == ReportType) { // print selected classes CClass* pClass; for (DWORD i = 0; i < ClassGuids; i++) { pClass = TheMachine.ClassGuidToClass(&ClassGuidList[i]); if (pClass) { PrintStatus = ThePrinter.PrintClass(pClass); } } } else if (2 == ReportType) { // print resource/system summary and all device information PrintStatus = ThePrinter.PrintAll(TheMachine); } else { SetLastError(ERROR_INVALID_PARAMETER); } ThePrinter.EndDoc(); } } return 0 != PrintStatus; } BOOL AddPageCallback( HPROPSHEETPAGE hPage, LPARAM lParam ) { CPropSheetData* ppsData = (CPropSheetData*)lParam; ASSERT(ppsData); return ppsData->InsertPage(hPage); } void ReportCmdLineError( HWND hwndParent, int ErrorStringID, LPCTSTR Caption ) { TCHAR Title[LINE_LEN + 1]; TCHAR Msg[LINE_LEN + 1]; ::LoadString(g_hInstance, ErrorStringID, Msg, ARRAYLEN(Msg)); if (!Caption) { ::LoadString(g_hInstance, IDS_NAME_DEVMGR, Title, ARRAYLEN(Title)); Caption = Title; } MessageBox(hwndParent, Msg, Caption, MB_OK | MB_ICONERROR); } STDAPI_(void) DeviceProperties_RunDLLA( HWND hwndStub, HINSTANCE hAppInstance, LPSTR lpCmdLine, int nCmdShow ) { try { CTString tstrCmdLine(lpCmdLine); DeviceProperties_RunDLL(hwndStub, hAppInstance, (LPCTSTR)tstrCmdLine, nCmdShow ); } catch (CMemoryException* e) { e->ReportError(); e->Delete(); } } STDAPI_(void) DeviceProperties_RunDLLW( HWND hwndStub, HINSTANCE hAppInstance, LPWSTR lpCmdLine, int nCmdShow ) { try { CTString tstrCmdLine(lpCmdLine); DeviceProperties_RunDLL(hwndStub, hAppInstance, (LPCTSTR)tstrCmdLine, nCmdShow ); } catch (CMemoryException* e) { e->ReportError(); e->Delete(); } } void DeviceProperties_RunDLL( HWND hwndStub, HINSTANCE hAppInstance, LPCTSTR lpCmdLine, int nCmdShow ) { try { CRunDLLCommandLine CmdLine; CmdLine.ParseCommandLine(lpCmdLine); if (NULL == CmdLine.GetDeviceID()) { ReportCmdLineError(hwndStub, IDS_NO_DEVICEID); return; } DevicePropertiesEx(hwndStub, CmdLine.GetMachineName(), CmdLine.GetDeviceID(), CmdLine.GetFlags(), CmdLine.ToShowDeviceTree() ); } catch (CMemoryException* e) { e->ReportError(); e->Delete(); return; } } STDAPI_(int) DevicePropertiesA( HWND hwndParent, LPCSTR MachineName, LPCSTR DeviceID, BOOL ShowDeviceTree ) { try { CTString tstrMachineName(MachineName); CTString tstrDeviceID(DeviceID); return DevicePropertiesEx(hwndParent, (LPCTSTR)tstrMachineName, (LPCTSTR)tstrDeviceID, DEVPROP_SHOW_RESOURCE_TAB, ShowDeviceTree ); } catch (CMemoryException* e) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); e->Delete(); } return 0; } STDAPI_(int) DevicePropertiesW( HWND hwndParent, LPCWSTR MachineName, LPCWSTR DeviceID, BOOL ShowDeviceTree ) { try { CTString tstrMachineName(MachineName); CTString tstrDeviceID(DeviceID); return DevicePropertiesEx(hwndParent, (LPCTSTR)tstrMachineName, (LPCTSTR)tstrDeviceID, DEVPROP_SHOW_RESOURCE_TAB, ShowDeviceTree ); } catch (CMemoryException* e) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); e->Delete(); } return 0; } STDAPI_(int) DevicePropertiesExA( HWND hwndParent, LPCSTR MachineName, LPCSTR DeviceID, DWORD Flags, BOOL ShowDeviceTree ) { try { CTString tstrMachineName(MachineName); CTString tstrDeviceID(DeviceID); return DevicePropertiesEx(hwndParent, (LPCTSTR)tstrMachineName, (LPCTSTR)tstrDeviceID, Flags, ShowDeviceTree ); } catch (CMemoryException* e) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); e->Delete(); } return 0; } STDAPI_(int) DevicePropertiesExW( HWND hwndParent, LPCWSTR MachineName, LPCWSTR DeviceID, DWORD Flags, BOOL ShowDeviceTree ) { try { CTString tstrMachineName(MachineName); CTString tstrDeviceID(DeviceID); return DevicePropertiesEx(hwndParent, (LPCTSTR)tstrMachineName, (LPCTSTR)tstrDeviceID, Flags, ShowDeviceTree ); } catch (CMemoryException* e) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); e->Delete(); } return 0; } int DevicePropertiesEx( HWND hwndParent, LPCTSTR MachineName, LPCTSTR DeviceID, DWORD Flags, BOOL ShowDeviceTree ) { HPROPSHEETPAGE hPage; DWORD DiFlags; DWORD DiFlagsEx; // // Verify that a DeviceID was passed in unless they want to show the // whole device tree. // if ((!DeviceID || (TEXT('\0') == *DeviceID)) && !ShowDeviceTree) { SetLastError(ERROR_INVALID_PARAMETER); return -1; } // // Verify that valid flags are passed in // if (Flags &~ DEVPROP_BITS) { SetLastError(ERROR_INVALID_FLAGS); return -1; } if (ShowDeviceTree) { return PropertyRunDeviceTree(hwndParent, MachineName, DeviceID); } int Result = -1; CDeviceGeneralPage* pGenPage = NULL; CDeviceDriverPage* pDrvPage = NULL; CDevice* pDevice; PVOID Context; try { CMachine TheMachine(MachineName); // create the machine just for this device if (!TheMachine.Initialize(hwndParent, DeviceID)) { return -1; } if (!TheMachine.GetFirstDevice(&pDevice, Context)) { SetLastError(SPAPI_E_NO_SUCH_DEVINST); return -1; } // // If the troubleshooter should be launched then set the appropriate // BOOL inside of the pDevice class. // if (Flags & DEVPROP_LAUNCH_TROUBLESHOOTER) { pDevice->m_bLaunchTroubleShooter = TRUE; } CPropSheetData& psd = pDevice->m_psd; // // Initialize CPropSheetData without ConsoleHandle // if (psd.Create(g_hInstance, hwndParent, MAX_PROP_PAGES, 0l)) { psd.m_psh.pszCaption = pDevice->GetDisplayName(); // // Add any class/device specific property pages. // TheMachine.DiGetClassDevPropertySheet(*pDevice, &psd.m_psh, MAX_PROP_PAGES, TheMachine.IsLocal() ? DIGCDP_FLAG_ADVANCED : DIGCDP_FLAG_REMOTE_ADVANCED); // // Add the general tab // DiFlags = TheMachine.DiGetFlags(*pDevice); DiFlagsEx = TheMachine.DiGetExFlags(*pDevice); if (DiFlags & DI_GENERALPAGE_ADDED) { TCHAR szText[MAX_PATH]; LoadResourceString(IDS_GENERAL_PAGE_WARNING, szText, ARRAYLEN(szText)); MessageBox(hwndParent, szText, pDevice->GetDisplayName(), MB_ICONEXCLAMATION | MB_OK); // // fall through to create our general page. // } SafePtr GenPagePtr; CDeviceGeneralPage* pGeneralPage = new CDeviceGeneralPage(); GenPagePtr.Attach(pGeneralPage); hPage = pGeneralPage->Create(pDevice); if (hPage) { if (psd.InsertPage(hPage, 0)) { GenPagePtr.Detach(); } else { ::DestroyPropertySheetPage(hPage); } } // // Add the driver tab // if (!(DiFlags & DI_DRIVERPAGE_ADDED)) { SafePtr DrvPagePtr; CDeviceDriverPage* pDriverPage = new CDeviceDriverPage(); DrvPagePtr.Attach(pDriverPage); hPage = pDriverPage->Create(pDevice); if (hPage) { if (psd.InsertPage(hPage)) { DrvPagePtr.Detach(); } else { ::DestroyPropertySheetPage(hPage); } } } // // Add the resource tab // if ((Flags & DEVPROP_SHOW_RESOURCE_TAB) && pDevice->HasResources() && !(DiFlags & DI_RESOURCEPAGE_ADDED)) { TheMachine.DiGetExtensionPropSheetPage(*pDevice, AddPageCallback, SPPSR_SELECT_DEVICE_RESOURCES, (LPARAM)&psd ); } #ifndef _WIN64 // // Add the power tab if this is the local machine // if (TheMachine.IsLocal() && !(DiFlagsEx & DI_FLAGSEX_POWERPAGE_ADDED)) { // // Check if the device support power management // CPowerShutdownEnable ShutdownEnable; CPowerWakeEnable WakeEnable; if (ShutdownEnable.Open(pDevice->GetDeviceID()) || WakeEnable.Open(pDevice->GetDeviceID())) { ShutdownEnable.Close(); WakeEnable.Close(); SafePtr PowerMgmtPagePtr; CDevicePowerMgmtPage* pPowerPage = new CDevicePowerMgmtPage; PowerMgmtPagePtr.Attach(pPowerPage); hPage = pPowerPage->Create(pDevice); if (hPage) { if (psd.InsertPage(hPage)) { PowerMgmtPagePtr.Detach(); } else { ::DestroyPropertySheetPage(hPage); } } } } #endif // // Add any Bus property pages if this is the local machine // if (TheMachine.IsLocal()) { CBusPropPageProvider* pBusPropPageProvider = new CBusPropPageProvider(); SafePtr ProviderPtr; ProviderPtr.Attach(pBusPropPageProvider); if (pBusPropPageProvider->EnumPages(pDevice, &psd)) { psd.AddProvider(pBusPropPageProvider); ProviderPtr.Detach(); } } Result = (int)psd.DoSheet(); if (-1 != Result) { if (TheMachine.DiGetExFlags(*pDevice) & DI_FLAGSEX_PROPCHANGE_PENDING) { // // property change pending, issue a DICS_PROPERTYCHANGE // to the class installer // SP_PROPCHANGE_PARAMS pcp; pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; pcp.Scope = DICS_FLAG_GLOBAL; pcp.StateChange = DICS_PROPCHANGE; TheMachine.DiSetClassInstallParams(*pDevice, &pcp.ClassInstallHeader, sizeof(pcp) ); TheMachine.DiCallClassInstaller(DIF_PROPERTYCHANGE, *pDevice); TheMachine.DiTurnOnDiFlags(*pDevice, DI_PROPERTIES_CHANGE); TheMachine.DiTurnOffDiExFlags(*pDevice, DI_FLAGSEX_PROPCHANGE_PENDING); } // // Merge restart/reboot flags // DiFlags = TheMachine.DiGetFlags(*pDevice); if (DI_NEEDREBOOT & DiFlags) { Result |= ID_PSREBOOTSYSTEM; } if (DI_NEEDRESTART & DiFlags) { Result |= ID_PSRESTARTWINDOWS; } } } } catch (CMemoryException* e) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); e->Delete(); } return -1; } STDAPI_(UINT) DeviceProblemTextA( HMACHINE hMachine, DEVNODE DevNode, ULONG ProblemNumber, LPSTR Buffer, UINT BufferSize ) { #ifndef UNICODE return GetDeviceProblemText(hMachine, DevNode, ProblemNumber, Buffer, BufferSize); #else WCHAR* wchBuffer = NULL; UINT RealSize = 0; if (BufferSize && !Buffer) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } if (BufferSize) { try { wchBuffer = new WCHAR[BufferSize]; } catch (CMemoryException* e) { e->Delete(); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; } } RealSize = GetDeviceProblemText(hMachine, DevNode, ProblemNumber, wchBuffer, BufferSize); if (RealSize && BufferSize > RealSize) { ASSERT(wchBuffer); RealSize = WideCharToMultiByte(CP_ACP, 0, wchBuffer, RealSize, Buffer, BufferSize, NULL, NULL); Buffer[RealSize] = '\0'; } if (wchBuffer) { delete wchBuffer; } return RealSize; #endif } STDAPI_(UINT) DeviceProblemTextW( HMACHINE hMachine, DEVNODE DevNode, ULONG ProblemNumber, LPWSTR Buffer, UINT BufferSize ) { #ifdef UNICODE return GetDeviceProblemText(hMachine, DevNode, ProblemNumber, Buffer, BufferSize); #else CHAR* chBuffer = NULL; UINT RealSize = 0; if (BufferSize && !Buffer) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } if (BufferSize) { try { chBuffer = new CHAR[BufferSize]; } catch (CMemoryException* e) { e->Delete(); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; } } RealSize = GetDeviceProblemText(hMachine, DevNode, ProblemNumber, chBuffer, BufferSize); if (RealSize && BufferSize > RealSize) { ASSERT(chBuffer); RealSize = MultiByteToWideChar((CP_ACP, 0, chBuffer, RealSize, Buffer, BufferSize); Buffer[RealSize] = UNICODE_NULL; } if (chBuffer) { delete chBuffer; } return RealSize; #endif } int PropertyRunDeviceTree( HWND hwndParent, LPCTSTR MachineName, LPCTSTR DeviceID ) { SHELLEXECUTEINFOW sei; TCHAR MachineOptions[MAX_PATH]; TCHAR DeviceIdOptions[MAX_PATH*2]; TCHAR CommandOptions[MAX_PATH]; TCHAR Parameters[MAX_PATH * 3]; TCHAR* FilePart; DWORD Size; Size = SearchPath(NULL, DEVMGR_MSC_FILE, NULL, MAX_PATH, Parameters, &FilePart); if (!Size || Size >=MAX_PATH) { lstrcpy(Parameters, DEVMGR_MSC_FILE); } lstrcat(Parameters, MMC_COMMAND_LINE); if (MachineName) { wsprintf(MachineOptions, DEVMGR_MACHINENAME_OPTION, MachineName); lstrcat(Parameters, MachineOptions); } if (DeviceID) { wsprintf(DeviceIdOptions, DEVMGR_DEVICEID_OPTION, DeviceID); wsprintf(CommandOptions, DEVMGR_COMMAND_OPTION, DEVMGR_CMD_PROPERTY); lstrcat(Parameters, DeviceIdOptions); lstrcat(Parameters, CommandOptions); } // no deviceid, no command. memset(&sei, 0, sizeof(sei)); sei.cbSize = sizeof(sei); sei.hwnd = hwndParent; sei.nShow = SW_NORMAL; sei.hInstApp = g_hInstance; sei.lpFile = MMC_FILE; sei.fMask = SEE_MASK_NOCLOSEPROCESS; sei.lpParameters = Parameters; if (ShellExecuteEx(&sei) && sei.hProcess) { WaitForSingleObject(sei.hProcess, INFINITE); return 1; } return 0; } STDAPI_(void) DeviceProblenWizard_RunDLLA( HWND hwndStub, HINSTANCE hAppInstance, LPSTR lpCmdLine, int nCmdShow ) { try { CTString tstrCmdLine(lpCmdLine); DeviceProblenWizard_RunDLL(hwndStub, hAppInstance, (LPCTSTR)tstrCmdLine, nCmdShow ); } catch (CMemoryException* e) { e->ReportError(); e->Delete(); } } STDAPI_(void) DeviceProblenWizard_RunDLLW( HWND hwndStub, HINSTANCE hAppInstance, LPWSTR lpCmdLine, int nCmdShow ) { try { CTString tstrCmdLine(lpCmdLine); DeviceProblenWizard_RunDLL(hwndStub, hAppInstance, (LPCTSTR)tstrCmdLine, nCmdShow ); } catch (CMemoryException* e) { e->ReportError(); e->Delete(); } } void DeviceProblenWizard_RunDLL( HWND hwndStub, HINSTANCE hAppInstance, LPCTSTR lpCmdLine, int nCmdShow ) { try { CRunDLLCommandLine CmdLine; CmdLine.ParseCommandLine(lpCmdLine); if (NULL == CmdLine.GetDeviceID()) { ReportCmdLineError(hwndStub, IDS_NO_DEVICEID); return; } DeviceProblemWizard(hwndStub, CmdLine.GetMachineName(), CmdLine.GetDeviceID() ); } catch (CMemoryException* e) { e->ReportError(); e->Delete(); return; } } STDAPI_(int) DeviceProblemWizardA( HWND hwndParent, LPCSTR MachineName, LPCSTR DeviceId ) { try { CTString tstrMachineName(MachineName); CTString tstrDeviceId(DeviceId); return DeviceProblemWizard(hwndParent, tstrMachineName, tstrDeviceId); } catch(CMemoryException* e) { e->Delete(); SetLastError(ERROR_NOT_ENOUGH_MEMORY); } return 0; } STDAPI_(int) DeviceProblemWizardW( HWND hwndParent, LPCWSTR MachineName, LPCWSTR DeviceId ) { try { CTString tstrMachineName(MachineName); CTString tstrDeviceId(DeviceId); return DeviceProblemWizard(hwndParent, tstrMachineName, tstrDeviceId); } catch (CMemoryException* e) { e->Delete(); SetLastError(ERROR_NOT_ENOUGH_MEMORY); } return 0; } int DeviceProblemWizard( HWND hwndParent, LPCTSTR MachineName, LPCTSTR DeviceId ) { DWORD Problem, Status; try { if (!DeviceId) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } CMachine TheMachine(MachineName); // create the machine just for this device if (!TheMachine.Initialize(hwndParent, DeviceId)) { return 0; } PVOID Context; CDevice* pDevice; if (!TheMachine.GetFirstDevice(&pDevice, Context)) { SetLastError(SPAPI_E_NO_SUCH_DEVINST); return 0; } if (pDevice->GetStatus(&Status, &Problem)) { // if the device is a phantom device, use the CM_PROB_DEVICE_NOT_THERE if (pDevice->IsPhantom()) { Problem = CM_PROB_PHANTOM; } // if the device is not started and no problem is assigned to it // fake the problem number to be failed start. if (!(Status & DN_STARTED) && !Problem && pDevice->IsRAW()) { Problem = CM_PROB_FAILED_START; } } CProblemAgent* pProblemAgent = new CProblemAgent(pDevice, Problem, TRUE); if (pProblemAgent) { pProblemAgent->FixIt(hwndParent); } return TRUE; } catch(CMemoryException* e) { e->Delete(); SetLastError(ERROR_NOT_ENOUGH_MEMORY); } return 0; } // This API creates a property sheet and asks the given device's property // provider to add any advanced pages to the property sheet. // The purpose of this API is for application to manage device advanced // properties. Standard device property pages(General, Driver, Resource, // Power, Bus) are not added. // // INPUT: // hwndParent -- the caller's window handle to be used as the owner // window of any widnows this function may create // MachineName -- optional machine name. If given, it must be in // its fully qualified form. NULL means local machine // DeviceId -- device id. // OUTPUT: // See PropertySheet API for the return value // STDAPI_(int) DeviceAdvancedPropertiesA( HWND hwndParent, LPTSTR MachineName, LPTSTR DeviceId ) { try { CTString tstrMachineName(MachineName); CTString tstrDeviceID(DeviceId); return DeviceAdvancedProperties(hwndParent, (LPCTSTR)tstrMachineName, (LPCTSTR)tstrDeviceID ); } catch (CMemoryException* e) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); e->Delete(); } return 0; } STDAPI_(int) DeviceAdvancedPropertiesW( HWND hwndParent, LPCWSTR MachineName, LPCWSTR DeviceId ) { try { CTString tstrMachineName(MachineName); CTString tstrDeviceID(DeviceId); return DeviceAdvancedProperties(hwndParent, (LPCTSTR)tstrMachineName, (LPCTSTR)tstrDeviceID ); } catch (CMemoryException* e) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); e->Delete(); } return 0; } int DeviceAdvancedProperties( HWND hwndParent, LPCTSTR MachineName, LPCTSTR DeviceId ) { if (!DeviceId) { SetLastError(ERROR_INVALID_PARAMETER); return -1; } CMachine TheMachine(MachineName); CDevice* pDevice; PVOID Context; try { if (TheMachine.Initialize(hwndParent, DeviceId) && TheMachine.GetFirstDevice(&pDevice, Context)) { TheMachine.EnableRefresh(FALSE); CPropSheetData& psd = pDevice->m_psd; //initialize CPropSheetData without ConsoleHandle if (psd.Create(g_hInstance, hwndParent, MAX_PROP_PAGES, 0l)) { psd.m_psh.pszCaption = pDevice->GetDisplayName(); if (TheMachine.DiGetClassDevPropertySheet(*pDevice, &psd.m_psh, MAX_PROP_PAGES, TheMachine.IsLocal() ? DIGCDP_FLAG_ADVANCED : DIGCDP_FLAG_REMOTE_ADVANCED)) { int Result = (int)psd.DoSheet(); if (-1 != Result) { // merge restart/reboot flags DWORD DiFlags = TheMachine.DiGetFlags(*pDevice); if (DI_NEEDREBOOT & DiFlags) { Result |= ID_PSREBOOTSYSTEM; } if (DI_NEEDRESTART & DiFlags) { Result |= ID_PSRESTARTWINDOWS; } } return Result; } } } } catch (CMemoryException* e) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); e->Delete(); } return -1; }