unit threadpoll; { Keeps a list of all the threads and notifies the debugger when a change has happened } {$mode delphi} interface uses jwawindows,windows,Classes, SysUtils,init, extcont, simpleThread, VEHDebugSharedMem; type TThreadPoller=class(TSimpleThread) private threadlist: TList; procedure GetCurrentList(list: tlist); procedure UpdateList; procedure CreateThreadEvent(threadid: dword); procedure DestroyThreadEvent(threadid: dword); public procedure execute; override; end; var ThreadPoller: TThreadPoller; implementation uses DebugHandler; //var debug_oldcontext, debug_newcontext: TContext; procedure TThreadPoller.CreateThreadEvent(threadid: dword); var {$ifdef cpu32} c: TEContext; {$else} c: TContext; {$endif} cp: PContext; ep: TEXCEPTIONPOINTERS; er: TEXCEPTIONRECORD; th: thandle; useValidContext: boolean; hasValidContext: boolean; begin OutputDebugString('CreateThreadEvent'); useValidContext:=((VEHSharedMem.ThreadWatchMethodConfig and TPOLL_TCREATEREALCONTEXT)>0) and (GetCurrentThreadId<>threadid); if usevalidcontext then begin cp:=@c; ep.ContextRecord:=cp; OutputDebugString('usevalidcontext=true'); th:=OpenThread(THREAD_GET_CONTEXT or THREAD_SET_CONTEXT or THREAD_SUSPEND_RESUME, false, threadid); if th<>0 then begin SuspendThread(th); zeromemory(@c, sizeof(c)); c.ContextFlags:=CONTEXT_ALL {$ifdef cpu32} or CONTEXT_EXTENDED{$endif}; hasValidContext:=GetThreadContext(th, cp^); if not hasValidContext then begin ep.ContextRecord:=nil; OutputDebugString(pchar(Format('Failure getting context th=%d @c=%p', [th, @c]))); end; // debug_oldcontext:=c; end; end else begin ep.ContextRecord:=nil; OutputDebugString('usevalidcontext=false'); end; ep.ExceptionRecord:=@er; er.NumberParameters:=0; er.ExceptionCode:=$ce000001; er.ExceptionRecord:=nil; OutputDebugString('Emulating CreateThreadEvent'); InternalHandler(@ep,threadid); OutputDebugString('After Emulating CreateThreadEvent'); if usevalidcontext then begin if (th<>0) and (hasValidContext) then begin //OutputDebugString(pchar(Format('old context=%p new context=%p', [@debug_oldcontext, @debug_newcontext]))); //debug_newcontext:=c; c.ContextFlags:=CONTEXT_ALL {$ifdef cpu32} or CONTEXT_EXTENDED{$endif}; SetThreadContext(th, cp^); ResumeThread(th); end; closehandle(th); end; end; procedure TThreadPoller.DestroyThreadEvent(threadid: dword); var ep: TEXCEPTIONPOINTERS; er: TEXCEPTIONRECORD; begin ep.ContextRecord:=nil; ep.ExceptionRecord:=@er; er.NumberParameters:=0; er.ExceptionCode:=$ce000002; //destroythread InternalHandler(@ep,threadid); end; procedure TThreadPoller.GetCurrentList(list: tlist); var ths: thandle; lpte: TThreadEntry32; check: boolean; cpi: dword; begin cpi:=GetCurrentProcessId(); ths:=CreateToolhelp32Snapshot(TH32CS_SNAPALL,cpi); if ths<>INVALID_HANDLE_VALUE then begin zeromemory(@lpte,sizeof(lpte)); lpte.dwSize:=sizeof(lpte); check:=Thread32First(ths, lpte); while check do begin if lpte.th32OwnerProcessID=cpi then list.add(pointer(lpte.th32ThreadID)); check:=Thread32next(ths,lpte); end; closehandle(ths); end; end; procedure TThreadPoller.UpdateList; var newlist: Tlist; i: integer; begin newlist:=tlist.create; GetCurrentList(newlist); //now try to find the differences //is there a threadid that's not in the current threadlist? for i:=0 to newlist.Count-1 do if threadlist.IndexOf(newlist[i])=-1 then //not found CreateThreadEvent(Dword(newlist[i])); for i:=0 to threadlist.count-1 do if newlist.IndexOf(threadlist[i])=-1 then //the new list doesn't contain this threadid DestroyThreadEvent(Dword(threadlist[i])); //free the old list and make the new list the current list threadlist.free; threadlist:=newlist; end; procedure TThreadPoller.execute; begin threadlist:=TList.Create; try GetCurrentList(threadlist); while not terminated do begin sleep(500); UpdateList; end; finally OutputDebugString('TThreadPoller terminated'); threadlist.free; end; end; end.