I know, this is a old thread but i have a nice solution to this.
You don't have to mess around with batch files. The trick is in the type of exe, it's subsystem attribute. After compiling the exe as GUI application (without the {$APPTYPE CONSOLE} directive, you must change it's subsystem attribute IMAGE_SUBSYSTEM_WINDOWS_GUI to IMAGE_SUBSYSTEM_WINDOWS_CUI. Nice thing is when you execute the console app from a console it doesn't show an extra console window and at that point you don't need a message like "Press Enter to close the window". EDIT: In case you starting another console app inside a console app like i did in a project of mine)
When you run it from explorer etc by clicking it or by start|run, Windows opens automaticly a console window when the subsystem attribute is IMAGE_SUBSYSTEM_WINDOWS_CUI. You don't need to specify {$APPTYPE CONSOLE} directive, it's all about the subsystem attribute.
The solution of RRUZ is a solution i also using but with one important difference. I check the subsystem of the parent process to show a "Press Enter to close this window". RUZZ it's solution only works in two cases, when it is cmd or explorer. By simply check if it's parent process has the attribute is NOT IMAGE_SUBSYSTEM_WINDOWS_CUI, you can display the message.
But how to check the exe subsystem? I found a solution on torry tips (http://www.swissdelphicenter.ch/torry/showcode.php?id=1302) to get the PE Header info and modify it into two functions: setExeSubSys() and getExeSubSys(). With the setExeSubSys() i made a little console app so that i can change the exe's subsystem attribute after compiling (it is only 50 kb!).
After you have the parent/potential process filename, you can simply do something like this:
//In the very beginning in the app determine the parent process (as fast as is possible).
// later on you can do:
if( getExeSubSys( parentFilename ) <> IMAGE_SUBSYSTEM_WINDOWS_CUI ) then
begin
writeln( 'Press Enter to close the window' );
readln;
end;
Here are the two functions i made but it is not working with streams (like the torry example), i use my own easy unit for files for it without the silly exeption stuff. But basically i think you get the idea around it.
To set (and also to get when you not specifying a pointer to a longint (nil)):
type
PLongInt = ^LongInt;
function setExeSubSys( fileName : string; pSubSystemId : PLongInt = nil ) : LongInt;
var
signature: DWORD;
dos_header: IMAGE_DOS_HEADER;
pe_header: IMAGE_FILE_HEADER;
opt_header: IMAGE_OPTIONAL_HEADER;
f : TFile;
begin
Result:=-1;
FillChar( f, sizeOf( f ), 0 );
if( fOpenEx( f, fileName, fomReadWrite )) and ( fRead( f, dos_header, SizeOf(dos_header)))
and ( dos_header.e_magic = IMAGE_DOS_SIGNATURE ) then
begin
if( fSeek( f, dos_header._lfanew )) and ( fRead( f, signature, SizeOf(signature))) and ( signature = IMAGE_NT_SIGNATURE ) then
begin
if( fRead( f, pe_header, SizeOf(pe_header))) and ( pe_header.SizeOfOptionalHeader > 0 ) then
begin
if( fRead( f, opt_header, SizeOf(opt_header))) then
begin
if( Assigned( pSubSystemId )) then
begin
opt_header.Subsystem:=pSubSystemId^;
if( fSeek( f, fPos( f )-SizeOf(opt_header) )) then
begin
if( fWrite( f, opt_header, SizeOf(opt_header)) ) then
Result:=opt_header.Subsystem;
end;
end
else Result:=opt_header.Subsystem;
end;
end;
end;
end;
fClose( f );
end;
To get:
function GetExeSubSystem( fileName : string ) : LongInt;
var
f : TFile;
signature : DWORD;
dos_header: IMAGE_DOS_HEADER;
pe_header : IMAGE_FILE_HEADER;
opt_header: IMAGE_OPTIONAL_HEADER;
begin
Result:=IMAGE_SUBSYSTEM_WINDOWS_CUI; // Result default is console app
FillChar( f, sizeOf( f ), 0 );
if( fOpenEx( f, fileName, fomRead )) and ( fRead( f, dos_header, SizeOf(dos_header)))
and ( dos_header.e_magic = IMAGE_DOS_SIGNATURE ) then
begin
if( fSeek( f, dos_header._lfanew )) and ( fRead( f, signature, SizeOf(signature))) and ( signature = IMAGE_NT_SIGNATURE ) then
begin
if( fRead( f, pe_header, SizeOf(pe_header))) and ( pe_header.SizeOfOptionalHeader > 0 ) then
begin
if( fRead( f, opt_header, SizeOf(opt_header))) then
Result:=opt_header.Subsystem;
end;
end;
end;
fClose( f );
end;
If you want more info at the subsystem, just google or go to the MSDN website.
Hope it was helpful to anyone.
Greetz,
Erwin Haantjes