Возврат варианта из c dll в Excel VBA на macos

В проекте Пауло Буэно https://github.com/buenop/MinXL он возвращает Variant из dll C++, например.

Declare PtrSafe Function IncrementArrayBy _
Lib "/Library/Application Support/Microsoft/YourLibrary.dylib" _
(ByRef v as Variant, ByVal d as Double) As Variant 

Я хотел бы сделать то же самое, но на C. Вот мой сокращенный код:

typedef uint16_t VARTYPE;  
typedef uint16_t WORD; 
typedef double DOUBLE;

typedef struct {
    VARTYPE vt;
    WORD    wReserved1;
    WORD    wReserved2;
    WORD    wReserved3;
    union {
        DOUBLE       dblVal;
    } data;
} VARIANT2;

enum VARENUM {
    VT_DOUBLE       = 0x0005,
};

VARIANT2 * new_VT_DOUBLE_PTR(double x) {
    VARIANT2 *answer = (VARIANT2 *) malloc(sizeof(VARIANT2));
    answer->vt = VT_DOUBLE;
    answer->data.dblVal = x;
    return answer;
}

VARIANT2 new_VT_DOUBLE(double x) {
    VARIANT2 answer;
    answer.vt = VT_DOUBLE;
    answer.data.dblVal = x;
    return answer;
}
Private Declare PtrSafe Function jinni_new_VT_DOUBLE _
Lib "/Library/Application Support/Microsoft/jinni.dylib" Alias "new_VT_DOUBLE" _
(ByVal x As Double) As Variant
Private Declare PtrSafe Function jinni_new_VT_DOUBLE_PTR _
Lib "/Library/Application Support/Microsoft/jinni.dylib" Alias "new_VT_DOUBLE_PTR" _
(ByVal x As Double) As Variant

Function newDoublePtr(x As Double) As Variant
    newDoublePtr = jinni_new_VT_DOUBLE_PTR(x)
End Function

Function newDouble(x As Double) As Variant
    newDouble = jinni_new_VT_DOUBLE(x)
End Function

На данный момент обе эти функции возвращают Empty в VBA. Это имеет смысл, как будто я смотрю на 16 байтов из ответа на первые несколько (т.е. vt равны 0), например. используя этот код.

Private Declare PtrSafe Sub memcpy _
Lib "/usr/lib/libSystem.dylib" _
(ByVal dest As LongPtr, ByVal src As LongPtr, ByVal count As Long)

Function peekMem(ptr As LongPtr, size As Long) As Byte()
    ReDim answer(1 To size) As Byte
    memcpy VarPtr(answer(1)), ptr, size
    peekMem = answer
End Function

Sub testVar()
    Dim fred As Variant, joe As Variant, p As LongPtr

    fred = 1#
    joe = peekMem(VarPtr(fred), 16)

    p = jinni_new_VT_DOUBLE_PTR2(5#)
    joe = peekMem(VarPtr(fred), 16)   ' this has the correct values is it

    fred = jinni_new_VT_DOUBLE_PTR(5#)
    joe = peekMem(VarPtr(fred), 16)   ' but this doesn't

    fred = jinni_new_VT_DOUBLE(5#)
    joe = peekMem(VarPtr(fred), 16)   ' and neither does this

End Sub

Любые идеи, как заставить это работать? VBA ожидает ВАРИАНТ **?

Я действительно не хочу копировать данные в предварительно выделенный вариант, так как мне нравится простота возврата варианта в стек.


Пауло подтвердил, что он возвращает вариант в стек, сводя проблему к тому, почему следующее отображается как 16 нулей?

VARIANT2 doubleInVariant(double x, VARIANT2 * out) {
    VARIANT2 answer;
    answer.vt = VT_R8;
    answer.data.dblVal = x;
    memcpy(out, &answer, sizeof(VARIANT2));
    return answer;
}

и

Private Declare PtrSafe Function jinni_doubleInVariant _
Lib "/Library/Application Support/Microsoft/jinni.dylib" Alias "doubleInVariant" _
(ByVal x As Double, ByRef cpy As Variant) As Variant


Пауло указал, что вариант равен 24 байтам, а не 16 байтам. Таким образом, изменение структуры варианта на:

typedef struct {
    VARTYPE vt;
    WORD    wReserved1;
    WORD    wReserved2;
    WORD    wReserved3;
    union {
        DOUBLE       dblVal;
    } data;
     WORD padding[4];                // due to __VARIANT_NAME_4 in the tagVARIANT struct
} VARIANT2;

Теперь все работает — см. https://github.com/coppertop-bones/jinni код src и пример электронной таблицы.

Вы не говорите, почему вы используете c. Возможно, вы сможете добиться желаемого, изменив свой код C на twinBasic (twinbasic.com/preview.html).

freeflow 02.04.2023 13:14

TwinBASIC не работает на macos

DangerMouse 02.04.2023 14:06

Верно, но создать стандартную dll в twinBasic очень просто. Поэтому, если функциональность вашего кода на C можно воспроизвести в twinBasic, это может быть более простым решением.

freeflow 02.04.2023 14:32
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
78
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Определение VARIANT с дополнительным дополнением, которое увеличивает размер структуры с 16 до 24 байт, работает.

typedef struct {
    VARTYPE vt;
    WORD    wReserved1;
    WORD    wReserved2;
    WORD    wReserved3;
    union {
        DOUBLE       dblVal;
    } data;
     WORD padding[4];                // due to __VARIANT_NAME_4 in the tagVARIANT struct
} VARIANT2;

Я чувствую себя немного школьником, но результаты быстрого поиска в Google, кажется, предполагают, что 16 байтов - это распространенное заблуждение. Для тех, кто сталкивается с этим, я надеюсь, что это поможет.

Другие вопросы по теме