Link to home
Start Free TrialLog in
Avatar of henryreynolds
henryreynoldsFlag for United Kingdom of Great Britain and Northern Ireland

asked on

Closing AND HANDLING WINDOWS Multiple Open Delphi exe AND HANDLING WINDOWS

Hi TheRealLoki

You help me with opening multiple exe and closing them. The reason why I opening this question again is as follows.

I have a EXE that acts as a Main Menu, the main menu call differnet delphi exe from the main form , depend on the user selection. PLEASE NOTE my main
menu form IS MY MENU APPLICATION, that's its only purpose to act as a MAIN MENU..

NOW I have a desktop  ICON on the client computers that points to the main menu e.g c:\ABC\MainMenu.exe.

Once the user clicks on the Shortcut it will open the Main Menu. If a user click on a menu item, it will create a new process and a new window will show .....
This mean their will be currently two windows open.. (TheRealLoki help me to opening new windows and it work 100% and Also closing them work 100%).

NOW MY NEW QUESTION IS AS FOLLOWS:::

If the user open a menu item and the new window show, then I want this windows to act as a child form of the main menu, or vice versa. What I want to accomplish is the following. If the user minimize the main form or any other window created from my main menu it must minimize ALL the windows,
OR IF THE USER CLICK ON THE SAME MENU ITEM CREATED PREVIOUSLY IT MUST MAXIMIZED THAT WINDOW. I want to limit the user of handling this windows created by my application, because currently now, if he opens a menu item from the main menu that already exists it just make a beep and it does not maximize that window. here is my code what I try to accomplish from my main menu..

procedure TfrmMain.FormCreate(Sender: TObject);
begin
prgName := ExtractFileName(Application.ExeName);
   
   //Check if other instance exist
  hMutex := CreateMutex(nil, False, pchar(prgName));
  foundApp := not (WaitForSingleObject(hMutex, 0) <> wait_TimeOut);

  if foundApplication then
  begin
      instHdl := StrToInt(strHwnd);
      setForegroundWindow(hMutex);
     PostMessage(Application.Handle, WM_QUIT, 0, 0);
     exit;
 end;


To make this question as simple as possible. I want the following.

If My main menu are already running, and the user click on the desktop shortcut IT must not create the window again, IT MUST MAXIMIZE THE CURRENT MAIN MENU AND SET IT AS THE FOCUS WINDOW ON THE DESKTOP.. the same for menu items if the menu item are already opened, and the user have ALT-TAB back to the main menu and try to open the same menu item, it must maximized that open window.

AND FOR A BONUS IF IT IS POSSIBLE, if the user minimize one of my windows it must minimize all the windows, the reason for this IS SOMETIMES will the user is busy with my application a client phones and the client reuest a document from word, NOW the user must go and minimize all my application windows ONE BY ONE, and that is quite BAD..


THANK YOU for trying to help me

HENRY
Avatar of TheRealLoki
TheRealLoki
Flag of New Zealand image

did you write all of the applications, and are you able to make changes to them for this?
The reason I ask is that if you did, then it gives you more options for the kind of control you want.
Avatar of henryreynolds

ASKER

Hi yes I am a single developer, I did all the applications.

Let me explain why I did all the single exe and One Main Form.

My customer have many small brances in south africa, some branches need a lot of changes to current applications like Capturing Of Sales transactions, for me to create ONE BIG DELPHI application with about 60 forms WAS a NO,NO, because of maintaining such big application.

Then I thought about creating small modules (exe) for each type of Transaction or report or enquiry, this mean each branch has it own set of exe's.
This makes my LIFE a lot easier, because now if a other branch ask me for a sales report and IF branch "D" have maybe that report already I just modify that exe and copy the exe to that branch. This way I can easily keep version control. The other reason why I aslo did it, because some branches doesnt want a other branches to have the same LOOK AND FEEL of a same application, now each branch has it own look of feel of applications like using a mouse, or keybord or have a blue or black background..........

***********
MY APPLICATIONS INHERITS A MAIN FORM AND A DATAMODULE. This mean each time a create a new app. I inherit my main form and a datamodule. This way I only call certain functions once.  

*** Each new application will then consist of the following forms..
Main Form (INHERIT FORM)
NewForm (This is the form where a place my button , grids etc.. on, it inherit from Main Form)
Datamode(Inherit)
Dm (new Datamodule that are inherited from Datamodule)

The reason why I explain this, maybe it will give you a idea how my applications works.

My Main Menu Application is the same it inherit from my Main Form and Datamodule.

Thanx I hope you have a idea.

(The only thing i want to accomlpish now is, to make this WHOLE APPLICATION to ACT AS ONE APPLICATION, because the closing of forms is 100% I just want the user to feel more incontrol, AND I dont want  the user to go and minimize one by one applications that where open by my main menu, AND if he click on the shortcut on the desktop again, then the main menu must resize again and set focus)

Thank you
HEnRy
ok, well to have your application only run once, and restore, change your .DPR to look similar to this
(Alt-View_Project Source)

var
PrevFMain : hwnd;   {handle variable}
 
begin
   Application.Initialize;
   PrevFMain := FindWindow('TFMain', 'Payroll Program- Main Form');
                         {Hyphens required(type mismatch if not used.) First }
                         {parameter is the class, second is the CAPTION  }
                         {that is used for your Main Form, NOT the name   }
                         {of the form.}
  if PrevFMain <> 0 then
    begin
       ShowWindow(PrevFMain, sw_restore);  {Activates and displays the window, if minimized or maximized, at}
                                           {it's original size and position}
           SetForegroundWindow(PrevFMain); {Brings it to the front}
           Application.Terminate;
      end;
     
      Application.CreateForm(TFMain, FMain); // otherwise, if this is the only instance, create the form and show it as normally
      Application.Run;
end.
Ok, I think this does everything you asked for

*** The Main "Menu" Applicaiton ***

unit Unit1;

interface

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

type
    TMyProcessObject = class
    public
        MsgMenuExec, ProgName, RunPath, Exename: string;
        ProcessID: cardinal;
        StillRunning: boolean;
        constructor Create(MsgMenuExec_, ProgName_, RunPath_, Exename_: string; ProcessID_: cardinal);
    end;

type
  TfrmMain = class(TForm)
    bStartNotepad: TButton;
    bStartCalc: TButton;
    Timer1: TTimer;
    bStartProject2: TButton;
    bStartProject3: TButton;
    Label1: TLabel;
    bRestoreAll: TButton;
    procedure bStartNotepadClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure bStartCalcClick(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure bStartProject2Click(Sender: TObject);
    procedure bStartProject3Click(Sender: TObject);
    procedure bRestoreAllClick(Sender: TObject);
  private
    { Private declarations }
    function SpawnOrRestoreProcess(MsgMenuExec_, ProgName_, RunPath_, Exename_: string): boolean;
    function SpawnProcess(MsgMenuExec_, ProgName_, RunPath_, Exename_: string): boolean;
    procedure Message_FromClientProgram(var msg: TMessage); message WM_USER+100;
  public
    { Public declarations }
    MyProcessList: TList;
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.DFM}

//This function finds the windows and closes them
function EnumWindowsProcClose(Handle: THandle; List: TList): boolean; stdcall;
    var
        i: integer;
        found: boolean;
        wndPid: THandle;
    begin
        Result := True;
        found := false;
        i := 0;
        GetWindowThreadProcessId(Handle, @wndPid);
        while (not found) and (i < List.Count) do
        begin
           if (wndPid = TMyProcessObject(List[i]).ProcessID) then
           begin
                found := true;
                PostMessage(Handle, WM_Close, 0, 0);
// or  PostMessage(Handle, WM_CancelMode, 0, 0); first in case it has a dialog, or wm_quit, etc..
           end
           else inc(i);
        end;
    end;

//This function finds the windows and sets the StillRunning flag
function EnumWindowsProcCheckRunning(Handle: THandle; List: TList): boolean; stdcall;
    var
        i: integer;
        found: boolean;
        wndPid: THandle;
    begin
        Result := True;
        found := false;
        i := 0;
        GetWindowThreadProcessId(Handle, @wndPid);
        while (not found) and (i < List.Count) do
        begin
           if (wndPid = TMyProcessObject(List[i]).ProcessID) then
           begin
                found := true;
                TMyProcessObject(List[i]).StillRunning := True;
           end
           else inc(i);
        end;
    end;

//This function finds the windows and minimizes them
function EnumWindowsProcMinimize(Handle: THandle; List: TList): boolean; stdcall;
    var
        i: integer;
        found: boolean;
        wndPid: THandle;
    begin
        Result := True;
        found := false;
        i := 0;
        GetWindowThreadProcessId(Handle, @wndPid);
        while (not found) and (i < List.Count) do
        begin
           if (wndPid = TMyProcessObject(List[i]).ProcessID) then
           begin
                found := true;
                SendMessage( Handle, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
           end
           else inc(i);
        end;
    end;

//This function finds the windows and restores them
function EnumWindowsProcRestore(Handle: THandle; List: TList): boolean; stdcall;
    var
        i: integer;
        found: boolean;
        wndPid: THandle;
    begin
        Result := True;
        found := false;
        i := 0;
        GetWindowThreadProcessId(Handle, @wndPid);
        while (not found) and (i < List.Count) do
        begin
           if (wndPid = TMyProcessObject(List[i]).ProcessID) then
           begin
                found := true;
                SendMessage( Handle, WM_SYSCOMMAND, SC_RESTORE, 0 );
           end
           else inc(i);
        end;
    end;

//This function restores and brings to front a specific process
function EnumWindowsProcRestoreAndBringToFrontSpecificProcess(Handle: THandle; ProcessID_: THandle): boolean; stdcall;
    var
        found: boolean;
        wndPid: THandle;
    begin
        Result := True;
        GetWindowThreadProcessId(Handle, @wndPid);
        if (wndPid = ProcessID_) then
        begin
            SendMessage( Handle, WM_SYSCOMMAND, SC_RESTORE, 0 );
            SetForegroundWindow(Handle);
        end;
    end;

procedure TfrmMain.bStartProject2Click(Sender: TObject);
    begin
        SpawnOrRestoreProcess('MsgMenuExec', 'Project2', ExtractFilePath(Paramstr(0)), 'project2.exe');
    end;

procedure TfrmMain.bStartProject3Click(Sender: TObject);
    begin
        SpawnOrRestoreProcess('MsgMenuExec', 'Project3', ExtractFilePath(Paramstr(0)), 'project3.exe');
    end;

procedure TfrmMain.bStartNotepadClick(Sender: TObject);
    begin
        SpawnOrRestoreProcess('MsgMenuExec', 'Notepad', 'c:\windows\', 'notepad.exe');
    end;

procedure TfrmMain.bStartCalcClick(Sender: TObject);
    begin
        SpawnOrRestoreProcess('MsgMenuExec', 'Calc', 'c:\windown\system32\', 'calc.exe');
    end;

procedure TfrmMain.bRestoreAllClick(Sender: TObject);
    begin
        EnumWindows(@EnumWindowsProcRestore, integer(MyProcessList));
        Application.Restore;
        Application.BringToFront;
    end;

function TfrmMain.SpawnOrRestoreProcess(MsgMenuExec_, ProgName_, RunPath_, Exename_: string): boolean;
    var
        i: integer;
        foundat: integer;
    begin
        result := false;
        i := 0;
        foundat := -1;
        while (foundat = -1) and (i < MyProcessList.Count) do
        begin
            if (
                 (TMyProcessObject(MyProcessList[i]).MsgMenuExec = MsgMenuExec_) and
                 (TMyProcessObject(MyProcessList[i]).ProgName = ProgName_)
               ) then foundat := i else inc(i);
        end;
        if foundat = -1 then result := SpawnProcess(MsgMenuExec_, ProgName_, RunPath_, Exename_)
        else
        begin // already running this so find it, restore it, and bring it to the front
            EnumWindows(@EnumWindowsProcRestoreAndBringToFrontSpecificProcess,
              integer(TMyProcessObject(MyProcessList[foundat]).ProcessID));
            result := true;
        end;
    end;

function TfrmMain.SpawnProcess(MsgMenuExec_, ProgName_, RunPath_, Exename_: string): boolean;
    var
        StartupInfo: TStartupInfo;
        ProcessInfo: TProcessInformation;
    begin
        result := false;
        Timer1.Enabled := False;
        try
            fillChar( startupInfo, sizeof( startupInfo ), 0 );
            StartupInfo.cb := sizeof( startupInfo );
            StartupInfo.wShowWindow := SW_SHOW;

            if (CreateProcess(nil, PChar(RunPath_ + ExeName_), nil, nil, False,
             NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo)) then
             begin
                MyProcessList.Add(TMyProcessObject.Create(MsgMenuExec_, ProgName_, RunPath_,
                  Exename_,ProcessInfo.dwProcessId));
                result := true;
             end
             else
               MessageDlg(MsgMenuExec_ + #13 + '(' + ProgName_ + ')', mtWarning, [mbOK], 0)
        finally
            Timer1.Enabled := True;
        end;
    end;

procedure TfrmMain.FormCreate(Sender: TObject);
    begin
        MyProcessList := TList.Create;
        Timer1.Enabled := True;
        Caption := 'Main Menu';
    end;

procedure TfrmMain.FormDestroy(Sender: TObject);
    begin
        MyProcessList.Clear;
        MyProcessList.Free;
    end;

procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
        Timer1.Enabled := False;
        EnumWindows(@EnumWindowsProcClose, integer(MyProcessList));
    end;

procedure TfrmMain.Message_FromClientProgram(var msg: TMessage);
    begin
        if msg.WParam = 1 then
        begin // minimize all related windows, including this one
            EnumWindows(@EnumWindowsProcMinimize, integer(MyProcessList));
            Application.Minimize;
        end;
    end;
   
procedure TfrmMain.Timer1Timer(Sender: TObject);
    var
        i: integer;
    begin
        Timer1.Enabled := False;
        try
            for i:= 0 to pred(MyProcessList.Count) do
              TMyProcessObject(MyProcessList[i]).StillRunning := False;
// this next part marks any processes as "StillRunning"
            EnumWindows(@EnumWindowsProcCheckRunning, integer(MyProcessList));
            for i:= pred(MyProcessList.Count) downto 0 do
            begin
                if not TMyProcessObject(MyProcessList[i]).StillRunning then
                begin // this process is no longer running, re-enable the button for it
                    if (
                         (TMyProcessObject(MyProcessList[i]).MsgMenuExec = 'MsgMenuExec') and
                         (TMyProcessObject(MyProcessList[i]).ProgName = 'Notepad')
                       ) then bStartNotepad.Enabled := True
                    else if (
                         (TMyProcessObject(MyProcessList[i]).MsgMenuExec = 'MsgMenuExec') and
                         (TMyProcessObject(MyProcessList[i]).ProgName = 'Calc')
                       ) then bStartCalc.Enabled := True
                    else if (
                         (TMyProcessObject(MyProcessList[i]).MsgMenuExec = 'MsgMenuExec') and
                         (TMyProcessObject(MyProcessList[i]).ProgName = 'Project2')
                       ) then bStartProject2.Enabled := True
                    else if (
                         (TMyProcessObject(MyProcessList[i]).MsgMenuExec = 'MsgMenuExec') and
                         (TMyProcessObject(MyProcessList[i]).ProgName = 'Project3')
                       ) then bStartProject3.Enabled := True;
// Delete this process from our list since it is no longer running
                    MyProcessList.Delete(i);
                end;
            end;

        finally
            Timer1.Enabled := True;
        end;
    end;

{ TMyProcessObject }

constructor TMyProcessObject.Create(MsgMenuExec_, ProgName_, RunPath_, Exename_: string; ProcessID_: cardinal);
    begin
        inherited Create;
        MsgMenuExec := MsgMenuExec_;
        ProgName := ProgName_;
            RunPath := RunPath_;
        Exename := Exename_;
        ProcessID := ProcessID_;
    end;

end.



******** FORM FOLLOWS *********

object frmMain: TfrmMain
  Left = 367
  Top = 247
  Width = 255
  Height = 290
  Caption = 'frmMain'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnClose = FormClose
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 24
    Top = 96
    Width = 200
    Height = 33
    AutoSize = False
    Caption =
      'The following 2 do not minimize and restore because we did not w' +
      'rite them'
    WordWrap = True
  end
  object bStartNotepad: TButton
    Left = 72
    Top = 136
    Width = 91
    Height = 25
    Caption = 'bStartNotepad'
    TabOrder = 2
    OnClick = bStartNotepadClick
  end
  object bStartCalc: TButton
    Left = 72
    Top = 168
    Width = 91
    Height = 25
    Caption = 'bStartCalc'
    TabOrder = 3
    OnClick = bStartCalcClick
  end
  object bStartProject2: TButton
    Left = 72
    Top = 16
    Width = 89
    Height = 25
    Caption = 'bStartProject2'
    TabOrder = 0
    OnClick = bStartProject2Click
  end
  object bStartProject3: TButton
    Left = 72
    Top = 56
    Width = 89
    Height = 25
    Caption = 'bStartProject3'
    TabOrder = 1
    OnClick = bStartProject3Click
  end
  object bRestoreAll: TButton
    Left = 72
    Top = 216
    Width = 91
    Height = 25
    Caption = 'bRestoreAll'
    TabOrder = 4
    OnClick = bRestoreAllClick
  end
  object Timer1: TTimer
    Enabled = False
    OnTimer = Timer1Timer
    Left = 192
    Top = 32
  end
end


**** NOW YOU NEED TO ADD THIS TO EACH "CLIENT" APPLICATION ***
I'd put this in your "base" unit/form
drop a TApplicationEvents component (from the additional tab) on to the mainform of your other projects
set it's OnMinimize event

    ApplicationEvents1: TApplicationEvents;

procedure TForm2.ApplicationEvents1Minimize(Sender: TObject);
    var
        mainmenuapp: HWnd;
    begin
        mainmenuapp := FindWindow('TfrmMain', 'Main Menu');
        if mainmenuapp <> 0 then
          PostMessage(mainmenuapp, WM_USER+100, 1, 0); // 1 means "Minimize" to the main menu
    end;
Morning TheRealLoki

Hi just started working now, I will do what you said and let you know through the course of the day.

Thank you again for your GREAT help

Henry
South Africa
Hi TheRealLoki

I have started with the .dpr PART.

I am not sure if i am correct. I took my Main Menu application and change the dpr of my main menu application is this CORRECT ??
This Is my code


  Application.Initialize;
   PrevFMain := FindWindow('TfrmMainMenu','MainMenu');
                         {Hyphens required(type mismatch if not used.) First }
                         {parameter is the class, second is the CAPTION  }
                         {that is used for your Main Form, NOT the name   }
                         {of the form.}
  if PrevFMain <> 0 then
  begin
     ShowWindow(PrevFMain, sw_restore);  {Activates and displays the window, if minimized or maximized, at}
                                           {it's original size and position}
     SetForegroundWindow(PrevFMain); {Brings it to the front}
     Application.Terminate;
  end;

  PerformPackageUpdate;
  Application.CreateForm(TfrmMainMenu, frmMainMenu);
  Application.Run;

*** But when a debug and comes to the line PrevFMain FindWindow, it founded already a instance.. If i go and create a new application from scratch  then IT WORKS.

I dont know if it is to do with my inheritance, because I inherited from a Form Call Main Form, and in the Main form on its oncreate event I intiliazie my
datamodule.. Here is a example.

procedure TfrmMain.FormCreate(Sender: TObject);
begin


  if dm = nil then dm := Tdm.Create(Application); //intiliaze Datamodule to create a login screen and load Default Database values

  dm.IBDatabase.Connected := False;

  if not dm.Login  then
  begin
    MessageDlg('Login failed.', mtWarning, [mbOk], 0);
    PostMessage(Application.Handle, WM_QUIT, 0, 0);
    exit;
  end;

  if not dm.IBDatabase.Connected then
  begin
    MessageDlg('Error connecting to database', mtError, [mbOk], 0);
    Application.Terminate;
    exit;
  end;
 
end;

Can it be something on my inheritance, because there are currently nowhere my Main Menu application are running.
Hi TheRealLoki

I have go on to the minimize part now......Still cant get first part right

Before I changed my Main menu I have first tested the new minimizing on a new project.
1) When I  run it and call project 2,3 (a single form with a label on) from the app IT work 100%.
BUT when I replace project2 with a exe created with the inheritance and login screen (my normal client applications) it calls correctly..
but when I minimize the client application, then on my taskbar and on top of it, its creating small rectangle blocks about 50 of them, and also when I minimize it seems as it does it twice (maybe it does it twice because it does it for the Normal form and once for the Inherited form)...
I really dont undertsand why it go's so weird.

And also when I click on my main menu again to call that module again then it acts weird, it brings the previoused created form to the front BUT it also creating a white rectangle block in my left corner of my screen.

I must have a probem with all the single individual modules(the Main and Inherited Form)  .

Sorry I give you a lot of problems, but you are the only one who understand my problem.

Thank you

Henry
Hi TheRealLoki

I have take a client application and remove the
if dm = nil then dm := Tdm.Create(Application); //intiliaze Datamodule to create a login screen and load Default Database values
from the Main Form, then it seems to work when I minimize the form. I dont know why the datamodule would make the screen go so funny.

Let me just refresh how I DID all the client application.

-In Delphi6 I created a new application.
-Then i removed Unit1 from the appication.
-The I go and Add to my project the Datamodule.pas and MainForm.Pas {These are the forms that will be Inherited, by the newly created forms.The Datamodule load database values and loads the login screen. The MainForm just do a resize and has some default buttons on it and some default functions like GetEmployee Details}

-Then I go and say File->New->Other->project->And select formMain as inherit, and Datamodule as inherit.

-Now I have a new Unit1, and Unit2.
-I rename Unit1 to the project name for the application like (frmMonthlySalesRep)
-I rename my Unit2 to dm
-I rename the project to prjMonthlySalesRep

This mean I have a frmMonthlySales where I place extra components on and do all my coding for this project. If I need to inherit some function I inherit from my MainForm, or inherit from my Datamodule

*****MY MainForm***********{My main form is just a .pas file it is not a project}
{I use paramaters to send to my datamodule, the paramaters are a username,password and a databasename
My MainMenu also get these paramaters from my Datamodule, I save thsese paramaters in local varaibles}
On my MainForm onCreate event I call the following

 if dm = nil then dm := Tdm.Create(Application); //intiliaze Datamodule to create a login screen and load Default Database values

  dm.IBDatabase.Connected := False;

  if not dm.Login  then  //in my datamodule I call a function login this function check if there are a username and passowrd and a database send as paramaters
  begin
    MessageDlg('Login failed.', mtWarning, [mbOk], 0);
    PostMessage(Application.Handle, WM_QUIT, 0, 0);
    exit;
  end;

  if not dm.IBDatabase.Connected then
  begin
    MessageDlg('Error connecting to database', mtError, [mbOk], 0);
    Application.Terminate;
    exit;
  end;

****************Somehwere here I must have a mistake*******************

I thought i just explain to you again to let you know how my mind work.

Thanx Henry



the main .DPR part may get confused and find the window in delphi
To stop this, set your main form's caption to "blah" in delphi
but in the main form's create set it to what you really want
(see my formcreate() above)
eg. caption := 'main menu';
Morning

Sorry have change the on create event of my main menu form to create the caption on the oncreate event. Now is works 100% it, only creates my main menu once. The only thing is, when i minimize the main menu and run the main menu again , then it maximixed. BUT you cant minimize the window again.

-> Now for all my single exe (modules) I have also change the the caption to the on create event. But when I still call this exe from my main menu application ,
It creates it fine, BUT when i minimize it it still makes rectangle blocks on the bottom of my desktop (small blue rectangle blocks) AND if I go
and click on the button to say run project 2 again (the exe that are cuurently minimized) if restore the windows BUT while it is restoring you can see on my desktop on the left how small windows are popuping up( it's like small windows popuping up from the bottom of my desktop) after that the windows will restore to normal.

As I said previously, I think its my Datamodule that makes this funny events of the windows, because if i take the datamodule out, then it works 100%

Thank you Henry
I think it is minimizing to a box on screen because your datamodule is the "main form" so to speak, instead of the form..
You need the application to minimize rather than just the form minimize I guess.
I'll look into it later, but you could try messing with the .dpr, or specifically set "Application.MainForm := Form1;
Thank you, I agree i think it minimize the datamodule also, because sometimes when activate the application again from the main menu it makes a white rectangle screen in the left of the windows(quite a big white window)

Thank you again for helping me, I APPRECIATE ITE A LOT

HENRY
ah yes, the "can't minimize" problem
that happens because you need an application.restore, the "showwindow" does not do enough
sorry.
change your main .DPR code to this

  if PrevFMain <> 0 then
  begin
     ShowWindow(PrevFMain, sw_restore);  {Activates and displays the window, if minimized or maximized, at}
                                         {it's original size and position}
     SetForegroundWindow(PrevFMain); {Brings it to the front}
     PostMessage(PrevFMain, wm_user + 100, 2, 0); // 2 means do a restore please
     Application.Terminate;
  end;


and change your main form procedure to this


procedure TfrmMain.Message_FromClientProgram(var msg: TMessage);
    begin
        if msg.WParam = 1 then
        begin // minimize all related windows, including this one
            EnumWindows(@EnumWindowsProcMinimize, integer(MyProcessList));
            Application.Minimize;
        end
        else if msg.WParam = 2 then
        begin // restore this application
            Application.Restore;
        end;
    end;
Morning TheRealLoki

How was your weekend? I have change my main menu dpr, its fine now thanx.

I just want to find out if you will still help me of fixing the problem when I minimize a called exe module, because I tried a lof of things this weekend with my datamodule but with no luck. I can undersatnd why it makes such funny windows when you minimize a seperate module (I AM CONFUSED), becayse if I just compile a new project without a datamodule  and called that exe then is is 100%.

THANK YOU

HENRY
can you paste the .DPR of one of thos e datamodule applications here
I know some code that will work aound it, but maybe we just need to change teh order of things in your dpr
Hi this is a module that performs journal enquiries... I have not change anything yet THIS IS EXACLTY HOW IT IS CURRENTLY



program prjJournalsEnquiry;

uses
  Forms,
  formMAIN in '..\..\Packages\formMAIN.pas' {frmMain},     //***********INHERIT FORMMAIN
  DataModule in '..\..\Packages\DataModule.pas' {dmBase: TDataModule},//***********INHERIT DATAMODULE
  data in 'data.pas' {dm: TDataModule},
  formJournalsEnquiry in 'formJournalsEnquiry.pas' {frmJournalsEnquiry},
  formReport in 'formReport.pas' {frmReport};

{$R *.res}

begin
  Application.Initialize;
  Application.Title := 'Journal Document Enquiry';
  Application.CreateForm(TfrmJournalsEnquiry, frmJournalsEnquiry);
  Application.Run;
Hi

Sorry but i am struggeling now for 5 hours with STILL the minimize problem when you restore the main menu. I said previously it work but when I tested i thourogly i saw sometimes the minimize still does not work.

Here is my dpr code for my main menu
program prjMainMenu;

uses
  Forms,
  Windows,
  SysUtils,
  Dialogs,
  Messages,
  formMAIN in '..\..\Packages\formMAIN.pas' {frmMain},
  UpdatePackage in 'UpdatePackage.pas',
  DataModule in '..\..\Packages\DataModule.pas' {dmBase: TDataModule},
  data in 'data.pas' {dm: TDataModule},
  formMainMenu in 'formMainMenu.pas' {frmMainMenu};

{$R *.res}
var
PrevFMain : hwnd;   {handle variable}
begin
   Application.Initialize;
   PerformPackageUpdate;
   PrevFMain := FindWindow('TfrmMainMenu', 'Bizcom Main Menu');
                         {Hyphens required(type mismatch if not used.) First }
                         {parameter is the class, second is the CAPTION  }
                         {that is used for your Main Form, NOT the name   }
                         {of the form.}
   if PrevFMain <> 0 then
   begin
     ShowWindow(PrevFMain, sw_restore);  {Activates and displays the window, if minimized or maximized, at}
                                         {it's original size and position}

     SetForegroundWindow(PrevFMain); {Brings it to the front}
     PostMessage(PrevFMain, wm_user + 100, 2, 0); // 2 means do a restore please
     Application.Terminate;
   end;



   Application.CreateForm(TfrmMainMenu, frmMainMenu); // otherwise, if this is the only instance, create the form and show it as normally
   Application.Run;
end.
I've tried making an application like yours, but I'm not getting the problem.
the .DPR creates the main form, and the ain form creates a datamodule.
when you click on the minimize button, youare getting it minimizing to the bottome left of the screen
is this correct?
It's not doing it for me. perhaps I need to try it with inheritence
Morning cant I sent you my forms then maybe it will be much easier for you to solve.

Thanx
sure lokiwashere at yahoo dot co dot nz, zip'em up if you can
Thank you I have sent the forms right now.

HEnry
ah found it
the problem is in my main menu code :-(
the EnumWindows calls see the datamodule as well as the form, so it sends them a minimize, causing it to go to the bottom left.
my code changes below will stop once it sends a minimize to the first window (which should be the main menu) so it works

change the following bits to this code :-

type
    TMyProcessObject = class
    public
        MsgMenuExec, ProgName, RunPath, Exename: string;
        ProcessID: cardinal;
        StillRunning: boolean;
        SentMinimize: boolean;
        constructor Create(MsgMenuExec_, ProgName_, RunPath_, Exename_: string; ProcessID_: cardinal);
    end;

...

//This function finds the windows and minimizes them
function EnumWindowsProcMinimize(Handle: THandle; List: TList): boolean; stdcall;
    var
        i: integer;
        found: boolean;
        wndPid: THandle;
    begin
        Result := True;
        found := false;
        i := 0;
        GetWindowThreadProcessId(Handle, @wndPid);
        while (not found) and (i < List.Count) do
        begin
           if (wndPid = TMyProcessObject(List[i]).ProcessID) and
           (not TMyProcessObject(List[i]).SentMinimize) then
           begin
                found := true;
                SendMessage( Handle, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
                TMyProcessObject(List[i]).SentMinimize := True;
           end
           else inc(i);
        end;
    end;

...

procedure TfrmMain.Message_FromClientProgram(var msg: TMessage);
    var
        i: integer;
    begin
        if msg.WParam = 1 then
        begin // minimize all related windows, including this one
            for i := 0 to pred(MyProcessList.Count) do TMyProcessObject(MyProcessList[i]).SentMinimize := False;
            EnumWindows(@EnumWindowsProcMinimize, integer(MyProcessList));
            Application.Minimize;
        end
        else if msg.WParam = 2 then
        begin // restore this application
            Application.Restore;
        end;
    end;
Hi Its almost there, did you see if the window is minimized, and you go and click to reopen that window from the main menu then it makes a with rectangle screen in the left corner when it restores that windows.

Thanx
Hi did you manage to see the problem when a windows rececive focus again, when you open a previuosed open window from the menu again. I als think it is the datamodule that does the white screen in the left corner.

Thanx
ASKER CERTIFIED SOLUTION
Avatar of TheRealLoki
TheRealLoki
Flag of New Zealand image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi, the probel is when you click on the menu again, AND IF THE WINDOW IS ALREADY opened and it refocus the window, THEN IT make a white window in the left corner. I have sent a screen shot to your yahoo account.

Thanx
Hi TheRealLoki

Did you maybe  managed to see what did the problem is when the windows receive focus again, from the main menu, the screenshot I have sent to your yahoo email account, with the white window in the left corner.

Thank you

Enjoy your weekend

Henry