I'm using a Scripting.Dictionary from the COM Library "Microsoft Scripting Runtime" (c:\windows\System32\scrrun.dll). I'm using import to get my wrappers and these are working. After adding some items, I'm trying to get the list of keys but I am stuck.
I have got some way. I can get the SAFEARRAY
of keys out of the Dictionary but I want to use the CComSafeArray
class defined in <atlsafe.h>
but I cannot figure out a good construction. Currently, the constructor throws an ATL
assertion complaining about vartype
mismatch. Admittedly, the newly constructed CComSafeArray has a vartype
of 52428 of CCCC in hex and this looks potentially like uninitialised memory. But the type inferred doesn't look right either, I am expecting the vartype of the safearray to be strings but the assertion code gives vartype 12 which is UI2. Very strange.
Anyway, this is probably easy for someone familiar with this. Here is a console program Minimal, Complete, Verifiable, Example (MCVE) as per SO standards.
#include "stdafx.h"
#include <atlbase.h>
#include <atlsafe.h>
#import "c:\windows\System32\scrrun.dll" raw_interfaces_only,raw_native_types, named_guids, rename("DeleteFile", "_DeleteFile"), rename("MoveFile","_MoveFile"), rename("CopyFile", "_CopyFile"), rename("GetFreeSpace", "_GetFreeSpace")
int main()
{
HRESULT hr = S_OK;
CoInitialize(0);
CComQIPtr<Scripting::IDictionary> dictColours;
hr = dictColours.CoCreateInstance(__uuidof(Scripting::Dictionary));
if (!SUCCEEDED(hr)) { return hr; }
CComVariant varZero(0); //dummy value, only interested in keys
hr = dictColours->Add(&variant_t(L"red"), &varZero);
if (!SUCCEEDED(hr)) { return hr; }
hr = dictColours->Add(&variant_t(L"green"), &varZero);
if (!SUCCEEDED(hr)) { return hr; }
hr = dictColours->Add(&variant_t(L"blue"), &varZero);
if (!SUCCEEDED(hr)) { return hr; }
long lColourCount(0);
hr = dictColours->get_Count(&lColourCount);
if (!SUCCEEDED(hr)) { return hr; }
CComVariant varColoursKeys;
hr = dictColours->Keys(&varColoursKeys);
if (!SUCCEEDED(hr)) { return hr; }
SAFEARRAY keys(*(varColoursKeys.parray));
//fine up to this point
CComSafeArray<VARIANT> varColours;
/* The following code throws an error for the next (line) live, vt=52428 or hex CCCC which looks like uninitialised memory
whilst GetType() returns 12 which is UI2 (and somehow I expected string type 8!)
VARTYPE vt;
HRESULT hRes = ::ATL::AtlSafeArrayGetActualVartype(const_cast<LPSAFEARRAY>(psaSrc), &vt);
ATLENSURE_SUCCEEDED(hRes);
ATLENSURE_THROW(vt == GetType(), E_INVALIDARG);
*/
varColours = (keys);
CoUninitialize();
return 0;
}
Change this:
SAFEARRAY keys(*(varColoursKeys.parray));
To this:
SAFEARRAY* keys = varColoursKeys.parray;
(optionally, first make sure that varColoursKeys.vt
has the VT_ARRAY
flag)
And then you can query keys
for its vt
:
hr = ::ATL::AtlSafeArrayGetActualVartype(keys, &vt);
Note that varColours = keys
is going to make a copy of the array data. If that is not what you really want, then you should Detach()
the array from the CComVariant
(or just use VARIANT
directly and not CComVariant
) and Attach()
it to the CComSafeArray
(then you can use the CComSafeArray::GetType()
method).
Also, you need to make sure all of your COM wrappers go out of scope and release resources before you call CoUninitialize()
.
Try this:
#include "stdafx.h"
#include <atlbase.h>
#include <atlsafe.h>
#import "c:\windows\System32\scrrun.dll" raw_interfaces_only,raw_native_types, named_guids, rename("DeleteFile", "_DeleteFile"), rename("MoveFile","_MoveFile"), rename("CopyFile", "_CopyFile"), rename("GetFreeSpace", "_GetFreeSpace")
HRESULT DoIt()
{
CComQIPtr<Scripting::IDictionary> dictColours;
hr = dictColours.CoCreateInstance(__uuidof(Scripting::Dictionary));
if (FAILED(hr)) { return hr; }
CComVariant varZero(0); //dummy value, only interested in keys
hr = dictColours->Add(&variant_t(L"red"), &varZero);
if (FAILED(hr)) { return hr; }
hr = dictColours->Add(&variant_t(L"green"), &varZero);
if (FAILED(hr)) { return hr; }
hr = dictColours->Add(&variant_t(L"blue"), &varZero);
if (FAILED(hr)) { return hr; }
long lColourCount(0);
hr = dictColours->get_Count(&lColourCount);
if (FAILED(hr)) { return hr; }
VARIANT varColoursKeys;
hr = dictColours->Keys(&varColoursKeys);
if (FAILED(hr)) { return hr; }
CComSafeArray<VARIANT> varColours;
varColours.Attach(varColoursKeys.parray);
// use varColours as needed...
VARTYPE vt = varColours.GetType();
LONG lLower = varColours.GetLowerBound();
LONG lUpper = varColours.GetUpperBound();
for (LONG i = lLower; i <= lUpper; ++i)
{
VARIANT &v = varColours.GetAt(i);
// use v.bstrVal as needed ...
}
//...
return S_OK;
}
int main()
{
HRESULT hr = CoInitialize(0);
if (FAILED(hr)) { return hr; }
hr = DoIt();
CoUninitialize();
return hr;
}