Solved

D3: "Docking" a window to another app

Posted on 1998-06-07
11
147 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
Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

 
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
 
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

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Tviruailstringtree sort multi columns on header click 1 61
Performance of SQL statement 37 111
Base1 Encode/Decode 3 77
Delphi: barcode reading on android platform 1 26
A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

806 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