好的,在Simon Mourrier 之前的回答的帮助下,我终于找到了实现目标的方法。
我创建了一个自定义用户控件:
Xaml 部分:
<UserControl x:Class="WpfApplication1.AppIsolatedView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" SizeChanged="UserControl_SizeChanged"
d:DesignHeight="300" d:DesignWidth="300" Loaded="UserControl_Loaded" Unloaded="UserControl_Unloaded">
<Grid>
<WindowsFormsHost Margin="12" Name="windowsFormsHost1" />
</Grid>
</UserControl>
有了这段代码:
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class AppIsolatedView : UserControl
{
public AppIsolatedView()
{
InitializeComponent();
_panel = new System.Windows.Forms.Panel();
windowsFormsHost1.Child = _panel;
}
string url = "http://theapptotest";
System.Windows.Forms.Panel _panel;
Process _process;
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
if (IsInDesignModeStatic) return; // Avoid consumer of the control to explode when in design mode
ProcessStartInfo psi = new ProcessStartInfo("iexplore.exe", "-noframemerging -private \"" + url + "\"");
_process = Process.Start(psi);
_process.WaitForInputIdle();
Thread.Sleep(2000);
SetParent(_process.MainWindowHandle, _panel.Handle);
// remove control box
int style = GetWindowLong(_process.MainWindowHandle, GWL_STYLE);
style = style & ~WS_CAPTION & ~WS_THICKFRAME;
SetWindowLong(_process.MainWindowHandle, GWL_STYLE, style);
// resize embedded application & refresh
ResizeEmbeddedApp();
}
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
{
if (_process != null)
{
_process.Refresh();
_process.Close();
}
}
private void ResizeEmbeddedApp()
{
if (_process == null)
return;
SetWindowPos(_process.MainWindowHandle, IntPtr.Zero, 0, 0, (int)_panel.ClientSize.Width, (int)_panel.ClientSize.Height, SWP_NOZORDER | SWP_NOACTIVATE);
}
protected override Size MeasureOverride(Size availableSize)
{
Size size = base.MeasureOverride(availableSize);
ResizeEmbeddedApp();
return size;
}
private static bool? _isInDesignMode;
/// <summary>
/// Gets a value indicating whether the control is in design mode (running in Blend
/// or Visual Studio).
/// </summary>
public static bool IsInDesignModeStatic
{
get
{
if (!_isInDesignMode.HasValue)
{
#if SILVERLIGHT
_isInDesignMode = DesignerProperties.IsInDesignTool;
#else
var prop = DesignerProperties.IsInDesignModeProperty;
_isInDesignMode
= (bool)DependencyPropertyDescriptor
.FromProperty(prop, typeof(FrameworkElement))
.Metadata.DefaultValue;
#endif
}
return _isInDesignMode.Value;
}
}
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
ResizeEmbeddedApp();
}
#region pinvoke stuff
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32")]
private static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent);
[DllImport("user32")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
private const int SWP_NOZORDER = 0x0004;
private const int SWP_NOACTIVATE = 0x0010;
private const int GWL_STYLE = -16;
private const int WS_CAPTION = 0x00C00000;
private const int WS_THICKFRAME = 0x00040000;
#endregion
}
}
我必须作弊:
- 为了避免内部 IE 会话共享,我必须
-noframemerging
在触发时添加。IExplore.exe
- 启动该过程后,我必须睡一会儿。不知道确切原因,但在
MainWindowHandle
几毫秒后属性会发生变化(我猜 iexplore 有一个引导程序进程来连接到现有进程或产生一个新进程,使用新句柄或类似的东西)。
我仍然必须扩展用户控件以接受输入参数(url 是硬编码的),但想法就在这里。我只需要专注于应用程序本身。