tags:

views:

738

answers:

3

I have the following C code:

const BYTE* Items[3];
Items[0] = item1;
Items[1] = item2;
Items[2] = item3;
int result = Generalize(3, Items);

with Generalize having a signature of

int __stdcall Generalize(INT count, const BYTE * const * items);

What is the best way to make that call with PInvoke?

+2  A: 

I can't guarantee this is the best way, but it's the first way I'd try.

    [DllImport("<unknown>", 
           EntryPoint="Generalize", 
           CallingConvention=CallingConvention.StdCall)]
    public static extern int Generalize(int count, IntPtr[] items);

    public static void CallGeneralize()
    {
        var itemCount = 3;
        var items = new IntPtr[itemCount];

        items[0] = item1; // where itemX is allocated by Marshal.AllocHGlobal(*)
        items[1] = item2;
        items[2] = item3;

        var result = Generalize(itemCount, items);
    }
MichaC
This worked. Leaving the question open for another hour or so to see if anyone finds anything more elegant.
JasonRShaver
Thank you Micha =)
JasonRShaver
+1  A: 

Why does it seem that so many people want to avoid C++/CLI? If you have to ask how to use P/Invoke, that might be a hint to use C++/CLI instead.

Something along the lines of the following in JasonRShaver.h

namespace StackOverflow
{
   public ref class JasonRShaver abstract sealed // "abstract sealed" -> "static"
   {
      public:
 static int Generalize(array<array<BYTE>^>^ items) {
  int count = items->Length;
  std::vector<const BYTE*> arrays(count);

  for each (array<BYTE>^ a in items)
  {
   BYTE* bytes = new BYTE[a->Length];
   for (int i=0; i<a->Length; i++)
    bytes[i] = a[i];
   arrays.push_back(bytes);
  }

  int retval = ::Generalize(count, &(arrays[0]));

  typedef std::vector<const BYTE*>::const_iterator it_t;
  for (it_t it = arrays.begin(); it != arrays.end(); ++it)
  {
   const BYTE* bytes = *it;
   delete[] bytes;
  }

  return retval;
 }

   };
}

This isn't production-quality code (e.g., exception handling), and you might be able to do even a better job with pin_ptr<> and the like. But you get the general idea.

Dan
Aye, that would be best, but there is a decent amount of 'other' code in there and this was the only method presenting problems.
JasonRShaver
+1  A: 

Since C++ doesn't have jagged arrays and only multidimensional arrays and accesses elements by using row * column, you could try flattening the multidimensional array before calling.

[DllImport("dllName.dll")]
private static extern int Generalize(int count, ref byte[] items);

public static int Generalize(int count, byte[,] items)
{
  return Generalize(count, ref items.Cast<byte>().ToArray());
}
Samuel
I tried this one and it did not work well.
JasonRShaver