Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从dll返回多个字符串_C++_String_Windows_Dll - Fatal编程技术网

C++ 从dll返回多个字符串

C++ 从dll返回多个字符串,c++,string,windows,dll,C++,String,Windows,Dll,我们正在讨论从一个dll函数返回多个字符串的好方法。目前我们有8个字符串,但会有更多。为了简单起见,现在我认为所有的字符串都有相等的长度。 extern "C" int DLLNAME_ _stdcall GetResult(TestResults* testResults); 在哪里 或者第二个选择:在哪里 struct TestResults { int stringLengths; char string1[64]; char string2[64]; c

我们正在讨论从一个dll函数返回多个字符串的好方法。目前我们有8个字符串,但会有更多。为了简单起见,现在我认为所有的字符串都有相等的长度。
extern "C" int DLLNAME_ _stdcall GetResult(TestResults* testResults);
在哪里

或者第二个选择:在哪里

struct TestResults
{
    int stringLengths;
    char string1[64];
    char string2[64];
    char string3[64];
    char string4[64];
    ...
};
第三种选择: 外部“C”int DLLNAME_ustdcall GetResult(int stringlength、char*string1、char*string2、char*string3等)

dll将通过串行线进行通信,并检索将填充到字符串中的信息。需要分配内存的地方是开放讨论的,可以作为答案的一部分

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

也许有更多的选择。Windows下的常见做法是什么?从Windows API或参数中选择一个或另一个的示例


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

当您将函数声明为
extern“C”
时,我想您不能使用
std::vector
作为返回类型

另一种可能性是:

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);
这样,您就可以灵活地返回任意多的字符串。此外,循环查看
测试结果也很容易

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

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

一个
BSTR
将通过:
BSTR MyBstr=SysAllocString(L“我是一个快乐的BSTR”)。此分配还设置包含字符串长度的成员。您必须使用:
SysFreeString(MyBstr)释放分配的内存。您还需要分配整个数组
BSTR*

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

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

在C++方面,可以使用<代码> ATL::CCOMSAFAREAREX < /COD>助手类,以简化安全数组编程。 您将在中找到有趣的内容(特别是,请查看生成安全字符串数组的段落)


从上述文章中可以看出:在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;
}

使用
char*
如何管理内存分配/释放?另外,concider
BSTR
作为一种跨语言类型(具有定义的内存管理)。我更新了问题以回答您的评论。我们没有严格的规则来说明分配需要在哪里进行。这可能是我们最终不知道什么是好的/常见的想法的部分原因。如果您与VB 6交互,您绝对应该使用
BSTR
。这就是VB6使用的字符串类型。在.NET应用程序中也可以正常工作,因为它是标准的COM类型。或者,您可以以以下形式返回它:一系列以null结尾的字符串,以空字符串(\0)结尾。以下是一个示例:String1\0String2\0String3\0LastString\0\0将您的
String
类型与MS Windows类型
BSTR
(请注意,BSTR已定义了语言间内存管理)无论如何,您都不应该在DLL中使用STL类型作为返回值。它们不能在不同版本的运行库之间互换使用。我强烈建议提供单独的freeResult函数。这使得用户可以轻松地解除分配,无论需要解除分配多少个不同的阵列。这样,就不再需要BSTR了,我们可以再次回到简单的C字符串。我们甚至可以将结构作为指针返回(错误时为NULL)。。。这两个函数将等价于Sys(Alloc | Free)字符串对。。。。。。而且不必担心字符串是如何分配的,我们甚至可以使用运算符new[]和delete[]。这很好,@Aconcagua,当您想要使用任何需要内存管理的东西时,包括STL类型时,这是推荐的模式。它也是一个真正的“通用”API,因为它适用于所有语言,从汇编语言和C语言到Python和Haskell语言。不幸的是,这给程序员带来了更大的负担,这在通常不需要手动内存管理的语言中是一个特别的缺点,因为程序员没有受到约束。BSTR是一种COM类型,在Windows中无处不在,并且在VB和.NET中自动管理。方便,误差小。
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;
}
[DllImport("MyDll.dll", PreserveSig = false)]
public static extern void MyDllGetStrings(
  [Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
  out string[] result);