使用以下代码,我设法在Windows窗体中加载一些应用程序。
这个功能的作用是......
Usings
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
常量
const int GWL_STYLE = -16;
const long WS_VISIBLE = 0x10000000,
WS_MAXIMIZE = 0x01000000,
WS_BORDER = 0x00800000,
WS_CHILD = 0x40000000;
功能
IntPtr LoadExtern(Control Panel, string Path)
{
try
{
Process Process = Process.Start(Path);
Process.WaitForInputIdle();
IntPtr Handle = Process.MainWindowHandle;
SetParent(Handle, Panel.Handle);
SetWindowLong(Handle, GWL_STYLE, (int)(WS_VISIBLE+(WS_MAXIMIZE|WS_BORDER)));
MoveWindow(Handle, 0, 0, Panel.Width, Panel.Height, true);
Panel.Resize += new EventHandler(
delegate(object sender, EventArgs e)
{
MoveWindow(Handle, 0, 0, Panel.Width, Panel.Height, true);
}
);
this.FormClosed += new FormClosedEventHandler(
delegate(object sender, FormClosedEventArgs e) {
SendMessage(Handle, 83, 0, 0);
Thread.Sleep(1000);
Handle = IntPtr.Zero;
}
);
return Handle;
}
catch (Exception e) { MessageBox.Show(this, e.Message, "Error"); }
return new IntPtr();
}
DLL Imports
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
static extern bool MoveWindow(IntPtr Handle, int x, int y, int w, int h, bool repaint);
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr Handle, int Msg, int wParam, int lParam);
此代码适用于某些应用程序,例如Windows记事本。记事本已启动并包含在我的表单面板中。没有标题,也没有边界,应该如此。
LoadExtern(panel1, "notepad.exe");
关闭表单后,嵌入式进程会像预期的那样终止。
不幸的是,我的代码不适用于其他(较大的)应用程序,如firefox或sublimetext。
LoadExtern(panel2, @"C:\Program Files (x86)\Mozilla Firefox\firefox.exe");
我的表单会启动并启动firefox,但是在自己的窗口中会发生什么。你能帮我在我的应用程序中包含sublimetext或firefox吗?
感谢盛江的答案,我得到了更多的应用程序。我所做的是等待主窗口处理。
Process.WaitForInputIdle();
IntPtr Handle = new IntPtr();
for (int i = 0; Handle == IntPtr.Zero && i < 300; i++)
{
Handle = Process.MainWindowHandle;
Thread.Sleep(10);
}
但我仍然无法嵌入像Windows资源管理器这样的应用程序。
答案 0 :(得分:3)
你的代码很巧妙。
即使主窗口是明显创建的,实际上是新流程中的第一个可见窗口,您仍可能遇到问题。
来自SetParent的文档:
应用程序可以使用SetParent函数设置弹出窗口,重叠窗口或子窗口的父窗口。
它并没有说您可以重新显示顶级窗口。实际上,顶级窗口提供了程序可能依赖的许多服务,例如
答案 1 :(得分:0)
此代码适用于大多数应用程序。我只是在表单上使用webbrowser控件嵌入文件资源管理器,并将其url设置为文件位置。然后,Internet Explorer控制器神奇地变成了文件浏览器。
这是我的最终代码,请随意将其用于您自己的项目。
IntPtr EmbedProcess(Control Panel, string Path)
{
string Name = NameFromPath(Path);
foreach (Process Task in Process.GetProcesses())
{
if (NameFromPath(Task.ProcessName).Contains(Name))
{
try { Task.Kill(); }
catch (Exception e) { }
}
}
try
{
Process Task = Process.Start(Path);
Task.WaitForInputIdle();
IntPtr Handle = new IntPtr();
for (int i = 0; Handle == IntPtr.Zero && i < 10; i++) { Handle = Task.MainWindowHandle; Thread.Sleep(100); }
SetParent(Handle, Panel.Handle);
SetWindowLong(Handle, GWL_STYLE, (int)(WS_VISIBLE + (WS_MAXIMIZE | WS_BORDER)));
MoveWindow(Handle, 0, 0, Panel.Width, Panel.Height, true);
Panel.Resize += new EventHandler(delegate(object sender, EventArgs e) { MoveWindow(Handle, 0, 0, Panel.Width, Panel.Height, true); });
this.FormClosed += new FormClosedEventHandler(delegate(object sender, FormClosedEventArgs e)
{
SendMessage(Handle, 83, 0, 0);
Thread.Sleep(100);
Handle = IntPtr.Zero;
});
return Handle;
}
catch (Exception e) { MessageBox.Show(this, e.Message, "Error"); }
return new IntPtr();
}
我有人对用于在窗体中嵌入窗口进程和控制台进程的漏洞C#类感兴趣,请查看this github repository。