187 lines
6.6 KiB
ObjectPascal
187 lines
6.6 KiB
ObjectPascal
{******************************************************************************}
|
|
{ }
|
|
{ Project JEDI Code Library (JCL) extension }
|
|
{ }
|
|
{ The contents of this file are subject to the Mozilla Public License Version }
|
|
{ 1.0 (the "License"); you may not use this file except in compliance with the }
|
|
{ License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ }
|
|
{ }
|
|
{ Software distributed under the License is distributed on an "AS IS" basis, }
|
|
{ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for }
|
|
{ the specific language governing rights and limitations under the License. }
|
|
{ }
|
|
{ The Original Code is JclDebugThread.pas. }
|
|
{ }
|
|
{ The Initial Developer of the Original Code is documented in the accompanying }
|
|
{ help file JCL.chm. Portions created by these individuals are Copyright (C) }
|
|
{ of these individuals. }
|
|
{ }
|
|
{ Last modified: July 16, 2001 }
|
|
{ }
|
|
{******************************************************************************}
|
|
|
|
unit JclDebugThread;
|
|
|
|
{$I jcl.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Classes, SysUtils;
|
|
|
|
procedure RegisterThread(ThreadID: DWORD; const ThreadName: string); overload;
|
|
procedure RegisterThread(Thread: TThread; const ThreadName: string; IncludeClassName: Boolean = True); overload;
|
|
|
|
procedure UnregisterThread(ThreadID: DWORD); overload;
|
|
procedure UnregisterThread(Thread: TThread); overload;
|
|
|
|
procedure ChangeThreadName(ThreadID: DWORD; const ThreadName: string); overload;
|
|
procedure ChangeThreadName(Thread: TThread; const ThreadName: string; IncludeClassName: Boolean = True); overload;
|
|
|
|
function ThreadNamesAvailable: Boolean;
|
|
|
|
implementation
|
|
|
|
uses
|
|
JclDebug, JclPeImage, JclSysUtils,
|
|
ThreadExpertSharedNames;
|
|
|
|
type
|
|
PThreadRec = ^TThreadRec;
|
|
TThreadRec = record
|
|
Func: TThreadFunc;
|
|
Parameter: Pointer;
|
|
end;
|
|
|
|
TJclDebugThreadNotifier = class(TObject)
|
|
public
|
|
procedure ThreadRegistered(ThreadID: DWORD);
|
|
end;
|
|
|
|
var
|
|
SharedThreadNames: TSharedThreadNames;
|
|
HookImports: TJclPeMapImgHooks;
|
|
Notifier: TJclDebugThreadNotifier;
|
|
Kernel32_CreateThread: function (lpThreadAttributes: Pointer;
|
|
dwStackSize: DWORD; lpStartAddress: TFNThreadStartRoutine;
|
|
lpParameter: Pointer; dwCreationFlags: DWORD; var lpThreadId: DWORD): THandle; stdcall;
|
|
Kernel32_ExitThread: procedure (dwExitCode: DWORD); stdcall;
|
|
|
|
function NewCreateThread(lpThreadAttributes: Pointer;
|
|
dwStackSize: DWORD; lpStartAddress: TFNThreadStartRoutine;
|
|
lpParameter: Pointer; dwCreationFlags: DWORD; var lpThreadId: DWORD): THandle; stdcall;
|
|
var
|
|
Instance: TObject;
|
|
begin
|
|
Result := Kernel32_CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId);
|
|
if (Result <> 0) and (lpParameter <> nil) then
|
|
try
|
|
Instance := PThreadRec(lpParameter)^.Parameter;
|
|
if Instance is TThread then
|
|
RegisterThread(TThread(Instance), '', True);
|
|
except
|
|
end;
|
|
end;
|
|
|
|
procedure NewExitThread(dwExitCode: DWORD); stdcall;
|
|
var
|
|
ThreadID: DWORD;
|
|
begin
|
|
ThreadID := GetCurrentThreadId;
|
|
Kernel32_ExitThread(dwExitCode);
|
|
try
|
|
UnregisterThread(ThreadID);
|
|
except
|
|
end;
|
|
end;
|
|
|
|
function CreateThreadName(const ThreadName, ThreadClassName: string): string;
|
|
begin
|
|
if ThreadClassName <> '' then
|
|
begin
|
|
if ThreadName = '' then
|
|
Result := Format('[%s]', [ThreadClassName])
|
|
else
|
|
Result := Format('[%s] "%s"', [ThreadClassName, ThreadName]);
|
|
end
|
|
else
|
|
Result := Format('"%s"', [ThreadName]);
|
|
end;
|
|
|
|
procedure RegisterThread(ThreadID: DWORD; const ThreadName: string);
|
|
begin
|
|
if Assigned(SharedThreadNames) then
|
|
SharedThreadNames.RegisterThread(ThreadID, CreateThreadName(ThreadName, ''));
|
|
end;
|
|
|
|
procedure RegisterThread(Thread: TThread; const ThreadName: string; IncludeClassName: Boolean);
|
|
begin
|
|
if Assigned(SharedThreadNames) then
|
|
SharedThreadNames.RegisterThread(Thread.ThreadID, CreateThreadName(ThreadName, Thread.ClassName));
|
|
end;
|
|
|
|
procedure UnregisterThread(ThreadID: DWORD);
|
|
begin
|
|
if Assigned(SharedThreadNames) then
|
|
SharedThreadNames.UnregisterThread(ThreadID);
|
|
end;
|
|
|
|
procedure UnregisterThread(Thread: TThread);
|
|
begin
|
|
if Assigned(SharedThreadNames) then
|
|
SharedThreadNames.UnregisterThread(Thread.ThreadID);
|
|
end;
|
|
|
|
procedure ChangeThreadName(ThreadID: DWORD; const ThreadName: string);
|
|
begin
|
|
if Assigned(SharedThreadNames) then
|
|
SharedThreadNames[ThreadID] := CreateThreadName(ThreadName, '');
|
|
end;
|
|
|
|
procedure ChangeThreadName(Thread: TThread; const ThreadName: string; IncludeClassName: Boolean);
|
|
begin
|
|
if Assigned(SharedThreadNames) then
|
|
SharedThreadNames[Thread.ThreadID] := CreateThreadName(ThreadName, Thread.ClassName);
|
|
end;
|
|
|
|
function ThreadNamesAvailable: Boolean;
|
|
begin
|
|
Result := Assigned(SharedThreadNames);
|
|
end;
|
|
|
|
procedure Init;
|
|
begin
|
|
if IsDebuggerAttached and TSharedThreadNames.Exists then
|
|
begin
|
|
SharedThreadNames := TSharedThreadNames.Create(False);
|
|
HookImports := TJclPeMapImgHooks.Create;
|
|
with HookImports do
|
|
begin
|
|
HookImport(SystemBase, kernel32, 'CreateThread', @NewCreateThread, @Kernel32_CreateThread);
|
|
HookImport(SystemBase, kernel32, 'ExitThread', @NewExitThread, @Kernel32_ExitThread);
|
|
end;
|
|
{ TODO -oPV -cDesign : TJclDebugThread could hold its name. In case of that the name could be read in hooked CreateThread }
|
|
Notifier := TJclDebugThreadNotifier.Create;
|
|
JclDebugThreadList.OnThreadRegistered := Notifier.ThreadRegistered;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclDebugThreadNotifier } ============================================
|
|
|
|
procedure TJclDebugThreadNotifier.ThreadRegistered(ThreadID: DWORD);
|
|
begin
|
|
with JclDebugThreadList do
|
|
SharedThreadNames.RegisterThread(ThreadID,
|
|
CreateThreadName(ThreadNames[ThreadID], JclDebugThreadList.ThreadClassNames[ThreadID]));
|
|
end;
|
|
|
|
initialization
|
|
Init;
|
|
|
|
finalization
|
|
FreeAndNil(HookImports);
|
|
FreeAndNil(SharedThreadNames);
|
|
FreeAndNil(Notifier);
|
|
|
|
end.
|