我们有一个wpf应用程序应该由传统的win32 winform应用程序“试用”。 (我们不拥有代码;))
遗留应用程序应该通过windowsclass名称来引导我们的应用程序(最小化,带到前面,关闭等),我们应该将其作为写入ini文件的配置参数提供。
问题是我们无法使用wpf,因为如果我们插入Spy ++给我们的类名,就没有任何反应。重点是Spi ++返回类似这样的东西
HwndWrapper[MyWpfProgram.exe;;16978ce2-3b8d-4c46-81ee-e1c6d6de4e6d]
每次运行时随机生成guid。
有没有办法解决这个问题?
谢谢。
答案 0 :(得分:2)
没有办法做我的要求。但我们找到了一个解决方案。 “简单地”将xaml窗口嵌入到窗体中。
以下是我们采取的步骤:
1 - 将Windows窗体添加到项目中。
2 - 删除app.xaml并将新表单作为应用程序的入口点。
3 - 由于我们需要main.xaml的hwnd,我们将此prop添加到其后面的代码中
public IntPtr Hwnd
{
get { return new WindowInteropHelper(this).Handle; }
}
4 - 然后从表单的构造函数中创建一个wpf窗口类的实例
private Main app;
public ContainerForm()
{
InitializeComponent();
app = new Main();
ElementHost.EnableModelessKeyboardInterop(app);
}
我们需要
ElementHost.EnableModelessKeyboardInterop(app);
因为我们希望所有键盘输入从windows窗体传递到xaml窗口
5 - 现在我们想将xpf窗口绑定到winform。为了做到这一点,我们需要使用Windows Api,我们在表单的OnShow事件中进行此操作(之后将详细解释的原因)。
[DllImport("user32.dll", SetLastError = true)]
private static extern long SetFocus(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
[DllImport("user32.dll", EntryPoint = "SetWindowLongA", SetLastError = true)]
private static extern long SetWindowLong(IntPtr hwnd, int nIndex, long dwNewLong);
private const int GWL_STYLE = (-16);
private const int WS_VISIBLE = 0x10000000;
private void ContainerForm_Shown(object sender, EventArgs e)
{
app.Show();
SetParent(app.Hwnd, this.Handle);
SetWindowLong(app.Hwnd, GWL_STYLE, WS_VISIBLE);
MoveWindow(app.Hwnd, 0, 0, this.Width, this.Height, true);
SetFocus(app.Hwnd);
}
带
SetParent(app.Hwnd, this.Handle);
我做魔术,然后用
SetWindowLong(app.Hwnd, GWL_STYLE, WS_VISIBLE);
我们从wpf窗口删除了chrome(即使窗口是无边界的,也有边框,不要问我原因)
然后我们让wpf窗口填充winform的所有客户区
MoveWindow(app.Hwnd, 0, 0, this.Width, this.Height, true);
然后我们关注wpf窗口
SetFocus(app.Hwnd);
这就是我们在show事件中做所有事情的原因。因为如果我们在form的构造函数中执行它,那么wpf窗口将失去焦点,因为在winform中主窗口从操作系统获得焦点。
我们不明白为什么我们需要在此时添加其他api调用,但是如果我们将它们留在构造函数中,那么这个技巧就不起作用了。
反正 问题解决了;)
答案 1 :(得分:1)
使用HwndSource。
您可以使用本机Windows API调用来创建具有预期类名的窗口,然后使用HwndSource向其添加WPF内容:
var source = HwndSource.FromHwnd(nativeWindowHandle);
source.RootVisual = mainGrid;
如果您需要使用WPF窗口,我认为您仍然可以通过“代理”窗口解决此问题,但它不会很漂亮:
答案 2 :(得分:0)
对于窗口句柄,标题和类名,Spy ++使用相当简单的Windows API。
FindWindowEx http://msdn.microsoft.com/en-us/library/windows/desktop/ms633500%28v=vs.85%29.aspx
EnumWindows http://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx
GetClassName http://msdn.microsoft.com/en-us/library/windows/desktop/ms633582%28v=vs.85%29.aspx
您可以创建一个“加载程序”程序......