1297 lines
30 KiB
C++
1297 lines
30 KiB
C++
/*++
|
|
|
|
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<CDeviceGeneralPage> 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<CDeviceDriverPage> 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<CDevicePowerMgmtPage> 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<CBusPropPageProvider> 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;
|
|
}
|