从 dll 返回多个字符串

Return multiple strings from dll

本文关键字:字符串 返回 dll      更新时间:2023-10-16

我们正在讨论从一个DLL函数返回多个字符串的好方法。目前我们有 8 个字符串,但还会有更多。为简单起见,我现在考虑所有字符串的长度相等。

extern "C" int DLLNAME_ _stdcall GetResult(TestResults* testResults);

哪里

struct TestResults
{
int stringLengths;
char* string1;
char* string2;
char* string3;
char* string4;
...
};

或第二种选择:其中

struct TestResults
{
int stringLengths;
char string1[64];
char string2[64];
char string3[64];
char string4[64];
...
};

第三种选择: extern "C" int DLLNAME_ _stdcall GetResult(int stringLengths, char* string1, char* string2, char* string3, ...);

dll 将通过串行线路进行通信,并检索将填充到字符串中的信息。需要分配内存的位置可以讨论,并且可以成为答案的一部分。

背景是,我们有一个首选第二种方法的 VB6 应用程序团队和一个首选第一种方法的 C++/C# 团队。最后一种方法看起来适合两个团队,但对我来说看起来有点奇怪,有这么多参数。

也许还有更多选择。Windows下的常见做法是什么?Windows API 中的任何示例或参数可以选择一个而不是另一个?

编辑:字符串的含义与名字,姓氏,电子邮件一样。我们目前有八个,但将来我们可能会添加几个例如地址。数组不是正确的选择,但这在原始上下文中并不清楚。

最好的方法可能是使用存储BSTR字符串的安全数组

VB 和 C# 都非常了解安全数组:在 C# 中,BSTR字符串的安全数组会自动转换为string[]数组。

在C++端,可以使用ATL::CComSafeArray帮助程序类来简化安全数组编程。

您将在这篇 MSDN 杂志文章中找到有趣的材料(特别是,请查看生成字符串的安全数组段落)。


从前面提到的文章中: 在C++端,你可以实现一个C 接口DLL,导出一个函数,如下所示:

extern "C" HRESULT MyDllGetStrings(/* [out] */ SAFEARRAY** ppsa)
{
try {  
// Create a SAFEARRAY containing 'count' BSTR strings
CComSafeArray<BSTR> sa(count);
for (LONG i = 0; i < count; i++) {
// Use ATL::CComBSTR to safely wrap BSTR strings in C++
CComBSTR bstr = /* your string, may build from std::wstring or CString */ ;
// Move the the BSTR string into the safe array
HRESULT hr = sa.SetAt(i, bstr.Detach(), FALSE);
if (FAILED(hr)) {
// Error...
return hr;
}
}
// Return ("move") the safe array to the caller
// as an output parameter (SAFEARRAY **ppsa)
*ppsa = sa.Detach();
} catch (const CAtlException& e) {
// Convert ATL exceptions to HRESULTs
return e;
}
// All right
return S_OK;
}

在 C# 端,可以使用以下 PInvoke 声明:

[DllImport("MyDll.dll", PreserveSig = false)]
public static extern void MyDllGetStrings(
[Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
out string[] result);

当您将函数声明为extern "C"时,我想您不能将std::vector<std::string>用作返回类型。

另一种可能性是:

struct String
{
int         size; /* size of string */
const char* str;  /* actual string  */
}
struct TestResults
{
int     size; /* number of strings             */
String* arr;  /* pointer to an array of String */
};

然后和以前一样:

extern "C" int DLLNAME_ _stdcall GetResult(TestResults* testResults);

有了它,您可以灵活地返回任意数量的字符串。循环浏览您的TestResults也很容易。

编辑#1:如评论中所述:使用BSTR。因此,您的结构将如下所示:

struct TestResults
{
int   size; /* number of strings           */
BSTR* arr;  /* pointer to an array of BSTR */
};

BSTR将按以下方式分配:BSTR MyBstr = SysAllocString(L"I am a happy BSTR");。此分配还设置包含字符串长度的成员。您必须通过以下方式释放分配的内存:SysFreeString(MyBstr);。您还需要分配整个数组BSTR*