// SetupClass.cpp : Implementation of CSetupClass #include "stdafx.h" #include "DevCon2.h" #include "SetupClass.h" #include "devices.h" #include "utils.h" #include "xStrings.h" ///////////////////////////////////////////////////////////////////////////// // CSetupClass CSetupClass::~CSetupClass() { if(pMachine) { SysFreeString(pMachine); } } HRESULT CSetupClass::Init(GUID *pGuid,LPWSTR Machine, IDeviceConsole *pDevCon) { ClassGuid = *pGuid; if(pMachine) { SysFreeString(pMachine); } if(Machine) { pMachine = SysAllocString(Machine); if(!pMachine) { return E_OUTOFMEMORY; } } else { pMachine = NULL; } DeviceConsole = pDevCon; return S_OK; } BOOL CSetupClass::IsDuplicate(GUID *pCheck) { // // only valid if pMachine/DeviceConsole known to be same // return memcmp(&ClassGuid,pCheck,sizeof(GUID)) ? FALSE : TRUE; } STDMETHODIMP CSetupClass::get_Name(BSTR *pVal) { HRESULT hr; DWORD Err; LPWSTR Buffer; DWORD BuffSize=128; DWORD ReqSize; for(;;) { Buffer = new WCHAR[BuffSize]; if(!Buffer) { return E_OUTOFMEMORY; } if(SetupDiClassNameFromGuidEx(&ClassGuid,Buffer,BuffSize,&ReqSize,pMachine,NULL)) { *pVal = SysAllocString(Buffer); delete [] Buffer; if(!*pVal) { return E_OUTOFMEMORY; } return S_OK; } Err = GetLastError(); delete [] Buffer; if(Err != ERROR_INSUFFICIENT_BUFFER) { hr = HRESULT_FROM_SETUPAPI(Err); return hr; } BuffSize = ReqSize+2; } return S_OK; } STDMETHODIMP CSetupClass::get_Description(BSTR *pVal) { HRESULT hr; DWORD Err; LPWSTR Buffer; DWORD BuffSize=128; DWORD ReqSize; for(;;) { Buffer = new WCHAR[BuffSize]; if(!Buffer) { return E_OUTOFMEMORY; } if(SetupDiGetClassDescriptionEx(&ClassGuid,Buffer,BuffSize,&ReqSize,pMachine,NULL)) { *pVal = SysAllocString(Buffer); delete [] Buffer; if(!*pVal) { return E_OUTOFMEMORY; } return S_OK; } Err = GetLastError(); delete [] Buffer; if(Err != ERROR_INSUFFICIENT_BUFFER) { hr = HRESULT_FROM_SETUPAPI(Err); return hr; } BuffSize = ReqSize+2; } return S_OK; } STDMETHODIMP CSetupClass::Devices(VARIANT flags,LPDISPATCH * pDevices) { DWORD diflags = 0; HRESULT hr; HDEVINFO hDevInfo; DWORD Err; hr = TranslateDeviceFlags(&flags,&diflags); if(FAILED(hr)) { return hr; } hDevInfo = SetupDiGetClassDevsEx(&ClassGuid,NULL,NULL,diflags,NULL,pMachine,NULL); if(hDevInfo == INVALID_HANDLE_VALUE) { Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } CComObject *d; hr = CComObject::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; } STDMETHODIMP CSetupClass::CreateEmptyDeviceList(LPDISPATCH *pDevices) { HRESULT hr; HDEVINFO hDevInfo; DWORD Err; hDevInfo = SetupDiCreateDeviceInfoListEx(&ClassGuid, NULL, pMachine, NULL); if(hDevInfo == INVALID_HANDLE_VALUE) { Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } CComObject *d; hr = CComObject::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; } STDMETHODIMP CSetupClass::get_Guid(BSTR *pVal) { LPOLESTR pStr; HRESULT hr = StringFromCLSID(ClassGuid,&pStr); if(FAILED(hr)) { return hr; } *pVal = SysAllocString(pStr); CoTaskMemFree(pStr); if(!*pVal) { return E_OUTOFMEMORY; } return S_OK; } GUID* CSetupClass::Guid() { return &ClassGuid; } STDMETHODIMP CSetupClass::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; } STDMETHODIMP CSetupClass::get__ClassGuid(GUID *pVal) { *pVal = ClassGuid; return S_OK; } STDMETHODIMP CSetupClass::get__Machine(BSTR *pVal) { return get_Machine(pVal); return S_OK; } HRESULT CSetupClass::GetClassProperty(DWORD prop, VARIANT *pVal) { #if 0 // // 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(SetupDiGetClassRegistryProperty(&ClassGuid,prop,&dataType,buffer,size,&reqSize,pMachine,NULL)) { 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 *strings; hr = CComObject::CreateInstance(&strings); if(FAILED(hr)) { break; } strings->AddRef(); LPWSTR p; UINT len = 0; for(p = (LPWSTR)buffer;*p;p+=len+1) { len = wcslen(p); hr = strings->InternalAdd(p,len); if(FAILED(hr)) { strings->Release(); break; } } V_VT(pVal) = VT_DISPATCH; V_DISPATCH(pVal) = strings; hr = S_OK; } break; default: hr = E_INVALIDARG; break; } delete [] buffer; return hr; #endif return E_NOTIMPL; } HRESULT CSetupClass::PutClassPropertyString(DWORD prop, VARIANT *pVal) { #if 0 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(SetupDiSetClassRegistryProperty(&ClassGuid, prop, data, len, pMachine, NULL)) { return S_OK; } DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); #endif return E_NOTIMPL; } HRESULT CSetupClass::PutClassPropertyDword(DWORD prop, VARIANT *pVal) { #if 0 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(SetupDiSetClassRegistryProperty(&ClassGuid, prop, data, len, pMachine, NULL)) { return S_OK; } DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); #endif return E_NOTIMPL; } HRESULT CSetupClass::PutClassPropertyMultiSz(DWORD prop, VARIANT *pVal) { #if 0 // // build a CStrings collection // HRESULT hr; CComObject *strings = NULL; DWORD len = 0; PBYTE data = NULL; LPWSTR multisz; if(!IsBlank(pVal)) { hr = CComObject::CreateInstance(&strings); if(FAILED(hr)) { return hr; } strings->AddRef(); hr = strings->Add(*pVal); if(FAILED(hr)) { strings->Release(); return hr; } // // now obtain multisz from the collection // hr = strings->GetMultiSz(&multisz,&len); strings->Release(); // done with temporary collection if(FAILED(hr)) { return hr; } // // now write the multi-sz value to device registry // len *= sizeof(WCHAR); data = (PBYTE)multisz; } CONFIGRET cr = CM_Get_Class_Registry_Property( if(SetupDiSetClassRegistryProperty(&ClassGuid, prop, (PBYTE)multisz, len, pMachine, NULL)) { if(multisz) { delete [] multisz; } return S_OK; } DWORD Err = GetLastError(); if(multisz) { delete [] multisz; } return HRESULT_FROM_SETUPAPI(Err); #endif return E_NOTIMPL; } STDMETHODIMP CSetupClass::get_Security(VARIANT *pVal) { return GetClassProperty(SPDRP_SECURITY_SDS,pVal); } STDMETHODIMP CSetupClass::put_Security(VARIANT newVal) { return PutClassPropertyString(SPDRP_SECURITY_SDS,&newVal); } STDMETHODIMP CSetupClass::get_DeviceTypeOverride(VARIANT *pVal) { return GetClassProperty(SPDRP_DEVTYPE,pVal); } STDMETHODIMP CSetupClass::put_DeviceTypeOverride(VARIANT newVal) { return PutClassPropertyDword(SPDRP_DEVTYPE,&newVal); } STDMETHODIMP CSetupClass::get_ForceExclusive(VARIANT *pVal) { return GetClassProperty(SPDRP_EXCLUSIVE,pVal); } STDMETHODIMP CSetupClass::put_ForceExclusive(VARIANT newVal) { return PutClassPropertyDword(SPDRP_EXCLUSIVE,&newVal); } STDMETHODIMP CSetupClass::get_CharacteristicsOverride(VARIANT *pVal) { return GetClassProperty(SPDRP_CHARACTERISTICS,pVal); } STDMETHODIMP CSetupClass::put_CharacteristicsOverride(VARIANT newVal) { return PutClassPropertyDword(SPDRP_CHARACTERISTICS,&newVal); } HRESULT CSetupClass::SubKeyInfo(LPCWSTR subkey, HKEY *hKey, LPWSTR *pSubKey,LPCWSTR *pKeyVal,BOOL writeable) { DWORD Scope = DICS_FLAG_GLOBAL; DWORD HwProfile = 0; HKEY hParentKey; LPWSTR keyname; LPCWSTR keyval; size_t len; hParentKey = SetupDiOpenClassRegKeyEx(&ClassGuid, writeable ? KEY_WRITE: KEY_READ, DIOCR_INSTALLER, pMachine, NULL ); if((hParentKey == NULL) || (hParentKey == INVALID_HANDLE_VALUE)) { DWORD Err = GetLastError(); return HRESULT_FROM_SETUPAPI(Err); } // // determine value part of key // keyval = wcsrchr(subkey,L'\\'); if(!keyval) { *hKey = hParentKey; *pKeyVal = subkey[0] ? subkey : NULL; *pSubKey = NULL; return S_OK; } len = keyval-subkey+1; keyname = new WCHAR[len]; if(!keyname) { RegCloseKey(hParentKey); return E_OUTOFMEMORY; } wcsncpy(keyname,subkey,len); keyname[len-1] = 0; keyval++; if(!keyval[0]) { keyval = NULL; } *hKey = hParentKey; *pSubKey = keyname; *pKeyVal = keyval; return S_OK; } STDMETHODIMP CSetupClass::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 *pStringTemp = NULL; hr = CComObject::CreateInstance(&pStringTemp); if(FAILED(hr)) { delete [] pByte; return hr; } pStringTemp->AddRef(); hr = pStringTemp->FromMultiSz((LPWSTR)pByte); if(FAILED(hr)) { pStringTemp->Release(); delete [] pByte; return hr; } V_VT(pValue) = VT_DISPATCH; V_DISPATCH(pValue) = pStringTemp; } 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 CSetupClass::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 *pStringTemp = NULL; hr = CComObject::CreateInstance(&pStringTemp); if(FAILED(hr)) { return hr; } pStringTemp->AddRef(); hr = pStringTemp->InternalInsert(0,pVal); if(FAILED(hr)) { pStringTemp->Release(); return hr; } hr = pStringTemp->GetMultiSz(&pString,&DataSize); pStringTemp->Release(); 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 CSetupClass::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; }