{**************************************************************************************************} { } { Project JEDI Code Library (JCL) } { } { The contents of this file are subject to the Mozilla Public License Version 1.1 (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 JclIdeThreadStatus.pas. } { } { The Initial Developer of the Original Code is Petr Vones. } { Portions created by Petr Vones are Copyright (C) of Petr Vones. } { } {**************************************************************************************************} { } { Delphi IDE debugger Thread Status window extension. } { } { Unit owner: Petr Vones } { Last modified: $Date: 2005/10/26 03:29:44 $ } { } {**************************************************************************************************} unit JclIdeThreadStatus; {$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; var SharedThreadNames: TSharedThreadNames; HookImports: TJclPeMapImgHooks; Kernel32_CreateThread: function(lpThreadAttributes: Pointer; dwStackSize: DWORD; lpStartAddress: TFNThreadStartRoutine; lpParameter: Pointer; dwCreationFlags: DWORD; var lpThreadId: DWORD): THandle; stdcall; Kernel32_ExitThread: procedure(dwExitCode: DWORD); stdcall; {$IFDEF DELPHI7_UP} Kernel32_ResumeThread: function(hThread: THandle): DWORD; stdcall; {$ENDIF DELPHI7_UP} 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 TJclDebugThread then RegisterThread(TJclDebugThread(Instance), TJclDebugThread(Instance).ThreadName, True) else if Instance is TThread then RegisterThread(TThread(Instance), '', True); except end; end; procedure NewExitThread(dwExitCode: DWORD); stdcall; var ThreadID: DWORD; begin ThreadID := GetCurrentThreadId; try UnregisterThread(ThreadID); except end; Kernel32_ExitThread(dwExitCode); end; {$IFDEF DELPHI7_UP} function NewResumeThread(hThread: THandle): DWORD; stdcall; begin Result := Kernel32_ResumeThread(hThread); if Result <= 1 then try SharedThreadNames.UpdateResumeStatus; except end; end; {$ENDIF DELPHI7_UP} 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); {$IFDEF DELPHI7_UP} HookImport(SystemBase, kernel32, 'ResumeThread', @NewResumeThread, @Kernel32_ResumeThread); {$ENDIF DELPHI7_UP} end; end; end; initialization Init; finalization FreeAndNil(HookImports); FreeAndNil(SharedThreadNames); // History: // $Log: JclIdeThreadStatus.pas,v $ // Revision 1.3 2005/10/26 03:29:44 rrossmair // - improved header information, added Date and Log CVS tags. // end.