2012-04-10 10 views
1

MacOSXのdylibからVBAからCコードが呼び出されたときに、VBAから渡された文字列を変換するためのコードをCで記述しました。私はいくつかの良いヒントhereを得た、と私は唯一のASCII文字列を気にするので、私は、単純なchar*BSTRを変換するには、以下の機能を書いている:CのMacOSXでのBSTRの処理

#include <stdlib.h> 
#include <stdio.h> 
#include <stdint.h> 
#include "myheader.h" 

size_t vbstrlen(BSTR *vbstr) 
{ 
    size_t len = 0U; 
    while(*(vbstr++)) ++len; 
    len = len*2; 
    return len; 
} 

void vbstochr(BSTR *vbstr, char** out) 
{ 
    int len2 = vbstrlen(vbstr); 
    char str[len+1]; 

    int i; 

    for(i = 0; i < len; i++) 
    { 
     str[i] = (char) (((uint16_t*) vbstr)[i]); 
    } 

    str[i] = '\0'; 

    asprintf(out, str); 
} 

int test(BSTR *arg1) 
{ 
    char* convarg; 
    vbstochr(arg1, &convarg); 

    return 1; 
} 

myheader.hは次のようになります。

typedef uint16_t OLECHAR; 
typedef OLECHAR * BSTR; 

。私はuint16_tをMacOSX Cコンパイラの4バイト(2バイトではない)のwchar_tのために使用しました。 vbstocharが、convargの内容を見るために呼び出された後にブレークポイントを追加しました。これはExcelから呼び出されたときに機能するようです。

だから、これは動作しますが、私は理解していない一つのことは、私は2でvbstrlen機能で私lenを乗算しなければならない理由は、私はCに新しいので、私はポインタに少し読んしなければならなかったです - BSTRには2バイトの文字が含まれているので、2倍にすることなく正しい文字列の長さを取得する必要があります。誰かが私にこのことを説明したり、チュートリアルへのリンクを投稿することができれば素晴らしいだろうか?

また、VBAで呼び出されたときの文字引数の関数は、最初の呼び出しの後でのみ機能します。だから私がBSTR*引数を持つ関数を最初に呼び出すと(BSTR*ポインタはちょうどいくつかの(ランダム?)アドレスを指すが文字列は指していない。私がVBAから関数を2回呼び出すと、すべてがうまくいきます。なぜこれが当てはまるのでしょうか?

+0

このコードはコンパイルできません。ポスト*本物のコード、いぼ、そしてすべて。 –

+0

@HansPassant 'vbstrlen'ビットは、重要ではない' #include 'をトリミングしてコンパイルしますが、dylibでコンパイルし、excel 2011 VBAから使用して、VBA文字列の戻り値0を保持します。 (with typedef wchar_t * BSTR; ') –

答えて

1

、手動で長さを計算する必要はありません。 2により長さを乗算する必要があるとして

BSTRは、2バイト文字を使用するが、charはわずか1バイトであるため、それがあります。あなたは文字数ではなく、BSTRのバイト数を返すようにvbstrlen()関数をコーディングしました。

あなたはASCII文字列のみに関心があるので、あなたは以下のコードを簡素化することができます。

#include <stdlib.h> 
#include <stdio.h> 
#include <stdint.h> 
#include "myheader.h" 

size_t vbstrlen(BSTR *vbstr) 
{ 
    if (vbstr) 
     return *(((uint32_t*)vbstr)-1); 
    return 0; 
} 

void vbstochr(BSTR *vbstr, char** out) 
{ 
    size_t len = vbstrlen(vbstr); 
    char str[len+1] = {0}; 

    for(size_t i = 0; i < len; ++i) 
     str[i] = (char) vbstr[i]; 

    asprintf(out, str); 
} 
+0

VBAで使用されているdylibでvbstrlen関数をテストしましたが(「excel 2011 on mac」)、「toto」文字列は0を返します。何か案が ? –

+0

[this](http://www.codeproject.com/Articles/810282/Microsoft-Office-VBA-to-the-Macs)および[this](http://stackoverflow.com/questions/9833808/)によると、 mac-office-2011-vba-and-dylib)を使用すると、MacOSX *上のExcel 2011 VBAは、COM BSTRが使用するのと同じメモリ内フォーマットを使用してdylibと文字列を交換しないようです。代わりにnullで終了する 'char *'文字列を使います。また、トリッキーな部分は、あなたのVBAコードは、文字列を割り当て、埋めるためにdylibにそれを渡す必要がありますので、dylibは、VBAが正しくそれを解放しないように、出力文字列を割り当て、VBAにそれを返すことができないということです。 –

+0

ワントリッキーな部分についての質問:それは彼またはWindowsの場合も? Windowsの、VB/VBAとCOMに –

0

VB文字列は、BMP、Basic Multilingual Plane、またはU + 0000..U + FFFFを超える文字を除く、文字あたり2バイトを使用するUTF-16文字列であり、サロゲートとしてエンコードされますペア)。したがって、あなたの 'ASCII'データの場合、ASCII文字とゼロバイトが交互に表示されます。 UTF-16は2バイトを使用してカウントされた各文字を格納するため、 '2での乗算'が行われます。私たちが見たときに

これはほとんど決定的である:A BSTRは埋め込まれた長さを持っている

typedef uint16_t OLECHAR; 
typedef OLECHAR * BSTR;