C# 为什么可以';我不能在表单中嵌入这些应用程序吗? 意图

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

使用以下代码,我成功地在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或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
即使主窗口是以可见的方式创建的,并且实际上是新流程中的第一个可见窗口,您可能仍然存在问题

从SetParent的文档中:

应用程序可以使用SetParent函数设置弹出窗口、重叠窗口或子窗口的父窗口

它并没有说您可以重新租用顶层窗口。事实上,顶层窗口提供了程序可能依赖的许多服务,例如

  • 充当测量工具,确定全屏请求是否完成(与新程序需要出现在面板内的要求相冲突)
  • 当新DDE对话开始时、当活动窗口/程序更改时、当新硬件到达时、当系统设置更改时、当用户注销时、当Windows资源管理器启动时、当用户按下嵌套对话框上的Enter键时收到通知,等等。仅发送到顶级窗口的窗口消息列表太长,无法在此列出
  • 如果程序选择,则充当模态对话框的默认所有者窗口(如果您在程序中也显示模态对话框,)

此代码适用于大多数应用程序。我只需在表单上使用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();
}
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资源管理器这样的应用程序”是什么意思-你是说你想嵌入资源管理器,但不能,还是你已经看到资源管理器嵌入了其他应用程序,你也想这样做(但是,通过引用包括我以前的评论——它不会起作用)我