Передача указателя байта методу C# через обратный PInvoke

В прошлом я передал массив байтов из метода C# в неуправляемую функцию C++. Теперь я пытаюсь передать указатель на буфер типа unsigned char из метода С++ обратно в метод С#, используя обратный PInvoke, который использует обратный вызов для возврата к коду С#. Я пробовал несколько разных идей, например, передачу Ref Byte, Byte * и IntPtr для второго аргумента, но ни одна из них не работает. Вот мой тестовый код для использования IntPtr:

Код С#:

namespace TestPInvoke
{
   class Program
   {
      static void Main(string[] args)
      {
         foo f = new foo();
         f.DispMsg();
      }
   }

   unsafe public class foo
   {
      public delegate void callback(int NumBytes, IntPtr pBuf);

      public static void callee(int NumBytes, IntPtr pBuf)
      {
         System.Console.WriteLine("NumBytes = " + NumBytes.ToString() + ", pBuf = ");
         String s = "";
         Byte* p = (Byte*)pBuf.ToPointer();
         for (int Loop = 0; Loop < 50; Loop++)
         {
            s += p++->ToString() + "  ";
         }
         System.Console.WriteLine(s);
      }

      public void DispMsg()
      {
         caller(new callback(foo.callee));
      }

      [DllImport(@"C:\Users\Bob\Documents\Visual Studio 2008\Projects\AttackPoker1\Win32Client\TestPInvoke\bin\Debug\TestPInvokeDLLCPP.dll", CallingConvention = CallingConvention.StdCall)]
      public static extern void caller(callback call);
   }

}

Код С++:

#include <stdio.h>
#include <string.h>

typedef unsigned char Byte;

typedef void (__stdcall *callback)(const int bytesInMsg, Byte* pintBuf);

extern "C" __declspec(dllexport) void __stdcall caller(callback call)
{
   // Debug Test on how to pass a pointer to a byte buffer to a C# method.
   Byte* pBuf = new Byte[50];
   // Initialize the buffer to something.
   Byte* p = pBuf;
   for (Byte Loop = 0; Loop < 50; Loop++)
      *p = Loop;
   // Initiate the callback into the C# code.
   call(50, pBuf);
   // Delete pBuf later.
}

Когда код C++ вызывает вызываемый метод обратного вызова C#, аргумент bytesInMsg является правильным. Но возвращенный указатель не указывает на начало буфера. Разыменование указателя всегда, кажется, указывает на последнее значение в буфере (49 или 0x31), но после просмотра его в окне памяти остальные байты как до, так и после являются мусором.

Есть ли у кого-нибудь предложения о том, как я могу заставить это работать без маршалинга большого массива? Что я надеюсь сделать, так это передать указатель на большой буфер, созданный на стороне C++ один раз, в класс C#, который затем сможет эффективно считывать данные из этого буфера.

Если этого сделать нельзя, то мне придется выделять буферы памяти из C#, закреплять их и передавать в методы C++.


person Bob Bryan    schedule 29.01.2013    source источник


Ответы (1)


Все пинвоки в порядке и работают исправно. У вас просто есть глупая ошибка в вашем коде C++, вы забываете увеличить указатель, поэтому вы всегда устанавливаете только первый элемент массива. Использовать

   *p++ = Loop;

Или более вменяемая версия, которая просто индексирует массив:

   // Initialize the buffer to something.
   for (int ix = 0; ix < 50; ++ix)
       pBuf[ix] = ix;
person Hans Passant    schedule 29.01.2013
comment
Спасибо. Иногда я слеп... Сейчас работает хорошо. - person Bob Bryan; 30.01.2013