Get Name / Description Startaddress Or From A Thread In A Process ( Delphi/Pascal ) - windows

Process Hacker has a process manager in C.
When you double-click in process manager on a process e.g. Explorer
You see a lot of info, including:
Topics related to the process. PDD, Cycles Delta Start, Address, priority.
Well I tried to do something similar in Delphi, but I get only the TID and priority ...
I can not put the info Start Address as follows: "msiltcfg.dll 0x258!" or can only return
00630EFA.
The (Original) Application Process Hacker show the information in the image below:
How do I solve this? based on the code example below.
procedure TForm1.Button7Click (Sender: TObject);
var
tbi: THREAD_BASIC_INFORMATION;
hThreadSnap, Process, hThread, ThreadInfo: THandle;
te32: tagTHREADENTRY32;
me32: MODULEENTRY32;
th32: THREADENTRY32;
dwPID: DWORD;
startaddr: Pointer;
Status: LongInt;
Error: DWORD;
modname: String;
hToken: DWORD;
TKP: TOKEN_PRIVILEGES;
otkp: TOKEN_PRIVILEGES;
dwLen: dword;
begin
hThreadSnap: = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0);
if hThreadSnap = INVALID_HANDLE_VALUE then
Exit;
try
dwPID: = GetProcessID (Trim (Edit1.Text));
te32.dwSize: = SizeOf (THREADENTRY32);
me32.dwSize: = SizeOf (MODULEENTRY32);
ListBox1.Items.Clear;
ListBox2.Items.Clear;
if not Thread32First (hThreadSnap, te32) then
Exit;
repeat
if te32.th32OwnerProcessID = dwPID then
begin
hThread: = OpenThread (THREAD_ALL_ACCESS,
False, te32.th32ThreadID);
status: = ZwQueryInformationThread (hThread,
9,
ThreadQuerySetWin32StartAddress {}
#Startaddr,
SizeOf (startaddr)
# DwLen);
listbox1.Items.AddObject (Format ('StartAddress:% p'
[Startaddr]) + 'ID:' + IntToStr(te32.th32ThreadID), TObject (hThread));
if hThread <> 0 then
CloseHandle (hThread);
end;
Until not Thread32Next (hThreadSnap, te32);
finally
CloseHandle (hThreadSnap);
end;
end;

Take a look at our logging class in the Open Source SynCommons.pas unit: you can trace the stack of any method into the log file. If the .map (or its compressed .mab equivalence) is available, the line number will be displayed.
I'm working on a log viewer able to add source code lines during viewing, from a save .map/.mab file.
It's now used by the unit testing classes, so that any failure will create an entry in the log with the source line, and stack trace:
C:\Dev\lib\SQLite3\exe\TestSQL3.exe 0.0.0.0 (2011-04-13)
Host=Laptop User=MyName CPU=2*0-15-1027 OS=2.3=5.1.2600 Wow64=0 Freq=3579545
TSynLogTest 1.13 2011-04-13 05:40:25
20110413 05402559 fail TTestLowLevelCommon(00B31D70) Low level common: TDynArray "" stack trace 0002FE0B SynCommons.TDynArray.Init (15148) 00036736 SynCommons.Test64K (18206) 0003682F SynCommons.TTestLowLevelCommon._TDynArray (18214) 000E9C94 TestSQL3 (163)
The difference between a test suit without logging (TSynTests) and a test suit with logging (TSynTestsLogged) is only this:
procedure TSynTestsLogged.Failed(const msg: string; aTest: TSynTestCase);
begin
inherited;
with TestCase[fCurrentMethod] do begin
fLogFile.Log(sllFail,'%: % "%"',
[Ident,TestName[fCurrentMethodIndex],msg],aTest);
end; {with}
end;
The sllFail level if used here, but you can use any available level.

Related

SHChangeNotify not updating URL= change in my .url shortcut file

I have a simple Delphi application that creates a desktop shortcut for a URL. It makes a two-line text file with a .url filename extension in the user's Desktop folder:
[InternetShortcut]
URL=http://127.0.0.1/admin
That works fine. When I need to update the file with a new URL, I overwrite the old file. But Windows will not recognize the change until I restart Explorer or reboot. So I learned about SHChangeNotify() and called it after overwriting the file:
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH or SHCNF_FLUSH, PChar(Path), nil);
But it has no effect:
I tried with and without the SHCNF_FLUSH flag;
also the SHCNF_FLUSHNOWAIT flag makes no difference.
I also tried deleting the file first and then using the SHCNE_DELETE event and then re-creating the file. That doesn't work either, it just keeps using the old URL.
How do I force Explorer to reload the URL from the file without a restart?
While the file's content can be treated like any INI file I yet have not found a direct way to control manipulations to it:
When creating a file its content is read as expected: the system's default application for the URL='s protocol is started (i.e. for http it is most likely the internet browser).
Modifying the file per file systems has no effect - either MSIE itself maintains a cache or the COM's magic.
Indirectly manipulation is possible in the following way:
Empty the file's existing content. Why? Because the later step will just add the same INI section with an URL= value again, but the first section's URL= value remains the one that is taken into account.
Access the file per COM and change its properties. Sadly this writes more into the file - in my case the outcome/file's content was:
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=http://127.0.0.1/index.php
IDList=
However, it "works" as in: the change (speak: a different URL) is recognized. Putting it all together my following code for Delphi 7 on Windows 7 should also work for you - just call the function:
uses
ShlObj, ActiveX, ComObj;
const
SID_IUniformResourceLocatorA= '{FBF23B80-E3F0-101B-8488-00AA003E56F8}';
SID_IUniformResourceLocatorW= '{CABB0DA0-DA57-11CF-9974-0020AFD79762}';
SID_InternetShortcut= '{FBF23B40-E3F0-101B-8488-00AA003E56F8}';
type
PUrlInvokeCommandInfoA= ^TUrlInvokeCommandInfoA;
TUrlInvokeCommandInfoA= record
dwcbSize,
dwFlags: DWORD; // Bit field of IURL_INVOKECOMMAND_FLAGS
hwndParent: HWND; // Parent window. Valid only if IURL_INVOKECOMMAND_FL_ALLOW_UI is set.
pcszVerb: LPCSTR; // Verb to invoke. Ignored if IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB is set.
end;
PUrlInvokeCommandInfoW= ^TUrlInvokeCommandInfoW;
TUrlInvokeCommandInfoW= record
dwcbSize,
dwFlags: DWORD;
hwndParent: HWND;
pcszVerb: LPCWSTR;
end;
IUniformResourceLocatorA= interface( IUnknown )
[SID_IUniformResourceLocatorA]
function SetURL( pcszURL: LPCSTR; dwInFlags: DWORD ): HRESULT; stdcall;
function GetURL( ppszURL: LPSTR ): HRESULT; stdcall;
function InvokeCommand( purlici: PUrlInvokeCommandInfoA ): HRESULT; stdcall;
end;
IUniformResourceLocatorW= interface( IUnknown )
[SID_IUniformResourceLocatorW]
function SetURL( pcszURL: LPCWSTR; dwInFlags: DWORD ): HRESULT; stdcall;
function GetURL( ppszURL: LPWSTR ): HRESULT; stdcall;
function InvokeCommand(purlici: PUrlInvokeCommandInfoW ): HRESULT; stdcall;
end;
function SetURL( sFile, sUrl: Widestring ): Integer;
const
CLSID_InternetShortCut: TGUID= SID_InternetShortcut;
var
oUrl: IUniformResourceLocatorW;
oFile: IPersistFile;
hFile: THandle;
begin
// First, the existing file's content should be emptied
hFile:= CreateFileW( PWideChar(sFile), GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0 );
if hFile= INVALID_HANDLE_VALUE then begin
result:= 1; // File might not exist, sharing violation, etc.
exit;
end;
// Initial file pointer is at position 0
if not SetEndOfFile( hFile ) then begin
result:= 2; // Missing permissions, etc.
CloseHandle( hFile );
exit;
end;
// Gracefully end accessing the file
if not CloseHandle( hFile ) then begin
result:= 3; // File system crashed, etc.
exit;
end;
// Using COM to access properties
result:= 0;
try
oUrl:= CreateComObject( CLSID_InternetShortCut ) as IUniformResourceLocatorW;
except
result:= 4; // CLSID unsupported, COM not available, etc.
end;
if result<> 0 then exit;
// Opening the file again
oFile:= oUrl as IPersistFile;
if oFile.Load( PWideChar(sFile), STGM_READWRITE )<> S_OK then begin
result:= 5; // Sharing violations, access permissions, etc.
exit;
end;
// Set the property as per interface - only saving the file is not enough
if oUrl.SetURL( PWideChar(sUrl), 0 )<> S_OK then begin
result:= 6;
exit;
end;
// Storing the file's new content - setting only the property is not enough
if oFile.Save( PWideChar(sFile), TRUE )<> S_OK then begin
result:= 7;
exit;
end;
// Success!
result:= 0;
end;
As per my desktop firewall the executing process modifies the memory of explorer.exe upon IPersistFile.Save() - after that executing the URL file should reflect its new content, while any attempt before that should still act upon the old file's content.

How to find the HWND that is preventing shutdown?

Somewhere in my application (along with 3rd party libraries of code) is a window procedure that is preventing Windows from:
logging off
shutting down
restarting
I found one spot in my code where I made the extraordinarily common mistake of calling DefWindowProc, but calling it incorrectly:
Before:
void Grobber.BroadcastListenerWindowProc(ref TMessage msg)
{
DefWindowProc(_broadcastListenerHwnd, msg.msg, msg.wparam, msg.lparam);
}
After:
void Grobber.BroadcastListenerWindowProc(ref TMessage msg)
{
//20170207: Forgetting to set the result can, for example, prevent Windows from restarting
msg.Result = DefWindowProc(_broadcastListenerHwnd, msg.msg, msg.wparam, msg.lparam);
}
I fixed that bug, and my test program no longer halted the shutdown.
But a full application does
I'm now faced with having to tear a program down to nothing, until my computer finally reboots.
Somewhere deep inside my application is a Window procedure attached to an HWND that is returning zero to WM_QUERYENDSESSION. If only i knew the HWND, i could use the Spy++ to find the Window.
But how can i find that hwnd?
The Windows Application event log notes the process that halt a shutdown:
And there very well be a more detailed log in the more detailed Applications and Services Logs. But those are undocumented.
How can i find my problematic hwnd?
Attempts
I tried to use EnumThreadWindows to get all the windows of my "main" thread, with the idea of manually sending WM_QUERYENDSESSION to them all to see who returns false:
var
wnds: TList<HWND>;
function DoFindWindow(Window: HWnd; Param: LPARAM): Bool; stdcall;
var
wnds: TList<HWND>;
begin
wnds := TList<HWND>(Param);
wnds.Add(Window);
Result := True;
end;
wnds := TList<HWND>.Create;
enumProc := #DoFindWindow;
EnumThreadWindows(GetCurrentThreadId, EnumProc, LPARAM(wnds));
Now i have a list of twelve hwnds. Poke them:
var
window: HWND;
res: LRESULT;
for window in wnds do
begin
res := SendMessage(window, WM_QUERYENDSESSION, 0, 0);
if res = 0 then
begin
ShowMessage('Window: '+IntToHex(window, 8)+' returned false to WM_QUERYENDSESSION');
end;
end;
But nobody did return zero.
So that's one tube down the drain.
EnumThreadWindows only enumerates the windows of one particular thread. It could be that the offending window was created in a thread. So I'd suggest that you use EnumWindows to enum all top level windows in your application for your test.
It's enough to initialize COM in a thread and you'll have a window you don't know about. That way a call to WaitForSingleObject in a thread could be your culprit:
Debugging an application that would not behave with WM_QUERYENDSESSION
This might sound a bit like overkill but here goes. I would solve this using code hooks for AllocateHWnd and DeallocateHWnd. We had to solve a different issue related to handles and it worked well for us.
Your replacement routines will just be copies of the versions in System.Classes. You will also need to copy all of the dependencies (PObjectInstance, TObjectInstance, CodeBytes, PInstanceBlock, TInstanceBlock, InstBlockList, InstFreeList, StdWndProc, CalcJmpOffset, MakeObjectInstance, FreeObjectInstance, CleanupInstFreeList, GetFreeInstBlockItemCount, ReleaseObjectInstanceBlocks, UtilWindowClass) from that unit. The only difference is that you log all allocated and deallocated handles in your replacement routines. It would help to include stack traces too.
That will give you a list of all of the handles that are allocated at the time of your shutdown along with their calling stack traces.
The basic structure is something like this. I can't post full code because it's mostly VCL code with the exception of the code hooks and logging.
const
{$IF Defined(CPUX86)}
CodeBytes = 2;
{$ELSEIF Defined(CPUX64)}
CodeBytes = 8;
{$ENDIF CPU}
InstanceCount = (4096 - SizeOf(Pointer) * 2 - CodeBytes) div SizeOf(TObjectInstance) - 1;
type
PInstanceBlock = ^TInstanceBlock;
TInstanceBlock = packed record
...
end;
var
InstBlockList: PInstanceBlock;
InstFreeList: PObjectInstance;
{ Standard window procedure }
function StdWndProc(Window: HWND; Message: UINT; WParam: WPARAM; LParam: WPARAM): LRESULT; stdcall;
...
function CalcJmpOffset(Src, Dest: Pointer): Longint;
...
function MakeObjectInstance(const AMethod: TWndMethod): Pointer;
...
procedure FreeObjectInstance(ObjectInstance: Pointer);
...
procedure CleanupInstFreeList(BlockStart, BlockEnd: PByte);
...
function GetFreeInstBlockItemCount(Item: PObjectInstance; Block: PInstanceBlock): Integer;
...
procedure ReleaseObjectInstanceBlocks;
...
var
UtilWindowClass: TWndClass = (
... );
function AllocateHWnd(const AMethod: TWndMethod): HWND;
begin
< Logging/Stack trace code here >
...
end;
procedure DeallocateHWnd(Wnd: HWND);
begin
< Logging/Stack trace code here >
...
end;
It may also be necessary to hook and log SetWindowLong, SetWindowLongA and SetWindowLongW too.

Delphi - Obtain Full Stack Trace on OSX

I have an application which can log a stacktrace, which can be later used for debugging.
On Windows, I've gotten by using the excellent JCLDebug unit provided by the JEDI project.
Now that my application is running on OSX, I've hit a bit of a hitch - I don't know how to obtain the correct stacktrace when an exception occurs.
I have got the basics down -
1) I can get a stacktrace using 'backtrace' (found in libSystem.dylib)
2) The resulting backtrace can be converted into line numbers using the .map file provided by Delphi's linker
The issue I'm left with is - I don't know where to call backtrace from. I know that Delphi uses Mach exceptions (on a separate thread), and that I cannot use posix signals, but that's all that I've managed to sort out.
I can get a backtrace in the 'try...except' block, but unfortunately, by that point the stack has already wound down.
How can I install a proper exception logger which will run right after the exception occurs?
Update:
As per 'Honza R's suggestion, I've taken a look at the 'GetExceptionStackInfoProc' procedure.
This function does get me 'inside' of the exception handling process, but unfortunately leaves me with some of the same issues I had previously.
First of all - on desktop platforms, this function 'GetExceptionStackInfoProc' is just a function pointer, which you can assign with your own exception info handler. So out of the box, Delphi doesn't provide any stack information provider.
If I assign a function to 'GetExceptionStackInfoProc' and then run a 'backtrace' inside of it, I receive a stacktrace, but that trace is relative to the exception handler, not the thread which caused the exception.
'GetExceptionStackInfoProc' does contain a pointer to a 'TExceptionRecord', but there's very limited documentation available on this.
I might be going beyond my depth, but how can I get a stacktrace from the correct thread? Would it be possible for me to inject my own 'backtrace' function into the exception handler and then return to the standard exception handler from there?
Update 2
Some more details. One thing to clear up - this question is about exceptions that are handled by MACH messages, not software exceptions that are handled entirely within the RTL.
Embarcadero has laid out some comments along with these functions -
System.Internal.MachExceptions.pas -> catch_exception_raise_state_identity
{
Now we set up the thread state for the faulting thread so that when we
return, control will be passed to the exception dispatcher on that thread,
and this POSIX thread will continue watching for Mach exception messages.
See the documentation at <code>DispatchMachException()</code> for more
detail on the parameters loaded in EAX, EDX, and ECX.
}
System.Internal.ExcUtils.pas -> SignalConverter
{
Here's the tricky part. We arrived here directly by virtue of our
signal handler tweaking the execution context with our address. That
means there's no return address on the stack. The unwinder needs to
have a return address so that it can unwind past this function when
we raise the Delphi exception. We will use the faulting instruction
pointer as a fake return address. Because of the fencepost conditions
in the Delphi unwinder, we need to have an address that is strictly
greater than the actual faulting instruction, so we increment that
address by one. This may be in the middle of an instruction, but we
don't care, because we will never be returning to that address.
Finally, the way that we get this address onto the stack is important.
The compiler will generate unwind information for SignalConverter that
will attempt to undo any stack modifications that are made by this
function when unwinding past it. In this particular case, we don't want
that to happen, so we use some assembly language tricks to get around
the compiler noticing the stack modification.
}
Which seem to be responsible for the issue I'm having.
When I do a stacktrace after this exception system has handed control over to the RTL, it looks like this - (bearing in mind, the stack unwinder has been superseded by a backtrace routine. The backtrace will hand control over to the unwinder once it is completed)
0: MyExceptionBacktracer
1: initunwinder in System.pas
2: RaiseSignalException in System.Internal.ExcUtils.pas
Since RaiseSignalException is called by SignalConverter, I'm led to believe that the backtrace function provided by libc is not compatible with the modifications made to the stack. So, it's incapable of reading the stack beyond that point, but the stack is still present underneath.
Does anyone know what to do about that (or whether my hypothesis is correct)?
Update 3
I've finally managed to get proper stacktraces on OSX. Huge thanks to both Honza and Sebastian. By combining both of their techniques, I found something that works.
For anyone else who could benefit from this, here's the basic source. Bear in mind that I'm not quite sure if it's 100% correct, if you can suggest improvements, go ahead. This technique hooks onto an exception right before Delphi unwinds the stack on the faulting thread, and compensates for any stack frame corruption that might have taken place beforehand.
unit MyExceptionHandler;
interface
implementation
uses
SysUtils;
var
PrevRaiseException: function(Exc: Pointer): LongBool; cdecl;
function backtrace2(base : NativeUInt; buffer : PPointer; size : Integer) : Integer;
var SPMin : NativeUInt;
begin
SPMin:=base;
Result:=0;
while (size > 0) and (base >= SPMin) and (base <> 0) do begin
buffer^:=PPointer(base + 4)^;
base:=PNativeInt(base)^;
//uncomment to test stacktrace
//WriteLn(inttohex(NativeUInt(buffer^), 8));
Inc(Result);
Inc(buffer);
Dec(size);
end;
if (size > 0) then buffer^:=nil;
end;
procedure UnInstallExceptionHandler; forward;
var
InRaiseException: Boolean;
function RaiseException(Exc: Pointer): LongBool; cdecl;
var b : NativeUInt;
c : Integer;
buff : array[0..7] of Pointer;
begin
InRaiseException := True;
asm
mov b, ebp
end;
c:=backtrace2(b - $4 {this is the compiler dependent value}, #buff, Length(buff));
//... do whatever you want to do with the stacktrace
Result := PrevRaiseException(Exc);
InRaiseException := False;
end;
procedure InstallExceptionHandler;
var
U: TUnwinder;
begin
GetUnwinder(U);
Assert(Assigned(U.RaiseException));
PrevRaiseException := U.RaiseException;
U.RaiseException := RaiseException;
SetUnwinder(U);
end;
procedure UnInstallExceptionHandler;
var
U: TUnwinder;
begin
GetUnwinder(U);
U.RaiseException := PrevRaiseException;
SetUnwinder(U);
end;
initialization
InstallExceptionHandler;
end.
You can use GetExceptionStackInfoProc, CleanUpStackInfoProc and GetStackInfoStringProc in Exception class you need to save stack trace in GetExceptionStackInfoProc and then retrieve it with GetStackInfoStringProc which will get called by RTL if you use StackTrace property of the Exception. Maybe you could also take look at https://bitbucket.org/shadow_cs/delphi-arm-backtrace which demonstrates this on Android.
To do this properly on Mac OS X the libc backtrace function cannot be used because Delphi will corrupt stack frame when calling the GetExceptionStackInfoProc from Exception.RaisingException. Own implementation must be used that is capable of walking the stack from different base address which can be corrected by hand.
Your GetExceptionStackInfoProc would then look like this (I used XE5 for this example the value added to EBP bellow may differ based on which compiler you use and this example was only tested on Mac OS X, Windows implementation may or may not differ):
var b : NativeUInt;
c : Integer;
buff : array[0..7] of Pointer;
begin
asm
mov b, ebp
end;
c:=backtrace2(b - $14 {this is the compiler dependent value}, #buff, Length(buff));
//... do whatever you want to do with the stacktrace
end;
And the backtrace2 function would look like this (note that stop conditions and other validations are missing in the implementation to ensure that AVs are not caused during stack walking):
function backtrace2(base : NativeUInt; buffer : PPointer; size : Integer) : Integer;
var SPMin : NativeUInt;
begin
SPMin:=base;
Result:=0;
while (size > 0) and (base >= SPMin) and (base <> 0) do begin
buffer^:=PPointer(base + 4)^;
base:=PNativeInt(base)^;
Inc(Result);
Inc(buffer);
Dec(size);
end;
if (size > 0) then buffer^:=nil;
end;
You could hook yourself into the Exception Unwinder. Then you can call backtrace where the exception happens. Here's an example. The unit SBMapFiles is what I use for reading the mapfiles. It is not required to get the exception call stack.
unit MyExceptionHandler;
interface
implementation
uses
Posix.Base, SysUtils, SBMapFiles;
function backtrace(result: PNativeUInt; size: Integer): Integer; cdecl; external libc name '_backtrace';
function _NSGetExecutablePath(buf: PAnsiChar; BufSize: PCardinal): Integer; cdecl; external libc name '__NSGetExecutablePath';
var
PrevRaiseException: function(Exc: Pointer): LongBool; cdecl;
MapFile: TSBMapFile;
const
MaxDepth = 20;
SkipFrames = 3;
procedure ShowCurrentStack;
var
StackLog: PNativeUInt; //array[0..10] of Pointer;
Cnt: Integer;
I: Integer;
begin
{$POINTERMATH ON}
GetMem(StackLog, SizeOf(Pointer) * MaxDepth);
try
Cnt := backtrace(StackLog, MaxDepth);
for I := SkipFrames to Cnt - 1 do
begin
if StackLog[I] = $BE00EF00 then
begin
WriteLn('---');
Break;
end;
WriteLn(IntToHex(StackLog[I], 8), ' ', MapFile.GetFunctionName(StackLog[I]));
end;
finally
FreeMem(StackLog);
end;
{$POINTERMATH OFF}
end;
procedure InstallExceptionHandler; forward;
procedure UnInstallExceptionHandler; forward;
var
InRaiseException: Boolean;
function RaiseException(Exc: Pointer): LongBool; cdecl;
begin
InRaiseException := True;
ShowCurrentStack;
Result := PrevRaiseException(Exc);
InRaiseException := False;
end;
procedure InstallExceptionHandler;
var
U: TUnwinder;
begin
GetUnwinder(U);
Assert(Assigned(U.RaiseException));
PrevRaiseException := U.RaiseException;
U.RaiseException := RaiseException;
SetUnwinder(U);
end;
procedure UnInstallExceptionHandler;
var
U: TUnwinder;
begin
GetUnwinder(U);
U.RaiseException := PrevRaiseException;
SetUnwinder(U);
end;
procedure LoadMapFile;
var
FileName: array[0..255] of AnsiChar;
Len: Integer;
begin
if MapFile = nil then
begin
MapFile := TSBMapFile.Create;
Len := Length(FileName);
_NSGetExecutablePath(#FileName[0], #Len);
if FileExists(ChangeFileExt(FileName, '.map')) then
MapFile.LoadFromFile(ChangeFileExt(FileName, '.map'));
end;
end;
initialization
LoadMapFile;
InstallExceptionHandler;
end.

Delphi, Windows: Best way to find whether web-browser is running?

What is the best way to find whether a web-browser is running?
Using Delphi XE2 and on Windows, I need to find whether the following web-browsers are currently running:
A) Mozilla Firefox
B) Apple Safari
C) Google Chrome
If found, the process will be terminated because the home page of the web-browser needs to be changed programmatically by modifying the web-browser configuration files (which is either not possible or could result in unpredictable results if done when the web-browser is running).
Does the output from the EnumWindows API function contain sufficient information needed to handle the above task? If yes, then are the window class names for each of the above web-browsers documented anywhere? If no, then which method is most reliable?
TIA.
Terminate a process without the user permission is not good practice, instead you must ask to the user if he wants terminate the app (in this case the web browser).
Now back to your question, you can detect if a app(webbroser) is running checking for the process name (firefox.exe, chrome.exe , safari.exe) using the CreateToolhelp32Snapshot method.
uses
Windows,
tlhelp32,
SysUtils;
function IsProcessRunning(const ListProcess: Array of string): boolean;
var
hSnapshot : THandle;
lppe : TProcessEntry32;
I : Integer;
begin
result:=false;
hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if hSnapshot <> INVALID_HANDLE_VALUE then
try
lppe.dwSize := SizeOf(lppe);
if Process32First(hSnapshot, lppe) then
repeat
for I := Low(ListProcess) to High(ListProcess) do
if SameText(lppe.szExeFile, ListProcess[i]) then
Exit(True);
until not Process32Next(hSnapshot, lppe);
finally
CloseHandle(hSnapshot);
end;
end;
and use like so
IsProcessRunning(['firefox.exe','chrome.exe','safari.exe'])
Now if you want a more reliable way you can search for the class name of the Window (using the FindWindowEx method) and then the PID of the process owner of the handle (using GetWindowThreadProcessId), from here you can use the PID of the process to resolve the name of exe.
{$APPTYPE CONSOLE}
uses
Windows,
tlhelp32,
SysUtils;
function GetProcessName(const th32ProcessID: DWORD): string;
var
hSnapshot : THandle;
lppe : TProcessEntry32;
begin
result:='';
hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if hSnapshot <> INVALID_HANDLE_VALUE then
try
lppe.dwSize := SizeOf(lppe);
if Process32First(hSnapshot, lppe) then
repeat
if lppe.th32ProcessID=th32ProcessID then
Exit(lppe.szExeFile);
until not Process32Next(hSnapshot, lppe);
finally
CloseHandle(hSnapshot);
end;
end;
function IsWebBrowserRunning(const ClassName, ExeName :string) : Boolean;
var
hWindow : THandle;
dwProcessId: DWORD;
begin
result:=False;
hWindow:= FindWindowEx(0, 0, PChar(ClassName), nil);
if hWindow<>0 then
begin
dwProcessId:=0;
GetWindowThreadProcessId(hWindow, dwProcessId);
if dwProcessId>0 then
exit(Sametext(GetProcessName(dwProcessId),ExeName));
end;
end;
begin
try
if IsWebBrowserRunning('MozillaWindowClass','firefox.exe') then
Writeln('Firefox is Running');
if IsWebBrowserRunning('{1C03B488-D53B-4a81-97F8-754559640193}','safari.exe') then
Writeln('Safari is Running');
if IsWebBrowserRunning('Chrome_WidgetWin_1','chrome.exe') then
Writeln('Chrome is Running');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.

Set EXE VersionInfo

The information on the version Exe-file I receive by means of VerQueryValue. Is there an inverse function (WinApi or Delphi) which can register (establish or change) such information?
Here, for example, there is a program which is able to do so. How may it work (http://www.angusj.com/resourcehacker)?
The version information is stored via resources; to edit that you simply need to edit that resource. Here is a unit I found that can clone an existing file version information and attach it to another file. It's very easy to do what you want starting from this code (it's coded by a friend of mine and is available public):
unit cloneinfo;
interface
uses Windows, SysUtils;
type
LANGANDCODEPAGE = record
wLanguage: Word;
wCodePage: Word;
end;
procedure clone(sFile,output:string);
implementation
procedure clone(sFile,output:string);
var
dwHandle, cbTranslate: cardinal;
sizeVers: DWord;
lpData, langData: Pointer;
lpTranslate: ^LANGANDCODEPAGE;
hRes : THandle;
begin
sizeVers := GetFileVersionInfoSize(PChar(sFile), dwHandle);
If sizeVers = 0 then
exit;
GetMem(lpData, sizeVers);
try
ZeroMemory(lpData, sizeVers);
GetFileVersionInfo (PChar(sFile), 0, sizeVers, lpData);
If not VerQueryValue (lpData, '\VarFileInfo\Translation', langData, cbTranslate) then
exit;
hRes := BeginUpdateResource(pchar(output), FALSE);
//For i := 0 to (cbTranslate div sizeof(LANGANDCODEPAGE)) do
//begin
lpTranslate := Pointer(Integer(langData) + sizeof(LANGANDCODEPAGE));
UpdateResource(hRes, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), lpTranslate^.wLanguage,lpData, sizeVers);
//end;
EndUpdateResource(hRes, FALSE);
finally
FreeMem(lpData);
end;
end;
end.

Resources