我们正在讨论从一个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*
。