简体   繁体   English

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

[英]How to return a string of unknown size from DLL to Visual Basic

I have a visual basic script that calls to a DLL which does network requests and returns the result of one request as a string. 我有一个可视化的基本脚本,该脚本调用执行网络请求的DLL并以字符串形式返回一个请求的结果。 The length of the result is unknown before calling the DLL. 调用DLL之前,结果的长度未知。 The DLL is written in C/C++ by myself. DLL由我自己用C / C ++编写。

As far as I see, the most often used way to return strings from a DLL is to pass a reference of a preallocated string object as arguement to the DLL. 据我所知,从DLL返回字符串的最常用方法是将预分配的字符串对象的引用作为对DLL的争论。 The DLL function then just fills this memory with the returning string. 然后,DLL函数将返回的字符串填充到此内存中。 The problem is that the allocated buffer has to be large enough, to make sure the result fits into it. 问题在于分配的缓冲区必须足够大,以确保结果适合该缓冲区。

Is it possible to directly return the resulting string from the DLL? 是否可以直接从DLL返回结果字符串? Or is there any other way to dynamically allocate a string object depending on the length of the result and return it to a VB caller? 还是有其他方法根据结果的长度动态分配字符串对象并将其返回给VB调用者?

I tried different approaches, for example like this (ugly, just examples): 我尝试了不同的方法,例如像这样(丑陋的示例):

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

Or like.. 或喜欢..

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

The visual basic side: 视觉基本方面:

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

Both without success - the resulting string in VB is filled with garbage. 两者都没有成功-VB中的结果字符串充满了垃圾。

Most DLLs don't return a string. 大多数DLL不返回字符串。 They accept a string as a param and copy a char array into that buffer. 他们接受一个字符串作为参数,并将一个char数组复制到该缓冲区中。 Try something like this: 尝试这样的事情:

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

And then copy your string into that buffer and return the number of chars: 然后将您的字符串复制到该缓冲区中并返回字符数:

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

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

When calling from VB, allocate a string and specify its size: 从VB调用时,分配一个字符串并指定其大小:

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

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

Edit: 编辑:

If you must return a string as the result of your function call, you can try creating a BSTR (a VB-style string) and returning that. 如果必须通过函数调用返回字符串,则可以尝试创建BSTR(VB样式的字符串)并返回它。 You'll need to convert your string to Unicode and then use SysAllocString() to create the BSTR. 您需要将字符串转换为Unicode,然后使用SysAllocString()创建BSTR。 For example: 例如:

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

Joining the conversation late, but... 加入对话较晚,但是...

The initial question asked how to handle a variable buffer size. 最初的问题询问如何处理可变的缓冲区大小。 I believe the only way to do this is thru two functions calls. 我相信做到这一点的唯一方法是通过两个函数调用。 One to get the buffer size, then another to get the string. 一个获取缓冲区大小,然后另一个获取字符串。

I'm using a similar technique to get an encryption string in an access form using a C++ function. 我正在使用类似的技术来使用C ++函数以访问形式获取加密字符串。 The VBA looks similar to this (details left out): 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

And some C++ functions with the guts stripped out (actual functions do heavier lifting than this - but you should get the idea) 并去除了某些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;
}

Your mileage may vary... 你的旅费可能会改变...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM