1

当从 MacOSX dylib 从 VBA 调用 C 代码时,我用 C 编写了一些代码来转换从 VBA 传递的字符串。我在这里得到了一些很好的提示,因为我只关心 ASCII 字符串,所以我编写了以下函数来将其转换BSTR为简单的char*

#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_tMacOSX C 编译器中的 4 字节(不是 2 字节)wchar_t。我在调用后添加了一个断点vbstochar来查看 的内容convarg,从 Excel 调用它似乎可以工作。

所以这行得通,但我不明白的一件事是为什么我必须将函数len中的我乘以vbstrlen2。我是 C 的新手,所以我不得不稍微阅读一下指针 - 我想自从我的 BSTR包含 2 个字节的字符,我应该得到正确的字符串长度而不必乘以 2?如果有人可以向我解释这一点,或者发布指向教程的链接,那就太好了?

此外,我的带有字符串参数的函数在 VBA 中调用时有效,但仅在第一次调用之后。因此,当我BSTR*第一次使用来自 dylib 的参数调用函数时(在我启动应用程序后,在本例中为 Excel),BSTR*指针只指向某个(随机?)地址,而不是字符串。当我第二次从 VBA 调用该函数时,一切正常 - 任何想法为什么会这样?!

4

2 回答 2

2

BSTR 具有嵌入长度,您无需手动计算长度。

至于需要将长度乘以2,那是因为BSTR使用2字节字符,但char只有1字节。您编写了 vbstrlen() 函数以返回 BSTR 中的字节数,而不是字符数。

由于您只对 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); 
} 
于 2012-04-10T01:39:53.837 回答
0

VB 字符串可能是 UTF-16 字符串,每个字符使用 2 个字节(BMP、基本多语言平面或 U+0000..U+FFFF 之外的字符除外,它们被编码为代理对)。因此,对于您的“ASCII”数据,您将交替使用 ASCII 字符和零字节。“乘以 2”是因为 UTF-16 使用两个字节来存储每个计数的字符。

当我们看到时,这几乎是确定的:

typedef uint16_t OLECHAR;
typedef OLECHAR * BSTR;
于 2012-04-10T01:31:12.107 回答