|
|
// Device.cpp : Implementation of CDevice
#include "stdafx.h"
#include "DevCon2.h"
#include "Device.h"
#include "xStrings.h"
#include "Driver.h"
#include "Drivers.h"
#include "DrvSearchSet.h"
#include "utils.h"
/////////////////////////////////////////////////////////////////////////////
// CDevice
CDevice::~CDevice() { //
// when this is destroyed, yank the entry out of HDEVINFO
//
if(DevInfoData.cbSize) { HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo != INVALID_HANDLE_VALUE) { SetupDiDeleteDeviceInfo(hDevInfo,&DevInfoData); } } }
HRESULT CDevice::Init(IDevInfoSet *pDevInfoSet, LPCWSTR pInstance,IDeviceConsole *pDevCon) { //
// init a new device (DeviceConsole/DevInfoSet are smart pointers)
//
DevInfoSet = pDevInfoSet; HDEVINFO hDevInfo = GetDevInfoSet(); HRESULT hr; DWORD err;
if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; } DeviceConsole = pDevCon; DevInfoData.cbSize = sizeof(DevInfoData); if(SetupDiOpenDeviceInfo(hDevInfo,pInstance,NULL,0,&DevInfoData)) { return S_OK; } err = GetLastError(); hr = HRESULT_FROM_SETUPAPI(err); DevInfoData.cbSize = 0; return hr; }
HRESULT CDevice::Init(IDevInfoSet *pDevInfoSet, PSP_DEVINFO_DATA pData,IDeviceConsole *pDevCon) { //
// init an existing device (DeviceConsole/DevInfoSet are smart pointers)
//
DevInfoSet = pDevInfoSet; DevInfoData = *pData; DeviceConsole = pDevCon; return S_OK; }
HDEVINFO CDevice::GetDevInfoSet() { ULONGLONG h; HRESULT hr;
if(!DevInfoSet) { return (HDEVINFO)INVALID_HANDLE_VALUE; } hr = DevInfoSet->get_Handle(&h); if(FAILED(hr)) { return (HDEVINFO)INVALID_HANDLE_VALUE; } return (HDEVINFO)h; }
STDMETHODIMP CDevice::get_InstanceId(BSTR *pVal) { if(!DevInfoData.cbSize) { return E_UNEXPECTED; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; } //
// get instance string given hDevInfo and DevInfoData
//
WCHAR devID[MAX_DEVICE_ID_LEN]; SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
devInfoListDetail.cbSize = sizeof(devInfoListDetail); if((!SetupDiGetDeviceInfoListDetail(hDevInfo,&devInfoListDetail)) || (CM_Get_Device_ID_Ex(DevInfoData.DevInst,devID,MAX_DEVICE_ID_LEN,0,devInfoListDetail.RemoteMachineHandle)!=CR_SUCCESS)) { return E_UNEXPECTED; } *pVal = SysAllocString(devID); if(!*pVal) { return E_OUTOFMEMORY; }
return S_OK; }
BOOL CDevice::SameAs(CDevice *pOther) { //
// only works if pOther is in same set as us
//
if(pOther == this) { return TRUE; } if(!pOther) { return FALSE; } if(DevInfoData.cbSize != pOther->DevInfoData.cbSize) { return FALSE; } if(DevInfoData.DevInst != pOther->DevInfoData.DevInst) { return FALSE; } return TRUE; }
STDMETHODIMP CDevice::Delete() { if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
SP_REMOVEDEVICE_PARAMS rmdParams;
ZeroMemory(&rmdParams,sizeof(rmdParams)); rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE; rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL; rmdParams.HwProfile = 0;
if(!SetupDiSetClassInstallParams(hDevInfo,&DevInfoData,&rmdParams.ClassInstallHeader,sizeof(rmdParams)) || !SetupDiCallClassInstaller(DIF_REMOVE,hDevInfo,&DevInfoData)) { DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } return CheckNoReboot(); }
STDMETHODIMP CDevice::Enable() { if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
SP_PROPCHANGE_PARAMS pcp; VARIANT_BOOL NeedReboot; VARIANT_BOOL NowNeedReboot; HRESULT hr;
//
// remember current reboot status
//
hr = get_RebootRequired(&NeedReboot); if(FAILED(hr)) { return hr; }
//
// attempt to enable globally
//
ZeroMemory(&pcp,sizeof(pcp)); pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; pcp.StateChange = DICS_ENABLE; pcp.Scope = DICS_FLAG_GLOBAL; pcp.HwProfile = 0; if(!SetupDiSetClassInstallParams(hDevInfo,&DevInfoData,&pcp.ClassInstallHeader,sizeof(pcp)) || !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,hDevInfo,&DevInfoData)) { //
// failed to invoke DIF_PROPERTYCHANGE
//
DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } hr = get_RebootRequired(&NowNeedReboot); if(FAILED(hr)) { return hr; } if(!(NeedReboot || NowNeedReboot)) { //
// reboot not required, we must have enabled the device
//
return S_OK; } if(!NeedReboot) { //
// reset reboot status back to how it was originally
//
put_RebootRequired(VARIANT_FALSE); } //
// also do config specific enable
//
pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; pcp.StateChange = DICS_ENABLE; pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; pcp.HwProfile = 0; if(SetupDiSetClassInstallParams(hDevInfo,&DevInfoData,&pcp.ClassInstallHeader,sizeof(pcp)) && SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,hDevInfo,&DevInfoData)) { //
// succeeded to invoke config-specific
//
if(NeedReboot) { //
// set back original status if reboot was required
//
put_RebootRequired(VARIANT_TRUE); } return CheckNoReboot(); } //
// if this failed, just imply reboot (our first result)
//
put_RebootRequired(VARIANT_TRUE); return CheckNoReboot(); }
STDMETHODIMP CDevice::Disable() { if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
SP_PROPCHANGE_PARAMS pcp;
//
// attempt to disable globally
//
ZeroMemory(&pcp,sizeof(pcp)); pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; pcp.StateChange = DICS_DISABLE; pcp.Scope = DICS_FLAG_GLOBAL; pcp.HwProfile = 0; if(!SetupDiSetClassInstallParams(hDevInfo,&DevInfoData,&pcp.ClassInstallHeader,sizeof(pcp)) || !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,hDevInfo,&DevInfoData)) { //
// failed to invoke DIF_PROPERTYCHANGE
//
DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } return CheckNoReboot(); }
STDMETHODIMP CDevice::Start() { if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
SP_PROPCHANGE_PARAMS pcp;
//
// attempt to start (can only be for this config)
//
ZeroMemory(&pcp,sizeof(pcp)); pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; pcp.StateChange = DICS_ENABLE; pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; pcp.HwProfile = 0; if(!SetupDiSetClassInstallParams(hDevInfo,&DevInfoData,&pcp.ClassInstallHeader,sizeof(pcp)) || !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,hDevInfo,&DevInfoData)) { //
// failed to invoke DIF_PROPERTYCHANGE
//
DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } return CheckNoReboot(); }
STDMETHODIMP CDevice::Stop() { if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
SP_PROPCHANGE_PARAMS pcp;
//
// attempt to start (can only be for this config)
//
ZeroMemory(&pcp,sizeof(pcp)); pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; pcp.StateChange = DICS_STOP; pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; pcp.HwProfile = 0; if(!SetupDiSetClassInstallParams(hDevInfo,&DevInfoData,&pcp.ClassInstallHeader,sizeof(pcp)) || !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,hDevInfo,&DevInfoData)) { //
// failed to invoke DIF_PROPERTYCHANGE
//
DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } return CheckNoReboot(); }
STDMETHODIMP CDevice::Restart() { if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
SP_PROPCHANGE_PARAMS pcp;
//
// attempt to stop then start (restart) (can only be for this config)
//
ZeroMemory(&pcp,sizeof(pcp)); pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; pcp.StateChange = DICS_PROPCHANGE; pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; pcp.HwProfile = 0; if(!SetupDiSetClassInstallParams(hDevInfo,&DevInfoData,&pcp.ClassInstallHeader,sizeof(pcp)) || !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,hDevInfo,&DevInfoData)) { //
// failed to invoke DIF_PROPERTYCHANGE
//
DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } return CheckNoReboot(); }
HRESULT CDevice::CheckNoReboot() { VARIANT_BOOL NeedReboot; HRESULT hr = get_RebootRequired(&NeedReboot); if(FAILED(hr)) { return hr; } if(NeedReboot) { if(DeviceConsole) { //
// set reboot required in device console too
//
DeviceConsole->put_RebootRequired(VARIANT_TRUE); } return S_FALSE; } return S_OK; }
STDMETHODIMP CDevice::get_RebootRequired(VARIANT_BOOL *pVal) { if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
SP_DEVINSTALL_PARAMS devParams; ZeroMemory(&devParams,sizeof(devParams));
devParams.cbSize = sizeof(devParams); if(!SetupDiGetDeviceInstallParams(hDevInfo,&DevInfoData,&devParams)) { DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } *pVal = (devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)) ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; }
STDMETHODIMP CDevice::put_RebootRequired(VARIANT_BOOL newVal) { if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
BOOL changed = FALSE; SP_DEVINSTALL_PARAMS devParams; ZeroMemory(&devParams,sizeof(devParams));
devParams.cbSize = sizeof(devParams); if(!SetupDiGetDeviceInstallParams(hDevInfo,&DevInfoData,&devParams)) { DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } if(newVal) { if((devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)) == 0) { devParams.Flags |= DI_NEEDREBOOT|DI_NEEDRESTART; changed = TRUE; if(DeviceConsole) { //
// set reboot required in device console too
//
DeviceConsole->put_RebootRequired(VARIANT_TRUE); } } } else { if((devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)) != 0) { devParams.Flags &= ~DI_NEEDREBOOT|DI_NEEDRESTART; changed = TRUE; } } if(changed) { if(!SetupDiSetDeviceInstallParams(hDevInfo,&DevInfoData,&devParams)) { DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } }
return S_OK; }
STDMETHODIMP CDevice::get_Description(BSTR *pVal) { //
// obtain a description for the device
//
HRESULT hr; CComVariant v; VARIANT final; VariantInit(&final);
hr = GetDeviceProperty(SPDRP_FRIENDLYNAME,&v); if(SUCCEEDED(hr)) { hr = v.ChangeType(VT_BSTR); if(SUCCEEDED(hr)) { if(V_BSTR(&v)!=NULL && V_BSTR(&v)[0]) { v.Detach(&final); *pVal = V_BSTR(&final); return S_OK; } } } v.Clear(); hr = GetDeviceProperty(SPDRP_DEVICEDESC,&v); if(SUCCEEDED(hr)) { hr = v.ChangeType(VT_BSTR); if(SUCCEEDED(hr)) { if(V_BSTR(&v)!=NULL && V_BSTR(&v)[0]) { v.Detach(&final); *pVal = V_BSTR(&final); return S_OK; } } } v.Clear(); *pVal = SysAllocString(L""); if(!*pVal) { return E_OUTOFMEMORY; } return S_OK; }
STDMETHODIMP CDevice::get_HardwareIds(VARIANT *pVal) { return GetDeviceProperty(SPDRP_HARDWAREID,pVal); }
STDMETHODIMP CDevice::put_HardwareIds(VARIANT newVal) { return PutDevicePropertyMultiSz(SPDRP_HARDWAREID,&newVal); }
STDMETHODIMP CDevice::get_CompatibleIds(VARIANT *pVal) { return GetDeviceProperty(SPDRP_COMPATIBLEIDS,pVal); }
STDMETHODIMP CDevice::put_CompatibleIds(VARIANT newVal) { return PutDevicePropertyMultiSz(SPDRP_COMPATIBLEIDS,&newVal); }
STDMETHODIMP CDevice::get_ServiceName(VARIANT *pVal) { return GetDeviceProperty(SPDRP_SERVICE,pVal); }
STDMETHODIMP CDevice::get_Class(VARIANT *pVal) { return GetDeviceProperty(SPDRP_CLASS,pVal); }
STDMETHODIMP CDevice::get_Manufacturer(VARIANT *pVal) { return GetDeviceProperty(SPDRP_MFG,pVal); }
STDMETHODIMP CDevice::get_FriendlyName(VARIANT *pVal) { return GetDeviceProperty(SPDRP_FRIENDLYNAME,pVal); }
STDMETHODIMP CDevice::put_FriendlyName(VARIANT newVal) { return PutDevicePropertyString(SPDRP_FRIENDLYNAME,&newVal); }
STDMETHODIMP CDevice::get_LocationInformation(VARIANT *pVal) { return GetDeviceProperty(SPDRP_LOCATION_INFORMATION,pVal); }
STDMETHODIMP CDevice::put_LocationInformation(VARIANT newVal) { return PutDevicePropertyString(SPDRP_LOCATION_INFORMATION,&newVal); }
STDMETHODIMP CDevice::get_UpperFilters(VARIANT *pVal) { return GetDeviceProperty(SPDRP_UPPERFILTERS,pVal); }
STDMETHODIMP CDevice::put_UpperFilters(VARIANT newVal) { return PutDevicePropertyMultiSz(SPDRP_UPPERFILTERS,&newVal); }
STDMETHODIMP CDevice::get_LowerFilters(VARIANT *pVal) { return GetDeviceProperty(SPDRP_LOWERFILTERS,pVal); }
STDMETHODIMP CDevice::put_LowerFilters(VARIANT newVal) { return PutDevicePropertyMultiSz(SPDRP_LOWERFILTERS,&newVal); }
STDMETHODIMP CDevice::get_EnumeratorName(VARIANT *pVal) { return GetDeviceProperty(SPDRP_ENUMERATOR_NAME,pVal); }
STDMETHODIMP CDevice::get_Security(VARIANT *pVal) { return GetDeviceProperty(SPDRP_SECURITY_SDS,pVal); }
STDMETHODIMP CDevice::put_Security(VARIANT newVal) { return PutDevicePropertyString(SPDRP_SECURITY_SDS,&newVal); }
STDMETHODIMP CDevice::get_DeviceTypeOverride(VARIANT *pVal) { return GetDeviceProperty(SPDRP_DEVTYPE,pVal); }
STDMETHODIMP CDevice::put_DeviceTypeOverride(VARIANT newVal) { return PutDevicePropertyDword(SPDRP_DEVTYPE,&newVal); }
STDMETHODIMP CDevice::get_ForceExclusive(VARIANT *pVal) { return GetDeviceProperty(SPDRP_EXCLUSIVE,pVal); }
STDMETHODIMP CDevice::put_ForceExclusive(VARIANT newVal) { return PutDevicePropertyDword(SPDRP_EXCLUSIVE,&newVal); }
STDMETHODIMP CDevice::get_CharacteristicsOverride(VARIANT *pVal) { return GetDeviceProperty(SPDRP_CHARACTERISTICS,pVal); }
STDMETHODIMP CDevice::put_CharacteristicsOverride(VARIANT newVal) { return PutDevicePropertyDword(SPDRP_CHARACTERISTICS,&newVal); }
HRESULT CDevice::GetDeviceProperty(DWORD prop, VARIANT *pVal) { if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
//
// first obtain raw registry data
//
LPBYTE buffer = NULL; DWORD size = 1024; DWORD bufsize; DWORD reqSize; DWORD dataType; HRESULT hr;
for(;;) { if(buffer) { delete [] buffer; } bufsize = size + sizeof(WCHAR)*2; buffer = new BYTE[bufsize]; if(!buffer) { return E_OUTOFMEMORY; } if(SetupDiGetDeviceRegistryProperty(hDevInfo,&DevInfoData,prop,&dataType,buffer,size,&reqSize)) { break; } DWORD Err = GetLastError(); if(Err != ERROR_INSUFFICIENT_BUFFER) { delete [] buffer; hr = HRESULT_FROM_SETUPAPI(Err); return hr; } }
//
// now determine how to parcel it to caller
//
switch(dataType) { case REG_DWORD: { //
// package value as a long
//
if(size != sizeof(DWORD)) { hr = E_INVALIDARG; } else { VariantClear(pVal); V_VT(pVal) = VT_I4; V_I4(pVal) = (long)*((DWORD*)buffer); hr = S_OK; } } break;
case REG_SZ: { //
// package value as string
//
VariantClear(pVal); ZeroMemory(buffer+size,sizeof(WCHAR)); BSTR pString = SysAllocString((LPWSTR)buffer); if(!pString) { hr = E_OUTOFMEMORY; } else { V_VT(pVal) = VT_BSTR; V_BSTR(pVal) = pString; hr = S_OK; } } break;
case REG_MULTI_SZ: { //
// package as string-list
//
VariantClear(pVal); ZeroMemory(buffer+size,sizeof(WCHAR)*2); CComObject<CStrings> *strings; hr = CComObject<CStrings>::CreateInstance(&strings); if(FAILED(hr)) { break; } CComPtr<IStrings> stringsPtr = strings; LPWSTR p; UINT len = 0; for(p = (LPWSTR)buffer;*p;p+=len+1) { len = wcslen(p); hr = strings->InternalAdd(p,len); if(FAILED(hr)) { break; } } V_VT(pVal) = VT_DISPATCH; V_DISPATCH(pVal) = stringsPtr.Detach(); hr = S_OK; } break;
default: hr = E_INVALIDARG; break; } delete [] buffer; return hr;
}
HRESULT CDevice::PutDevicePropertyString(DWORD prop, VARIANT *pVal) { if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
HRESULT hr; DWORD len = 0; PBYTE data = NULL; CComVariant v; if(!IsBlank(pVal)) { hr = v.ChangeType(VT_BSTR,pVal); if(FAILED(hr)) { return hr; } len = (SysStringLen(V_BSTR(&v))+1)*sizeof(WCHAR); data = (PBYTE)V_BSTR(&v); }
if(SetupDiSetDeviceRegistryProperty(hDevInfo, &DevInfoData, prop, data, len)) { return S_OK; } DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); }
HRESULT CDevice::PutDevicePropertyDword(DWORD prop, VARIANT *pVal) { if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
CComVariant v; HRESULT hr; DWORD len = 0; PBYTE data = NULL; if(!IsBlank(pVal)) { hr = v.ChangeType(VT_I4,pVal); if(FAILED(hr)) { return hr; } len = sizeof(V_I4(&v)); data = (PBYTE)&V_I4(&v); }
if(SetupDiSetDeviceRegistryProperty(hDevInfo, &DevInfoData, prop, data, len)) { return S_OK; } DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err);
}
HRESULT CDevice::PutDevicePropertyMultiSz(DWORD prop, VARIANT *pVal) { if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
//
// build a CStrings collection
//
HRESULT hr; CComObject<CStrings> *strings = NULL; CComPtr<IStrings> stringsPtr; DWORD len = 0; PBYTE data = NULL; LPWSTR multisz; if(!IsBlank(pVal)) { hr = CComObject<CStrings>::CreateInstance(&strings); if(FAILED(hr)) { return hr; } stringsPtr = strings; // handle ref-counting
hr = strings->Add(*pVal); if(FAILED(hr)) { return hr; } //
// now obtain multisz from the collection
//
hr = strings->GetMultiSz(&multisz,&len); if(FAILED(hr)) { return hr; } //
// now write the multi-sz value to device registry
//
len *= sizeof(WCHAR); data = (PBYTE)multisz; } if(SetupDiSetDeviceRegistryProperty(hDevInfo, &DevInfoData, prop, (PBYTE)multisz, len)) { if(multisz) { delete [] multisz; } return S_OK; } DWORD Err = GetLastError(); if(multisz) { delete [] multisz; } return HRESULT_FROM_SETUPAPI(Err); }
HRESULT CDevice::GetRemoteMachine(HANDLE *hMachine) { if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
devInfoListDetail.cbSize = sizeof(devInfoListDetail); if(!SetupDiGetDeviceInfoListDetail(hDevInfo,&devInfoListDetail)) { DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } *hMachine = devInfoListDetail.RemoteMachineHandle; return S_OK; }
STDMETHODIMP CDevice::get_IsRunning(VARIANT_BOOL *pVal) { HANDLE hMachine; ULONG status = 0; ULONG problem = 0; HRESULT hr = GetRemoteMachine(&hMachine); if(FAILED(hr)) { return hr; } if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) { return E_UNEXPECTED; } if(status & DN_STARTED) { *pVal = VARIANT_TRUE; } else { *pVal = VARIANT_FALSE; }
return S_OK; }
STDMETHODIMP CDevice::get_IsDisabled(VARIANT_BOOL *pVal) { HANDLE hMachine; ULONG status = 0; ULONG problem = 0; HRESULT hr = GetRemoteMachine(&hMachine); if(FAILED(hr)) { return hr; } if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) { return E_UNEXPECTED; } if(status & DN_HAS_PROBLEM) { if((problem == CM_PROB_DISABLED) || (problem == CM_PROB_HARDWARE_DISABLED)) { *pVal = VARIANT_TRUE; return S_OK; } } *pVal = VARIANT_FALSE;
return S_OK; }
STDMETHODIMP CDevice::get_HasProblem(VARIANT_BOOL *pVal) { HANDLE hMachine; ULONG status = 0; ULONG problem = 0; HRESULT hr = GetRemoteMachine(&hMachine); if(FAILED(hr)) { return hr; } if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) { return E_UNEXPECTED; } if(status & (DN_HAS_PROBLEM|DN_PRIVATE_PROBLEM)) { *pVal = VARIANT_TRUE; } else { *pVal = VARIANT_FALSE; }
return S_OK; }
STDMETHODIMP CDevice::get_ProblemCode(long *pVal) { HANDLE hMachine; ULONG status = 0; ULONG problem = 0; HRESULT hr = GetRemoteMachine(&hMachine); if(FAILED(hr)) { return hr; } if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) { return E_UNEXPECTED; } if(status & DN_HAS_PROBLEM) { *pVal = (long)problem; } else { *pVal = 0; }
return S_OK; }
STDMETHODIMP CDevice::get_HasPrivateProblem(VARIANT_BOOL *pVal) { HANDLE hMachine; ULONG status = 0; ULONG problem = 0; HRESULT hr = GetRemoteMachine(&hMachine); if(FAILED(hr)) { return hr; } if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) { return E_UNEXPECTED; } if(status & DN_PRIVATE_PROBLEM) { *pVal = VARIANT_TRUE; } else { *pVal = VARIANT_FALSE; }
return S_OK; }
STDMETHODIMP CDevice::get_IsRootEnumerated(VARIANT_BOOL *pVal) { HANDLE hMachine; ULONG status = 0; ULONG problem = 0; HRESULT hr = GetRemoteMachine(&hMachine); if(FAILED(hr)) { return hr; } if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) { return E_UNEXPECTED; } if(status & DN_ROOT_ENUMERATED) { *pVal = VARIANT_TRUE; } else { *pVal = VARIANT_FALSE; }
return S_OK; }
STDMETHODIMP CDevice::get_IsDisableable(VARIANT_BOOL *pVal) { HANDLE hMachine; ULONG status = 0; ULONG problem = 0; HRESULT hr = GetRemoteMachine(&hMachine); if(FAILED(hr)) { return hr; } if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) { return E_UNEXPECTED; } if(status & DN_DISABLEABLE) { *pVal = VARIANT_TRUE; } else { *pVal = VARIANT_FALSE; }
return S_OK; }
STDMETHODIMP CDevice::get_IsRemovable(VARIANT_BOOL *pVal) { HANDLE hMachine; ULONG status = 0; ULONG problem = 0; HRESULT hr = GetRemoteMachine(&hMachine); if(FAILED(hr)) { return hr; } if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) { return E_UNEXPECTED; } if(status & DN_REMOVABLE) { *pVal = VARIANT_TRUE; } else { *pVal = VARIANT_FALSE; }
return S_OK; }
BOOL CDevice::SameAs(LPWSTR str) { BSTR pThisStr; HRESULT hr = get_InstanceId(&pThisStr); if(FAILED(hr)) { return FALSE; } BOOL f = _wcsicmp(str,pThisStr)==0; SysFreeString(pThisStr); return f; }
STDMETHODIMP CDevice::RegRead(BSTR key,VARIANT * pValue) { HKEY hParentKey; HKEY hKey; LPCWSTR val; LPWSTR subkey; LONG regerr; DWORD regType; DWORD regSize; LPBYTE pByte;
if(!pValue) { return E_INVALIDARG; } VariantInit(pValue);
HRESULT hr = SubKeyInfo(key,&hParentKey,&subkey,&val,FALSE); if(FAILED(hr)) { return hr; } //
// now work out and marshell data
//
if(subkey) { regerr = RegOpenKeyEx(hParentKey,subkey,0,KEY_READ,&hKey); delete [] subkey; RegCloseKey(hParentKey); if(regerr != NO_ERROR) { return HRESULT_FROM_SETUPAPI(regerr); } } else { hKey = hParentKey; } regSize = 0; regerr = RegQueryValueEx(hKey,val,NULL,®Type,NULL,®Size); if(regerr != NO_ERROR) { RegCloseKey(hKey); return HRESULT_FROM_SETUPAPI(regerr); } pByte = new BYTE[regSize+sizeof(WCHAR)*2]; if(!pByte) { RegCloseKey(hKey); return E_OUTOFMEMORY; } regerr = RegQueryValueEx(hKey,val,NULL,®Type,pByte,®Size); RegCloseKey(hKey); if(regerr != NO_ERROR) { delete [] pByte; return HRESULT_FROM_SETUPAPI(regerr); } switch(regType) { case REG_DWORD: if(regSize != 4) { delete [] pByte; return DISP_E_TYPEMISMATCH; }
V_VT(pValue) = VT_UI4; V_UI4(pValue) = *(DWORD*)pByte; break;
case REG_BINARY: switch(regSize) { case 1: V_VT(pValue) = VT_UI1; V_UI1(pValue) = *((BYTE*)pByte); break; case 2: V_VT(pValue) = VT_UI2; V_UI2(pValue) = *((WORD*)pByte); break; case 4: V_VT(pValue) = VT_UI4; V_UI4(pValue) = *((DWORD*)pByte); break; default: delete [] pByte; return DISP_E_TYPEMISMATCH; } break;
case REG_SZ: ZeroMemory(pByte+regSize,sizeof(WCHAR)*1); V_VT(pValue) = VT_BSTR; V_BSTR(pValue) = SysAllocString((LPWSTR)pByte); if(!V_BSTR(pValue)) { delete [] pByte; return E_OUTOFMEMORY; } break;
case REG_MULTI_SZ: { ZeroMemory(pByte+regSize,sizeof(WCHAR)*2); CComObject<CStrings> *pStringTemp = NULL; hr = CComObject<CStrings>::CreateInstance(&pStringTemp); if(FAILED(hr)) { delete [] pByte; return hr; } CComPtr<IStrings> stringTempPtr = pStringTemp; // handle ref-counting
hr = pStringTemp->FromMultiSz((LPWSTR)pByte); if(FAILED(hr)) { delete [] pByte; return hr; } V_VT(pValue) = VT_DISPATCH; V_DISPATCH(pValue) = stringTempPtr.Detach(); } break;
case REG_EXPAND_SZ: ZeroMemory(pByte+regSize,sizeof(WCHAR)*1); regSize = ExpandEnvironmentStrings((LPWSTR)pByte,NULL,0); if(regSize == 0) { V_VT(pValue) = VT_BSTR; V_BSTR(pValue) = SysAllocString((LPWSTR)pByte); } else { LPWSTR pExp = new WCHAR[regSize+1]; if(!pExp) { delete [] pByte; return E_OUTOFMEMORY; } regSize = ExpandEnvironmentStrings((LPWSTR)pByte,NULL,regSize); V_VT(pValue) = VT_BSTR; V_BSTR(pValue) = SysAllocString(pExp); delete [] pExp; } if(!V_BSTR(pValue)) { delete [] pByte; return E_OUTOFMEMORY; } break;
default: delete [] pByte; return HRESULT_FROM_SETUPAPI(regerr); } delete [] pByte; return S_OK; }
STDMETHODIMP CDevice::RegWrite(BSTR key, VARIANT val, VARIANT strType) { HKEY hParentKey; HKEY hKey; LPCWSTR valname; LPWSTR subkey; LONG regerr; CComVariant strType_v; CComVariant val_v; LPCWSTR pType; HRESULT hr; DWORD dwType; BOOL DetermineType = FALSE; LPBYTE pData = NULL; LPWSTR pString = NULL; DWORD DataSize = 0; BYTE SimpleData[4]; LPVARIANT pVal = &val;
while(V_VT(pVal) == (VT_BYREF|VT_VARIANT)) { pVal = V_VARIANTREF(pVal); }
//
// validate strType
//
hr = GetOptionalString(&strType,strType_v,&pType); if(FAILED(hr)) { return hr; }
if((pType == NULL) || !pType[0]) { //
// determine type of variant
//
if(IsNumericVariant(pVal)) { dwType = REG_DWORD; } else if(IsMultiValueVariant(pVal)) { dwType = REG_MULTI_SZ; } else { dwType = REG_SZ; } } else if(_wcsicmp(pType,L"REG_DWORD")==0) { dwType = REG_DWORD; } else if(_wcsicmp(pType,L"REG_SZ")==0) { dwType = REG_SZ; } else if(_wcsicmp(pType,L"REG_EXPAND_SZ")==0) { dwType = REG_EXPAND_SZ; } else if(_wcsicmp(pType,L"REG_MULTI_SZ")==0) { dwType = REG_MULTI_SZ; } else if(_wcsicmp(pType,L"REG_BINARY")==0) { dwType = REG_BINARY; } else { return DISP_E_TYPEMISMATCH; }
//
// build up value data
//
switch(dwType) { case REG_BINARY: pData = SimpleData; switch V_VT(pVal) { case VT_I1: case VT_UI1: *(LPBYTE)pData = V_UI1(pVal); DataSize = 1; break; case VT_I1|VT_BYREF: case VT_UI1|VT_BYREF: *(LPBYTE)pData = *V_UI1REF(pVal); DataSize = 1; break; case VT_I2: case VT_UI2: *(LPWORD)pData = V_UI2(pVal); DataSize = 2; break; case VT_I2|VT_BYREF: case VT_UI2|VT_BYREF: *(LPWORD)pData = *V_UI2REF(pVal); DataSize = 2; break; case VT_I4: case VT_UI4: *(LPDWORD)pData = V_UI4(pVal); DataSize = 4; break; case VT_I4|VT_BYREF: case VT_UI4|VT_BYREF: *(LPDWORD)pData = *V_UI4REF(pVal); DataSize = 4; break; default: return DISP_E_TYPEMISMATCH; } break;
case REG_DWORD: pData = SimpleData; hr = val_v.ChangeType(VT_UI4,pVal); if(FAILED(hr)) { return DISP_E_TYPEMISMATCH; } *(LPDWORD)pData = V_UI4(pVal); DataSize = 4; break;
case REG_SZ: case REG_EXPAND_SZ: hr = val_v.ChangeType(VT_BSTR,pVal); if(FAILED(hr)) { return DISP_E_TYPEMISMATCH; }
DataSize = (SysStringLen(V_BSTR(&val_v))+1); pString = new WCHAR[DataSize]; if(!pString) { return E_OUTOFMEMORY; } pData = (LPBYTE)pString; DataSize *= sizeof(WCHAR); memcpy(pData,V_BSTR(&val_v),DataSize); break;
case REG_MULTI_SZ: { CComObject<CStrings> *pStringTemp = NULL; hr = CComObject<CStrings>::CreateInstance(&pStringTemp); if(FAILED(hr)) { return hr; } CComPtr<IStrings> pStringTempPtr = pStringTemp; // for ref-counting
hr = pStringTemp->InternalInsert(0,pVal); if(FAILED(hr)) { return hr; } hr = pStringTemp->GetMultiSz(&pString,&DataSize); if(FAILED(hr)) { return hr; } pData = (LPBYTE)pString; DataSize *= sizeof(WCHAR); } break; default: return DISP_E_TYPEMISMATCH; }
hr = SubKeyInfo(key,&hParentKey,&subkey,&valname,TRUE); if(FAILED(hr)) { if(pString) { delete [] pString; } return hr; } if(subkey) { regerr = RegCreateKeyEx(hParentKey,subkey,0,NULL,0,KEY_WRITE,NULL,&hKey,NULL); delete [] subkey; RegCloseKey(hParentKey); if(regerr != NO_ERROR) { if(pString) { delete [] pString; } return HRESULT_FROM_SETUPAPI(regerr); } } else { hKey = hParentKey; }
regerr = RegSetValueEx(hKey,valname,0,dwType,pData,DataSize); if(pString) { delete [] pString; } RegCloseKey(hKey); if(regerr != NO_ERROR) { return HRESULT_FROM_SETUPAPI(regerr); }
return S_OK; }
STDMETHODIMP CDevice::RegDelete(BSTR key) { HKEY hParentKey; HKEY hKey; LPCWSTR valname; LPWSTR subkey; LONG regerr; HRESULT hr = SubKeyInfo(key,&hParentKey,&subkey,&valname,TRUE); if(FAILED(hr)) { return hr; } if(subkey) { regerr = RegOpenKeyEx(hParentKey,subkey,0,KEY_WRITE,&hKey); delete [] subkey; RegCloseKey(hParentKey); if(regerr != NO_ERROR) { return HRESULT_FROM_SETUPAPI(regerr); } } else { hKey = hParentKey; } regerr = RegDeleteValue(hKey,valname); RegCloseKey(hKey); if(regerr != NO_ERROR) { return HRESULT_FROM_SETUPAPI(regerr); } return S_OK; }
HRESULT CDevice::SubKeyInfo(LPCWSTR subkey, HKEY *hKey, LPWSTR *pSubKey,LPCWSTR *pKeyVal,BOOL writeable) { //
// first 3 chars of subkey can be "SW\" or "HW\"
//
LPCWSTR partkey; DWORD Scope = DICS_FLAG_GLOBAL; DWORD HwProfile = 0; DWORD KeyType; HKEY hParentKey; LPWSTR keyname; LPCWSTR keyval; size_t len;
if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
if((subkey[0] == L'S' || subkey[0] == L's') &&(subkey[1] == L'W' || subkey[1] == L'w') &&(subkey[2] == L'\\')) { partkey = subkey+3; KeyType = DIREG_DRV; } else if((subkey[0] == L'H' || subkey[0] == L'h') &&(subkey[1] == L'W' || subkey[1] == L'w') &&(subkey[2] == L'\\')) { partkey = subkey+3; KeyType = DIREG_DEV; } else { return E_INVALIDARG; } hParentKey = SetupDiOpenDevRegKey(hDevInfo, &DevInfoData, Scope, HwProfile, KeyType, writeable ? KEY_WRITE: KEY_READ ); if((hParentKey == NULL) || (hParentKey == INVALID_HANDLE_VALUE)) { DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } //
// determine value part of key
//
keyval = wcsrchr(partkey,L'\\'); if(!keyval) { *hKey = hParentKey; *pKeyVal = partkey[0] ? partkey : NULL; *pSubKey = NULL; return S_OK; } len = keyval-partkey+1; keyname = new WCHAR[len]; if(!keyname) { RegCloseKey(hParentKey); return E_OUTOFMEMORY; } wcsncpy(keyname,partkey,len); keyname[len-1] = 0; keyval++; if(!keyval[0]) { keyval = NULL; } *hKey = hParentKey; *pSubKey = keyname; *pKeyVal = keyval; return S_OK; }
STDMETHODIMP CDevice::CurrentDriverPackage(LPDISPATCH *pDriver) { *pDriver = NULL; //
// create a search set for finding current driver
//
HRESULT hr;
if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; } HANDLE remote; if(SUCCEEDED(GetRemoteMachine(&remote)) && remote) {
//
// remote driver search not implemented
//
return E_NOTIMPL; }
CComObject<CDrvSearchSet> *pSet = NULL;
hr = CComObject<CDrvSearchSet>::CreateInstance(&pSet); if(FAILED(hr)) { return hr; } CComPtr<IDrvSearchSet> pSetPtr = pSet; // for ref-counting
hr = pSet->Init(this,SPDIT_CLASSDRIVER); if(FAILED(hr)) { return hr; }
//
// use temporary device information
//
HDEVINFO SetDevInfo = pSet->GetDevInfoSet(); PSP_DEVINFO_DATA SetDevInfoData = pSet->GetDevInfoData();
//
// WinXP has a nice feature for obtaining current driver
//
DWORD Err; SP_DEVINSTALL_PARAMS DeviceInstallParams; SP_DRVINFO_DATA DriverInfoData;
ZeroMemory(&DeviceInstallParams, sizeof(DeviceInstallParams)); ZeroMemory(&DriverInfoData, sizeof(DriverInfoData));
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
if(!SetupDiGetDeviceInstallParams(SetDevInfo, SetDevInfoData, &DeviceInstallParams)) { Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); }
//
// Set the flags that tell SetupDiBuildDriverInfoList to just put the currently installed
// driver node in the list, and that it should allow excluded drivers.
//
DeviceInstallParams.FlagsEx |= (DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
if(SetupDiSetDeviceInstallParams(SetDevInfo, SetDevInfoData, &DeviceInstallParams) && SetupDiBuildDriverInfoList(SetDevInfo, SetDevInfoData, SPDIT_CLASSDRIVER)) { if(!SetupDiEnumDriverInfo(SetDevInfo,SetDevInfoData,SPDIT_CLASSDRIVER,0,&DriverInfoData)) { //
// flag recognized, but no driver
//
return S_OK; } //
// DriverInfoData contains driver
//
} else {
//
// get information about a driver to do a full search
//
WCHAR SectionName[LINE_LEN]; WCHAR DrvDescription[LINE_LEN]; HKEY hKey = NULL; DWORD RegDataLength; DWORD RegDataType; long regerr;
//
// get driver key - if it doesn't exist, no driver
//
hKey = SetupDiOpenDevRegKey(SetDevInfo, SetDevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ );
if(hKey == INVALID_HANDLE_VALUE) { //
// no such value exists, so we haven't an associated driver
//
RegCloseKey(hKey); return S_OK; }
//
// obtain path of INF
//
RegDataLength = sizeof(DeviceInstallParams.DriverPath); // want in bytes, not chars
regerr = RegQueryValueEx(hKey, REGSTR_VAL_INFPATH, NULL, &RegDataType, (PBYTE)DeviceInstallParams.DriverPath, &RegDataLength );
if((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ)) { //
// no such value exists, so we haven't an associated driver
//
RegCloseKey(hKey); return S_OK; }
RegDataLength = sizeof(DriverInfoData.ProviderName); regerr = RegQueryValueEx(hKey, REGSTR_VAL_PROVIDER_NAME, NULL, &RegDataType, (PBYTE)DriverInfoData.ProviderName, &RegDataLength );
if((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ)) { //
// no such value exists, so we don't have a valid associated driver
//
RegCloseKey(hKey); return S_OK; }
RegDataLength = sizeof(SectionName); regerr = RegQueryValueEx(hKey, REGSTR_VAL_INFSECTION, NULL, &RegDataType, (PBYTE)SectionName, &RegDataLength );
if((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ)) { //
// no such value exists, so we don't have a valid associated driver
//
RegCloseKey(hKey); return S_OK; }
//
// driver description is usually same as original device description
// but sometimes obtained from strings section
//
RegDataLength = sizeof(DrvDescription); regerr = RegQueryValueEx(hKey, REGSTR_VAL_DRVDESC, NULL, &RegDataType, (PBYTE)DrvDescription, &RegDataLength );
RegCloseKey(hKey);
if((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ)) { //
// no such value exists, so we don't have a valid associated driver
//
return S_OK; }
//
// Manufacturer
//
if(!SetupDiGetDeviceRegistryProperty(SetDevInfo, SetDevInfoData, SPDRP_MFG, NULL, // datatype is guaranteed to always be REG_SZ.
(PBYTE)DriverInfoData.MfgName, sizeof(DriverInfoData.MfgName), NULL)) { //
// no such value exists, so we don't have a valid associated driver
//
return S_OK; }
//
// Description
//
if(!SetupDiGetDeviceRegistryProperty(SetDevInfo, SetDevInfoData, SPDRP_DEVICEDESC, NULL, // datatype is guaranteed to always be REG_SZ.
(PBYTE)DriverInfoData.Description, sizeof(DriverInfoData.Description), NULL)) { //
// no such value exists, so we don't have a valid associated driver
//
return S_OK; }
//
// now search for drivers listed in the INF
//
//
DeviceInstallParams.Flags |= DI_ENUMSINGLEINF; DeviceInstallParams.FlagsEx &= ~DI_FLAGSEX_INSTALLEDDRIVER; DeviceInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
if(!SetupDiSetDeviceInstallParams(SetDevInfo, SetDevInfoData, &DeviceInstallParams)) { Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } if(!SetupDiBuildDriverInfoList(SetDevInfo, SetDevInfoData, SPDIT_CLASSDRIVER)) { return S_OK; }
//
// enumerate drivers to find a good match
//
SP_DRVINFO_DATA ThisDriverInfoData; ZeroMemory(&ThisDriverInfoData, sizeof(ThisDriverInfoData)); ThisDriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
DWORD c; BOOL match = FALSE; for(c=0;SetupDiEnumDriverInfo(SetDevInfo,SetDevInfoData,SPDIT_CLASSDRIVER,c,&ThisDriverInfoData);c++) { if((_wcsicmp(DriverInfoData.MfgName,ThisDriverInfoData.MfgName)==0) &&(_wcsicmp(DriverInfoData.ProviderName,ThisDriverInfoData.ProviderName)==0)) { //
// these two fields match, try more detailed info
//
SP_DRVINFO_DETAIL_DATA detail; detail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA); if(!SetupDiGetDriverInfoDetail(SetDevInfo,SetDevInfoData,&ThisDriverInfoData,&detail,sizeof(detail),NULL)) { Err = GetLastError(); if((Err != NO_ERROR) && (Err != ERROR_INSUFFICIENT_BUFFER)) { continue; } } if((_wcsicmp(SectionName,detail.SectionName)==0) && (_wcsicmp(DrvDescription,detail.DrvDescription)==0)) { DriverInfoData = ThisDriverInfoData; match = TRUE; break; } } } if(!match) { return S_OK; } }
//
// create the driver object
//
CComObject<CDriverPackage> *driver = NULL; hr = CComObject<CDriverPackage>::CreateInstance(&driver); if(FAILED(hr)) { return hr; } CComPtr<IDriverPackage> driverPtr = driver; // for ref-counting
hr = driver->Init(pSet,&DriverInfoData); if(FAILED(hr)) { return hr; } *pDriver = driverPtr.Detach(); return S_OK; }
STDMETHODIMP CDevice::FindDriverPackages(VARIANT ScriptPath, LPDISPATCH *pDriversOut) { *pDriversOut = NULL;
//
// Treat variant as a multi-sz array if it exists
//
CComObject<CStrings> *pStrings = NULL; CComPtr<IStrings> pStringsPtr; CComObject<CDrvSearchSet> *pSet = NULL; CComPtr<IDrvSearchSet> pSetPtr; CComObject<CDriverPackages> *pDrivers = NULL; CComPtr<IDriverPackages> pDriversPtr; CComObject<CDriverPackage> *pDriver = NULL; CComPtr<IDriverPackage> pDriverPtr; HRESULT hr;
if(!IsNoArg(&ScriptPath)) { hr = CComObject<CStrings>::CreateInstance(&pStrings); if(FAILED(hr)) { return hr; } pStringsPtr = pStrings;
hr = pStrings->InternalInsert(0,&ScriptPath); if(FAILED(hr)) { return hr; } }
//
// create context for driver search
//
hr = CComObject<CDrvSearchSet>::CreateInstance(&pSet); if(FAILED(hr)) { return hr; } pSetPtr = pSet; hr = pSet->Init(this,SPDIT_COMPATDRIVER); if(FAILED(hr)) { return hr; }
//
// use temporary device information
//
HDEVINFO SetDevInfo = pSet->GetDevInfoSet(); PSP_DEVINFO_DATA SetDevInfoData = pSet->GetDevInfoData(); DWORD Err; SP_DEVINSTALL_PARAMS DeviceInstallParams; SP_DRVINFO_DATA DriverInfoData; DWORD c;
ZeroMemory(&DeviceInstallParams, sizeof(DeviceInstallParams)); ZeroMemory(&DriverInfoData, sizeof(DriverInfoData));
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
if(!SetupDiGetDeviceInstallParams(SetDevInfo, SetDevInfoData, &DeviceInstallParams)) { Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); }
//
// Do a search in standard directories.
//
DeviceInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
BOOL done_wild = FALSE; BSTR str;
for(c=0,str=NULL;(pStrings==NULL) || (pStrings->InternalEnum(c,&str));c++) {
if(str && str[0] && ((str[0] != '*') || str[1])) { DWORD attr = GetFileAttributes(str); if(attr == (DWORD)(-1)) { continue; } DWORD sz = GetFullPathName(str,MAX_PATH,DeviceInstallParams.DriverPath,NULL); if(sz >= MAX_PATH) { DeviceInstallParams.DriverPath[0] = '\0'; continue; } if(!(attr & FILE_ATTRIBUTE_DIRECTORY)) { DeviceInstallParams.FlagsEx |= DI_ENUMSINGLEINF; } } else if(done_wild) { continue; } else { done_wild = TRUE; }
if(!SetupDiSetDeviceInstallParams(SetDevInfo, SetDevInfoData, &DeviceInstallParams)) { Err = GetLastError(); hr = HRESULT_FROM_SETUPAPI(Err); goto final; }
if(!SetupDiBuildDriverInfoList(SetDevInfo, SetDevInfoData, SPDIT_COMPATDRIVER)) { Err = GetLastError(); hr = HRESULT_FROM_SETUPAPI(Err); goto final; }
SetupDiGetDeviceInstallParams(SetDevInfo, SetDevInfoData, &DeviceInstallParams); DeviceInstallParams.FlagsEx |= DI_FLAGSEX_APPENDDRIVERLIST; DeviceInstallParams.FlagsEx &= ~DI_ENUMSINGLEINF; DeviceInstallParams.DriverPath[0] = '\0'; }
//
// now create the collection to hold search results
//
hr = CComObject<CDriverPackages>::CreateInstance(&pDrivers); if(FAILED(hr)) { pDrivers = NULL; goto final; } pDriversPtr = pDrivers; hr = pDrivers->Init(pSet); if(FAILED(hr)) { goto final; }
for(c=0;SetupDiEnumDriverInfo(SetDevInfo,SetDevInfoData,SPDIT_COMPATDRIVER,c,&DriverInfoData);c++) {
//
// create the driver object
//
hr = CComObject<CDriverPackage>::CreateInstance(&pDriver); if(FAILED(hr)) { goto final; } pDriverPtr = pDriver; hr = pDriver->Init(pSet,&DriverInfoData); if(FAILED(hr)) { goto final; } hr = pDrivers->InternalAdd(pDriver); if(FAILED(hr)) { goto final; } }
final:
if(FAILED(hr)) { return hr; } *pDriversOut = pDriversPtr.Detach(); return S_OK; }
STDMETHODIMP CDevice::HasInterface(BSTR Interface, VARIANT_BOOL *pFlag) { //
// create a search set for finding current driver
//
HRESULT hr;
if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; }
GUID guid; hr = CLSIDFromString(Interface,&guid); if(FAILED(hr)) { return hr; } SP_DEVICE_INTERFACE_DATA data; ZeroMemory(&data,sizeof(data)); data.cbSize = sizeof(data); BOOL f = SetupDiEnumDeviceInterfaces(hDevInfo,&DevInfoData,&guid,0,&data); DWORD Err = GetLastError();
*pFlag = f? VARIANT_TRUE: VARIANT_FALSE;
return S_OK; }
STDMETHODIMP CDevice::get_Machine(BSTR *pVal) { *pVal = NULL;
HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; } SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
devInfoListDetail.cbSize = sizeof(devInfoListDetail); if(!SetupDiGetDeviceInfoListDetail(hDevInfo,&devInfoListDetail)) { DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); }
if((devInfoListDetail.RemoteMachineHandle == NULL) || !devInfoListDetail.RemoteMachineName[0]) { *pVal = SysAllocString(L""); if(*pVal) { return S_FALSE; } } else { *pVal = SysAllocString(devInfoListDetail.RemoteMachineName); if(*pVal) { return S_OK; } } return E_OUTOFMEMORY; }
STDMETHODIMP CDevice::get__ClassGuid(GUID *pVal) { WCHAR ClassGuid[40]; HRESULT hr;
if(!DevInfoData.cbSize) { return E_INVALIDARG; } HDEVINFO hDevInfo = GetDevInfoSet(); if(hDevInfo == INVALID_HANDLE_VALUE) { return E_UNEXPECTED; } DWORD reqSize; if(!SetupDiGetDeviceRegistryProperty(hDevInfo, &DevInfoData, SPDRP_CLASSGUID, NULL, (LPBYTE)ClassGuid, sizeof(ClassGuid), &reqSize)) { DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } hr = CLSIDFromString(ClassGuid,pVal); if(FAILED(hr)) { return hr; }
return S_OK; }
STDMETHODIMP CDevice::get__Machine(BSTR *pVal) { return get_Machine(pVal); }
|