Interop: passing an array of strings

  • Thread starter Jon Skeet [C# MVP]
  • Start date
J

Jon Skeet [C# MVP]

I'm just dipping my toes into writing a native DLL and P/Invoking it.
I'd like to pass an array of strings to a function in the DLL, but it's
currently failing. The documentation is somewhat inpenetrable to my
interop-newbie brain - anyone care to enlighten me? I'm trying:

[DllImport("xxx.dll")]
public static extern int yyy(string[] value);

in the C#, and:

extern "C" xxx_API HRESULT yyy(const wchar_t **value);

in the DLL. Passing a string as wchar_t* works fine. Clearly I was
being a tad optimistic trying the above - but is there a simple way of
doing it?

If it's particularly hard, it would work out okay to pass each string
in a separate call, but it's not ideal.
 
A

Alex Feinman [MVP]

There is no simple way to it. The cheapest solution, if you are in control
of both sides, will be stuff all strings in an array that looks like
"String1\0String2\0...StringN\0\0". Since .NET strings are counted, it can
be easily achieved by using a StringBuilder
sb.Append(string1);
sb.Append('\0');
....

Then use Encoding.Unicode.GetBytes(sb.ToString) to get a byte array. On the
C side parse the string into array. If you are planning on storing the
strings down there, make copies.
 
J

Jon Skeet [C# MVP]

Alex Feinman said:
There is no simple way to it. The cheapest solution, if you are in control
of both sides, will be stuff all strings in an array that looks like
"String1\0String2\0...StringN\0\0". Since .NET strings are counted, it can
be easily achieved by using a StringBuilder
sb.Append(string1);
sb.Append('\0');
...

Then use Encoding.Unicode.GetBytes(sb.ToString) to get a byte array. On the
C side parse the string into array. If you are planning on storing the
strings down there, make copies.

Ironically, I started off with the string being tab-delimited anyway...

Having run a few tests, it looks like it's easiest just to either pass
the string in and process it in one go as you suggested, or (as I
currently have) pass the string in several times, passing in the start
position and the length. That way I need to do as little as possible in
unmanaged code :)

It's a bit fast and loose at the moment, but it's getting the time to
insert 28900 rows into SQL CE down from over 5 minutes to 47 seconds...
 
A

Alex Feinman [MVP]

From the speed standpoint, PInvoke is expensive, so it might be beneficial
to minimize the number of calls to the unmanaged code
 
J

Jon Skeet [C# MVP]

Alex Feinman said:
From the speed standpoint, PInvoke is expensive, so it might be beneficial
to minimize the number of calls to the unmanaged code

That's what I thought, too - but it looks like the P/Invoking is only
taking at most about 10% of the elapsed time. I'll have a go at doing
the splitting in C instead, but I doubt it'll make much difference.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top