如何初始化从 Scripting.Dictionary Keys 方法返回的 SAFEARRAY CComSafeArray
How to initialise CComSafeArray which a SAFEARRAY returned from a Scripting.Dictionary Keys method
我正在使用来自 COM 库 "Microsoft Scripting Runtime" (c:\windows\System32\scrrun.dll) 的 Scripting.Dictionary。我正在使用 import 来获取我的包装器,它们正在工作。添加一些项目后,我试图获取键列表,但我卡住了。
我有办法了。我可以从字典中获取 SAFEARRAY
键,但我想使用 <atlsafe.h>
中定义的 CComSafeArray
class,但我想不出一个好的结构。目前,构造函数抛出一个 ATL
断言抱怨 vartype
不匹配。诚然,新构造的 CComSafeArray 有一个 vartype
的十六进制 CCCC 52428,这看起来可能像未初始化的内存。但是推断的类型看起来也不正确,我希望 safearray 的 vartype 是字符串,但断言代码给出 vartype 12,即 UI2。很奇怪。
无论如何,对于熟悉此内容的人来说,这可能很容易。这是一个符合 SO 标准的最小、完整、可验证、示例 (MCVE) 控制台程序。
#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;
}
改变这个:
SAFEARRAY keys(*(varColoursKeys.parray));
为此:
SAFEARRAY* keys = varColoursKeys.parray;
(可选,首先确保 varColoursKeys.vt
具有 VT_ARRAY
标志)
然后你可以查询 keys
它的 vt
:
hr = ::ATL::AtlSafeArrayGetActualVartype(keys, &vt);
请注意,varColours = keys
将对数组数据进行 复制。如果这不是您真正想要的,那么您应该 Detach()
来自 CComVariant
的数组(或者直接使用 VARIANT
而不是 CComVariant
)和 Attach()
它到CComSafeArray
(然后你可以使用CComSafeArray::GetType()
方法)。
另外,在调用 CoUninitialize()
.
之前,您需要确保所有 COM 包装器超出范围并释放资源
试试这个:
#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;
}
我正在使用来自 COM 库 "Microsoft Scripting Runtime" (c:\windows\System32\scrrun.dll) 的 Scripting.Dictionary。我正在使用 import 来获取我的包装器,它们正在工作。添加一些项目后,我试图获取键列表,但我卡住了。
我有办法了。我可以从字典中获取 SAFEARRAY
键,但我想使用 <atlsafe.h>
中定义的 CComSafeArray
class,但我想不出一个好的结构。目前,构造函数抛出一个 ATL
断言抱怨 vartype
不匹配。诚然,新构造的 CComSafeArray 有一个 vartype
的十六进制 CCCC 52428,这看起来可能像未初始化的内存。但是推断的类型看起来也不正确,我希望 safearray 的 vartype 是字符串,但断言代码给出 vartype 12,即 UI2。很奇怪。
无论如何,对于熟悉此内容的人来说,这可能很容易。这是一个符合 SO 标准的最小、完整、可验证、示例 (MCVE) 控制台程序。
#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;
}
改变这个:
SAFEARRAY keys(*(varColoursKeys.parray));
为此:
SAFEARRAY* keys = varColoursKeys.parray;
(可选,首先确保 varColoursKeys.vt
具有 VT_ARRAY
标志)
然后你可以查询 keys
它的 vt
:
hr = ::ATL::AtlSafeArrayGetActualVartype(keys, &vt);
请注意,varColours = keys
将对数组数据进行 复制。如果这不是您真正想要的,那么您应该 Detach()
来自 CComVariant
的数组(或者直接使用 VARIANT
而不是 CComVariant
)和 Attach()
它到CComSafeArray
(然后你可以使用CComSafeArray::GetType()
方法)。
另外,在调用 CoUninitialize()
.
试试这个:
#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;
}