AppDomain.GetCurrentThreadID vs Thread.ManagedThreadID для вызовов Windows API?
Я пытаюсь создать крючок для контроля текущей позиции курсора мыши. Ничего важного, мне просто нужно подсчитать некоторые пиксели во время разработки интерфейса и захотелось узнать, как создать крючок, поэтому я решил пойти нелегко, вместо разумного способа.
Я нашел пример кода, который объявляет следующую функцию:
<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 устарел, потому что он не обеспечивает стабильный идентификатор, когда управляемые потоки работают на волокнах (также известный как легкий потоки). Чтобы получить стабильный идентификатор управляемого потока, используйте свойство ManagedThreadId для Thread. "
Я пытался использовать ManagedThreadID, но это не работает. Идентификатор потока, как представляется, является логическим идентификатором потока потока, поскольку он работает в среде .net, а не в идентификаторе потока Win32.
Вызов функции с AppDomain.GetCurrentThreadID работает, но я действительно хотел бы иметь "стабильный идентификатор" для моего потока.
Может кто-нибудь объяснить мне, можно ли использовать ManagedThreadID в этом контексте (я предполагаю, что нет) и, если нет, то, что мне нужно избегать, чтобы остановить AppDomain.CurrentThreadID, стать неустойчивым?
Приветствия
Ответы
Ответ 1
В этом контексте невозможно использовать ManagedThreadId. Это полностью управляемая концепция и не имеет реального представительства в родном мире. Следовательно, это не имеет никакого смысла для API, к которому вы его передаете.
Причина, по которой ManagedThreadId существует, заключается в том, что не обязательно сопоставление 1-1 между нативным и управляемым потоками. CLR может использовать несколько собственных потоков для запуска одного управляемого потока, если родной поток совместим с тем, который он заменяет. Он не может, например, находиться в другой квартире COM.
В некотором смысле вы немного застряли здесь. AFAIK, нет возможности гарантировать 100%, что у вас будет тот же собственный поток для данного управляемого потока. Вы можете достичь очень высокого уровня гарантии, хотя, например, если вы используете WinForms или приложение WPF, а вызов собственного кода происходит в потоке пользовательского интерфейса. Причина в том, что обе эти структуры пользовательского интерфейса живут в квартирах STA, что делает его очень трудным (если вообще возможно) для CLR переключаться из-под вас.
Краткая версия. Если вы работаете в WinForms или WPF-приложении и запускаете это в потоке пользовательского интерфейса, вы можете предположить приемлемый уровень стабильности для этого идентификатора.
Ответ 2
Для будущих читателей:
Существуют также функции System.Threading.Thread.BeginThreadAffinity()/EndThreadAffinity(), которые якобы останавливают виртуальную машину от переключения между различными физическими потоками. Я не верю, что эти гарантии стабильности, но я думаю, что они, скорее всего, будут стабильными.
Ответ 3
Вы можете использовать:
using System.Diagnostics;
Process.GetCurrentProcess().Threads[0].Id
вместо
AppDomain.GetCurrentThreadId()
Проблема заключается только в том, чтобы найти правильный номер потока, если у вас больше потоков, чем запущен основной поток.
Ответ 4
var thread = Process.GetCurrentProcess().Threads.OfType<ProcessThread>().
SingleOrDefault(x => x.ThreadState == ThreadState.Running);
if (thread != null)
{
// do stuff here
}
Ответ 5
использование:
[DllImport ( "kernel32.dll" )]
static extern uint GetCurrentThreadId();