通过来自 c# net core 的非托管 c++ dll 订阅 windows 消息
Subscribing to windows messages through unmanaged c++ dll from c# net core
我正在尝试使用 pinvoke 通过 unamanged c++ dll 从 c# net core 订阅 windows 消息 events/messaging 系统。
我遇到的问题。
获取我的进程的句柄或创建一个空的 window(.net 是否支持)。
var hwnd = Process.GetCurrentProcess().Handle;
var hwnd1 = Process.GetCurrentProcess().Handle.ToPointer();
其中任何一个都可以有效获取句柄。
如何将该句柄编组为 C++ HWND
类型。 IntPtr
似乎是显而易见的选择,但它行不通。
这是我用来订阅事件的内容
public class MsgSubscribe : IDisposable
{
private readonly Importer _importer;
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate Status DMsgSubscribe(uint msgType, uint msgQ, int hwnd, uint msgId);
private static DMsgSubscribe _dMsgSubscribe;
private IntPtr PMsgSubscribe { get; set; }
public bool Available { get; set; }
public MsgSubscribe(Importer importer)
{
_importer = importer;
if (_importer.hCurModule != IntPtr.Zero)
{
PMsgSubscribe = Importer.GetProcAddress(_importer.hCurModule, "MsgSubscribe");
Available = PUlyMsgSubscribe != IntPtr.Zero;
}
}
public Status MsgSubscribe(uint msgType, uint msgQ, int hwnd, uint msgId)
{
Status result = Status.FunctionNotAvailable;
if (Available)
{
_dMsgSubscribe = (DMsgSubscribe)Marshal.GetDelegateForFunctionPointer(PMsgSubscribe, typeof(DMsgSubscribe));
result = _dMsgSubscribe(msgType, msgQ, hwnd, msgId);
}
return result;
}
public void Dispose()
{
}
}
我已尝试 IntPtr
和 int
进行 HWND
编组,但均无效。
此外,我不确定我应该如何捕获 window 基于消息的事件,如果有的话,在线的很少。
感谢任何帮助。
通常使用 IntPtr 是正确的。
Handle()
Returns 这样一个 IntPtr.
您似乎正在尝试使用您的进程 HWND 来获取 window 消息,这将不起作用,因为您必须使用 window HWND 来获取与该 HWND 关联的消息.
最终找到了使这项工作可行的方法,它涉及通过 C++ pinvoke 创建 window。
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Constants.Constants;
using Constants.Enums;
using Models.WindowsApiModels;
namespace Dependencies.MessagingHandling
{
public class CustomWindow : IDisposable
{
delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
private const int ErrorClassAlreadyExists = 1410;
public IntPtr Handle { get; private set; }
public List<YourType> Messages { get; set; }
public void Dispose()
{
if (Handle != IntPtr.Zero)
{
Importer.DestroyWindow(Handle);
Handle = IntPtr.Zero;
}
}
public CustomWindow()
{
Messages = new List<YourType>();
var className = "Prototype Messaging Class";
WndProc mWndProcDelegate = CustomWndProc;
// Create WNDCLASS
WNDCLASS windClass = new WNDCLASS
{
lpszClassName = className,
lpfnWndProc = Marshal.GetFunctionPointerForDelegate(mWndProcDelegate)
};
UInt16 classAtom = Importer.RegisterClassW(ref windClass);
int lastError = Marshal.GetLastWin32Error();
if (classAtom == 0 && lastError != ErrorClassAlreadyExists)
{
throw new Exception("Could not register window class");
}
// Create window
Handle = Importer.CreateWindowExW(
0,
className,
"Prototype Messaging Window",
0, 0, 0, 0, 0,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero
);
}
private IntPtr CustomWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
//handle your message here
return Importer.DefWindowProc(hWnd, msg, wParam, lParam);
}
public Task GetMessage()
{
IntPtr handle = Handle;
int bRet;
while ((bRet = Importer.GetMessage(out var msg, Handle, 0, 0)) != 0)
{
switch (bRet)
{
case -1:
Console.WriteLine("Error");
CancellationToken token = new CancellationToken(true);
return Task.FromCanceled(token);
default:
Importer.TranslateMessage(ref msg);
Importer.DispatchMessage(ref msg);
break;
}
}
return Task.FromResult(true);
}
}
}
运行 在主线程中的 main 方法中,在辅助线程中 menu/gui
Task.Run(ShowMenu);
_customWindow.GetMessage();
导入器是自定义的 class,包含 create/handle window 的 c++ 编组函数,请按名称查找,因为它们是相同的。所有 CAPS class/struct 都是 windows/c++ api 结构,这些可以在官方 msdn 上找到。
我正在尝试使用 pinvoke 通过 unamanged c++ dll 从 c# net core 订阅 windows 消息 events/messaging 系统。
我遇到的问题。
获取我的进程的句柄或创建一个空的 window(.net 是否支持)。
var hwnd = Process.GetCurrentProcess().Handle;
var hwnd1 = Process.GetCurrentProcess().Handle.ToPointer();
其中任何一个都可以有效获取句柄。
如何将该句柄编组为 C++ HWND
类型。 IntPtr
似乎是显而易见的选择,但它行不通。
这是我用来订阅事件的内容
public class MsgSubscribe : IDisposable
{
private readonly Importer _importer;
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate Status DMsgSubscribe(uint msgType, uint msgQ, int hwnd, uint msgId);
private static DMsgSubscribe _dMsgSubscribe;
private IntPtr PMsgSubscribe { get; set; }
public bool Available { get; set; }
public MsgSubscribe(Importer importer)
{
_importer = importer;
if (_importer.hCurModule != IntPtr.Zero)
{
PMsgSubscribe = Importer.GetProcAddress(_importer.hCurModule, "MsgSubscribe");
Available = PUlyMsgSubscribe != IntPtr.Zero;
}
}
public Status MsgSubscribe(uint msgType, uint msgQ, int hwnd, uint msgId)
{
Status result = Status.FunctionNotAvailable;
if (Available)
{
_dMsgSubscribe = (DMsgSubscribe)Marshal.GetDelegateForFunctionPointer(PMsgSubscribe, typeof(DMsgSubscribe));
result = _dMsgSubscribe(msgType, msgQ, hwnd, msgId);
}
return result;
}
public void Dispose()
{
}
}
我已尝试 IntPtr
和 int
进行 HWND
编组,但均无效。
此外,我不确定我应该如何捕获 window 基于消息的事件,如果有的话,在线的很少。
感谢任何帮助。
通常使用 IntPtr 是正确的。
Handle()
Returns 这样一个 IntPtr.
您似乎正在尝试使用您的进程 HWND 来获取 window 消息,这将不起作用,因为您必须使用 window HWND 来获取与该 HWND 关联的消息.
最终找到了使这项工作可行的方法,它涉及通过 C++ pinvoke 创建 window。
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Constants.Constants;
using Constants.Enums;
using Models.WindowsApiModels;
namespace Dependencies.MessagingHandling
{
public class CustomWindow : IDisposable
{
delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
private const int ErrorClassAlreadyExists = 1410;
public IntPtr Handle { get; private set; }
public List<YourType> Messages { get; set; }
public void Dispose()
{
if (Handle != IntPtr.Zero)
{
Importer.DestroyWindow(Handle);
Handle = IntPtr.Zero;
}
}
public CustomWindow()
{
Messages = new List<YourType>();
var className = "Prototype Messaging Class";
WndProc mWndProcDelegate = CustomWndProc;
// Create WNDCLASS
WNDCLASS windClass = new WNDCLASS
{
lpszClassName = className,
lpfnWndProc = Marshal.GetFunctionPointerForDelegate(mWndProcDelegate)
};
UInt16 classAtom = Importer.RegisterClassW(ref windClass);
int lastError = Marshal.GetLastWin32Error();
if (classAtom == 0 && lastError != ErrorClassAlreadyExists)
{
throw new Exception("Could not register window class");
}
// Create window
Handle = Importer.CreateWindowExW(
0,
className,
"Prototype Messaging Window",
0, 0, 0, 0, 0,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero
);
}
private IntPtr CustomWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
//handle your message here
return Importer.DefWindowProc(hWnd, msg, wParam, lParam);
}
public Task GetMessage()
{
IntPtr handle = Handle;
int bRet;
while ((bRet = Importer.GetMessage(out var msg, Handle, 0, 0)) != 0)
{
switch (bRet)
{
case -1:
Console.WriteLine("Error");
CancellationToken token = new CancellationToken(true);
return Task.FromCanceled(token);
default:
Importer.TranslateMessage(ref msg);
Importer.DispatchMessage(ref msg);
break;
}
}
return Task.FromResult(true);
}
}
}
运行 在主线程中的 main 方法中,在辅助线程中 menu/gui
Task.Run(ShowMenu);
_customWindow.GetMessage();
导入器是自定义的 class,包含 create/handle window 的 c++ 编组函数,请按名称查找,因为它们是相同的。所有 CAPS class/struct 都是 windows/c++ api 结构,这些可以在官方 msdn 上找到。