Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return multiple strings from dll

we are having a discussion as what is a good way to return multiple strings from one dll function. Currently we have 8 strings, but there will be more. For simplicity I now consider all strings will have equal lengths.

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

where

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

or second option: where

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

third option: extern "C" int DLLNAME_ _stdcall GetResult(int stringLengths, char* string1, char* string2, char* string3, ...);

The dll will communicate over a serial line and retrieve information that will be filled into the strings. Where the memory needs to be allocated is open for discussion and can be part of the answer.

The background is that we have a VB6 application team that prefers the second method and a C++/C# team that prefers the first method. Last method looks to suit both teams but looks a bit strange to me with so many parameters.

Maybe there are more options. What is common practice under Windows? Any examples from the Windows API or arguments to choose one over the other?

Edit: The strings have a meaning as in first name, last name, email. We currently have eight, but in the future we might add a couple for example for address. An array would not be the correct choice for this, but that was not clear from the original context.

like image 728
Jef Patat Avatar asked Dec 01 '25 11:12

Jef Patat


1 Answers

The best way is probably using a safe array storing BSTR strings.

Both VB and C# understand safe arrays very well: in C#, a safe array of BSTR strings is automatically converted to a string[] array.

On the C++ side, you can use the ATL::CComSafeArray helper class to simplify safe array programming.

You will find interesting material in this MSDN Magazine article (in particular, take a look at the paragraph Producing a Safe Array of Strings).


From the aforementioned article: On the C++ side, you can implement a C-interface DLL, exporting a function like this:

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;
}

On the C# side, you can use this PInvoke declaration:

[DllImport("MyDll.dll", PreserveSig = false)]
public static extern void MyDllGetStrings(
  [Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
  out string[] result);
like image 70
Mr.C64 Avatar answered Dec 03 '25 01:12

Mr.C64



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!