C++中unsigned char**赋值问题及VB调用异常排查
问题背景
需编写替代旧版本的DLL,其中GetText函数必须遵循签名:
int GetText(unsigned char** outBuf, unsigned int* outLen);
测试时函数返回0(OK状态),但VB端弹出“Reading failed with status 0”对话框,且文本框无法显示内容。
相关代码
C++端GetText实现
int GetText(unsigned char** outBuf, unsigned int* outLen){ *outBuf = NULL; *outLen = 0; //Create a char array from scratch, just to test... unsigned char text[] = "Hello"; //outLen is the size of text *outLen = sizeof(text); //I allocate size to outBuf *outBuf = new unsigned char[*outLen]; //I copy value of text into outBuf memcpy(*outBuf, &text, *outLen); return OK; };
VB端调用代码
'lance la lecture StatusInt = LectureText(NumText, textStr) If StatusInt = 0 Then 'traitement des sauts de ligne textStr= Replace(textStr, Chr(&HD) + Chr(&HA), Chr(&HA)) textStr= Replace(textStr, Chr(&HA), Chr(&HD) + Chr(&HA)) 'copie dans la textbox Text1.Text = textStr Else MsgBox "Lecture failed with err " & Str(StatusInt) End If
VB端包装函数
Public Function LectureText(ByVal NumText, ByRef Text As String) As Long Dim AddrText As Long 'Dim TextAs String Dim LengthText As Long Dim status As Long 'lecture du text status = GetText(AddrText, LengthText) 'si lecture ok, copie et libère le buffer If status = 0 And LengthText <> 0 Then 'Alloue l'espace nécessaire pour le text Text = String(LengthText, vbNullChar) 'copie du text CopyMemory ByVal Text, ByVal AddrText, LengthText End If 'retourne status LectureText= status End Function
问题分析与修复方案
1. VB包装函数的参数传递错误
GetText的第一个参数是unsigned char**,需要接收分配好的缓冲区地址,因此在VB调用时必须以引用方式传递AddrText。原代码中调用GetText(AddrText, LengthText)时默认是传值(ByVal),导致AddrText无法被DLL修改,始终为初始值0,后续CopyMemory访问地址0会触发内存错误,最终导致内容无法显示且弹出错误提示。
修复: 修改VB包装函数中的GetText调用,给AddrText和LengthText都加上ByRef:
status = GetText(ByRef AddrText, ByRef LengthText)
同时要确保GetText在VB中的声明匹配:
Declare Function GetText Lib "YourDllName.dll" (ByRef outBuf As Long, ByRef outLen As Long) As Long
2. C++代码中memcpy的源地址错误
原代码中memcpy(*outBuf, &text, *outLen);使用&text作为源地址,虽然地址值与数组首地址相同,但&text是指向整个数组的指针(类型为unsigned char (*)[6]),语义上应直接使用数组首地址text。修正后避免潜在类型匹配问题:
memcpy(*outBuf, text, *outLen);
3. 内存释放问题(可选但重要)
C中用new分配的内存,VB无法直接用delete释放,会导致内存泄漏。如果旧版本DLL使用Windows堆分配函数,建议将C中的new替换为LocalAlloc,以便VB后续用LocalFree释放:
*outBuf = (unsigned char*)LocalAlloc(LPTR, *outLen);
然后在VB的CopyMemory之后添加释放代码:
LocalFree ByVal AddrText
总结
核心问题是VB调用GetText时未以引用方式传递缓冲区地址变量,导致DLL无法将分配的缓冲区地址返回给VB,后续内存访问出错。修正参数传递方式后,即可正常获取并显示文本内容。
内容的提问来源于stack exchange,提问作者momone50

