gpt4 book ai didi

C#/C++ 回调类(非函数)Interop - 操作方法?

转载 作者:太空狗 更新时间:2023-10-29 21:39:55 25 4
gpt4 key购买 nike

如果有重复,我深表歉意 - 我一直在努力寻找答案(我发现了一些关于使用函数回调的 C++ 函数的问题,以及一些在从 C/C++ 调用时使用类作为回调的答案,但是..

  • 我在 C# 中。
  • 我正在调用 C++ 函数
  • 我无法更改 C++ 函数的签名。
  • 此外,我正在使用 p/invoke 的动态方法而不是静态绑定(bind)(我在下面的示例);

我可以处理函数采用简单值或包含简单值的结构并返回简单值的情况,但在这种情况下,我有一个采用回调对象的 C 函数。

根据网上的一些想法,我尝试制作一个具有相同签名的类,然后固定该类,并将其传入。但我得到了 C# 错误“Object is non-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);
}
}

欢迎提出建议

最佳答案

您可以为实现ICallback 接口(interface)的托管Callbacker 类创建一些非托管包装器。像这样:

typedef void (*PointerToManagedFunctionToInvoke)(const someData_t&);

class UnmanagedDelegate : public FOO::ICallback {
private:
PointerToManagedFunctionToInvoke managedCallback;
public:
UnmanagedDelegate(PointerToManagedFunctionToInvoke inManagedCallback)
: managedCallback(inManagedCallback) {}

virtual void Callback(const someData_t &response)
{
managedCallback(response);
}
};

// Export this to managed part
UnmanagedDelegate* CreateUnmanagedDelegate(PointerToManagedFunctionToInvoke inManagedCallback)
{
return new UnmanagedDelegate(inManagedCallback);
}

然后在 C# 部分,您可以创建一个委托(delegate)以编码(marshal)为 PointerToManagedFunctionToInvoke,将其传递给 CreateUnmanagedDelegate 接收 ICallback 的非托管实现并使用它传递给您的进程

请注意,当 UnmanagedDelegate 类对象处于事件状态时,managedCallback 应保持分配在 C# 端。当不再使用 UnmanagedDelegate 对象时,您应该将其删除。

或者您可以使用瘦 C++/CLI 来实现此包装器。

关于C#/C++ 回调类(非函数)Interop - 操作方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31873568/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com