我正在尝试创建一个钩子来监视鼠标光标的当前位置。没什么重要的,我只需要在界面设计中计算一些像素,并想学习如何创建一个钩子,所以我决定采用一种艰难的方式而不是一种理智的方式。
我找到了声明以下函数的示例代码:
<DllImport("User32.dll", CharSet:=CharSet.Auto, _
CallingConvention:=CallingConvention.StdCall)> _
Public Overloads Shared Function SetWindowsHookEx _
(ByVal idHook As Integer, ByVal HookProc As CallBack, _
ByVal hInstance As IntPtr, ByVal wParam As Integer) As Integer
End Function
调用该函数时,使用以下代码:
hHook = SetWindowsHookEx(WH_MOUSE, _
hookproc, _
IntPtr.Zero, _
AppDomain.GetCurrentThreadId())
但Appdomain.GetCurrentThreadID生成警告:“'公共共享函数GetCurrentThreadId()As Integer'已过时:'AppDomain.GetCurrentThreadId已被弃用,因为当托管线程在光纤上运行时,它不提供稳定的Id(也称为轻量级)要获得托管线程的稳定标识符,请使用Thread上的ManagedThreadId属性。“
我尝试过使用ManagedThreadID,但这不起作用。返回的线程ID似乎是线程的逻辑线程ID,因为它在.net运行时运行,而不是Win32线程标识符。
调用函数ith AppDomain.GetCurrentThreadID有效,但我真的想为我的线程提供一个“稳定标识符”。
有人可以向我解释是否可以在此上下文中使用ManagedThreadID(我假设不是),如果没有,我需要避免的事情是为了阻止AppDomain.CurrentThreadID变得“不稳定”?
干杯
答案 0 :(得分:14)
在此上下文中无法使用ManagedThreadId。这是一个完全管理的概念,在本地世界中没有真正的代表。因此,对你传递给它的API没有任何意义。
ManagedThreadId存在的原因是因为本机和托管线程之间不一定存在1-1映射。只要本机线程与其替换的线程兼容,CLR就可以自由地使用多个本机线程来运行单个托管线程。例如,它不能在不同的COM公寓中。
在某些方面,你有点卡在这里。 AFAIK,没有办法100%保证您将为给定的托管线程拥有相同的本机线程。如果您运行WinForms或WPF应用程序并且在UI线程上调用本机代码,则可以实现非常高级别的保证。原因是这两个UI框架都存在于STA公寓中,这使得CLR很难(如果可能的话)从你的下面切换出来。
简短版本:如果您在WinForms或WPF应用程序中并在UI线程上运行它,则可以假定此标识符具有合理的稳定性级别。
答案 1 :(得分:3)
对于未来的读者: 还有System.Threading.Thread.BeginThreadAffinity()/ EndThreadAffinity()函数,据称阻止VM在不同的物理线程之间切换。我不相信这些保证稳定性,但我认为它们更有可能保持稳定。
答案 2 :(得分:3)
您可以使用:
using System.Diagnostics;
Process.GetCurrentProcess().Threads[0].Id
而不是
AppDomain.GetCurrentThreadId()
如果线程数多于主线程0运行的话,问题只是找到正确的线程数。
答案 3 :(得分:3)
var thread = Process.GetCurrentProcess().Threads.OfType<ProcessThread>().
SingleOrDefault(x => x.ThreadState == ThreadState.Running);
if (thread != null)
{
// do stuff here
}
答案 4 :(得分:1)
使用:
[的DllImport( “KERNEL32.DLL”)] static extern uint GetCurrentThreadId();