How to pass a custom struct into a _variant_t in C++ (non-CLI)?
I'm trying to pass a struct e. g.:
struct SVec3
{
public:
float X;
float Y;
float Z;
};
into a _variant_t, to store it in an SAFEARRAY. My approach for that is first creating an instance:
SVec3 rot;
rot.X = 0.1f;
rot.Y = 0.65f;
rot.Z = 0.01f;
Then i fit it via reference into a _variant_t
_variant_t var((IUnknown*)&rot, true);
And store it in the SAFEARRAY:
LONG index = 0;
SAFEARRAY* psaArgs = SafeArrayCreateVector(VT_VARIANT, 0, 1);
SafeArrayPutElement(psaArgs, &index, &var); // This throws a memory access exception.
So what is my mistake here? Is there an other way to do that? If so, how should I pass a SAFEARRAY开发者_如何学Python of those structs into a SAFEARRAY? Is there a common way? Or am I missing something like a Recorddescription, because in this way the SAFEARRAY doesn't contain the data, it contains Pointers to the Data. But how to store the data in a SAFEARRAY?
Regards Nem
You're casting a SVec3 pointer to a pointer to IUnknown interface. Your data structure is a simple data type and not a full-blown class implementing IUnknown. So your application breaks as soon as Windows tries to call methods on IUnknown.
Some quick Googling reveals some links that might be useful in regards to variants and user defined types:
- http://social.msdn.microsoft.com/Forums/en/vclanguage/thread/38dca037-f6da-43dc-8fa3-0358638681ce
- http://msdn.microsoft.com/en-us/library/ms221039(VS.85).aspx
- http://msdn.microsoft.com/en-us/library/ms221210(VS.85).aspx
- Especially for you: Passing a Safearray of UDTs: http://msdn.microsoft.com/en-us/library/ms221212(VS.85).aspx
- http://msdn.microsoft.com/en-us/library/ms221543(VS.85).aspx
You'll have to start with putting your UDT in a type library...
Long topic, long day. I don't want to register my assembly as COM object (this would be against the my requirements for that project), so I have to avoid that COM-Stuff. For that I've done a workaround. Here is an example to illustrate that (C# Assemblycode):
[EditorBrowsable(EditorBrowsableState.Never)]
public float[] INTEROP_Position
{
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_R4)]
get { return (float[])this.Position; }
[param: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_R4)]
set { this.Position = (DataTypes.Vec3)value; }
}
// Inside the Vec3 Definition:
public static explicit operator Vec3(float[] arr)
{
if (arr.Length != 3) throw new Exception("The array must have a length of 3.");
return new Vec3(arr[0], arr[1], arr[2]);
}
public static explicit operator float[](Vec3 vec3)
{
return new float[] { vec3.X, vec3.Y, vec3.Z };
}
On C++ side i marshall it by hand
_variant_t Convert::svec3tovar(SVec3 vec) {
LONG index = 0;
SAFEARRAY* psaStruct = SafeArrayCreateVector(VT_R4, 0, 3);
SafeArrayPutElement(psaStruct, &index, &vec.X);
index = 1;
SafeArrayPutElement(psaStruct, &index, &vec.Y);
index = 2;
SafeArrayPutElement(psaStruct, &index, &vec.Z);
VARIANT vV ;
vV.vt = VT_ARRAY | VT_R4;
vV.parray = psaStruct;
return _variant_t(vV);
}
and back
SVec3 Convert::vartosvec3(_variant_t var) {
SVec3 vec;
SAFEARRAY* psaStruct = var.parray;
LONG index = 0;
SafeArrayGetElement(psaStruct, &index, &vec.X);
index = 1;
SafeArrayGetElement(psaStruct, &index, &vec.Y);
index = 2;
SafeArrayGetElement(psaStruct, &index, &vec.Z);
return vec;
}
And it works great. Without all that COM stuff. :)
I know the real answer for that was given by James, but to avoid COM this is my answer. Maybe user786653's comment was the correct answer to solve my problem. But thank you James (and the others), for your invested time.
/Solved
精彩评论