Go Premium for a chance to win a PS4. Enter to Win

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

D3: "Docking" a window to another app

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
zitt
Asked:
zitt
  • 6
  • 5
1 Solution
 
interCommented:
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
 
interCommented:
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
 
zittAuthor Commented:
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
Industry Leaders: 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!

 
interCommented:
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
 
zittAuthor Commented:
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
 
interCommented:
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
 
zittAuthor Commented:
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
 
interCommented:
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
 
zittAuthor Commented:
Sure post whatever you'd like.
0
 
interCommented:


      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
 
zittAuthor Commented:
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

Industry Leaders: 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!

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