在BS中将BSTR转换为char *;取决于VBA / C#调用者的不同结果

时间:2010-06-10 15:09:58

标签: c# excel vba dll casting

我有一个接受BSTR参数的dll函数。在用于其他事情之前,它们被转换为char *。

当从VBA代码调用dll时,这可行。但是,当从C#代码调用它时,只指向第一个字符。

这两个版本都是适用于2007之前版本和2007年版本的Office的Excel addIns,它们可以调用更快的C ++ AddIn。他们直接称呼它,而不是通过Excel。

VBA函数声明:

Private Declare Function Test Lib "ExcelAddIn.xll" (ByVal param As String) As String

C#函数声明:

[DllImport("ExcelAddIn.xll", CharSet=CharSet.Ansi)]
[return:MarshalAs(UnmanagedType.BStr)]
private static extern string Test([MarshalAs(UnmanagedType.BStr)] string param);

调试dll并观察输入的BSTR值时,两者看起来都是正确的;只有C#one才会投出第一个角色。

Charset=CharSet.Unicode没有任何区别。

C ++代码。

BSTR __stdcall Test(BSTR param)
{
char* Param= "";

if(param!= NULL)
    Param= (char*)param;

    return OtherClass.DoOtherStuff(Param);
}

2 个答案:

答案 0 :(得分:1)

BSTR是Unicode字符串。正如您所看到的,如果您尝试使用LE Unicode字符串作为ANSI,您将只获得第一个字母(如果它是ASCII等)

ATL / MFC的CComBSTR类可能有所帮助:您可以附加您收到的BSTR,我认为它将为您处理单字节转换。 如果你想在内部使用Unicode字符串,那么使用它也可能更安全 - 我不认为BSTR可以保证是零终止的(它们的长度在索引-1处)。 [edit]纠正由dkackman在下面,谢谢。

您最好的解决方案是将OtherClass转换为使用Unicode字符串而不是MBCS,或者如果它仅用于COM上下文,您可以将其转换为使用BSTR甚至。您的计划将更好地支持国际化扩展您的市场等。但这并不总是一个简单的转换。

答案 1 :(得分:1)

原因与您编组数据的方式有关。

VB声明不包含string参数的注释,因此它将作为普通char*参数进行编组。 CLR不能对pinvoke进行类型验证,并且基本上将char*放入需要BSTR的插槽中。您的代码虽然立即将其转换为char*,但它修复了编组问题。

在C#示例中,虽然您明确表示将string编组为BSTRBSTR实际上是一个在引擎盖下使用wchar的字符串。通过对char*执行简单投射,您实际上是将wchar*投射到char*,这解释了为什么您只能看到第一个角色。

最简单的解决方案是让Test方法采用char*参数并删除C#版本上的编组注释。