我知道,这是一个旧线程,但我有一个很好的解决方案。
您不必处理批处理文件。诀窍在于 exe 的类型,它的子系统属性。将 exe 编译为 GUI 应用程序后(没有 {$APPTYPE CONSOLE} 指令,您必须将其子系统属性 IMAGE_SUBSYSTEM_WINDOWS_GUI 更改为 IMAGE_SUBSYSTEM_WINDOWS_CUI。好消息是当您从控制台执行控制台应用程序时,它不会显示额外的控制台窗口,并且在那时你不需要像“按 Enter 关闭窗口”这样的消息。编辑:如果你在控制台应用程序中启动另一个控制台应用程序,就像我在我的项目中所做的那样) p>
当您从资源管理器等通过单击它或通过开始|运行运行它时,当子系统属性为 IMAGE_SUBSYSTEM_WINDOWS_CUI 时,Windows 会自动打开一个控制台窗口。你不需要指定 {$APPTYPE CONSOLE} 指令,它都是关于子系统属性的。
RRUZ 的解决方案是我也使用的解决方案,但有一个重要区别。我检查父进程的子系统以显示“按 Enter 关闭此窗口”。 RUZZ 它的解决方案只在两种情况下有效,当它是 cmd 或 explorer 时。只需检查它的父进程是否具有 NOT IMAGE_SUBSYSTEM_WINDOWS_CUI 属性,就可以显示该消息。
但是如何检查exe子系统呢?我在 torry 提示 (http://www.swissdelphicenter.ch/torry/showcode.php?id=1302) 上找到了一个解决方案,用于获取 PE Header 信息并将其修改为两个函数:setExeSubSys() 和 getExeSubSys()。使用 setExeSubSys() 我制作了一个小控制台应用程序,这样我就可以在编译后更改 exe 的子系统属性(它只有 50 kb!)。
获得父/潜在进程文件名后,您可以简单地执行以下操作:
//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;
这是我创建的两个函数,但它不适用于流(如 torry 示例),我使用我自己的简单单元来处理文件,而没有愚蠢的例外。但基本上我认为你已经明白了。
设置(以及当你没有指定指向 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;
获得:
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;
如果您想了解有关子系统的更多信息,只需 google 或访问 MSDN 网站。
希望它对任何人都有帮助。
问候,
欧文·汉杰斯