windows-nt/Source/XPSP1/NT/base/pnp/tools/devcon2/setupclasses.cpp
2020-09-26 16:20:57 +08:00

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;
}