我们正在讨论从一个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或参数中的任何示例都可以选择其中一个?
编辑:字符串具有名字,姓氏,电子邮件的含义。我们目前有八个,但将来我们可能会添加一对例如地址。数组不是正确的选择,但原始上下文中并不清楚。
答案 0 :(得分:5)
最好的方法可能是使用安全数组存储BSTR
字符串。
VB和C#都非常理解安全数组:在C#中,BSTR
字符串的安全数组自动转换为string[]
数组。
在C ++方面,您可以使用ATL::CComSafeArray
帮助程序类来简化安全数组编程。
您可以在this MSDN Magazine article中找到有趣的资料(特别是,请查看段落制作安全数组字符串)。
从上述文章:在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);
答案 1 :(得分:1)
当您将函数声明为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
allocated将BSTR MyBstr = SysAllocString(L"I am a happy BSTR");
:SysFreeString(MyBstr);
。此分配还设置包含字符串长度的成员。您必须使用以下内容释放已分配的内存:BSTR*
。您还需要分配整个数组 <authentication mode="Forms">
<forms loginUrl="~/Login" timeout="525600" />
</authentication>
<sessionState mode="InProc" timeout="525600" />
<machineKey validationKey="" decryptionKey="" validation="SHA1" decryption="AES" />
。