// Strings.cpp : Implementation of CStrings #include "stdafx.h" #include "DevCon2.h" #include "xStrings.h" #include "StringsEnum.h" #include "utils.h" ///////////////////////////////////////////////////////////////////////////// // CStrings CStrings::~CStrings() { DWORD c; if(pMultiStrings) { for(c=0;c *pEnum = NULL; hr = CComObject::CreateInstance(&pEnum); if(FAILED(hr)) { return hr; } if(!pEnum) { return E_OUTOFMEMORY; } pEnum->AddRef(); if(!pEnum->CopyStrings(pMultiStrings,Count)) { pEnum->Release(); return E_OUTOFMEMORY; } *ppUnk = pEnum; return S_OK; } HRESULT CStrings::InternalAdd(LPCWSTR Value, UINT len) { if(len == (UINT)(-1)) { len = wcslen(Value); } BSTR ValueCopy = NULL; if(!IncreaseArraySize(1)) { return E_OUTOFMEMORY; } ValueCopy = SysAllocStringLen(Value,len); if(!ValueCopy) { return E_OUTOFMEMORY; } pMultiStrings[Count++] = ValueCopy; return S_OK; } STDMETHODIMP CStrings::Add(VARIANT Value) { return InternalInsert(Count,&Value); } BOOL CStrings::IncreaseArraySize(DWORD strings) { BSTR* pNewStrings; DWORD Inc; DWORD c; if((ArraySize-Count)>=strings) { return TRUE; } Inc = ArraySize + strings + 32; pNewStrings = new BSTR[Inc]; if(!pNewStrings) { return FALSE; } for(c=0;cCount) { return E_INVALIDARG; } return InternalInsert(i,&Value); } STDMETHODIMP CStrings::Remove(VARIANT Index) { HRESULT hr; DWORD i; hr = GetIndex(&Index,&i); if(FAILED(hr)) { return hr; } if(i>=Count) { return E_INVALIDARG; } DWORD c; SysFreeString(pMultiStrings[i]); Count--; for(c=i;c pEnum; if(IsArrayVariant(pVal,&pArray,&vt)) { return InternalInsertArray(Index,vt,pArray); } if(IsCollectionVariant(pVal,&pEnum)) { return InternalInsertCollection(Index,pEnum); } // // now see if we can treat it as a string // hr = v.ChangeType(VT_BSTR,pVal); if(SUCCEEDED(hr)) { return InternalInsertString(Index,V_BSTR(&v)); } return hr; } HRESULT CStrings::InternalInsertArray(DWORD Index, VARTYPE vt, SAFEARRAY *pArray) { HRESULT hr; UINT dims = SafeArrayGetDim(pArray); if(!dims) { return S_FALSE; } long *pDims = new long[dims]; if(!pDims) { return E_OUTOFMEMORY; } // // write values into a temporary collection // CComObject *pStringTemp = NULL; hr = CComObject::CreateInstance(&pStringTemp); if(FAILED(hr)) { delete [] pDims; return hr; } pStringTemp->AddRef(); hr = InternalInsertArrayDim(pStringTemp,vt,pArray,pDims,0,dims); delete [] pDims; if(FAILED(hr)) { pStringTemp->Release(); return hr; } // // now quickly insert pStringTemp strings into this collection // DWORD Added = pStringTemp->Count; if(!IncreaseArraySize(Added)) { pStringTemp->Release(); return E_OUTOFMEMORY; } DWORD c; for(c=Count;c>Index;c--) { pMultiStrings[c-1+Added] = pMultiStrings[c-1]; } for(c=0;cpMultiStrings[c]; } Count += Added; // // throw strings in temp collection away without free'ing them // pStringTemp->Count = 0; pStringTemp->Release(); return S_OK; } HRESULT CStrings::InternalInsertArrayDim(CComObject *pStringTemp, VARTYPE vt, SAFEARRAY *pArray,long *pDims,UINT dim,UINT dims) { long lower; long upper; long aIndex; HRESULT hr; UINT nextdim = dim+1; hr = SafeArrayGetLBound(pArray,nextdim,&lower); if(FAILED(hr)) { return hr; } hr = SafeArrayGetUBound(pArray,nextdim,&upper); if(FAILED(hr)) { return hr; } if(nextdimAdd(v); } VariantClear(&v); if(FAILED(hr)) { delete [] buffer; return hr; } } return S_OK; } HRESULT CStrings::InternalInsertCollection(DWORD Index, IEnumVARIANT *pEnum) { pEnum->Reset(); CComVariant ent; // // get first item - this allows us to do little work if // source collection is empty // HRESULT hr = pEnum->Next(1,&ent,NULL); if(FAILED(hr)) { return hr; } if(hr != S_OK) { // // empty // return S_FALSE; } // // create a temporary collection for working // CComObject *pStringTemp = NULL; hr = CComObject::CreateInstance(&pStringTemp); if(FAILED(hr)) { return hr; } pStringTemp->AddRef(); do { // // this will recursively process an element of this collection // hr = pStringTemp->Add(ent); if(FAILED(hr)) { break; } // // next // ent.Clear(); hr = pEnum->Next(1,&ent,NULL); } while(hr == S_OK); if(FAILED(hr)) { pStringTemp->Release(); return hr; } // // now quickly insert pStringTemp strings into this collection // DWORD Added = pStringTemp->Count; if(!IncreaseArraySize(Added)) { pStringTemp->Release(); return E_OUTOFMEMORY; } DWORD c; for(c=Count;c>Index;c--) { pMultiStrings[c-1+Added] = pMultiStrings[c-1]; } for(c=0;cpMultiStrings[c]; } Count += Added; // // throw strings in temp collection away without free'ing them // pStringTemp->Count = 0; pStringTemp->Release(); return S_OK; } HRESULT CStrings::InternalInsertString(DWORD Index, BSTR pString) { DWORD c; BSTR ValueCopy = NULL; if(Index>Count) { return E_INVALIDARG; } if(!IncreaseArraySize(1)) { return E_OUTOFMEMORY; } ValueCopy = SysAllocStringLen(pString,SysStringLen(pString)); if(!ValueCopy) { return E_OUTOFMEMORY; } for(c=Count;c>Index;c--) { pMultiStrings[c] = pMultiStrings[c-1]; } pMultiStrings[Index] = ValueCopy; Count++; return S_OK; } HRESULT CStrings::GetMultiSz(LPWSTR *pResult, DWORD *pSize) { // // get a multi-sz buffer from this list of strings // DWORD c; DWORD buflen = 1; DWORD actlen = 0; LPWSTR buffer = NULL; for(c=0;c=Count) { return FALSE; } *pNext = pMultiStrings[index]; return TRUE; } STDMETHODIMP CStrings::Find(BSTR name, long *pFound) { // // find an existing device that matches this // DWORD c; for(c=0;c