繁体   English   中英

WINUI中如何hook WndProc

[英]How to hook WndProc in WINUI

多年来,我在 WinForms 中从 VB3 到 C# 的所有内容中都使用了 WndProc,没有任何问题,但是 WINUI-3 和 C# 给我带来了问题。

我的 DLL 导入的是:


        /// <summary>
        /// Sets window data.
        /// </summary>
        /// <param name="hWnd">The handle of the window to set.</param>
        /// <param name="nIndex">The index of the item to set.</param>
        /// <param name="dwNewLong">The new value.</param>
        /// <returns></returns>
        [DllImport("user32.dll",
            EntryPoint = "SetWindowLongPtr",
            CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, IntPtr dwNewLong);

        // Defines our window WndProcDelegate.
        private delegate IntPtr WndProcDelegate(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam);

        // This handles calling the underlying base WndProc.
        [DllImport("user32.dll", 
            CallingConvention = CallingConvention.Cdecl,
            CharSet=CharSet.Auto)]
        static extern IntPtr CallWindowProc(WndProcDelegate lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

实际的子类/非子类等,看起来像这样:

 public IntPtr GetHwnd()
        {
            IntPtr handle = WinRT.Interop.WindowNative.GetWindowHandle(this.m_MainWindow);
            return handle;
        }

// Subclass the window.
        public void Subclass(object window)
        {
            if (this.m_isSubclassed)
            {
                return;
            }

            this.m_MainWindow = window;
            this.m_NewWndProcDelegate = new WndProcDelegate(this.ReplacementWndProc);
            IntPtr hWnd = this.GetHwnd();
            HandleRef handleRef = new(this, hWnd);
            IntPtr newDelegatePtr = Marshal.GetFunctionPointerForDelegate(this.m_NewWndProcDelegate);
            IntPtr oldDelegatePtr = SetWindowLongPtr64(handleRef, GWLP_WNDPROC, newDelegatePtr);
            this.m_OldWndProcDelegate = (WndProcDelegate)Marshal.GetDelegateForFunctionPointer(
                oldDelegatePtr,
                typeof(WndProcDelegate));
            this.m_isSubclassed = true;
        }

// Unsubclass the window.
        public void Unsubclass()
        {
            if (!this.m_isSubclassed)
            {
                return;
            }
            IntPtr hWnd = this.GetHwnd();
            SetWindowLongPtr64(new HandleRef(this, hWnd), GWLP_WNDPROC, Marshal.GetFunctionPointerForDelegate(this.m_OldWndProcDelegate));
            this.m_isSubclassed = false;
        }

        public bool IsSubclassed()
        {
            return this.m_isSubclassed;
        }


        /// <summary>
        /// This is the replacement WndProc.
        /// </summary>
        /// <param name="hwnd"></param>
        /// <param name="message"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        private IntPtr ReplacementWndProc(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam)
        {
            // Our custom Windows messages code...
            /*if (message == WM_COPYDATA)
            {
                CopyDataStruct copyStruct = (CopyDataStruct)Marshal.PtrToStructure(lParam, typeof(CopyDataStruct));
                string messageText = Utf8PtrToString(copyStruct.lpData);
                int cbData = copyStruct.cbData;
                // Do something with the messageText and cbData.
            }*/

            // Finally, call the original WndProc.
            return CallWindowProc(this.m_OldWndProcDelegate, hwnd, message, wParam, lParam);
        }

我遇到的问题是一个模糊的 SystemEngineException (-2146233082) 错误,包含所有 null 信息。

所以,我的实施显然出了问题。 在 WINUI 中是否有一种经过验证的方法可以做到这一点?

对于任何想知道我为什么要这样做的人,我需要处理 WM_COPYDATA 消息。

提前谢谢了,

杰森

有一篇博客文章描述了这个确切的任务和错误消息。

在那种情况下,作者使用SetWindowLongPtr来存储指向GetFunctionPointerForDelegate结果的指针,并在 C# 检测到委托不可访问后调用它。

您通过将委托存储到成员变量来使委托保持活动状态。 GCHandle.Alloc也可以。 所以这很好……至少在Subclass function 中是这样。

但是,您的Unsubclass已损坏。 您似乎假设GetFunctionPointerForDelegate是 GetDelegateForFunctionPointer 的逆GetDelegateForFunctionPointer 不是,它创建了一个链接到托管委托实例的全新蹦床。 您需要保留原始的oldDelegatePtr并将其放回去。

事实上,您根本没有理由使用GetDelegateForFunctionPointer ,因为旧的 wndproc 只会传回 WinApi 个函数。 只需将其保留为IntPtr

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM