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

时间:2021-11-03 03:06:54

I'm trying to create a hook to monitor the current position of the mouse cursor. Nothing important, I just need to count some pixels during interface design and wanted to learn how to create a hook, so I decided to go for a hard way instead of a sane way.

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

I've found example code which declares the following function:

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

 <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

When the function is called, the following code is used:

调用该函数时,使用以下代码:

        hHook = SetWindowsHookEx(WH_MOUSE, _
                                 hookproc, _
                                 IntPtr.Zero, _
                                 AppDomain.GetCurrentThreadId())

But Appdomain.GetCurrentThreadID generates the warning: "'Public Shared Function GetCurrentThreadId() As Integer' is obsolete: 'AppDomain.GetCurrentThreadId has been deprecated because it does not provide a stable Id when managed threads are running on fibers (aka lightweight threads). To get a stable identifier for a managed thread, use the ManagedThreadId property on Thread."

但是Appdomain.GetCurrentThreadID生成警告:“'公共共享函数GetCurrentThreadId()As Integer'已过时:'AppDomain.GetCurrentThreadId已被弃用,因为当托管线程在光纤(也称为轻量级线程)上运行时,它不提供稳定的Id。要获取托管线程的稳定标识符,请使用Thread上的ManagedThreadId属性。“

I've tried using ManagedThreadID, but that doesn't work. The thread ID returned seems to be the logical thread ID of the thread, as it runs in the .net runtime, rather than the Win32 thread identifier.

我尝试过使用ManagedThreadID,但这不起作用。返回的线程ID似乎是线程的逻辑线程ID,因为它在.net运行时运行,而不是Win32线程标识符。

Calling the function ith AppDomain.GetCurrentThreadID works, but I really would like to have a "stable identifier" for my thread.

调用函数ith AppDomain.GetCurrentThreadID有效,但我真的想为我的线程提供一个“稳定的标识符”。

Can someone explain to me whether it is possible to use ManagedThreadID in this context (I assume not) and, if not, the things I need to avoid in order to stop the AppDomain.CurrentThreadID from becoming "unstable"?

有人可以向我解释是否可以在此上下文中使用ManagedThreadID(我假设不是),如果没有,我需要避免的事情是为了阻止AppDomain.CurrentThreadID变得“不稳定”?

Cheers

5 个解决方案

#1


14  

It is not possible to use ManagedThreadId in this context. This is a completely managed concept and has no real representation in the native world. Hence it doesn't make any sense to the API's you're passing it to.

在此上下文中无法使用ManagedThreadId。这是一个完全管理的概念,在本地世界中没有真正的代表。因此,对于您传递给它的API没有任何意义。

The reason ManagedThreadId exists is because there is not necessarily a 1-1 mapping between a native and managed thread. The CLR is free to use multiple native threads to run a single managed thread as long as the native thread is compatible with the one it's replacing. It cannot for instance, be in a different COM apartment.

ManagedThreadId存在的原因是因为本机和托管线程之间不一定存在1-1映射。只要本机线程与其替换的线程兼容,CLR就可以*地使用多个本机线程来运行单个托管线程。例如,它不能在不同的COM公寓中。

In some ways you're a bit stuck here. AFAIK, there is no way to 100% guarantee that you will have the same native thread for a given managed thread. You can achieve a very high level of guarantee though if you are for instance running a WinForms or WPF application and the call to native code occurs on the UI thread. The reason being that both of these UI frameworks live in STA apartments which makes it very hard (if even possible) for the CLR to switch out from under you.

在某些方面你有点卡在这里。 AFAIK,没有办法100%保证您将拥有给定托管线程的相同本机线程。如果您运行WinForms或WPF应用程序并且在UI线程上调用本机代码,则可以实现非常高级别的保证。原因是这两个UI框架都存在于STA公寓中,这使得CLR很难(如果可能的话)从你的下面切换出来。

Short Version: If you're in a WinForms or WPF application and running this on the UI thread, you can assume a reasonable level of stability for this identifier.

简短版本:如果您在WinForms或WPF应用程序中并在UI线程上运行它,则可以为此标识符提供合理的稳定性级别。

#2


3  

For future readers: There are also System.Threading.Thread.BeginThreadAffinity() / EndThreadAffinity() functions that purportedly stop the VM from switching between different physical threads. I don't believe these guarantee stability, but I think they're more likely to be stable.

对于未来的读者:还有System.Threading.Thread.BeginThreadAffinity()/ EndThreadAffinity()函数,据称阻止VM在不同的物理线程之间切换。我不相信这些保证稳定性,但我认为它们更有可能保持稳定。

#3


3  

You could use:

你可以使用:

using System.Diagnostics;
Process.GetCurrentProcess().Threads[0].Id

instead of

AppDomain.GetCurrentThreadId()

The problem is only to find the correct number of the thread if you have more threads than the main thread 0 running.

问题是只有找到正确的线程数,如果你有比正在运行的主线程0更多的线程。

#4


3  

var thread = Process.GetCurrentProcess().Threads.OfType<ProcessThread>().
    SingleOrDefault(x => x.ThreadState == ThreadState.Running);

if (thread != null)
{
    // do stuff here
}

#5


1  

use:

[DllImport("kernel32.dll")] static extern uint GetCurrentThreadId();

[DllImport(“kernel32.dll”)] static extern uint GetCurrentThreadId();

#1


14  

It is not possible to use ManagedThreadId in this context. This is a completely managed concept and has no real representation in the native world. Hence it doesn't make any sense to the API's you're passing it to.

在此上下文中无法使用ManagedThreadId。这是一个完全管理的概念,在本地世界中没有真正的代表。因此,对于您传递给它的API没有任何意义。

The reason ManagedThreadId exists is because there is not necessarily a 1-1 mapping between a native and managed thread. The CLR is free to use multiple native threads to run a single managed thread as long as the native thread is compatible with the one it's replacing. It cannot for instance, be in a different COM apartment.

ManagedThreadId存在的原因是因为本机和托管线程之间不一定存在1-1映射。只要本机线程与其替换的线程兼容,CLR就可以*地使用多个本机线程来运行单个托管线程。例如,它不能在不同的COM公寓中。

In some ways you're a bit stuck here. AFAIK, there is no way to 100% guarantee that you will have the same native thread for a given managed thread. You can achieve a very high level of guarantee though if you are for instance running a WinForms or WPF application and the call to native code occurs on the UI thread. The reason being that both of these UI frameworks live in STA apartments which makes it very hard (if even possible) for the CLR to switch out from under you.

在某些方面你有点卡在这里。 AFAIK,没有办法100%保证您将拥有给定托管线程的相同本机线程。如果您运行WinForms或WPF应用程序并且在UI线程上调用本机代码,则可以实现非常高级别的保证。原因是这两个UI框架都存在于STA公寓中,这使得CLR很难(如果可能的话)从你的下面切换出来。

Short Version: If you're in a WinForms or WPF application and running this on the UI thread, you can assume a reasonable level of stability for this identifier.

简短版本:如果您在WinForms或WPF应用程序中并在UI线程上运行它,则可以为此标识符提供合理的稳定性级别。

#2


3  

For future readers: There are also System.Threading.Thread.BeginThreadAffinity() / EndThreadAffinity() functions that purportedly stop the VM from switching between different physical threads. I don't believe these guarantee stability, but I think they're more likely to be stable.

对于未来的读者:还有System.Threading.Thread.BeginThreadAffinity()/ EndThreadAffinity()函数,据称阻止VM在不同的物理线程之间切换。我不相信这些保证稳定性,但我认为它们更有可能保持稳定。

#3


3  

You could use:

你可以使用:

using System.Diagnostics;
Process.GetCurrentProcess().Threads[0].Id

instead of

AppDomain.GetCurrentThreadId()

The problem is only to find the correct number of the thread if you have more threads than the main thread 0 running.

问题是只有找到正确的线程数,如果你有比正在运行的主线程0更多的线程。

#4


3  

var thread = Process.GetCurrentProcess().Threads.OfType<ProcessThread>().
    SingleOrDefault(x => x.ThreadState == ThreadState.Running);

if (thread != null)
{
    // do stuff here
}

#5


1  

use:

[DllImport("kernel32.dll")] static extern uint GetCurrentThreadId();

[DllImport(“kernel32.dll”)] static extern uint GetCurrentThreadId();