c++ - 如何初始化 SAFEARRAY 从 Scripting.Dictionary Keys 方法返回的 CComSafeArray

标签 c++ safearray scripting.dictionary

我正在使用 COM 库“Microsoft Scripting Runtime”(c:\windows\System32\scrrun.dll) 中的 Scripting.Dictionary。我正在使用 import 来获取我的包装器,这些包装器正在工作。添加一些项目后,我试图获取键列表,但我卡住了。

我有办法。我可以得到 SAFEARRAY字典中的键,但我想使用 CComSafeArray <atlsafe.h>中定义的类但我无法找出一个好的结构。目前,构造函数抛出 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 标志)

然后你可以查询keysvt:

hr = ::ATL::AtlSafeArrayGetActualVartype(keys, &vt);

请注意,varColours = keys 将创建数组数据的拷贝。如果这不是您真正想要的,那么您应该从 CComVariantDetach() 数组(或者直接使用 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;
}

关于c++ - 如何初始化 SAFEARRAY 从 Scripting.Dictionary Keys 方法返回的 CComSafeArray,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49619401/

相关文章:

vba - 如何从脚本字典将数组添加到单元格内下拉列表中?

c++ - 动态内存分配...这种类型的初始化怎么样?

python - switch case 的运行时类型检查

c++ - 从 COM TypeLib 自动生成的 C++ 类不会在方法中返回 SAFEARRAY

c# - COM Interop 中内存释放的责任

optimization - 字典/客户端 VS 应用程序变量

c++ - C++ 类的构造函数中的线程池被杀死

c++ - IEEE 754 float ,< 1 的最大数是多少?

c++ - 如何遍历 SAFEARRAY **

database - VBScript:从 Scripting.Dictionary 中排序项目