VB6经C++传递字符串至C#时出现截断问题
解决VB6→C++ DLL→.NET DLL的字符串传递问题
一、核心问题根源
VB6默认调用外部DLL时,传递的是ANSI编码的LPSTR(8位字符指针),而非COM标准的BSTR(带长度前缀的16位Unicode字符串)。你之前在C++中错误将参数声明为BSTR,导致把ANSI字符串的字节当成BSTR结构解析(BSTR前4字节是长度值,后续是Unicode字符),才出现乱码+仅最后一个字符正常的异常。
二、具体解决方案
方案1:转成标准Unicode字符串传递(优先实现可读字符串)
1. 修正C++ DLL的导出函数参数
将参数从BSTR改为LPCSTR,正确接收VB6传来的ANSI字符串:
// 错误声明(导致乱码) // extern "C" __declspec(dllexport) void ProcessString(BSTR vbStr); // 修正后的正确声明 extern "C" __declspec(dllexport) void ProcessString(LPCSTR vbAnsiStr);
2. C++内转Unicode并封装为BSTR传给.NET
利用Windows API将ANSI字符串转成宽字符,再封装为COM标准的BSTR,确保.NET能正确解析:
#include <comutil.h> #pragma comment(lib, "comsuppw.lib") extern "C" __declspec(dllexport) void ProcessString(LPCSTR vbAnsiStr) { // 计算宽字符所需长度 int wideLen = MultiByteToWideChar(CP_ACP, 0, vbAnsiStr, -1, NULL, 0); wchar_t* wideStr = new wchar_t[wideLen]; MultiByteToWideChar(CP_ACP, 0, vbAnsiStr, -1, wideStr, wideLen); // 封装为BSTR(自动处理长度前缀) BSTR bstr = SysAllocString(wideStr); // 调用.NET COM对象的方法,传入BSTR YourDotNetComInstance->ProcessString(bstr); // 释放资源 SysFreeString(bstr); delete[] wideStr; }
3. .NET COM端直接接收字符串
.NET会自动将BSTR转换为CLR字符串,直接声明string类型参数即可:
[ComVisible(true)] public interface IYourComInterface { void ProcessString(string input); } [ComVisible(true)] public class YourDotNetComClass : IYourComInterface { public void ProcessString(string input) { // 此处可获取完整的"ABCDEFGHI"字符串 } }
方案2:直接传递字节数组(适配特殊编码场景)
如果VB6传递的是自定义8位编码字符串,可跳过编码转换,直接传递字节数组:
1. C++端封装字节数组为SAFEARRAY
extern "C" __declspec(dllexport) void ProcessString(LPCSTR vbAnsiStr) { int strLen = strlen(vbAnsiStr); // 创建字节类型的SAFEARRAY SAFEARRAY* sa = SafeArrayCreateVector(VT_UI1, 0, strLen); BYTE* data; SafeArrayAccessData(sa, (void**)&data); memcpy(data, vbAnsiStr, strLen); SafeArrayUnaccessData(sa); // 调用.NET COM对象的字节数组处理方法 YourDotNetComInstance->ProcessBytes(sa); SafeArrayDestroy(sa); }
2. .NET端接收字节数组并转字符串
[ComVisible(true)] public interface IYourComInterface { void ProcessBytes([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)] byte[] inputBytes); } [ComVisible(true)] public class YourDotNetComClass : IYourComInterface { public void ProcessBytes(byte[] inputBytes) { // 按对应编码转字符串,例如GB2312或系统默认ANSI编码 string str = Encoding.GetEncoding("GB2312").GetString(inputBytes); } }
三、关键验证点
- VB6中声明DLL函数时必须加
ByVal,确保传递的是字符串指针而非指针的指针:Declare Sub ProcessString Lib "YourCppDll.dll" (ByVal vbStr As String) - C导出函数必须加
extern "C",避免C名字修饰导致VB6找不到函数。
内容的提问来源于stack exchange,提问作者djv
相关产品推荐
相关产品推荐

