JasonRShaver
JasonRShaver

Reputation: 4394

PInvoke an Array of a Byte Arrays

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?

Upvotes: 0

Views: 3211

Answers (3)

Samuel
Samuel

Reputation: 38346

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

Upvotes: 1

&#208;аn
&#208;аn

Reputation: 10875

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.

Upvotes: 2

MichaC
MichaC

Reputation: 2844

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

Upvotes: 1

Related Questions