BSTR y VARIANTE bajo ... mac os x

Bajo Mac OS X tengo Office 2011 y su Excel y VBA, y tengo g ++ de gcc-5.3.0.

Jugué mucho para pasar matrices (de tipos numéricos integrados) de VBA a dylib (extensión de dll en mac os x) y actualizarlas y enviarlas de vuelta a VBA, ver por ejemplo:

pasando la función c / c ++ dylib tomando el puntero a VBA en mac

Ahora, me gustaría hacer lo mismo con las cadenas, y primero con una sola cadena, no una matriz. Quiero recibir la cadena de VBA, modificarla en C ++ y enviarla de vuelta, actualizada, a VBA.

El código en elC++ lado es:

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

en el archivothedylib.dylib, compilado de la siguiente manera (office 2011 para mac os x es de 32 bits):

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

mientras que en el lado de VBA (en Excel 2011 para Mac OS X) tengo este código:

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

y al ejecutarlo sale "LUDWIG VON MISES" como se esperaba.

Observación 1. Nota laByVal delante de la cadena en la firma del sub. Poniendo unByRef en cambio, habría producido un bloqueo en tiempo de ejecución. Aún más extraño: imagina que agrego untolowerfunc en mi dylib (mismo código que paratoupperfunc pero confiando enctype.h'stolower Función C ++). También funciona como se esperaba, pero esta vez, poniendo unByRef delante de la cadena en la firma en lugar de unByVal ya no provoca un bloqueo en tiempo de ejecución. Entonces, ¿hay algo diferente entre las funciones de C ++toupper ytolower ? Entonces qué ?¿Qué explica este comportamiento?

Observación 2. Como corolario del hecho de que lo que describí anteriormente funciona, ahora sabemos que Excel 2011 VBA en una Mac OS X no intercambia cadenas con un dylib que usa el mismo formato en memoria que usa un COM BSTR. Utiliza terminación nulachar* cadenas en su lugar.

Teniendo en cuenta el comentario 2 y como "usar VARIANT bajo os x" era mi objetivo a largo plazo, ver por ejemplo:

Pasar un VARIANTE de mac OS X Excel 2011 VBA a c ++,

Finalmente imité unVARIANT estructura en unVARIANT.h archivo como puede ver en el siguiente código:

#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

Me apego a lo que se hace en el lado de las ventanas para todo exceptoBSTR para lo cual establezco:

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

(También eliminé material COM puro, es decir, porciones de código relacionadasIUnknown yIDispatch.)

Habiendo definido esta "luz"VARIANT estructura, quiero jugar el mismo juego que para las matrices dedouble's y parastringes decir, intercambioVARIANT's entre VBA y una biblioteca dinámica de C ++. Entonces diseñé este código 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;
              }
          }
      }
}

meter enthevarianttest.cpp, compilado de la siguiente manera:

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

y se usa en el lado de VBA (en excel 2011 para mac os x) de la siguiente manera:

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

La ejecución de este código VBA ahora aparece sucesivamente: -1332 ludwig von mises Ludwig von Mises

los dos primeros están bien, pero para el último, se esperaba "LUDWIG VON MISES" ... Y el último depende en última instancia de C ++toupper función, la misma función del comentario anterior 1 que no me permitíaByRef utilizar en el VBA en el primer ejemplo ...

Entonces, ¿qué está pasando? ¿Por qué estaba funcionando en el primer ejemplo y ya no en este segundo?

Observación 3. Nota laByRef en frente deVARIANT La firma del sub. Poniendo unByVal en su lugar provoca un bloqueo en tiempo de ejecución ... (Es lo contrario de lo que estaba sucediendo con cadenas y sin variantes, en el primer código VBA).

Respuestas a la pregunta(0)

Su respuesta a la pregunta