首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WPF 整合 Win32 控件:HwndHost 實作與座標轉換

     編輯:關於.NET

建立 Win32 視窗類別與視窗實例

雖 WPF 功能強大,但成熟的 Win32 控件仍具不可替代價值。整合流程始於定義 WNDCLASSEX 結構、註冊視窗類別、呼叫 CreateWindowEx 建立子視窗,最後透過 ShowWindow 顯示。核心步驟如下:

WNDCLASSEX wndClsEx = new WNDCLASSEX();
wndClsEx.Init();
wndClsEx.style = WndClassType.CS_VREDRAW | WndClassType.CS_HREDRAW;
wndClsEx.lpfnWndProc = new WndProcDelegate(User32Dll.DefWindowProc);
wndClsEx.hInstance = Kernal32Dll.GetModuleHandle(null);
wndClsEx.lpszClassName = m_WndClsName;

bool success = User32Dll.RegisterClassEx(ref wndClsEx) != 0;

IntPtr windowHandle = User32Dll.CreateWindowEx(
    ExtendedWndStyle.WS_EX_LAYOUTRTL, m_WndClsName, null,
    WndStyle.WS_VISIBLE | WndStyle.WS_CHILD,
    this.Left, this.Top, this.Width, this.Height,
    this.Parent.Handle, IntPtr.Zero,
    Kernal32Dll.GetModuleHandle(null), IntPtr.Zero);
Spy++ 檢視視窗樣式

HwndHost:WPF 與 Win32 的橋樑

WPF 視覺樹與 Win32 HWND 屬不同渲染層,存在「空域」問題導致像素無法互通。HwndHost 類別封裝了視窗父子關係、訊息迴路、鍵盤導航等複雜邏輯,開發者僅需繼承並覆寫 BuildWindowCore 回傳 HandleRef:

protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
    UserControl1 userControl = new UserControl1();
    userControl.Height = hostHeight;
    userControl.Width = hostWidth;
    User32Dll.SetParent(userControl.Handle, hwndParent.Handle);
    return new HandleRef(userControl, userControl.Handle);
}

矩陣變換數學基礎

WPF 無法直接對 Win32 控件套用 Transform,需自行計算矩陣並透過訊息傳遞。以二維旋轉為例,點 P(x,y) 繞原點逆時針旋轉 α 度後座標推導:

x1 = x * cos(α) - y * sin(α)
y1 = y * cos(α) + x * sin(α)

引入齊次座標後,平移、旋轉、縮放可統一為 3×3 矩陣乘法。WPF 當前裝置變換矩陣可透過 PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice 取得。

旋轉座標推導示意圖 矩陣變換示意圖

跨進程訊息傳遞:WM_COPYDATA

將矩陣參數傳遞給 Win32 控件需使用 SendMessage 搭配 COPYDATASTRUCT 結構。序列化物件至記憶體區塊,透過 Marshal.AllocHGlobal 分配非託管記憶體,接收端再反序列化還原:

public struct CopyDataStruct
{
    public int cbData;
    public IntPtr lpData;
}

// 發送端
BinaryFormatter formatter = new BinaryFormatter();
byte[] datas;
using (MemoryStream ms = new MemoryStream())
{
    formatter.Serialize(ms, matrix);
    datas = ms.ToArray();
}
IntPtr ptr = Marshal.AllocHGlobal(datas.Length);
Marshal.Copy(datas, 0, ptr, datas.Length);
CopyDataStruct data = new CopyDataStruct { cbData = datas.Length, lpData = ptr };
SendMessage(hwndListBox, 700, 0, ref data);
Marshal.FreeHGlobal(ptr);
訊息傳遞效果圖

透過 HwndHost 封裝與矩陣變換同步,可實現 WPF 與 Win32 控件的深度整合。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved