Как передать пользовательскую структуру в _variant_t в C ++ (не CLI)? - PullRequest
1 голос
/ 02 августа 2011

Я пытаюсь передать struct e. g.:

struct SVec3
{
public:
    float X;
    float Y;
    float Z;
};

в _variant_t, чтобы сохранить его в SAFEARRAY. Мой подход к этому - сначала создать экземпляр:

SVec3 rot;
rot.X = 0.1f;
rot.Y = 0.65f;
rot.Z = 0.01f;

Тогда я подгоняю его по ссылке в _variant_t

_variant_t var((IUnknown*)&rot, true);

И сохраните его в SAFEARRAY:

LONG index = 0;
SAFEARRAY* psaArgs = SafeArrayCreateVector(VT_VARIANT, 0, 1);
SafeArrayPutElement(psaArgs, &index, &var);  // This throws a memory access exception.

Так в чем здесь моя ошибка? Есть ли другой способ сделать это? Если так, как я должен передать SAFEARRAY из этих структур в SAFEARRAY? Есть ли общий способ? Или я пропускаю что-то вроде описания записи, потому что таким образом SAFEARRAY не содержит данных, он содержит указатели на данные. Но как хранить данные в SAFEARRAY?

С уважением, Нем

Ответы [ 2 ]

3 голосов
/ 02 августа 2011

Вы приводите указатель SVec3 к указателю на интерфейс IUnknown.Ваша структура данных - это простой тип данных, а не полноценный класс, реализующий IUnknown.Таким образом, ваше приложение разрывается, как только Windows пытается вызвать методы для IUnknown.

Некоторое быстрое поиск в Google показывает некоторые ссылки, которые могут быть полезны в отношении вариантов и пользовательских типов:

Вам нужно начать с помещения вашего UDT в библиотеку типов ...

0 голосов
/ 03 августа 2011

Длинная тема, длинный день. Я не хочу регистрировать свою сборку как COM-объект (это противоречит моим требованиям для этого проекта), поэтому я должен избегать этого COM-Stuff. Для этого я сделал обходной путь. Вот пример, чтобы проиллюстрировать это (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 };
    }

На стороне C ++ я делаю это вручную

_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);
}

и обратно

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;
}

И это прекрасно работает. Без всего этого СОМ. :)

Я знаю, что реальный ответ на этот вопрос был дан Джеймсом, но чтобы избежать COM, это мой ответ. Возможно, комментарий user786653 был правильным ответом для решения моей проблемы. Но спасибо Джеймс (и другим) за потраченное время.

/ решаемые

...