[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1121
  • Last Modified:

DOS Application window in my form

This is a strange one. I want to be able to run a DOS application so it displays INSIDE my form. Like when you start command prompt it appears in its own window. I want this window to be in my form.

1. The application will be initiated from Delphi.
2. DOS Application should be terminated from itself or from my Delphi application

0
graga
Asked:
graga
  • 4
  • 4
  • 3
  • +5
1 Solution
 
Tomas Helgi JohannssonCommented:
Hi!

Take a look at the TDosMemo v.1.00 on Torry's Delphi Pages
http://www.torry.net/memos.htm
This is a great way to display a running DOS application "inside" a Delphi form.

Regards,
Tomas Helgi
0
 
ginsonicCommented:
interested
0
 
gragaAuthor Commented:
Tomas, which memo component is that?
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Tomas Helgi JohannssonCommented:
I gave you the name of the component (TDosMemo).
Go to the link I posted and scroll half way down and
you should see it.

Regards,
Tomas Helgi
0
 
gragaAuthor Commented:
Tomas, sorry it's been a long day...

I'm just reading the description of the component. It looks like the component lets you re-direct output from a DOS application to a memo, not to run the program. That's not what I need.

Graga
0
 
MBoCommented:
0
 
MBoCommented:
sorry above link isn't working
Try
http://master-brain.boom.ru
then press Download
and find
DosCommand.zip
0
 
geobulCommented:
listening...
0
 
gragaAuthor Commented:
MBo,

I think we are on the wrong track. Both components allow to capture DOS command output to a memo field. This is not what I want. I want to display an interactive DOS application.

graga
0
 
Lee_NoverCommented:
well you can launch the dos app with CreateProcess then use dwProcessID from  the returned PROCESSINFO structure
to get the window from the processid use the folowing code

function EnumWindowsProc(Wnd: hWnd; ProcWndInfo: PProcessWindow): BOOL;
stdcall;
var
    WndProcessID: Cardinal;
begin
    GetWindowThreadProc(Wnd, WndProcessID);
    if WndProcessID = ProcWndInfo^.TargetProcessID then begin
        ProcWndInfo^.FoundWindow := Wnd;
        Result := False; // This tells EnumWindows to stop enumerating since
we've already found a window.
    end else Result := True; // Keep searching
end;

function GetProcessWindow(TargetProcessID: Cardinal): hWnd;
var
    ProcWndInfo: TProcessWindow;
begin
    ProcWndInfo.TargetProcessID := TargetProcessID;
    ProcWndInfo.FoundWindow := 0;
    EnumWindows(@EnumWindowsProc, @ProcWndInfo);
    Result := ProcWndInfo.FoundWindow;
end;


then simply set the windows parent to your form or panel or whatever control you wish  
the usage would be smth like :

ok:=CreateProcess(nil, 'DosApp.exe, nil, nil, true,
      NORMAL_PRIORITY_CLASS, nil, nil, si, pi);
if ok then
  Windows.SetParent(GetProcessWindow(pi.dwProcessId), somePanel.Handle);

I haven't tested it but that's the basic idea :)
0
 
Lee_NoverCommented:
forgot the :

type
  PProcessWindow = ^TProcessWindow;
  TProcessWindow = record
    TargetProcessID: Cardinal;
    FoundWindow: hWnd;
  end;
0
 
Lee_NoverCommented:
ehh :) just made a test app ,, the code bellow works just fine :



unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  PProcessWindow = ^TProcessWindow;
  TProcessWindow = record
    TargetProcessID: Cardinal;
    FoundWindow: hWnd;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    OpenD: TOpenDialog;
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  hDosWin: HWND = 0;

implementation

{$R *.dfm}

function EnumWindowsProc(Wnd: hWnd; ProcWndInfo: PProcessWindow): BOOL;stdcall;
var
   WndProcessID: Cardinal;
begin
   GetWindowThreadProcessId(Wnd, WndProcessID);
   if WndProcessID = ProcWndInfo^.TargetProcessID then begin
       ProcWndInfo^.FoundWindow := Wnd;
       Result := False; // This tells EnumWindows to stop enumerating since we've already found a window.
   end else Result := True; // Keep searching
end;

function GetProcessWindow(TargetProcessID: Cardinal): hWnd;
var
   ProcWndInfo: TProcessWindow;
begin
   ProcWndInfo.TargetProcessID := TargetProcessID;
   ProcWndInfo.FoundWindow := 0;
   EnumWindows(@EnumWindowsProc, Integer(@ProcWndInfo));
   Result := ProcWndInfo.FoundWindow;
end;

procedure TForm1.Button1Click(Sender: TObject);
var si: STARTUPINFO;
    pi: TProcessInformation;
    ok: Boolean;
begin
     if not OpenD.Execute then exit;
     FillChar(si, SizeOf(si), 0);
     si.cb:=SizeOf(si);
     si.wShowWindow:=SW_SHOW;
     ok:=CreateProcess(nil, PChar(OpenD.FileName), nil,
       nil, true, CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil, si, pi);

     if not ok then exit;

     hDosWin:=GetProcessWindow(pi.dwProcessID);
     if hDosWin > 0 then
     begin
       Windows.SetParent(hDosWin, Panel1.Handle);
       SetWindowPos(hDosWin, 0, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOZORDER);
     end;

     // we don't need the handles so we close them
     CloseHandle(pi.hProcess);
     CloseHandle(pi.hThread);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
     if hDosWin > 0 then
        PostMessage(hDosWin, WM_CLOSE, 0, 0);
end;

end.
0
 
gragaAuthor Commented:
Lee, this looks good!
I can't however compile your code. It's complaining about "Variants" in uses clause.
When removed, GetWindowThreadProcessId complains about incompatible types.
I'm running D5
0
 
geobulCommented:
Hi,

I also like it. Nice code Lee_Nover ;-)

1. My uses clause (D5):
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, StdCtrls;

2.
GetWindowThreadProcessId(Wnd, @WndProcessID);

3.Add
Sleep(100);
or more after CreateProcess to let the new process to create its main window.

Regards, Geo
0
 
Lee_NoverCommented:
ahh yes sorry about the incompatibility :)
as you can see from the first code it is made for D5, I had to change it coz I'm using D6 :)
glad it helps :)
0
 
L44Commented:
I would also like to know how to run command prompt in my application ? Lee Nover, I've compiled your code,but still don't know how does it work?! what should I open, when open dialog appear ? cmd.exe ?

Thanks
0
 
RBritzCommented:
Hi all, I know this is an old thread, but, I was wondering...

The above code compiles/runs without any errors, but doesn't move/assign the dos window to the Panel as a parent (maybe it does, but the dos window is still not running in the panel), BUT as soon as I debug and step through it.... the dos window is assigned to the panel. I'm using D6... Any Ideas!?
0
 
geobulCommented:
Hi,

Add
Sleep(100);
or more after CreateProcess to let the new process to create its main window. Otherwise GetProcessWindow will return nothing and you won't have a window handle to set parent to.

Regards, Geo
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 4
  • 4
  • 3
  • +5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now