BSTR и VARIANT под ... Mac OS X

Под Mac OS X у меня есть Office 2011 и его Excel и VBA, и у меня gcc-5.3.0 в g ++.

Я много играл, передавая массивы (числовых встроенных типов) из VBA в dylib (расширение dll в mac os x), обновляя их и отправляя обратно в VBA, см., Например:

Передача dylib-функции c / c ++ с указателем на VBA на Mac

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

Код наC++ сторона это:

#include <stdlib.h>
#include <ctype.h> //for toupper

extern "C"
{
      void toupperfunc(char *vbstr)
      {
          size_t i = 0U;
          char c;
          do {
              c = vbstr[i];
              vbstr[i]=toupper(c);
              ++i;
          } while(vbstr[i]!=0);
      }
}

в файлеthedylib.dylib, скомпилирован следующим образом (Office 2011 для Mac OS X составляет 32 бита):

g++ -m32 -Wall -g -c ./thedylib.cpp
g++ -m32 -dynamiclib ./thedylib.o -o ./thedylib.dylib

тогда как на стороне VBA (в Excel 2011 для Mac OS X) у меня есть этот код:

Declare Sub toupperfunc Lib "/path/to/the/dylib/thedylib.dylib" (ByVal str As String)

Public Sub DoIt()
    Dim str As String
    str = "Ludwig von Mises"
    Call toupperfunc(str)
    MsgBox (str)
End Sub

и выполняя его, выдает "LUDWIG VON MISES", как и ожидалось.

Замечание 1 Обратите вниманиеByVal перед строкой в ​​подписи сабвуфера. ПоложитьByRef вместо этого произойдет сбой во время выполнения. Еще более странно: представьте, я добавляюtolowerfunc в моем dylib (тот же код, что и дляtoupperfunc но полагаясь наctype.h«stolower Функция C ++). Это также работает, как и ожидалось, но на этот раз, поставивByRef перед строкой в ​​подписи вместоByVal больше не провоцирует сбой во время выполнения. Итак, есть ли что-то другое между функциями C ++toupper а такжеtolower ? Если да, то ?Чем объясняется такое поведение?

Замечание 2. Как следствие того, что то, что я описал выше, работает, мы теперь знаем, что Excel 2011 VBA на Mac OS X не обменивается строками с dylib, используя тот же формат в памяти, который использует COM BSTR. Он использует нулевое окончаниеchar* Строки вместо.

Принимая во внимание замечание 2 и поскольку «использование VARIANT под OS x» было моей долгосрочной целью, см., Например:

Передача VARIANT из Mac OS X Excel 2011 VBA в c ++,

Я наконец подражалVARIANT структура вVARIANT.h файл, как вы можете видеть в следующем коде:

#ifndef VARIANT_H
#define VARIANT_H

#include <inttypes.h> // needed for gcc analogues of __int64 and unsigned __int64

typedef unsigned short VARTYPE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
// typedef __int64 LONGLONG;
typedef int64_t LONGLONG;
// typedef unsigned __int64 ULONGLONG;
typedef uint64_t ULONGLONG;
typedef long LONG;
typedef unsigned char BYTE;
typedef short SHORT;
typedef float FLOAT;
typedef double DOUBLE;
/* 0 == FALSE, -1 == TRUE */
typedef short VARIANT_BOOL;
/* For backward compatibility */
typedef bool _VARIANT_BOOL;
typedef LONG SCODE;
typedef unsigned long ULONG;
typedef unsigned short USHORT;
typedef unsigned long ULONG;
typedef char CHAR;
typedef unsigned char byte;
typedef int INT;
typedef unsigned int UINT;
typedef unsigned int * PUINT;
typedef union tagCY
{
        struct _tagCY
        {
                ULONG Lo;
                LONG Hi;
        } DUMMYSTRUCTNAME;
        LONGLONG int64;
} CY;

typedef double DATE;

/*#ifndef _MAC*/
//typedef wchar_t WCHAR;    // wc,   16-bit UNICODE character
typedef char WCHAR;
/*#else
   // some Macintosh compilers don't define wchar_t in a convenient location, or define it as a char
   typedef unsigned short WCHAR;    // wc,   16-bit UNICODE character
 #endif*/

typedef WCHAR OLECHAR;
typedef OLECHAR * BSTR;
typedef BSTR * LPBSTR;
typedef void * PVOID;
/*// #define POINTER_64 __ptr64
 #define POINTER_64 unsigned long long*/

//typedef void *POINTER_64 PVOID64;
typedef struct tagSAFEARRAYBOUND
{
        ULONG cElements;
        LONG lLbound;
}       SAFEARRAYBOUND;

typedef struct tagSAFEARRAYBOUND * LPSAFEARRAYBOUND;

typedef struct tagSAFEARRAY
{
        USHORT cDims;
        USHORT fFeatures;
        ULONG cbElements;
        ULONG cLocks;
        PVOID pvData;
        SAFEARRAYBOUND rgsabound[1];
}       SAFEARRAY;

typedef SAFEARRAY * LPSAFEARRAY;

typedef struct tagDEC
{
        USHORT wReserved;
        union
        {
                struct
                {
                        BYTE scale;
                        BYTE sign;
                } DUMMYSTRUCTNAME;
                USHORT signscale;
        } DUMMYUNIONNAME1;
        ULONG Hi32;
        union
        {
                struct
                {
                        ULONG Lo32;
                        ULONG Mid32;
                } DUMMYSTRUCTNAME;
                ULONGLONG Lo64;
        } DUMMYUNIONNAME2;
} DECIMAL;

/*#define __tagVARIANT
   #define __VARIANT_NAME_1
   #define __VARIANT_NAME_2
   #define __VARIANT_NAME_3
   #define __tagBRECORD
 #define __VARIANT_NAME_4*/

typedef /* [wire_marshal] */ struct tagVARIANT VARIANT;

struct tagVARIANT
{
        union
        {
                struct __tagVARIANT
                {
                        VARTYPE vt;
                        WORD wReserved1;
                        WORD wReserved2;
                        WORD wReserved3;
                        union
                        {
                                // non ptr stuff
                                LONGLONG llVal;
                                LONG lVal;
                                BYTE bVal;
                                SHORT iVal;
                                FLOAT fltVal;
                                DOUBLE dblVal;
                                VARIANT_BOOL boolVal;
                                // _VARIANT_BOOL bool;
                                SCODE scode;
                                CY cyVal;
                                DATE date;
                                BSTR bstrVal;
                                // ptr stuff
                                /*IUnknown*/ void *punkVal;
                                /*IDispatch*/ void *pdispVal;
                                SAFEARRAY * parray;
                                BYTE * pbVal;
                                SHORT * piVal;
                                LONG * plVal;
                                LONGLONG * pllVal;
                                FLOAT * pfltVal;
                                DOUBLE * pdblVal;
                                VARIANT_BOOL * pboolVal;
                                _VARIANT_BOOL * pbool;
                                SCODE * pscode;
                                CY * pcyVal;
                                DATE * pdate;
                                BSTR * pbstrVal;
                                /*IUnknown*/ void ** ppunkVal;
                                /*IDispatch*/ void ** ppdispVal;
                                SAFEARRAY ** pparray;
                                VARIANT * pvarVal;
                                PVOID byref;
                                CHAR cVal;
                                USHORT uiVal;
                                ULONG ulVal;
                                ULONGLONG ullVal;
                                INT intVal;
                                UINT uintVal;
                                DECIMAL * pdecVal;
                                CHAR * pcVal;
                                USHORT * puiVal;
                                ULONG * pulVal;
                                ULONGLONG * pullVal;
                                INT * pintVal;
                                UINT * puintVal;
                                struct __tagBRECORD
                                {
                                        PVOID pvRecord;
                                        /*IRecordInfo*/ void * pRecInfo;
                                } VARIANT_NAME_4;
                        }  VARIANT_NAME_3;
                } VARIANT_NAME_2;
                DECIMAL decVal;
        } VARIANT_NAME_1;
};

typedef VARIANT * LPVARIANT;

typedef VARIANT VARIANTARG;

typedef VARIANT * LPVARIANTARG;





#endif

Я придерживаюсь того, что сделано на стороне окон для всего, кромеBSTR для которого я установил:

typedef char WCHAR;
typedef WCHAR OLECHAR;
typedef OLECHAR * BSTR;

(Я также вырезал чистый материал COM, а именно части кода, касающиесяIUnknown а такжеIDispatch.)

Определив этот «свет»VARIANT структура, я хочу играть в ту же игру, что и для массивовdoubleи дляstringто есть обменVARIANTнаходится между VBA и динамической библиотекой C ++. Итак, я разработал этот код C ++:

#include "/path/to/VARIANT.h"
#include <ctype.h>

VARTYPE getvt(const VARIANT & var_in)
{
    return var_in.VARIANT_NAME_1.VARIANT_NAME_2.vt;
}

extern "C"
{
      void updatevar(VARIANT * var_in_out, bool converttoupper)
      {
          VARTYPE vt = getvt(*var_in_out);
          switch (vt)
          {
              case 3:
              {
                  long l = (*var_in_out).VARIANT_NAME_1.VARIANT_NAME_2.VARIANT_NAME_3.lVal;
                  l *= 2L;
                  (*var_in_out).VARIANT_NAME_1.VARIANT_NAME_2.VARIANT_NAME_3.lVal = l;
              }
              break;
              case 8024:
              {

              }
              break;
              case 8:
              {
                  BSTR wc = (*var_in_out).VARIANT_NAME_1.VARIANT_NAME_2.VARIANT_NAME_3.bstrVal ;
                  int i = 0;
                  do
                  {
                      char c = wc[i];
                      wc[i]= converttoupper ? static_cast<char>(toupper(c)) : static_cast<char>(tolower(c));
                      ++i;
                  } while(wc[i]!=0);
                  (*var_in_out).VARIANT_NAME_1.VARIANT_NAME_2.VARIANT_NAME_3.bstrVal = &wc[0];
              }
              break;
              default:
              {
                  return;
              }
          }
      }
}

Путинthevarianttest.cppсоставлен следующим образом:

g++ -m32 -Wall -g -c ./thevarianttest.cpp
g++ -m32 -dynamiclib ./thevarianttest.o -o ./thevarianttest.dylib

и используется на стороне VBA (в Excel 2011 для Mac OS X) следующим образом:

Declare Sub updatevar Lib "/path/to/the/dylib/thevarianttest.dylib" (ByRef x As Variant, ByVal istoupper As Boolean)

Public Sub doit()
    Dim x As Variant
    Dim l As Long
    l = -666
    x = l
    Call updatevar(x, True)
    MsgBox (x)
    Dim s as String
    s = "Ludwig von Mises"
    x = s
    Call updatevar(x, False)
    MsgBox (x)
    s = "Ludwig von Mises"
    x = s
    Call updatevar(x, True)
    MsgBox (x) 'FAILURE...
End Sub

Выполнение этого кода VBA теперь последовательно выдает: -1332 Людвиг фон Мизес Людвиг фон Мизес

первые два в порядке, но для последнего ожидалось "LUDWIG VON MISES" ... И последнее в конечном итоге опирается на C ++toupper функция, та же функция из предыдущего замечания 1, которая не позволяла мнеByRef использовать в VBA в первом примере ...

Так, что происходит ? Почему это работает в первом примере, а не во втором?

Замечание 3. Обратите вниманиеByRef напротивVARIANT подпись саб. ПоложитьByVal вместо этого провоцирует сбой во время выполнения ... (Это противоположно тому, что происходило со строками и без вариантов в первом коде VBA.)

Ответы на вопрос(0)

Ваш ответ на вопрос