I know this is an old thread, but I have a good solution.
You do not need to bother with batch files. Focus in the exe type is an attribute of the subsystem. After compiling exe as a GUI application (without the {$ APPTYPE CONSOLE} directive, you must change the attribute of the subsystem IMAGE_SUBSYSTEM_WINDOWS_GUI to IMAGE_SUBSYSTEM_WINDOWS_CUI. The good thing is that when you start the console application from the console, it doesn’t display an additional console window and you don’t need to “Press Enter to close the window.” EDIT: if you run another console application in a console application, as in my project)
When you start it from Explorer, etc., by clicking on it or at startup, Windows will automatically open a console window when the subsystem attribute is IMAGE_SUBSYSTEM_WINDOWS_CUI. You do not need to specify the {$ APPTYPE CONSOLE} directive, all about the subsystem attribute.
The RRUZ solution is a solution that is also used, but with one important difference. I check the parent process subsystem to show "Press Enter to close this window." RUZZ this solution works only in two cases, when it is cmd or explorer. Just check if the parent process is NOT IMAGE_SUBSYSTEM_WINDOWS_CUI attribute, you can display a message.
But how to check the exe subsystem? I found a solution at toric tips ( http://www.swissdelphicenter.ch/torry/showcode.php?id=1302 ) to get PE header information and change it to two functions: setExeSubSys () and getExeSubSys (). Using setExeSubSys (), I made a small console application, so after compilation I can change the attribute of the exe subsystem (it's only 50 kb!).
Once you have the file name of the parent / potential process, 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 two functions that I did, but it does not work with streams (for example, torry example), I use my own simple block for files for it without stupid exeption things. But basically, I think you are considering an idea.
Install (and also get when you did not point to a pointer to 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 obtain:
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 information in the subsystem, just go to Google or go to the MSDN website. Hope this was helpful to everyone.
Greetz, Erwin Haantes