如何将未知大小的字符串从DLL返回到Visual Basic

时间:2015-07-14 14:06:00

标签: c++ dll vb6

我有一个可视化基本脚本,它调用一个执行网络请求的DLL,并将一个请求的结果作为字符串返回。在调用DLL之前,结果的长度是未知的。 DLL本身是用C / C ++编写的。

据我所知,从DLL返回字符串最常用的方法是将预分配字符串对象的引用作为争论传递给DLL。然后DLL函数只用返回的字符串填充这个内存。 问题是分配的缓冲区必须足够大,以确保结果适合它。

是否可以直接从DLL返回结果字符串?或者是否有其他方法根据结果的长度动态分配字符串对象并将其返回给VB调用者?

我尝试了不同的方法,例如像这样(丑陋,只是例子):

__declspec(dllexport) const char* sendCommand(const char* cmd, const char* ipAddress)
{
    // do request stuff... 
    long lengthOfResult = ...
    const char* result = new char[lengthOfResult];
    return result;
}

或者喜欢..

__declspec(dllexport) BSTR sendCommand(const char* cmd, const char* ipAddress)
{
    _bstr_t result("Test string.");
    BSTR bstrResult = result.copy();
    return bstrResult;
}

视觉基本方面:

Declare Function sendCommand Lib "magicdll.dll" (cmd as String, ip as String) As String
result = sendCommand("any command", "192.168.1.1")

两者都没有成功 - VB中的结果字符串充满了垃圾。

2 个答案:

答案 0 :(得分:3)

大多数DLL都不会返回字符串。它们接受一个字符串作为参数,并将一个char数组复制到该缓冲区中。尝试这样的事情:

_declspec(dllexport) int sendCommand(const char* cmd, 
                                     const char* ipAddress, 
                                     char* pszBuffer, 
                                     int nBufferSize)

然后将您的字符串复制到该缓冲区并返回字符数:

int nSize = nBufferSize;
if (lstrlen(szMyResult) < nBufferSize)
    nSize = lstrlen(szMyResult);

lstrcpyn(pszBuffer, szMyResult, nSize);
return nSize;

从VB调用时,分配一个字符串并指定其大小:

Dim s As String, intChars As Long
s = Space$(128)

intChars = sendCommand("...", "...", s, Len(s))
s = Left$(s, intChars) 

修改

如果你必须返回一个字符串作为函数调用的结果,你可以尝试创建一个BSTR(一个VB风格的字符串)并返回它。您需要将字符串转换为Unicode,然后使用SysAllocString()创建BSTR。例如:

BSTR ReturnVBString() 
{
    return SysAllocString(L"This string is from a C DLL.");
} 

答案 1 :(得分:0)

迟到加入对话,但是......

最初的问题是如何处理变量缓冲区大小。我相信这样做的唯一方法是通过两个函数调用。一个用于获取缓冲区大小,另一个用于获取字符串。

我正在使用类似的技术在使用C ++函数的访问表单中获取加密字符串。 VBA看起来与此类似(详情遗漏):

Private Declare Function DllAes_ComputeCipher _
    Lib "c:\RTScada\bin\ObjProc.dll" _
    Alias "Aes_ComputeCipher" (ByRef sKey As String, ByRef sStr As String) As Integer

Private Declare Function DllAes_GetCipher _
    Lib "c:\RTScada\bin\ObjProc.dll" _
    Alias "Aes_GetCipher" (ByVal sEncode As Long) As Boolean

Private Sub CipherString_LostFocus()
.
.
.
    iSize = DllAes_ComputeCipher(sKey, sString)
    sEncoded = Space(iSize)
    bSuccess = DllAes_GetCipher(StrPtr(sEncoded))

End Sub

并且一些C ++功能被剥离了(实际功能比这更重 - 但你应该明白这一点)

//    Define a global string - in reality this is computed by the ComputeCipher function
char* gpStr = "we are the dreamers of dreams and we are the music makers";

#define CLASS_DECLSPEC   extern "C"  __declspec(dllexport)

//========================================================================
CLASS_DECLSPEC int __stdcall Aes_ComputeCipher(const char* pKey, const char* pStr)
{
  return strlen(gpStr);
}

//========================================================================
CLASS_DECLSPEC bool __stdcall Aes_GetCipher(LPSTR pReturn)
{
  char pStr = gpStr;
  int iLen = strlen(pStr);

  int idx;
  for (idx = 0; idx < iLen; idx++) {
    *pReturn  = *pStr;
    pReturn += 2;
    pStr++;
  }
  return true;
}

您的里程可能会有所不同......