Wpf和Hwnd唯一名称

时间:2013-08-07 12:45:02

标签: wpf

我们有一个wpf应用程序应该由传统的win32 winform应用程序“试用”。 (我们不拥有代码;))

遗留应用程序应该通过windowsclass名称来引导我们的应用程序(最小化,带到前面,关闭等),我们应该将其作为写入ini文件的配置参数提供。

问题是我们无法使用wpf,因为如果我们插入Spy ++给我们的类名,就没有任何反应。重点是Spi ++返回类似这样的东西

 HwndWrapper[MyWpfProgram.exe;;16978ce2-3b8d-4c46-81ee-e1c6d6de4e6d]

每次运行时随机生成guid。

有没有办法解决这个问题?

谢谢。

3 个答案:

答案 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窗口,我认为您仍然可以通过“代理”窗口解决此问题,但它不会很漂亮:

  • 让您的WPF应用程序生成本机message-only窗口。
  • 使用HwndSource.AddHook处理本机窗口上的WM_CLOSE,WM_SIZE等消息,并将它们传递给“真正的”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

您可以创建一个“加载程序”程序......

  • 启动wpf app
  • 使用上述API获取正确的类名和窗口句柄
  • 编辑旧版INI
  • 启动旧版应用