【发布时间】:2012-09-29 14:11:44
【问题描述】:
意图
使用以下代码,我设法在我的 Windows 窗体中加载了一些应用程序。
代码
这个函数的作用是……
- 陈述过程
- 将流程嵌入到我的表单面板中
- 最大化嵌入式进程
- 向面板添加调整大小事件处理程序以更新面板调整大小时嵌入进程的大小
- 向表单添加关闭的事件处理程序以在表单关闭时终止嵌入式进程
用途
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 导入
[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 资源管理器等应用程序。
【问题讨论】:
-
这通常可以工作的唯一方法是如果另一个程序是该行为的一部分 - 它可能不会被编写为期望它的一个或多个窗口不是' t 顶级窗口(这是相当合理的 - 为什么那些开发人员要在他们不希望发生的事情上花费精力?)
-
“但我仍然无法嵌入 Windows 资源管理器之类的应用程序”是什么意思。 - 你的意思是你想嵌入资源管理器,但不能,或者你已经看到资源管理器嵌入了其他应用程序,并且你想做同样的事情(但是,通过引用包括我以前的 cmets - 它不会工作)
-
我想在我的表单中嵌入一个文件浏览器窗口。不幸的是,我无法与我想嵌入的流程的开发人员一起工作。
-
好吧,正如我所说的——这些程序不一定是为了期望嵌入到其他程序中而构建的。您可能想要它,但这并不意味着它是真实的或可用的。
-
MainWindowHandle可能不是您所期望的。作为测试,您使用另一个工具 (spy++) 获取hWnd并将其嵌入以查看是否有效,如果有效,则需要枚举 windows int hat 进程以找到您想要的。
标签: c# winapi process embed handler