如何直接访问C++中的VARIANT变量中的内容?

huangapple go评论82阅读模式
英文:

How to directly access to what's in VARIANT variables in C++?

问题

我的程序使用外部的ocx库,并通过它接收数据。下面的代码显示了它是如何工作的。

    VARIANT    varArrItem, varArrData;

    ocx_instance.GetItemArr(real, &varArrItem);      // 1) 接收数据
    long lLBound, lUBound;
    VARIANT varItem, varData;

    long index[2];
    index[0] = 0;
    index[1] = 0;

    COleSafeArray* pSafeItemArr = (COleSafeArray*)&varArrItem;    // 2) 将varArrItem转换为COleSafeArray
    CString strItem;
    CStringArray arrItem;

    pSafeItemArr->GetLBound(1, &lLBound);
    pSafeItemArr->GetUBound(1, &lUBound);

    int nItemCnt = (lUBound - lLBound + 1);
    for (int i = 0; i < nItemCnt; i++)
    {
        index[0] = i;
        VariantInit(&varItem);

        pSafeItemArr->GetElement(index, (void *)&varItem);    // 3) 使用GetElement获取其值
        strItem = varItem.bstrVal;
        arrItem.Add(strItem);
        
        VariantClear(&varItem);
    }

该程序的一个重大问题是,这段代码每当有新数据到达时都会运行,而这种情况非常频繁,会消耗大量资源。因此,我想简化代码,只获取varArrItem的内容,例如作为字符串或字符串数组的结构体数组。

varArrItem.vt给我8204,它由8192(VT_ARRAY)12(VT_VARIANT)组成。我在这里陷入困境,不知道在此之后该怎么做。如何简单地获取其中的内容?是否可以在不使用COleSafeArray的情况下访问它们?

英文:

My program uses an external ocx library and receives data through it. The code below shows how it works.

    VARIANT    varArrItem, varArrData;

    ocx_instance.GetItemArr(real, &amp;varArrItem);      // the library provides GetItemArr
                                                     // 1) receives data 
    long lLBound, lUBound;
    VARIANT varItem, varData;

    long index[2];
    index[0] = 0;
    index[1] = 0;

    COleSafeArray* pSafeItemArr = (COleSafeArray*)&amp;varArrItem;    // 2) casts varArrItem to COleSafeArray
    CString strItem;
    CStringArray arrItem;

    pSafeItemArr-&gt;GetLBound(1, &amp;lLBound);
    pSafeItemArr-&gt;GetUBound(1, &amp;lUBound);

    int nItemCnt = (lUBound - lLBound + 1);
    for (int i = 0; i &lt; nItemCnt; i++)
    {
        index[0] = i;
        VariantInit(&amp;varItem);

        pSafeItemArr-&gt;GetElement(index, (void *)&amp;varItem);    // 3) gets its values using GetElement
        strItem = varItem.bstrVal;
        arrItem.Add(strItem);
        
        VariantClear(&amp;varItem);
    }

A big problem of the program is that this code is run whenever new data arrives, which is quite often, and it consumes a lot of resources. So, I'd like to simplify the code and get just contents of varArrItem, as strings or an array of structs of strings, for example.

varArrItem.vt gives me 8204 and it's said that it consists of 8192(VT_ARRAY) and 12(VT_VARIANT). I'm stuck here and don't know what to do after this. How can I simply get what's in them? Is it possible to access to them without using COleSafeArray?

答案1

得分: 1

不需要使用 COleSafeArray,它只是一个方便的包装器。您可以直接从 varArrItem 中提取 SAFEARRAY* 指针,然后直接使用 SafeArray API:SafeArrayGet(L|U)Bound()SafeArrayGetElement() 等等。如果性能很重要,可以考虑使用 SafeArrayAccessData() 直接访问 VARIANT[] 数组以及其中的 BSTR 指针。您在处理数据时进行的拷贝操作越少,代码运行速度就越快。这段代码实际上需要进行的唯一数据拷贝是初始 VARIANT 的赋值以及将每个 CString 添加到 CStringArray 中:

VARIANT varArray;
ocx_instance.GetItemArr(real, &varArray);

LPSAFEARRAY psa = varArrar.parray;

LONG lLBound, lUBound;
SafeArrayGetLBound(psa, 1, &lLBound);
SafeArrayGetUBound(psa, 1, &lUBound); 

CStringArray arrItem;

VARIANT *varArrayData;
if (SUCCEEDED(SafeArrayAccessData(psa, (void**) &varArrayData)))
{
	int nItemCnt = (lUBound - lLBound + 1);

	for (int i = 0; i < nItemCnt; i++)
	{
		CString strItem = varArrayData[i].bstrVal;
		arrItem.Add(strItem);
	}

	SafeArrayUnaccessData(psa);
}
英文:

You don't NEED to use COleSafeArray, it is just a wrapper for convenience. You could just extract the SAFEARRAY* pointer directly from varArrItem and then use the SafeArray APIs directly: SafeArrayGet(L|U)Bound(), SafeArrayGetElement(), etc, though if performance is important then consider using SafeArrayAccessData() to access the VARIANT[] array directly, and thus its BSTR pointers. The less copying of data you do, the faster the code will run. The only copy of data this code actually needs to make is the assignment of the initial VARIANT and each CString you add to the CStringArray:

VARIANT varArray;
ocx_instance.GetItemArr(real, &amp;varArray);

LPSAFEARRAY psa = varArrar.parray;

LONG lLBound, lUBound;
SafeArrayGetLBound(psa, 1, &amp;lLBound);
SafeArrayGetUBound(psa, 1, &amp;lUBound); 

CStringArray arrItem;

VARIANT *varArrayData;
if (SUCCEEDED(SafeArrayAccessData(psa, (void**) &amp;varArrayData)))
{
	int nItemCnt = (lUBound - lLBound + 1);

	for (int i = 0; i &lt; nItemCnt; i++)
	{
		CString strItem = varArrayData[i].bstrVal;
		arrItem.Add(strItem);
	}

	SafeArrayUnaccessData(psa);
}

huangapple
  • 本文由 发表于 2020年1月7日 00:16:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/59615441.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定