12

In my Win32 VCL application I am using ShellExecute to launch a number of smaller Delphi console applications. Is there a way to control the position of those console windows? I would like to launch them centered on screen.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • 3
    Can you re-compile the Delphi console applications? you could get the handle of the console window via `GetConsoleWindow` and `SetWindowPos`... – kobik Aug 27 '12 at 09:01
  • 1
    @kobik I can recompile, so in all of my console apps I should use this GetConsoleWindow and SetWindowPos sequence before any code? –  Aug 27 '12 at 09:18
  • yes. the only defect I see is that the console window is "jumping" to it's new position. – kobik Aug 27 '12 at 09:39
  • 3
    @kobik, then you can use [`CreateProcess`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx) and specify its [`STARTUPINFO`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms686331(v=vs.85).aspx) structure. – TLama Aug 27 '12 at 09:46
  • What about redirecting the console output to your own window instead? – Leonardo Herrera Aug 27 '12 at 12:58

2 Answers2

19

You can use CreateProcess and specify the window size and position in its STARTUPINFO structure parameter. In the following example function, you can specify the size of a console window, which is then according to the specified size centered on the current desktop. The function returns process handle, if succeed, 0 otherwise:

function RunConsoleApplication(const ACommandLine: string; AWidth,
  AHeight: Integer): THandle;
var
  CommandLine: string;
  StartupInfo: TStartupInfo;
  ProcessInformation: TProcessInformation;
begin
  Result := 0;
  FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
  FillChar(ProcessInformation, SizeOf(TProcessInformation), 0);
  StartupInfo.cb := SizeOf(TStartupInfo);
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USEPOSITION or 
    STARTF_USESIZE;
  StartupInfo.wShowWindow := SW_SHOWNORMAL;
  StartupInfo.dwXSize := AWidth;
  StartupInfo.dwYSize := AHeight;
  StartupInfo.dwX := (Screen.DesktopWidth - StartupInfo.dwXSize) div 2;
  StartupInfo.dwY := (Screen.DesktopHeight - StartupInfo.dwYSize) div 2;
  CommandLine := ACommandLine;
  UniqueString(CommandLine);
  if CreateProcess(nil, PChar(CommandLine), nil, nil, False,
    NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInformation)
  then
    Result := ProcessInformation.hProcess;
end;
TLama
  • 75,147
  • 17
  • 214
  • 392
12

If you have control over the console application, You could set the console window position from inside the console application itself:

program Project1;
{$APPTYPE CONSOLE}
uses
  Windows,
  MultiMon;

function GetConsoleWindow: HWND; stdcall; external kernel32 name 'GetConsoleWindow';

procedure SetConsoleWindowPosition;
var
  ConsoleHwnd: HWND;
  R: TRect;
begin
  ConsoleHwnd := GetConsoleWindow;
  // Center the console window
  GetWindowRect(ConsoleHwnd, R);
  SetWindowPos(ConsoleHwnd, 0,
    (GetSystemMetrics(SM_CXVIRTUALSCREEN) - (R.Right - R.Left)) div 2,
    (GetSystemMetrics(SM_CYVIRTUALSCREEN) - (R.Bottom - R.Top)) div 2,
    0, 0, SWP_NOSIZE);
end;

begin
  SetConsoleWindowPosition;  
  // Other code...
  Readln;
end.

If you can't recompile the console application, you could use FindWindow('ConsoleWindowClass', '<path to the executable>') to obtain the console window handle (the Title parameter could vary if it was set via SetConsoleTitle). The downside with this approach, is that the console window is seen "jumping" from it's default position to it's new position (tested with Windows XP).

kobik
  • 21,001
  • 4
  • 61
  • 121