BSTR和VARIANT在...... mac os x

时间:2016-03-11 12:19:28

标签: c++ macos excel-vba variant bstr

在mac os x下我有办公室2011及其excel和VBA,我有gcc-5.3.0的g ++。

我为将数组(数值内置类型)从VBA传递到dylib(mac os x上的dll的扩展名)并更新它们并将它们发送回VBA做了很多,参见例如:

passing c/c++ dylib function taking pointer to VBA on 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 for mac os x是32位):

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

而在VBA方面(在excel 2011 for 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会在运行时产生崩溃。更奇怪的是:想象一下,我在我的dylib中添加tolowerfunc(代码与toupperfunc相同,但依赖于ctype.h的{​​{1}} C ++函数)。它也可以按预期工作,但这一次,在签名中将tolower放在字符串前面而不是ByRef不会引起运行时崩溃。那么,C ++函数ByValtoupper之间是否有不同之处?如果是这样,什么? 有什么可以解释这种行为?

备注2。作为上述内容可行的事实的推论,我们现在知道mac os x上的Excel 2011 VBA不会使用相同的内容与dylib交换字符串。 COM BSTR使用的内存格式。它使用以null结尾的tolower字符串。

考虑到备注2和“在os x下使用VARIANT”是我的长期目标,请参阅:

Passing a VARIANT from mac OS X Excel 2011 VBA to c++

我终于在char*文件中模仿了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 之外,我坚持在Windows窗口所做的一切:

BSTR

(我还删除了纯粹的COM内容,即有关typedef char WCHAR; typedef WCHAR OLECHAR; typedef OLECHAR * BSTR; IUnknown的部分代码。)

定义了这个“轻型”IDispatch结构后,我想玩VARIANTdouble的数组游戏,即交换{{ 1}}介于VBA和C ++动态库之间。所以我设计了这个C ++代码:

string

输入VARIANT,编译如下:

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

并在VBA端(在excel 2011中用于mac os x)中使用如下:

thevarianttest.cpp

现在连续弹出执行此VBA代码:    -1332    路德维希冯米塞斯    Ludwig von Mises

前两个是好的,但最后一个,“LUDWIG VON MISES”是预期的...最后一个最终依赖于C ++的g++ -m32 -Wall -g -c ./thevarianttest.cpp g++ -m32 -dynamiclib ./thevarianttest.o -o ./thevarianttest.dylib 函数,与之前的注释1相同的函数不是允许我在第一个例子中使用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中使用...

那是怎么回事?为什么它在第一个例子中工作而在第二个例子中不再工作?

备注3. 请注意toupper子签名前面的ByRef。放置ByRef会引发运行时崩溃...(这与第一个VBA代码中的字符串和没有变体的情况相反。)

0 个答案:

没有答案