powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Как захватить окно чужого приложения и встроить в своё окно?
6 сообщений из 6, страница 1 из 1
Как захватить окно чужого приложения и встроить в своё окно?
    #40051344
registered
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Есть функция SetParent, но фокус у того окна остаётся отдельным, а нужно, чтобы был общий фокус.
Некоторые программы так делают, например, SumatraPDF в качестве плагина (не знаю, через SetParent, или нет).

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
function RunApp(app,path,params:string):dword;
var
  sInfo: TStartupInfo;
  pInfo: TProcessInformation;
begin

  result:=0;

  FillChar(sInfo, SizeOf(sInfo), 0);
  sInfo.cb := SizeOf(sInfo);

  if CreateProcess(PChar(app), PChar(app+' '+params), 0, 0, False, CREATE_NO_WINDOW, 0, PChar(path), sInfo, pInfo) then
  begin
    result:=pInfo.hProcess;
    exit;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var h,handle1:thandle;
    tt:cardinal;
    lCurStyle:dword;
begin
h:=RunApp('c:\windows\notepad.exe','c:\windows','');
if h>0 then
  begin
  handle1:=0;
  tt:=GetTickCount;
    repeat
    handle1 := FindWindow('Notepad',nil);
    if GetTickCount-tt>2000 then break;
    if handle1=0 then sleep(1);
    until handle1<>0;
  if handle1>0 then
    begin
    winapi.windows.setparent(handle1,handle);
    SetWindowLong( handle1, GWL_STYLE, GetWindowLong( Handle1, GWL_STYLE ) and not WS_CAPTION and not WS_SYSMENU and not WS_THICKFRAME and not WS_MINIMIZE and not WS_MAXIMIZEBOX) ;
    lCurStyle := GetWindowLong(handle1, GWL_EXSTYLE);
    SetWindowLong(handle1, GWL_EXSTYLE, lCurStyle or WS_EX_DLGMODALFRAME);
    SetWindowPos(handle1,0,form1.ClientRect.Left,form1.ClientRect.Top,form1.ClientRect.Right-form1.ClientRect.Left,form1.ClientRect.bottom-form1.ClientRect.top,SWP_NOZORDER{ or SWP_NOACTIVATE});
    end;
  end;
end;


Дополнительно: пытаюсь скрыть заголовок у Notepad, не получается. Если убрать SetParent, то окно Notepad вообще пропадает (остаётся мусор).
...
Рейтинг: 0 / 0
Как захватить окно чужого приложения и встроить в своё окно?
    #40051496
ma1tus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
registered
а нужно, чтобы был общий фокус

a) не тренироваться на примитивном "notepad.exe" *явно дёрнуто с интернетов: как встроить блокнот в свою программу
b) вешать хук winproc (или цепочку оных) с отловом и передачей nc_activate окну по getancestor(hwnd, ga_root)
с) даже с aсtivex - без гарантии, что получение фокуса его, дочерним, окном, активирует заголовок верхнего парента
...
Рейтинг: 0 / 0
Как захватить окно чужого приложения и встроить в своё окно?
    #40051545
Фотография Кроик Семён
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
registered,

https://alt.lang.delphi.narkive.com/dXS11op1/external-application-from-within-a-delphi-form

скопировал сюда, вдруг код рабочий, тогда имеет смысл сохранить здесь на родном sql.ru

External Application from within a Delphi Formвзял отсюда:
https://alt.lang.delphi.narkive.com/dXS11op1/external-application-from-within-a-delphi-form

Q:
I know how to run an external application from within Delphi.. what I need
to know is it possible to have an external program run inside a Delphi
form?

I use this very cumbersome application at work. Its a mainfraim emulator.
There are at least 12 different screens I access numerous times a day. I
thought that I could write a simple shell program with tabs so I could run
the mainframe emulator within the shell and have different instances of
the program for each tab. Is this possible with Delphi?

Thanks,
Dave

A:
It seems to work quite nicely.
Here is a Demo
- Followed by a few comments.

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
unit Unit1;

// Launch App and Re-Parent in a Panel
// 25th June 2004 - J French

// Add Two Buttons and One Large Panel

interface

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

type
TForm1 = class(TForm)
   Button1: TButton;
   Button2: TButton;
   Panel1: TPanel;
   procedure Button1Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
private
   { Private declarations }
   mHWnd :HWND; // hWnd of Slave App
public
   { Public declarations }
   Constructor Create( AOwner:TComponent );Override;
end;

var
   Form1: TForm1;

implementation

{$R *.DFM}
//------------------------------------------------------------------------------
constructor TForm1.Create(AOwner: TComponent);
begin
   Inherited;
   Button1.Caption := 'Launch Notepad';
   Button2.Caption := 'Terminate Notepad';
end;
//------------------------------------------------------------------------------
{
Get hWnd from a Process ID
}
Function InstanceToWnd( Const TgtPID:DWORD):HWND;
Var
   ThisHWnd :HWND;
   ThisPID :DWORD;
Begin
   Result := 0;
   ThisPID := 0;
   // Find the first window
   ThisHWnd := FindWindow( Nil, Nil);
   While ThisHWnd <> 0 Do
   Begin
      //Check if the window isn't a child
      If GetParent( ThisHWnd ) = 0 Then
      Begin
         //Get the window's thread & ProcessId
         GetWindowThreadProcessId( ThisHWnd, Addr(ThisPID) );
         If ThisPID = TgtPID Then
         Begin
            Result := ThisHWnd;
            Break;
         End;
      End;
      // 'retrieve the next window
      ThisHWnd := GetWindow( ThisHWnd, GW_HWNDNEXT );
   End;

End;{InstanceToWnd}
//------------------------------------------------------------------------------
{
Launch App and return hWnd
}
Function ExecCmd( Const cmdline:String):HWND;
Var
   PI :PROCESS_INFORMATION;
   SI :STARTUPINFO;
   Ret :LONGBOOL;
Begin;
   Result := 0;
   ZeroMemory( Addr(PI), SizeOf(PI) );
   ZeroMemory( Addr(SI), SizeOf(SI) );
   // Initialize the STARTUPINFO structure
   SI.cb := SizeOf(SI);

   // Start the shelled application:
   Ret := CreateProcessA( Nil, PChar( cmdline ),
                          Nil, Nil, True,
                          NORMAL_PRIORITY_CLASS,
                          Nil, Nil,
                          SI, PI);
   // --- let it start - this seems important
   WaitForSingleObject( PI.hProcess, 500 );
   If Ret Then
   Begin
      Result := InstanceToWnd( PI.dwProcessID );
      CloseHandle( PI.hThread );
      CloseHandle( PI.hProcess );
   End;

End;{ExecCmd}
//------------------------------------------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
begin
   // Lock the window update - prevent flashing
   // Does not work under XP
   LockWindowUpdate( GetDesktopWindow );

   // Execute notepad.Exe - Get its hWnd
   mHWnd := ExecCmd( 'notepad.exe' );
   If mHWnd = 0 Then
      ShowMessage( 'Error starting the app' );

   // Set the notepad's parent
   If mHWnd <> 0 Then
   Begin
      Windows.SetParent( mHWnd, Panel1.Handle );
      Windows.MoveWindow(mHWnd, 0, 0,
      Panel1.ClientWidth,
      Panel1.ClientHeight, True);
      // Put the focus on notepad
      Windows.SetFocus( mHWnd );
   End;

   // Unlock window update
   LockWindowUpdate( 0 );
end;
//------------------------------------------------------------------------------
procedure TForm1.Button2Click(Sender: TObject);
begin
   SendMessage(mHWnd, WM_CLOSE, 0, 0);
end;
//------------------------------------------------------------------------------

end.



Under Win95 the LockWindowUpdate() prevents the App showing up as
'normal' just before it is Re-Parented

This does not work under XP
A workaround would be to start it minimized and then resize it

WHILE DEBUGGING comment out the LockWindowUpdate

Notice that the Slave App does not appear in the Taskbar
- this may or may not be a problem

Slave Apps do appear in the Task Manager under Win95
Under XP they appear in the list of Processes not Running Apps

I have only (so far) tested this under Delphi using NotePad as the
slave App.

Also notice that the Delphi 'Host' loses focus when the Slave has
focus. This can be spoofed by trapping WM_ACTIVATEAPP

It would be an idea for someone else to give this code a once over,
just in case I've slipped up somewhere.

Hope this is useful
...
Рейтинг: 0 / 0
Как захватить окно чужого приложения и встроить в своё окно?
    #40051576
Фотография Кроик Семён
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
P.S.

добавил две вставочки
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
//procedure TForm1.btnLaunchNotepadClick(Sender: TObject);
procedure TForm1.Button1Click(Sender: TObject);
begin
   // Lock the window update - prevent flashing
   // Does not work under XP
   LockWindowUpdate( GetDesktopWindow );

   // Execute notepad.Exe - Get its hWnd
   mHWnd := ExecCmd( 'notepad.exe' );
   If mHWnd = 0 Then
      ShowMessage( 'Error starting the app' );

   // Set the notepad's parent
   If mHWnd <> 0 Then
   Begin
      //скрываем заголовок и окантовку
      SetWindowLong(mHWnd,
                    GWL_STYLE,
                    GetWindowLong(Handle, GWL_STYLE) and
                       not WS_OVERLAPPEDWINDOW and
                       not WS_OVERLAPPED and
                       not WS_CAPTION and
                       not WS_SYSMENU and
                       not WS_BORDER and
                       not WS_SIZEBOX and
                       not WS_DLGFRAME );


      Windows.SetParent( mHWnd, Panel1.Handle );

      Windows.MoveWindow(mHWnd, 0, 0,
                         Panel1.ClientWidth, Panel1.ClientHeight,
                         True);

      //махимизируем на всю панель Panel1
      ShowWindow(mHWnd,
                 SW_MAXIMIZE);

      // Put the focus on notepad
      Windows.SetFocus( mHWnd );
   End;

   // Unlock window update
   LockWindowUpdate( 0 );
end;
...
Рейтинг: 0 / 0
Как захватить окно чужого приложения и встроить в своё окно?
    #40051664
registered
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А почему у моей не работает?
Чтобы был общий фокус, нужно WS_CHILD, но нет меню.
Если убрать ShowWindow(mHWnd, SW_MAXIMIZE), то будет мусор вместо заголовка и меню, и фокус не получает (вообще, а не по SetFocus).
Если SetParent раньше, чем SetWindowLong, то тоже фокус не получает.
...
Рейтинг: 0 / 0
Как захватить окно чужого приложения и встроить в своё окно?
    #40051682
Фотография Кроик Семён
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
я,кстати, ошибся хендлом.
и вообще, как оказалось "not WS_OVERLAPPEDWINDOW" достаточно

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
...
      //скрываем заголовок и окантовку
      SetWindowLong(mHWnd,
                    GWL_STYLE,
                    GetWindowLong(mHWnd, GWL_STYLE) and
                       not WS_OVERLAPPEDWINDOW {and
                       not WS_OVERLAPPED and
                       not WS_CAPTION and
                       not WS_SYSMENU and
                       not WS_BORDER and
                       not WS_SIZEBOX and
                       not WS_DLGFRAME} );
...
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Как захватить окно чужого приложения и встроить в своё окно?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]