如何将std::variant作为VARIANT*传递给ExecWB?

3

我查看了有关使用std::variant的文章。这是因为以下代码触发了代码分析警告:

void CChristianLifeMinistryHtmlView::OnTimer(UINT_PTR nIDEvent)
{
    if (nIDEvent == ID_TIMER_ZOOM)
    {
        //get the zoom value
        VARIANT vZoom{};
        vZoom.vt = VT_I4;
        vZoom.lVal = 0;
        ExecWB(OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, nullptr, &vZoom);
        TRACE("zoom %d\n", vZoom.lVal);

        //kill the timer
        KillTimer(nIDEvent);

        GetParent()->PostMessage(UWM_HTMLVIEW_CHANGE_ZOOM_MSG, vZoom.lVal);
        return;
    }

    CHtmlView::OnTimer(nIDEvent);
}

警告:

警告 C26476:表达式/符号{{0, 0, 0, 0, {0}}}使用了一个具有多种类型指针的裸联合体 'union' :请改用 variant(type.7)。

我开始尝试更改代码:

void CChristianLifeMinistryHtmlView::OnTimer(UINT_PTR nIDEvent)
{
    if (nIDEvent == ID_TIMER_ZOOM)
    {
        //get the zoom value
        std::variant<long> vZoom(0);

        ExecWB(OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, nullptr, &vZoom);
        TRACE("zoom %d\n", vZoom.lVal);

        //kill the timer
        KillTimer(nIDEvent);

        GetParent()->PostMessage(UWM_HTMLVIEW_CHANGE_ZOOM_MSG, vZoom.lVal);
        return;
    }

    CHtmlView::OnTimer(nIDEvent);
}

但问题在于ExecWB需要一个VARIANT *,而我不知道如何传递这个std::variant


1
使用 VARIANT vZoom; VariantInit(&vZoom); 进行初始化。或者使用建议的 variant_tCComVariant,它们会自动执行此操作。 - Barmak Shemirani
@BarmakShemirani 谢谢 - VariantInit - 另一个我不知道的新函数! - Andrew Truckle
2个回答

5
诊断是正确的,尽管建议过于笼统而不实用。虽然std::variant通常是表示类型安全的区分联合体的好方法,但它与在COM中使用的VARIANT结构无关。
在这种情况下,您需要使用其他类型,如Microsoft的_variant_t类。它封装了原始的VARIANT,并处理其区分联合体的内部。
它提供了几个构造函数来正确地管理设置内部状态,并从VARIANT派生,以便可以将任何实例的地址传递给接受VARIANT*的任何函数:
#include <comutil.h>
#pragma comment(lib, "comsuppw.lib")

int main() {
    auto zoom{ _variant_t(long{ 0 }) };
    ExecWB(OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, nullptr, &zoom);
}

谢谢。我之前不知道 variant_t - Andrew Truckle
4
Microsoft 提供了 COM 支持库,其中包括 _bstr_t_com_error_com_ptr_variant_t,它们提供资源管理和更强的类型安全性。这几乎涵盖了你在 COM 编程中会遇到的所有类型。由于 VARIANT 结构的复杂性,_variant_t 特别有用。 - IInspectable

3

很抱歉,您不能在此处使用 std::variant

VARIANT 是 COM 中用于不同组件间进行互操作的数据类型,即使这些组件由不同语言编写并存在于不同的进程中。

std::variant 提供了一种类型安全的任意类型变体,该变体作为模板参数传递。即使两个 std::variant 具有不同的模板参数,它们也是不兼容的,并且都与 VARIANT 不兼容。

使您的程序更加健壮的最佳方法是使用 ATL 中的 CComVariant ,或查找/创建另一个 VARIANT 结构的包装器。不确定是否可以消除警告信息。


1
谢谢。我决定采用被接受答案中建议的 _variant_t - Andrew Truckle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接