In Delphi I've used ShellExecute for years to launch (and optionally wait for) other applications. Now though, I need to have one of these applications appear in one of my Delphi app forms. I've tried the code below as a simple test to open notepad (which it does) and to display the result within PAnel1 on my form (which it doesnt). Can some kind person put me on the right track? Thanks
在Delphi中,我使用ShellExecute多年来启动(并可选择等待)其他应用程序。现在,我需要在我的一个Delphi应用程序表单中显示其中一个应用程序。我已经尝试了下面的代码作为一个简单的测试来打开记事本(它确实如此)并在我的表单上显示PAnel1中的结果(它没有)。有些人可以让我走上正轨吗?谢谢
var
Rec : TShellExecuteInfo;
wnd : HWnd;
const
AVerb = 'open';
AParams = '';
AFileName = 'Notepad.exe';
ADir = '';
begin
FillChar(Rec, SizeOf(Rec), #0);
Rec.cbSize := SizeOf(Rec);
Rec.fMask := SEE_MASK_NOCLOSEPROCESS;
Rec.lpVerb := PChar( AVerb );
Rec.lpFile := PChar( AfileName );
Rec.lpParameters := PChar( AParams );
Rec.lpDirectory := PChar( Adir );
Rec.nShow := sw_Show;
ShellExecuteEx(@Rec);
wnd := Windows.FindWindow( 'Notepad', nil );
Windows.SetParent( Wnd, PAnel1.Handle );
end;
3 个解决方案
#1
All error checking omitted, but this should get you started:
省略了所有错误检查,但这应该让你开始:
procedure TForm1.Button1Click(Sender: TObject);
var
Rec: TShellExecuteInfo;
const
AVerb = 'open';
AParams = '';
AFileName = 'Notepad.exe';
ADir = '';
begin
FillChar(Rec, SizeOf(Rec), #0);
Rec.cbSize := SizeOf(Rec);
Rec.fMask := SEE_MASK_NOCLOSEPROCESS;
Rec.lpVerb := PChar( AVerb );
Rec.lpFile := PChar( AfileName );
Rec.lpParameters := PChar( AParams );
Rec.lpDirectory := PChar( Adir );
Rec.nShow := SW_HIDE;
ShellExecuteEx(@Rec);
WaitForInputIdle(Rec.hProcess, 5000);
fNotepadHandle := Windows.FindWindow( 'Notepad', nil );
Windows.SetParent( fNotepadHandle, Handle );
Resize;
ShowWindow(fNotepadHandle, SW_SHOW);
end;
procedure TForm1.FormResize(Sender: TObject);
begin
if IsWindow(fNotepadHandle) then begin
SetWindowPos(fNotepadHandle, 0, 0, 0, ClientWidth, ClientHeight,
SWP_ASYNCWINDOWPOS);
end;
end;
What you should definitely do is enumerate the windows of the new process, instead of simply using any window handle that FindWindow() returns.
你应该做的是枚举新进程的窗口,而不是简单地使用FindWindow()返回的任何窗口句柄。
#2
var
URL: string;
begin
URL:= DBMemoURL.Text;
// ShellExecute(self.WindowHandle,'open', PChar(URL), nil, nil, SW_SHOW); //default browser
ShellExecute(self.WindowHandle,'open','chrome.exe', PChar(URL), nil, SW_SHOW);
#3
That will be a tricky one, if it's even possible.
如果可能的话,这将是一个棘手的问题。
I've seen approaches that will work for text-based applications - they generally capture the standard output of the process as it happens and put it into a text control.
我已经看到了适用于基于文本的应用程序的方法 - 它们通常会捕获流程的标准输出,并将其放入文本控件中。
But what you're talking about is a fully fledged graphical application (Notepad, despite working on text, display pixels, not character codes).
但你所说的是一个完全成熟的图形应用程序(记事本,尽管处理文本,显示像素,而不是字符代码)。
So, unless Notepad provides an interface where you can:
因此,除非记事本提供了一个界面,您可以:
- request arbitrary characters in the buffer; and
- send arbitrary keystrokes to the program, I'd say you're flat out of luck.
请求缓冲区中的任意字符;和
发送任意击键到程序,我会说你运气不好。
Definitely a kludge, but one option is to continuously monitor the Notepad windows and ensure it's always superimposed over your forms client area. That's pretty horrible since you have to stop it moving, resizing, minimizing and so on, and maintain its z-order to be just above your applications. I wouldn't wish those requirements on my worst enemy.
肯定是一个kludge,但一个选项是持续监控记事本窗口,并确保它始终叠加在您的窗体客户区域。这是非常可怕的,因为你必须停止移动,调整大小,最小化等等,并保持其z顺序高于你的应用程序。我不希望对我最大的敌人提出这些要求。
Have you thought of using an editor control built specifically for Delphi (or an ActiveX editor that you could embed)? That might be a better approach.
您是否考虑过使用专为Delphi构建的编辑器控件(或者您可以嵌入的ActiveX编辑器)?这可能是一种更好的方法。
#1
All error checking omitted, but this should get you started:
省略了所有错误检查,但这应该让你开始:
procedure TForm1.Button1Click(Sender: TObject);
var
Rec: TShellExecuteInfo;
const
AVerb = 'open';
AParams = '';
AFileName = 'Notepad.exe';
ADir = '';
begin
FillChar(Rec, SizeOf(Rec), #0);
Rec.cbSize := SizeOf(Rec);
Rec.fMask := SEE_MASK_NOCLOSEPROCESS;
Rec.lpVerb := PChar( AVerb );
Rec.lpFile := PChar( AfileName );
Rec.lpParameters := PChar( AParams );
Rec.lpDirectory := PChar( Adir );
Rec.nShow := SW_HIDE;
ShellExecuteEx(@Rec);
WaitForInputIdle(Rec.hProcess, 5000);
fNotepadHandle := Windows.FindWindow( 'Notepad', nil );
Windows.SetParent( fNotepadHandle, Handle );
Resize;
ShowWindow(fNotepadHandle, SW_SHOW);
end;
procedure TForm1.FormResize(Sender: TObject);
begin
if IsWindow(fNotepadHandle) then begin
SetWindowPos(fNotepadHandle, 0, 0, 0, ClientWidth, ClientHeight,
SWP_ASYNCWINDOWPOS);
end;
end;
What you should definitely do is enumerate the windows of the new process, instead of simply using any window handle that FindWindow() returns.
你应该做的是枚举新进程的窗口,而不是简单地使用FindWindow()返回的任何窗口句柄。
#2
var
URL: string;
begin
URL:= DBMemoURL.Text;
// ShellExecute(self.WindowHandle,'open', PChar(URL), nil, nil, SW_SHOW); //default browser
ShellExecute(self.WindowHandle,'open','chrome.exe', PChar(URL), nil, SW_SHOW);
#3
That will be a tricky one, if it's even possible.
如果可能的话,这将是一个棘手的问题。
I've seen approaches that will work for text-based applications - they generally capture the standard output of the process as it happens and put it into a text control.
我已经看到了适用于基于文本的应用程序的方法 - 它们通常会捕获流程的标准输出,并将其放入文本控件中。
But what you're talking about is a fully fledged graphical application (Notepad, despite working on text, display pixels, not character codes).
但你所说的是一个完全成熟的图形应用程序(记事本,尽管处理文本,显示像素,而不是字符代码)。
So, unless Notepad provides an interface where you can:
因此,除非记事本提供了一个界面,您可以:
- request arbitrary characters in the buffer; and
- send arbitrary keystrokes to the program, I'd say you're flat out of luck.
请求缓冲区中的任意字符;和
发送任意击键到程序,我会说你运气不好。
Definitely a kludge, but one option is to continuously monitor the Notepad windows and ensure it's always superimposed over your forms client area. That's pretty horrible since you have to stop it moving, resizing, minimizing and so on, and maintain its z-order to be just above your applications. I wouldn't wish those requirements on my worst enemy.
肯定是一个kludge,但一个选项是持续监控记事本窗口,并确保它始终叠加在您的窗体客户区域。这是非常可怕的,因为你必须停止移动,调整大小,最小化等等,并保持其z顺序高于你的应用程序。我不希望对我最大的敌人提出这些要求。
Have you thought of using an editor control built specifically for Delphi (or an ActiveX editor that you could embed)? That might be a better approach.
您是否考虑过使用专为Delphi构建的编辑器控件(或者您可以嵌入的ActiveX编辑器)?这可能是一种更好的方法。