При разработке приложений на Delphi иногда возникают проблемы с доступом к информации о потоках, особенно в контексте отладки и мониторинга. Одна из таких проблем связана с получением доступа к данным о потоках в рамках собственного приложения.
Проблема
При попытке итерации по потокам собственного приложения для отладки и поиска "rogue" потоков, возникает ошибка доступа, если threadId = GetCurrentThreadId(). Это происходит из-за попытки открыть поток с помощью OpenThread, что приводит к ERROR_ACCESS_DENIED.
Пример кода
Вот пример кода, демонстрирующего проблему:
program Project9;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows, System.SysUtils, TlHelp32;
type
TOpenThreadFunc = function(DesiredAccess: DWORD; InheritHandle: BOOL; ThreadID: DWORD): THandle; stdcall;
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, h: THandle;
TThreadEntry: TThreadEntry32;
NextProc: Boolean;
pid, tid: Cardinal;
begin
pid := GetCurrentProcessId;
tid := GetCurrentThreadId;
SnapProcHandle := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if SnapProcHandle <> INVALID_HANDLE_VALUE then
try
TThreadEntry.dwSize := SizeOf(TThreadEntry);
NextProc := Thread32First(SnapProcHandle, TThreadEntry);
while NextProc do
begin
if TThreadEntry.th32OwnerProcessID = pid then
begin
if TThreadEntry.th32ThreadID = tid then
begin
h := OpenThread(THREAD_GET_CONTEXT or THREAD_QUERY_INFORMATION, False, tid);
if h <> 0 then
CloseHandle(h)
else
writeln('Access denied: ' + SysErrorMessage(GetLastError));
end;
end;
NextProc := Thread32Next(SnapProcHandle, TThreadEntry);
end;
finally
CloseHandle(SnapProcHandle);
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. Такой поток имеет уровень системного обязательного уровня безопасности (System Mandatory Level), который не позволяет открывать поток с правами чтения или записи.
Решение
Для решения этой проблемы можно использовать функцию GetCurrentThread(), которая возвращает псевдо-десриптор текущего потока, доступный с полными правами. Также можно использовать DuplicateHandle для получения дескриптора текущего потока с теми же правами доступа.
Альтернативные решения
Использовать инструменты, такие как Process Explorer от Sysinternals, для просмотра информации о потоках без написания собственного кода.
В случае, если приложение должно работать в фоновом режиме на сервере, можно настроить логирование информации о потоках и анализировать его позже.
Итог
Для успешной работы с потоками в Delphi важно понимать особенности доступа к информации о потоках, особенно в контексте системного уровня безопасности. Использование псевдо-десриптора GetCurrentThread() и DuplicateHandle позволяет избежать проблем с доступом к информации о текущем потоке.
В контексте разработки на Delphi рассматривается проблема доступа к информации о потоках, связанная с получением доступа к данным о потоках в рамках собственного приложения, что может быть особенно актуально при отладке и мониторинге.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.