Follow along with the video below to see how to install our site as a web app on your home screen.
Note: This feature may not be available in some browsers.
unit comprompt;
// written by Glenn9999 @ tek-tips.com on 04/23/2015
interface
uses controls, extctrls, classes, windows, messages, graphics, sysutils;
type
TPColorType = (tctBlack, tctDarkBlue, tctDarkGreen, tctDarkCyan, tctDarkRed,
tctDarkMagenta, tctDarkYellow, tctLightGray, tctDarkGray,
tctLightBlue, tctLightGreen, tctLightCyan, tctLightRed,
tctLightMagenta, tctLightYellow, tctWhite);
TComPromptPanel = class(TCustomPanel)
private
fForeground: TPColorType;
fBackground: TPColorType;
InputPipeRead, InputPipeWrite: THandle;
ProcessInfo : TProcessInformation;
function GetConsoleWindow(cpid: Dword): HWND;
procedure PromptSize(var thewidth, theheight: integer);
procedure RunPrompt(Exec: String);
procedure RunQuit;
function GetComSpec: String;
procedure HideTitlebar(Handle: THandle);
protected
procedure Loaded; override;
public
procedure WritePipeOut(InString: string);
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Foreground: TPColorType read fForeground write fForeground;
property Background: TPColorType read fBackground write fBackground;
end;
procedure Register;
implementation
function TComPromptPanel.GetComSpec: String;
{ return the COMSPEC line in the environment }
var
PathName: PChar;
Buffer: array[0..255] of char;
begin
PathName := PChar('COMSPEC');
GetEnvironmentVariable(PathName, @Buffer, Sizeof(Buffer));
Result := String(Buffer);
end;
procedure TComPromptPanel.HideTitlebar(Handle: HWND);
// hides the title bar of the window handle given.
var
Style: Longint;
begin
Style := GetWindowLong(Handle, GWL_STYLE);
SetWindowLong(Handle, GWL_STYLE, Style and (not (WS_CAPTION))
or DS_MODALFRAME or WS_DLGFRAME);
end;
constructor TComPromptPanel.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
// set the parent window.
Parent := AOwner as TWinControl;
// set defaults for the control.
fForeground := tctWhite;
fBackground := tctBlack;
end;
procedure TComPromptPanel.Loaded;
{ initializations of the control }
begin
inherited loaded;
// only load the command prompt if not in designing state.
if not (CsDesigning in ComponentState) then
RunPrompt(GetComSpec);
end;
destructor TComPromptPanel.Destroy;
begin
// if not in the designer, quit.
if not (CsDesigning in ComponentState) then
RunQuit;
inherited;
end;
procedure TComPromptPanel.WritePipeOut(InString: string);
// writes Instring to the command prompt.
var
byteswritten: DWord;
begin
// most console programs require CR/LF after their input.
InString := InString + #13#10;
WriteFile(InputPipeWrite, Instring[1], Length(Instring), byteswritten, nil);
end;
var
thewndhandle: HWnd;
function GCCallBackFunc(TheHWnd: HWND; cpid: LParam): Bool; stdcall;
// enumwindows callback function for GetConsoleWindow
var
wpid: DWord;
begin
Result := true;
GetWindowthreadProcessID(TheHWND, @wpid);
if wpid = DWord(cpid) then // does window handle belong to the process started?
begin
Result := false;
thewndhandle := TheHWnd;
end;
end;
function TComPromptPanel.GetConsoleWindow(cpid: Dword): HWND;
// find the window handle associated with the process id entered in.
begin
EnumWindows(@GCCallbackFunc, LParam(cpid));
Result := thewndhandle;
end;
procedure TComPromptPanel.RunQuit;
// does the tasks to quit the command prompt.
begin
// close process handles
WritePipeOut('EXIT');
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
// close pipe handles
CloseHandle(InputPipeRead);
CloseHandle(InputPipeWrite);
end;
procedure TComPromptPanel.PromptSize(var thewidth, theheight: integer);
// this tries to find the number of the command prompt characters that can
// fit in the panel and returns that in thewidth and theheight. This is a
// kludge fix as I really didn't want to focus too much on this as I was
// more interested in putting the called process window into the panel and
// making it work.
var
tc: TBitmap;
gutter: integer;
begin
tc := TBitmap.Create;
try
tc.canvas.font.name := 'Lucida Console';
gutter := tc.Canvas.TextWidth('88') - tc.Canvas.TextWidth('8');
thewidth := Self.Width div (tc.canvas.textwidth('8'));
thewidth := thewidth - (thewidth div gutter);
theheight := Self.Height div (tc.canvas.textheight('8'));
theheight := theheight - (theheight div gutter);
finally
tc.free;
end;
end;
procedure TComPromptPanel.RunPrompt(Exec: String);
// runs "Exec" and puts the window into the Panel.
var
DosApp: String;
Security : TSecurityAttributes;
start : TStartUpInfo;
thewnd: HWND;
begin
Dosapp := Exec;
UniqueString(DosApp); // necessary for CreateProcess.
// create pipe to feed input from the main program into the prompt.
With Security do
begin
nlength := SizeOf(TSecurityAttributes) ;
binherithandle := true;
lpsecuritydescriptor := nil;
end;
CreatePipe(InputPipeRead, InputPipeWrite, @Security, 0);
// start command-interpreter
FillChar(Start,Sizeof(Start),#0) ;
start.cb := SizeOf(start) ;
// input pipe set, standard handles otherwise.
start.hStdInput := InputPipeRead;
start.hStdOutput := GetStdHandle(STD_OUTPUT_HANDLE);
start.hStdError := GetStdHandle(STD_ERROR_HANDLE);
// flags indicating things we will set.
start.dwFlags := STARTF_USESTDHANDLES + STARTF_USECOUNTCHARS
+ STARTF_USESIZE + STARTF_USEFILLATTRIBUTE;
// prompt size in characters, will try to fit them into the panel.
PromptSize(start.dwxcountchars, start.dwycountchars);
// pixel size of the command prompt. -3 is to kludge for the panel border.
Start.dwXSize := Width-3;
Start.dwYSize := Height-3;
// set the foreground and background colors.
Start.dwFillAttribute := (DWord(fBackground) shl 4) or DWord(fForeground);
if CreateProcess(nil, PChar(DosApp), @Security, @Security, true,
CREATE_NEW_CONSOLE or SYNCHRONIZE,
nil, nil, start, ProcessInfo) then
begin
// wait until the process stops.
WaitForInputIdle(ProcessInfo.hProcess, INFINITE);
// give the process a chance to create its window so it can be found.
sleep(50);
// find window handle for the process we just started.
thewnd := GetConsoleWindow(ProcessInfo.dwProcessID);
// set the parent window to the panel's window.
Windows.SetParent(thewnd, Handle);
// send a maximize message so the process window fills the panel window.
PostMessage(thewnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
// hide the title bar of the process window
HideTitleBar(thewnd);
end;
end;
procedure Register;
begin
RegisterComponents('My Controls', [TComPromptPanel]);
end;
end.