【发布时间】:2018-04-30 01:57:49
【问题描述】:
出于调试目的,我正在迭代我自己的应用程序的线程,并尝试报告线程时间(寻找流氓线程)。当我迭代线程时,如果threadId = GetCurrentThreadId,我会被拒绝访问。
这是一个演示问题的代码示例(delphi):
program Project9;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows, System.SysUtils, TlHelp32;
type
TOpenThreadFunc = function(DesiredAccess: DWORD; InheritHandle: BOOL; ThreadID: DWORD): THandle; stdcall;
var
OpenThreadFunc: TOpenThreadFunc;
function OpenThread(id : DWORD) : THandle;
const
THREAD_GET_CONTEXT = $0008;
THREAD_QUERY_INFORMATION = $0040;
var
Kernel32Lib, ThreadHandle: THandle;
begin
Result := 0;
if @OpenThreadFunc = nil then
begin
Kernel32Lib := GetModuleHandle(kernel32);
OpenThreadFunc := GetProcAddress(Kernel32Lib, 'OpenThread');
end;
result := OpenThreadFunc(THREAD_QUERY_INFORMATION, False, id);
end;
procedure dumpThreads;
var
SnapProcHandle: THandle;
NextProc : Boolean;
TThreadEntry : TThreadEntry32;
Proceed : Boolean;
pid, tid : Cardinal;
h : THandle;
begin
pid := GetCurrentProcessId;
tid := GetCurrentThreadId;
SnapProcHandle := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); //Takes a snapshot of the all threads
Proceed := (SnapProcHandle <> INVALID_HANDLE_VALUE);
if Proceed then
try
TThreadEntry.dwSize := SizeOf(TThreadEntry);
NextProc := Thread32First(SnapProcHandle, TThreadEntry);//get the first Thread
while NextProc do
begin
if TThreadEntry.th32OwnerProcessID = PID then //Check the owner Pid against the PID requested
begin
write('Thread '+inttostr(TThreadEntry.th32ThreadID));
if (tid = TThreadEntry.th32ThreadID) then
write(' (this thread)');
h := OpenThread(TThreadEntry.th32ThreadID);
if h <> 0 then
try
writeln(': open ok');
finally
CloseHandle(h);
end
else
writeln(': '+SysErrorMessage(GetLastError));
end;
NextProc := Thread32Next(SnapProcHandle, TThreadEntry);//get the Next Thread
end;
finally
CloseHandle(SnapProcHandle);//Close the Handle
end;
end;
function DebugCtrlC(dwCtrlType : DWORD) :BOOL;
begin
writeln('ctrl-c');
dumpThreads;
end;
var
s : String;
begin
SetConsoleCtrlHandler(@DebugCtrlC, true);
try
writeln('enter anything to see threads, ''x'' to exit. or press ctrl-c to see threads');
repeat
readln(s);
if s <> '' then
dumpThreads;
until s = 'x';
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
当我按下 ctrl-c 时,我被拒绝访问该线程 - 为什么线程不能获得自身的句柄,但它可以用于进程中的所有其他线程?
【问题讨论】:
-
通常一个线程使用 DuplicateHandle 获得一个自己的句柄 - 如果需要一个真正的句柄。如果没有,GetCurrentThread。顺便说一句,“windows.OpenThread”有什么问题?
-
这里有很多代码,比必要的要多得多。需要minimal reproducible example。因为你声称是真实的东西不容易被复制。 idownvotedbecau.se/nomcve
-
@RbMm 如果您使用 cmets 中的信息和答案,您可以复制。但不在问题中。您必须了解 SO 不是针对提问者的临时问题解决服务,而是问答主题的资源。一旦提供了minimal reproducible example,这是一个很好的问题,但就目前而言,它对未来的访问者没有用处。
-
@DavidHeffernan - 是的,基于从
ctrl+c处理程序调用的代码中的答案信息。当然需要重写问题。不需要任何CreateToolhelp32Snapshot等。只需从HandlerRoutine调用SetConsoleCtrlHandler(HandlerRoutine, TRUE);和OpenThread(THREAD_QUERY_INFORMATION, FALSE, GetCurrentThreadId());。但真正有趣的是这个新创建的线程 (CtrlRoutine) 具有系统完整性级别,这会阻止该线程打开 -
@SertacAkyuz - 很有趣,但你从一开始就更正了 -
DuplicateHandle对于当前线程总是可以的,尽管当OpenThread可能失败时,尽管线程 SD、令牌等。即使在致电ZwImpersonateAnonymousToken(GetCurrentThread())之后 -DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hThread, 0, 0, DUPLICATE_SAME_ACCESS);也可以
标签: multithreading delphi winapi