Solved

D3: "Docking" a window to another app

Posted on 1998-06-07
11
142 Views
Last Modified: 2010-04-04
My program will be calling other generic Windows Applications. These generic apps should be assumed that they are NOT Delphi Apps and I don't have the source.

So, How would I go about Placing a small Delphi TFORM on top of these generic apps. It should look to the user that they are "combined". When one window is resized or move, the other will follow.

Has anyone done this? Do you have any pre-build componets to do this? Do you have any code examples?

John
0
Comment
Question by:zitt
  • 6
  • 5
11 Comments
 
LVL 5

Expert Comment

by:inter
ID: 1351245
Hi,
The following code does what you want. Modify it to fit your needs.

To test open a Notepad. Paste the following code as unit1 to a new project. Adjust the HEIGHT of your window since I do not control it.

// CODE BEGINS
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure MoveForm(wp: TRect);
  end;

  TDockThread = class(TThread)
    procedure Execute; override;
  end;

var
  Form1: TForm1;
  DockThread: TDockThread = nil;

implementation

{$R *.DFM}

var
  hw: HWND;
  op: TRect;

procedure TForm1.MoveForm(wp: TRect);
begin
  left := wp.left;
  top := wp.top - Height;
  width := wp.right - left;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  hw := FindWindow('Notepad', nil);
  // if we find the window then proceed
  if hw <> 0 then
  begin
  //create suspended to modify properties
    DockThread := TDockThread.Create(True);
    DockThread.FreeOnTerminate := true;
    DockThread.Resume;
  end;
end;

procedure TDockThread.Execute;
var
  wp: TRect;
begin
  while not Terminated and
    not Application.Terminated do
  begin
    if hw <> 0 then
      GetWindowRect(hw, wp)
    else continue; //if the hw is invalid do not process
    if StrLComp(@wp, @op, sizeof(wp)) <> 0 then
    begin
      Form1.MoveForm(wp);
      op := wp;
    end;
    Sleep(50);
  end;
end;

end.
//CODE ENDS
Regards, Igor
0
 
LVL 5

Expert Comment

by:inter
ID: 1351246
Hi again,
Doing thread loop as follows is more efficient:

  while not Terminated and
    not Application.Terminated do
  begin
    Sleep(50);
    if hw <> 0 then
      GetWindowRect(hw, wp)
    else continue; //if the hw is invalid do not process
    if StrLComp(@wp, @op, sizeof(wp)) <> 0 then
    begin
      Form1.MoveForm(wp);
      op := wp;
    end;
  end;
Bye, Igor
0
 

Author Comment

by:zitt
ID: 1351247
Thanks for your proposed answer... however, you'll note that I stated a "generic" window. Also to clearify:

It should also be assumed that the program cannot be coded to FindWindow() a specific title bar (or class) as my app will be configurable to call _any_ app.

John
0
 
LVL 5

Expert Comment

by:inter
ID: 1351248
Hi,
What do we now about that GENERIC application? We should choose the application somehow. Please explain more, I think I can help on this.
Igor
0
 

Author Comment

by:zitt
ID: 1351249
My application will provide "plug-in" support. Any user can plug any app into my app and my app will run it. The only thing we'll know about the "plug-in" is it's Process ID passed back from CreateProcess().

My research todate has shown that I can do some EnumWindows() to associate a top-level window to the process ID. Now I have a HWND I can pass to GetWindowRect() functions to find the sizes of the window.

The problem is I want to avoid "polling" the HWnd using GetWindowRect() if possible. I'd like to write a shared memory DLL to interrupt my app telling it the window moved. I have the code written... but I've getting GPFs and/or page faults.

Maybe I'll get lucky tonight and get it working. Any ideas?
John
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 5

Expert Comment

by:inter
ID: 1351250
Ok then,
If you have the HWND, you can inject your MessageProc to that HWND an get all the windows messages before it receives. Then position your window according to that windows WM_MOVE or WM_SIZE messages => you do not need to poll. What do you think? I see that you are an advanced programmer, anyway if you want help in injecting your windows proc I am here for help.
Regards,
Igor
0
 

Author Comment

by:zitt
ID: 1351251
I now have a working DLL. The problems getting this method to work was in getting a "shared" memory space so that "generic" applications could read/write during the HOOK callback function. Without the shared memory, other apps would GPF the DLL.

Trust me when I say this wasn't easy. And also trust me when I say there are no examples on the "net" to show this.

So, right now I'm in the process or taking what I've learned and writing a set of componets for Delphi 3.0. Since this code has taken me many days of "hacking", I proably won't offer it for free if I even offer it. I'm going to write the componets to make it easier on me and my current app. If there is interest, I'll consider release complied units as Shareware. Watch www.zittware.com for more information.

Inter, thanks for your help. As my components near completion (I expect no later than few wks) I'll award the points to you for your effort.

John
0
 
LVL 5

Expert Comment

by:inter
ID: 1351252
Hi,
I am happy that you be succeeded. May I post my prev answer so that other people can have that primitive docking code without browsing the discussion?
Regards, Igor
0
 

Author Comment

by:zitt
ID: 1351253
Sure post whatever you'd like.
0
 
LVL 5

Accepted Solution

by:
inter earned 100 total points
ID: 1351254


      To test open a Notepad. Paste the following code as unit1 to a new project. Adjust the HEIGHT of
      your window since I do not control it.

      // CODE BEGINS
      unit Unit1;

      interface

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

      type
        TForm1 = class(TForm)
          procedure FormCreate(Sender: TObject);
        private
          { Private declarations }
        public
          { Public declarations }
          procedure MoveForm(wp: TRect);
        end;

        TDockThread = class(TThread)
          procedure Execute; override;
        end;

      var
        Form1: TForm1;
        DockThread: TDockThread = nil;

      implementation

      {$R *.DFM}

      var
        hw: HWND;
        op: TRect;

      procedure TForm1.MoveForm(wp: TRect);
      begin
        left := wp.left;
        top := wp.top - Height;
        width := wp.right - left;
      end;

      procedure TForm1.FormCreate(Sender: TObject);
      begin
        hw := FindWindow('Notepad', nil);
        // if we find the window then proceed
        if hw <> 0 then
        begin
        //create suspended to modify properties
          DockThread := TDockThread.Create(True);
          DockThread.FreeOnTerminate := true;
          DockThread.Resume;
        end;
      end;

      procedure TDockThread.Execute;
      var
        wp: TRect;
      begin
        while not Terminated and
          not Application.Terminated do
        begin
          if hw <> 0 then
            GetWindowRect(hw, wp)
          else continue; //if the hw is invalid do not process
          if StrLComp(@wp, @op, sizeof(wp)) <> 0 then
          begin
            Form1.MoveForm(wp);
            op := wp;
          end;
          Sleep(50);
        end;
      end;

      end.
      //CODE ENDS
      Regards, Igor
0
 

Author Comment

by:zitt
ID: 1351255
If anyone remains interested in my Generic control that will perform a "auto" DOCK to any window opened under program control, please send e-mail to zitt@bigfoot.com or watch
www.zittware.com for more information.

Ingor, thanks for attempt at helping me... Who know something seemingly simple could be so difficult.

John
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

26 Experts available now in Live!

Get 1:1 Help Now