2013-08-07 56 views
3

我們有一個wpf應用程序,應該由傳統win32 winform應用程序「試用」。 (我們不擁有代碼;))Wpf和Hwnd的獨特名稱

傳統應用程序應該通過windowsclass名稱來引導我們的應用程序(最小化,前置,關閉等),我們應該提供一個寫入ini文件的配置參數。

問題是我們不能使它與WPF一起工作,因爲如果我們插入類名Spy ++給我們,沒有任何反應。關鍵是Spi ++返回類似於這樣的內容

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

其中guid在每次運行時隨機生成。

有什麼辦法可以解決這個問題嗎?

謝謝。

回答

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應用程序
  • 使用上面的API來獲得正確的類名和Windows處理
  • 編輯遺留INI
  • 啓動繼承應用程序
+0

如果細您的解決方案,但我們的目的是不是有用,因爲是傳統的應用程序,啓動我們的應用程序,所以類名應該是唯一的 –

+0

@ Stefano.net - 當您在Spy ++中使用查找窗口工具該類的輸出是什麼:???這正是你在問題中展示的例子嗎? http://msdn.microsoft.com/en-us/library/dd460750.aspx –

+0

是的。正如我在問題中所述,guid每次執行都會發生變化 –

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窗口。
+0

這完全是我們所做的。看到我的答案 –

2

有沒有辦法做我所問。但是我們發現了一個解決方案。 「簡單地」在Windows窗體中嵌入xaml窗口。

這是我們遵循的步驟:

1 - Windows窗體添加到項目中。

2 - 刪除app.xaml並使新窗體成爲應用程序的入口點。

3 - 由於我們需要我們增加了這個道具的代碼背後

public IntPtr Hwnd 
    { 
     get { return new WindowInteropHelper(this).Handle; } 
    } 

4 main.xaml的HWND - 然後從窗體的構造函數,我們創建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窗口中刪除人的鉻(存在即使窗口被定義無邊界的邊界,不要問我爲什麼)

然後我們使wpf窗口填充winform的所有客戶區域

MoveWindow(app.Hwnd, 0, 0, this.Width, this.Height, true); 

,然後我們把重點放在WPF窗口

SetFocus(app.Hwnd); 

這就是爲什麼我們在做節目時的一切。因爲如果我們在窗體的構造函數中執行它,那麼wpf窗口將失去焦點,因爲在winform中,主窗口從操作系統獲得焦點。

我們不明白爲什麼我們現在需要添加其他api調用,但是如果我們將它們留在構造函數中,那麼這個技巧就無法工作。

反正 問題就解決了;)