从dll返回多个字符串

时间:2017-06-07 08:35:18

标签: c++ string windows dll

我们正在讨论从一个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或参数中的任何示例都可以选择其中一个?

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

2 个答案:

答案 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 allocatedBSTR 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" />