438 lines
7.8 KiB
C++
438 lines
7.8 KiB
C++
|
// SetupClasses.cpp : Implementation of CSetupClasses
|
||
|
#include "stdafx.h"
|
||
|
#include "DevCon2.h"
|
||
|
#include "SetupClass.h"
|
||
|
#include "SetupClassEnum.h"
|
||
|
#include "SetupClasses.h"
|
||
|
#include "DeviceConsole.h"
|
||
|
#include "Devices.h"
|
||
|
#include "xStrings.h"
|
||
|
#include "utils.h"
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CSetupClasses
|
||
|
|
||
|
CSetupClasses::~CSetupClasses()
|
||
|
{
|
||
|
DWORD c;
|
||
|
if(pSetupClasses) {
|
||
|
for(c=0;c<Count;c++) {
|
||
|
pSetupClasses[c]->Release();
|
||
|
}
|
||
|
delete [] pSetupClasses;
|
||
|
}
|
||
|
if(pMachine) {
|
||
|
SysFreeString(pMachine);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP CSetupClasses::get_Count(long *pVal)
|
||
|
{
|
||
|
*pVal = (long)Count;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CSetupClasses::Item(long Index, LPDISPATCH *ppVal)
|
||
|
{
|
||
|
*ppVal = NULL;
|
||
|
DWORD i = (DWORD)Index;
|
||
|
if(i<1 || i > Count) {
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
i--;
|
||
|
pSetupClasses[i]->AddRef();
|
||
|
*ppVal = pSetupClasses[i];
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CSetupClasses::get__NewEnum(IUnknown **ppUnk)
|
||
|
{
|
||
|
*ppUnk = NULL;
|
||
|
HRESULT hr;
|
||
|
CComObject<CSetupClassEnum> *pEnum = NULL;
|
||
|
hr = CComObject<CSetupClassEnum>::CreateInstance(&pEnum);
|
||
|
if(FAILED(hr)) {
|
||
|
return hr;
|
||
|
}
|
||
|
if(!pEnum) {
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
pEnum->AddRef();
|
||
|
if(!pEnum->CopySetupClasses(pSetupClasses,Count)) {
|
||
|
pEnum->Release();
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
*ppUnk = pEnum;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL CSetupClasses::IncreaseArraySize(DWORD add)
|
||
|
{
|
||
|
CSetupClass** pNewSetupClasses;
|
||
|
DWORD Inc;
|
||
|
DWORD c;
|
||
|
|
||
|
if((ArraySize-Count)>=add) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
Inc = ArraySize + add + 32;
|
||
|
pNewSetupClasses = new CSetupClass*[Inc];
|
||
|
if(!pNewSetupClasses) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
for(c=0;c<Count;c++) {
|
||
|
pNewSetupClasses[c] = pSetupClasses[c];
|
||
|
}
|
||
|
delete [] pSetupClasses;
|
||
|
pSetupClasses = pNewSetupClasses;
|
||
|
ArraySize = Inc;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT CSetupClasses::Init(LPCWSTR Machine, IDeviceConsole *pDevCon)
|
||
|
{
|
||
|
if(pMachine) {
|
||
|
SysFreeString(pMachine);
|
||
|
}
|
||
|
if(Machine) {
|
||
|
pMachine = SysAllocString(Machine);
|
||
|
if(!pMachine) {
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
} else {
|
||
|
pMachine = NULL;
|
||
|
}
|
||
|
DeviceConsole = pDevCon;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CSetupClasses::AppendClass(LPCWSTR Filter)
|
||
|
{
|
||
|
DWORD nClasses;
|
||
|
DWORD nClasses2;
|
||
|
DWORD c;
|
||
|
DWORD Err;
|
||
|
HRESULT hr;
|
||
|
|
||
|
if(Filter[0]==L'{') {
|
||
|
//
|
||
|
// possibly GUID
|
||
|
//
|
||
|
GUID guid;
|
||
|
hr = CLSIDFromString((LPWSTR)Filter,&guid);
|
||
|
if(SUCCEEDED(hr)) {
|
||
|
//
|
||
|
// class is in GUID format
|
||
|
//
|
||
|
if(FindDuplicate(&guid)) {
|
||
|
return S_OK;
|
||
|
}
|
||
|
return AddGuid(&guid);
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// class is probably in text format
|
||
|
// obtain list of class id's that match class name
|
||
|
// append all class devices for each class guid
|
||
|
//
|
||
|
if(SetupDiClassGuidsFromNameEx(Filter,NULL,0,&nClasses,pMachine,NULL) || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||
|
if(!nClasses) {
|
||
|
//
|
||
|
// no classes
|
||
|
//
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
GUID *pList = new GUID[nClasses];
|
||
|
if(!pList) {
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
if(SetupDiClassGuidsFromNameEx(Filter,pList,nClasses,&nClasses2,pMachine,NULL) || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||
|
//
|
||
|
// count may have changed since last call
|
||
|
//
|
||
|
if(nClasses>nClasses2) {
|
||
|
nClasses = nClasses2;
|
||
|
}
|
||
|
if(!nClasses) {
|
||
|
//
|
||
|
// no classes
|
||
|
//
|
||
|
delete [] pList;
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
for(c=0;c<nClasses;c++) {
|
||
|
if(FindDuplicate(&pList[c])) {
|
||
|
continue;
|
||
|
}
|
||
|
hr = AddGuid(&pList[c]);
|
||
|
if(FAILED(hr)) {
|
||
|
delete [] pList;
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
delete [] pList;
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
Err = GetLastError();
|
||
|
return HRESULT_FROM_SETUPAPI(Err);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CSetupClasses::AddGuid(GUID *pGuid)
|
||
|
{
|
||
|
if(!IncreaseArraySize(1)) {
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
CComObject<CSetupClass> *d;
|
||
|
HRESULT hr;
|
||
|
hr = CComObject<CSetupClass>::CreateInstance(&d);
|
||
|
if(FAILED(hr)) {
|
||
|
return hr;
|
||
|
}
|
||
|
d->AddRef();
|
||
|
hr = d->Init(pGuid,pMachine,DeviceConsole);
|
||
|
if(FAILED(hr)) {
|
||
|
d->Release();
|
||
|
return hr;
|
||
|
}
|
||
|
pSetupClasses[Count++] = d;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CSetupClasses::Add(VARIANT ClassNames)
|
||
|
{
|
||
|
//
|
||
|
// can pass in a collection
|
||
|
//
|
||
|
CComObject<CStrings> *pStrings = NULL;
|
||
|
HRESULT hr;
|
||
|
DWORD c;
|
||
|
BSTR str;
|
||
|
|
||
|
hr = CComObject<CStrings>::CreateInstance(&pStrings);
|
||
|
if(FAILED(hr)) {
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
pStrings->AddRef();
|
||
|
hr = pStrings->InternalInsert(0,&ClassNames);
|
||
|
if(FAILED(hr)) {
|
||
|
pStrings->Release();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
for(c=0;pStrings->InternalEnum(c,&str);c++) {
|
||
|
hr = AppendClass(str);
|
||
|
if(FAILED(hr)) {
|
||
|
pStrings->Release();
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
pStrings->Release();
|
||
|
return c ? S_OK : S_FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL CSetupClasses::FindDuplicate(GUID *pGuid)
|
||
|
{
|
||
|
DWORD c;
|
||
|
for(c=0;c<Count;c++) {
|
||
|
if(pSetupClasses[c]->IsDuplicate(pGuid)) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP CSetupClasses::Remove(VARIANT v)
|
||
|
{
|
||
|
// TODO: Add your implementation code here
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CSetupClasses::GetIndex(LPVARIANT Index, DWORD *pAt)
|
||
|
{
|
||
|
CComVariant v;
|
||
|
HRESULT hr;
|
||
|
if(IsNumericVariant(Index)) {
|
||
|
hr = v.ChangeType(VT_I4,Index);
|
||
|
if(FAILED(hr)) {
|
||
|
return DISP_E_TYPEMISMATCH;
|
||
|
}
|
||
|
if(V_I4(&v)<1) {
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
*pAt = ((DWORD)V_I4(&v))-1;
|
||
|
return S_OK;
|
||
|
}
|
||
|
//
|
||
|
// user actually supplied guid?
|
||
|
//
|
||
|
hr = v.ChangeType(VT_BSTR,Index);
|
||
|
if(FAILED(hr)) {
|
||
|
return DISP_E_TYPEMISMATCH;
|
||
|
}
|
||
|
if(!Count) {
|
||
|
//
|
||
|
// cannot match anything
|
||
|
//
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
BSTR pMatch = V_BSTR(&v);
|
||
|
if(pMatch[0]!=L'{') {
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
//
|
||
|
// obtain GUID
|
||
|
//
|
||
|
GUID guid;
|
||
|
hr = CLSIDFromString((LPWSTR)pMatch,&guid);
|
||
|
if(FAILED(hr)) {
|
||
|
return hr;
|
||
|
}
|
||
|
DWORD c;
|
||
|
for(c=0;c<Count;c++) {
|
||
|
if(pSetupClasses[c]->IsDuplicate(&guid)) {
|
||
|
*pAt = c;
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// still none found
|
||
|
//
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CSetupClasses::Devices(VARIANT flags, LPDISPATCH *pDevices)
|
||
|
{
|
||
|
//
|
||
|
// combine devices for all classes
|
||
|
//
|
||
|
DWORD diflags = 0;
|
||
|
HRESULT hr;
|
||
|
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
|
||
|
HDEVINFO hPrevDevInfo = NULL;
|
||
|
DWORD Err;
|
||
|
DWORD c;
|
||
|
|
||
|
hr = TranslateDeviceFlags(&flags,&diflags);
|
||
|
if(FAILED(hr)) {
|
||
|
return hr;
|
||
|
}
|
||
|
for(c=0;c<Count;c++) {
|
||
|
hDevInfo = SetupDiGetClassDevsEx(pSetupClasses[c]->Guid(),NULL,NULL,diflags,hPrevDevInfo,pMachine,NULL);
|
||
|
if(hDevInfo == INVALID_HANDLE_VALUE) {
|
||
|
Err = GetLastError();
|
||
|
if(hPrevDevInfo) {
|
||
|
SetupDiDestroyDeviceInfoList(hPrevDevInfo);
|
||
|
}
|
||
|
return HRESULT_FROM_SETUPAPI(Err);
|
||
|
}
|
||
|
hPrevDevInfo = hDevInfo;
|
||
|
}
|
||
|
if(hDevInfo == INVALID_HANDLE_VALUE) {
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
CComObject<CDevices> *d;
|
||
|
hr = CComObject<CDevices>::CreateInstance(&d);
|
||
|
if(FAILED(hr)) {
|
||
|
SetupDiDestroyDeviceInfoList(hDevInfo);
|
||
|
return hr;
|
||
|
}
|
||
|
d->AddRef();
|
||
|
hr = d->Init(hDevInfo,DeviceConsole);
|
||
|
if(FAILED(hr)) {
|
||
|
d->Release();
|
||
|
return hr;
|
||
|
}
|
||
|
*pDevices = d;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CSetupClasses::AllClasses()
|
||
|
{
|
||
|
DWORD nClasses;
|
||
|
DWORD nClasses2;
|
||
|
DWORD c;
|
||
|
DWORD Err;
|
||
|
HRESULT hr;
|
||
|
|
||
|
//
|
||
|
// start with empty list
|
||
|
//
|
||
|
if(pSetupClasses) {
|
||
|
for(c=0;c<Count;c++) {
|
||
|
pSetupClasses[c]->Release();
|
||
|
}
|
||
|
delete [] pSetupClasses;
|
||
|
}
|
||
|
//
|
||
|
// all classes
|
||
|
//
|
||
|
if(SetupDiBuildClassInfoListEx(0,NULL,0,&nClasses,pMachine,NULL) || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||
|
if(!nClasses) {
|
||
|
//
|
||
|
// no classes
|
||
|
//
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
GUID *pList = new GUID[nClasses];
|
||
|
if(!pList) {
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
if(SetupDiBuildClassInfoListEx(0,pList,nClasses,&nClasses2,pMachine,NULL) || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||
|
//
|
||
|
// count may have changed since last call
|
||
|
//
|
||
|
if(nClasses>nClasses2) {
|
||
|
nClasses = nClasses2;
|
||
|
}
|
||
|
if(!nClasses) {
|
||
|
//
|
||
|
// no classes
|
||
|
//
|
||
|
delete [] pList;
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
for(c=0;c<nClasses;c++) {
|
||
|
hr = AddGuid(&pList[c]);
|
||
|
if(FAILED(hr)) {
|
||
|
delete [] pList;
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
delete [] pList;
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
Err = GetLastError();
|
||
|
return HRESULT_FROM_SETUPAPI(Err);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CSetupClasses::get_Machine(BSTR *pVal)
|
||
|
{
|
||
|
if((pMachine == NULL) || !pMachine[0]) {
|
||
|
*pVal = SysAllocString(L"");
|
||
|
if(*pVal) {
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
} else {
|
||
|
*pVal = SysAllocString(pMachine);
|
||
|
if(*pVal) {
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
*pVal = NULL;
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|