我想将BSTR的SAFEARRAY从C ++ DLL传递给VB6。这就是我当前的DLL实现(在Win7 x64 SP1上使用VC2013U5编译):
sabstrtovb6.h:
#ifdef SABSTRTOVB6_EXPORTS
#define SABSTRTOVB6_API __declspec(dllexport)
#else
#define SABSTRTOVB6_API __declspec(dllimport)
#endif
#include <OAIdl.h>
SABSTRTOVB6_API HRESULT __stdcall FnSABSTRToVB6(LPSAFEARRAY* ppSABSTR);
sabstrtovb6.cpp(注意:我正在使用SysAllocStringByteLen()
分配ANSI字符串,因为VB6在与DLL接口时总是执行宽字符/ ANSI和反之亦然的字符串转换。当函数返回时,VB6执行数组中每个字符串的宽字符转换。):
#include "stdafx.h"
#include "sabstrtovb6.h"
#include <atlsafe.h>
SABSTRTOVB6_API HRESULT __stdcall FnSABSTRToVB6(LPSAFEARRAY* ppSABSTR)
{
if (!ppSABSTR)
return E_POINTER;
if (*ppSABSTR)
return DISP_E_BADINDEX;
HRESULT hr = SafeArrayDestroy(*ppSABSTR);
if FAILED(hr)
return hr;
CComSafeArray<BSTR> cSABSTR(ULONG(0), LONG(0));
cSABSTR.Add(SysAllocStringByteLen("Apple\0", strlen("Apple\0")));
cSABSTR.Add(SysAllocStringByteLen("Orange\0", strlen("Orange\0")));
cSABSTR.Add(SysAllocStringByteLen("Wall\0", strlen("Wall\0")));
cSABSTR.Add(SysAllocStringByteLen("Bananas\0", strlen("Bananas\0")));
cSABSTR.Add(SysAllocStringByteLen("Fax\0", strlen("Fax\0")));
*ppSABSTR = cSABSTR.Detach();
return S_OK;
}
一切都很好,除了一些字符串的长度与NULL字符的偏移量不匹配。在VB6中执行以下代码时...
Option Explicit
Private Declare Function FnSABSTRToVB6 Lib "sabstrtovb6" (ByRef sa() As String) As Long
Private Sub Form_Load()
ChDrive App.Path: ChDir App.Path
Dim sa() As String
Dim res As Long: res = FnSABSTRToVB6(sa)
If res >= 0 Then
Dim i As Long
For i = 0 To UBound(sa)
Debug.Print (sa(i) + ":" + CStr(Len(sa(i))))
Next
End If
End Sub
...这是调试窗口显示为输出的内容:
Apple :6
Orange:6
Wall:4
Bananas :8
Fax :4
显然,Apple,Bananas和Fax的长度指示器是错误的。我觉得所有带有奇数编号的字符串都用一个额外的字节填充。这里发生了什么?有人可以帮我解决这个问题吗?
UPDATE:似乎CComSafeArray包装器在这里引起了麻烦。当我以老式的方式分配BSTR时,如...
SAFEARRAYBOUND bounds;
bounds.cElements = 5;
bounds.lLbound = 0;
*ppSABSTR = SafeArrayCreate(VT_BSTR, 1, &bounds);
SafeArrayLock(*ppSABSTR);
BSTR *SABSTRArray = (BSTR *)(*ppSABSTR)->pvData;
SABSTRArray[0] = SysAllocStringByteLen("Apple\0", strlen("Apple\0"));
SABSTRArray[1] = SysAllocStringByteLen("Orange\0", strlen("Orange\0"));
SABSTRArray[2] = SysAllocStringByteLen("Wall\0", strlen("Wall\0"));
SABSTRArray[3] = SysAllocStringByteLen("Bananas\0", strlen("Bananas\0"));
SABSTRArray[4] = SysAllocStringByteLen("Fax\0", strlen("Fax\0"));
SafeArrayUnlock(*ppSABSTR);
VB6中的 ... Len
将显示正确的值:
Apple:5
Orange:6
Wall:4
Bananas:7
Fax:3
在处理BSTR时,这是CComSafeArray的已知行为吗?