Извините, если есть дубликат - я изо всех сил пытался найти ответ (я нашел несколько вопросов о функциях C++, которые используют обратные вызовы функций, и некоторые ответы, которые используют классы как обратные вызовы при вызове с C/C++, но ..C#/C++ Класс обратного вызова (не функция) Interop - howto?
- Я в C#.
- я называю C функция ++
- Я не могу изменить сигнатуру функции C++.
- Кроме того, я использую динамический метод р/вызова, а то статическая привязка (мой пример ниже);
Я могу обработать ситуацию, когда функция принимает простое значение или структуру, содержащую простые значения, и возвращает простые значения, но в этом случае у меня есть функция C, которая принимает объект обратного вызова.
Следуя некоторым идеям в Интернете, я попытался создать класс с той же подписью, а затем прикрепить этот класс и передать его., Но я получаю ошибку C#: «Object is not-Blittable» (который он не делает В нем нет переменных!).
Заголовочный файл:
снова извинения, если есть какие-либо ошибки в моем примере, я пытался раздеть все не соответствующий код и взрываются макросы, но я надеюсь, что вы понимаете суть того, что происходит
struct someData_t
{
int length; /**< JSON data length */
char* pData; /*< JSON data */
};
namespace FOO {
class ICallback
{
public: virtual ~ICallback() {}
virtual void Callback(const someData_t &response) = 0;
};
}
extern "C" __declspec(dllexport) void process(const someData_t *inData, FOO::ICallback *listener);
Мой C# файл:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace Scratchpad {
class Program {
static void Main(string[] args) {
Console.Out.WriteLine("I'm in Managed C#...");
IntPtr user32 = NativeMethods.LoadLibrary(@"somelongpath\my_c.dll");
IntPtr pAddressOfFunctionToCall = NativeMethods.GetProcAddress(user32, "process");
process proc = (process)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(process));
String someJson = "{ \"type\":\"someTestJson\"}";
byte[] rawdata = Encoding.UTF8.GetBytes(someJson);
someData myData = new someData();
int dataLength = rawdata.Length * Marshal.SizeOf(typeof(byte)); // I realise byte is size 1 but..
myData.length = rawdata.Length;
myData.pData = Marshal.AllocHGlobal(dataLength);
Marshal.Copy(rawdata, 0, myData.pData, dataLength);
Console.Out.WriteLine("Size of mydata: " + Marshal.SizeOf(myData));
IntPtr unmanagedADdr = Marshal.AllocHGlobal(Marshal.SizeOf(myData));
Marshal.StructureToPtr(myData, unmanagedADdr, true);
// ################################################################
// FIXME: This area still working
Callbacker myCallback = new Callbacker();
GCHandle gch = GCHandle.Alloc(myCallback, GCHandleType.Pinned);
IntPtr mycallbackPtr = gch.AddrOfPinnedObject();
// FIXME: close of working area.
// ################################################################
// CALL THE FUNCTION!
proc(unmanagedADdr, mycallbackPtr);
myData = (someData) Marshal.PtrToStructure(unmanagedADdr, typeof(someData));
Marshal.FreeHGlobal(unmanagedADdr);
Marshal.FreeHGlobal(myData.pData);
gch.Free();
unmanagedADdr = IntPtr.Zero;
bool result = NativeMethods.FreeLibrary(user32);
Console.Out.WriteLine("Fini!)");
}
private delegate void process(IntPtr data, IntPtr callback);
[StructLayout(LayoutKind.Sequential)]
private struct someData {
public int length;
public IntPtr pData;
}
private class Callbacker {
public void Callback(someData response) {
Console.WriteLine("callback Worked!!!");
}
}
}
static class NativeMethods {
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
}
Любые предложения приветствуются
Вы не можете передать указатель на управляемый класс здесь, потому что ваш управляемый класс Callbacker не реализует интерфейс FOO :: ICallback – AccessViolation