One of my colleagues asked me,
"What's the difference between
If you look at the definitions in the
header file, you'll see that
VARIANTARG is just
an alias for
typedef VARIANT VARIANTARG; typedef VARIANT *LPVARIANTARG;
"Why have two names for the same thing?"
The two structures are physically identical, but the rules surrounding them are different.
This is mentioned rather opaquely in
the documentation for
VARIANTARG describes arguments passed within DISPPARAMS, and VARIANT to specify variant data that cannot be passed by reference.
When a variant refers to another variant by using the VT_VARIANT | VT_BYREF vartype, the variant being referred to cannot also be of type VT_VARIANT | VT_BYREF. VARIANTs can be passed by value, even if VARIANTARGs cannot.
The first sentence says that you use
as part of a
which is the structure used to pass parameters (also known as "arguments")
to methods of dispatch interfaces.
The second sentence is not relevant to the discussion. It says that only one level of pointer chasing is allowed. You can't send the method on a wild goose chase where you pass a variant that says "The real data is over there, in that other variant", and then have the second variant say, "Ha ha, fooled, you. The real data is over there in that other other variant."
The third sentence starts to hint at the underlying issue.
It says that
VARIANTs can be passed by value,
Interesting, but no real insight as to why you can pass
by value but not
There's another MSDN page titled VARIANT and VARIANTARG. Maybe that'll help us get to the bottom of the mystery.
The VARIANT type cannot have the VT_BYREF bit set.
Aha, that's the difference.
VARIANTARG structure is allowed to say,
"Hey, I don't contain the data you want, but you can look over there for it."
For example, it could set its variant type to
VT_BYREF | VT_I4 to say,
"There is an integer, but it's not stored in the
Instead, you have to go to the
which is a pointer to the integer you want."
This explains why
VARIANT can be copied,
If you try to copy a
VARIANTARG that uses
you are just copying the raw pointer to the data,
not the data itself.
You have no control over the memory being pointed to,
so you have no way to prevent it from being freed.
VT_BYREF is allowed in a
because the caller assumes the responsibility of keeping the
pointed-to data valid for the duration of the method call.
That's just one of the
basic ground rules of programming,
specifically the stability requirement.
The caller has to wait for the method call to return before it can
free the memory pointed to by the
Okay, so what if you're implementing a method and you want to make
a copy of the
How do you deal with the
This is where
comes into play.
This function takes a
and converts it into a
It does this by chasing the pointer one level and copying the
value back into the
For example, if the
VARIANTARG were a
VT_BYREF | VT_I4,
would follow the
read the integer stored there,
and copy it to the output
resulting in a simple
The "Ind" therefore stands for "Indirect".
indirects through the pointer hiding inside the
Well, that was a strange bit of spelunking.