C# 为什么可以';我不能在表单中嵌入这些应用程序吗? 意图
使用以下代码,我成功地在windows窗体中加载了一些应用程序 代码 这个函数的作用是C# 为什么可以';我不能在表单中嵌入这些应用程序吗? 意图,c#,winapi,process,embed,handler,C#,Winapi,Process,Embed,Handler,使用以下代码,我成功地在windows窗体中加载了一些应用程序 代码 这个函数的作用是 陈述过程 将流程嵌入到我表单的面板中 最大化嵌入式进程 向面板添加调整大小事件处理程序,以更新面板调整大小时嵌入进程的大小 向窗体添加关闭的事件处理程序以在窗体关闭时终止嵌入进程 使用 using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Windows.Forms; 常数 c
- 陈述过程
- 将流程嵌入到我表单的面板中
- 最大化嵌入式进程
- 向面板添加调整大小事件处理程序,以更新面板调整大小时嵌入进程的大小
- 向窗体添加关闭的事件处理程序以在窗体关闭时终止嵌入进程
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或SublimiteText
LoadExtern(panel2, @"C:\Program Files (x86)\Mozilla Firefox\firefox.exe");
我的表单启动,firefox启动,但在它自己的窗口中。你能帮我在我的应用程序中加入SublimiteText或firefox吗
部分解决方案
多亏了盛江的回答,我让它能为更多的应用程序工作。我所做的是等待一个主窗口句柄
Process.WaitForInputIdle();
IntPtr Handle = new IntPtr();
for (int i = 0; Handle == IntPtr.Zero && i < 300; i++)
{
Handle = Process.MainWindowHandle;
Thread.Sleep(10);
}
Process.waitForInputId();
IntPtr Handle=新的IntPtr();
对于(inti=0;Handle==IntPtr.Zero&&i<300;i++)
{
Handle=Process.MainWindowHandle;
睡眠(10);
}
但是我仍然不能嵌入像windows资源管理器这样的应用程序。你的代码碰巧工作得很好
- WaitForInput不需要等待UI线程。例如,由其他程序创建的输入方法或钩子可能会创建一个简单线程,该线程在UI线程仍忙于初始化时变为空闲李>
- MainWindowHandle搜索第一个可见的顶层窗口。当发生错误时,它不会返回逻辑主窗口
- 主窗口不是创建的第一个可见窗口(例如,首先创建登录对话框)
- 主窗口不是以可见样式创建的(请考虑在系统托盘的通知区域中只有一个图标的程序)
- 根本没有创建主窗口(例如,一些应用程序在现有实例中打开新文档/URL,如浏览器和Windows资源管理器)
- 没有主窗口,但有多个具有相同状态的顶级窗口。想想IE6/Outlook/Word
- 充当测量工具,确定全屏请求是否完成(与新程序需要出现在面板内的要求相冲突)
- 当新DDE对话开始时、当活动窗口/程序更改时、当新硬件到达时、当系统设置更改时、当用户注销时、当Windows资源管理器启动时、当用户按下嵌套对话框上的Enter键时收到通知,等等。仅发送到顶级窗口的窗口消息列表太长,无法在此列出
- 如果程序选择,则充当模态对话框的默认所有者窗口(如果您在程序中也显示模态对话框,)
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();
}
IntPtr嵌入过程(控制面板,字符串路径)
{
字符串名称=NameFromPath(路径);
foreach(Process.getprocesss()中的流程任务)
{
if(NameFromPath(Task.ProcessName).Contains(Name))
{
尝试{Task.Kill();}
捕获(例外e){}
}
}
尝试
{
流程任务=流程.Start(路径);
Task.waitForInputId();
IntPtr Handle=新的IntPtr();
对于(inti=0;Handle==IntPtr.Zero&&i<10;i++){Handle=Task.MainWindowHandle;Thread.Sleep(100);}
SetParent(句柄、面板、句柄);
SetWindowLong(句柄,GWL_样式,(int)(WS_可见+(WS_最大化| WS_边框));
移动窗口(句柄,0,0,面板宽度,面板高度,真);
Panel.Resize+=neweventhandler(委托(对象发送者,EventArgs e){MoveWindow(句柄,0,0,Panel.Width,Panel.Height,true);});
this.FormClosed+=新的FormClosedEventHandler(委托(对象发送方,FormClosedEventArgs e)
{
SendMessage(句柄,83,0,0);
睡眠(100);
Handle=IntPtr.Zero;
});
返回手柄;
}
catch(异常e){MessageBox.Show(this,e.Message,“Error”);}
返回新的IntPtr();
}
如果有人对用于将窗口进程和控制台进程嵌入表单的hole C#类感兴趣,请查看。这通常可以工作的唯一方法是,如果另一个程序是act的一部分,那么编写它时可能不会期望它的一个或多个窗口不是顶级窗口(这是相当合理的-为什么那些开发人员要在他们不希望发生的事情上花费精力?)你说的“但我仍然不能嵌入像windows资源管理器这样的应用程序”是什么意思-你是说你想嵌入资源管理器,但不能,还是你已经看到资源管理器嵌入了其他应用程序,你也想这样做(但是,通过引用包括我以前的评论——它不会起作用)我