I have looked at this article about using std::variant
. This is because the following code was raising a code analysis warning:
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);
}
The warning:
Warning C26476: Expression/symbol
{{0, 0, 0, 0, {0}}}
uses a naked union 'union ' with multiple type pointers: Usevariant
instead (type.7).
I started to try and change the code:
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);
}
But the problem is that ExecWB
expects a VARIANT *
and I do not see how to pass this std::variant
.
The diagnostic is correct, even though the advice is too generic to be useful. While std::variant
is, in general, a great way to represent typesafe discriminated unions, it is unrelated to the VARIANT
structure used in COM.
In this situation you would need to use a different type, such as Microsoft's _variant_t
class. It encapsulates the raw VARIANT
, and deals with the internals of its discriminated union.
It provides several constructors that properly manage setting the internal state, and derives from VARIANT
so that any instance's address can be passed to any function that accepts a 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);
}