gpt4 book ai didi

c# - C# 回调函数不是从 C++ 代码调用的

转载 作者:行者123 更新时间:2023-12-02 10:28:14 25 4
gpt4 key购买 nike

我需要通过我的 C# 代码与程序通信。我从制作该程序的公司那里收到了一个通信库,以及关于如何与应用程序集成的非常详细的解释。我觉得我做的一切都正确,C++ 函数都返回成功状态,但最重要的部分,回调函数,从未被调用。
我无法使用 [DllImport(...)] ,我得用LoadLibrary , GetProcAddressMarshal.GetDelegateForFunctionPointer将库加载到内存中并调用它的函数。这是我在内存中保留库的一个实例,以便它记住回调函数。这是因为回调函数被注册,然后被后续请求用来传递附加信息。
我保留对回调函数的引用,因此 GC 不会收集它,并且它不可用于 C++ 代码。
当我等待回调时,什么也没有发生。我没有收到错误,我没有看到任何具体的事情发生,它只是让我永远等待。回调不会发生。
我希望有人能告诉我我错过了什么,因为我再也看不到解决方案了。

class Program
{
private static Callback keepAlive;
static void Main(string[] args)
{
try
{
var comLib = LoadLibrary(@"C:\BIN\ComLib.dll");

var isInstalledHandle = GetProcAddress(comLib, nameof(IsInstalled));
var isInstalled = Marshal.GetDelegateForFunctionPointer<IsInstalled>(isInstalledHandle);
var isInstalledResult = isInstalled("activation-key"); // returns success
Console.WriteLine("Is installed result: " + isInstalledResult);

var registerCallbackHandle = GetProcAddress(comLib, nameof(RegisterCallback));
var registerCallback = Marshal.GetDelegateForFunctionPointer<RegisterCallback>(registerCallbackHandle);
keepAlive = CallbackFunc;
var registerResult = registerCallback(keepAlive); // returns success
Console.WriteLine("Register result: " + registerResult);

var initHandle = GetProcAddress(comLib, nameof(Init));
var init = Marshal.GetDelegateForFunctionPointer<Init>(initHandle);
var initResult = init("ERP_INTEGRATION", "activation-key"); // returns success
Console.WriteLine("Init result: " + initResult);

Console.WriteLine("Wait...");
Console.ReadLine();

FreeLibrary(comLib);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}

private static int CallbackFunc(int id, string data)
{
Console.WriteLine($"{id} > {data}");
return 0;
}

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int IsInstalled(string registryKey);

private delegate int Callback(int id, string data);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int RegisterCallback(Callback callback);

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int Init(string id, string command);

[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);

[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string lpProcName);

[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern bool FreeLibrary(IntPtr hModule);
}
编辑 1:我从软件开发人员那里回来了。显然,因为我在主线程上做所有的工作,应用程序不能回调,因为线程很忙。我应该将应用程序(和回调方法)卸载到另一个线程,以便应用程序可以自由调用回调函数。不幸的是,我不知道如何做到这一点。
编辑 2:根据要求,我将代码放在 WinForms 应用程序中,回调在那里运行良好。我不完全理解为什么,除了回调必须在 a) 主线程空闲(等待来自表单的输入)或 b) 将回调卸载到另一个线程时发生。我不知道如何在控制台应用程序中进行模拟。

最佳答案

我找到了一个有点笨拙的答案,但它有效。我将控制台应用程序转换为 WinForms 应用程序。这使我可以访问 System.Windows.Forms.Application.DoEvents .这让我可以启动一个 Task它会耗尽进程并不断刷新需要处理的事件。这允许外部程序调用回调函数。

private bool _callbackOccured = false;
static async Task Main(string[] args)
{
try
{
var comLib = LoadLibrary(@"C:\BIN\ComLib.dll");

await Task.Run(async () => {
var isInstalledHandle = GetProcAddress(comLib, nameof(IsInstalled));
var isInstalled = Marshal.GetDelegateForFunctionPointer<IsInstalled>(isInstalledHandle);
var isInstalledResult = isInstalled("activation-key"); // returns success
Console.WriteLine("Is installed result: " + isInstalledResult);

var registerCallbackHandle = GetProcAddress(comLib, nameof(RegisterCallback));
var registerCallback = Marshal.GetDelegateForFunctionPointer<RegisterCallback>(registerCallbackHandle);
keepAlive = CallbackFunc;
var registerResult = registerCallback(keepAlive); // returns success
Console.WriteLine("Register result: " + registerResult);

var initHandle = GetProcAddress(comLib, nameof(Init));
var init = Marshal.GetDelegateForFunctionPointer<Init>(initHandle);
var initResult = init("ERP_INTEGRATION", "activation-key"); // returns success
Console.WriteLine("Init result: " + initResult);

while (!_callbackOccured)
{
await Task.Delay(100);
Appliction.DoEvents();
}

FreeLibrary(comLib);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}

private static int CallbackFunc(int id, string data)
{
Console.WriteLine($"{id} > {data}");
_callbackOccured = true;
return 0;
}
编辑 :它不能完全与 Task.Run 一起使用, 我不得不使用一个实际的 Thread.Start使其正常工作。一个 Task被杀得太快了,我仍然遇到同样的问题,即外部应用程序在它开始做任何有用的事情之前就被关闭了,但是有一个 Thread它按预期工作。

关于c# - C# 回调函数不是从 C++ 代码调用的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63409981/

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