用于Windows API调用的AppDomain.GetCurrentThreadID vs Thread.ManagedThreadID?

时间:2009-04-21 12:37:03

标签: .net vb.net winapi

我正在尝试创建一个钩子来监视鼠标光标的当前位置。没什么重要的,我只需要在界面设计中计算一些像素,并想学习如何创建一个钩子,所以我决定采用一种艰难的方式而不是一种理智的方式。

我找到了声明以下函数的示例代码:

 <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变得“不稳定”?

干杯

5 个答案:

答案 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();