代码之家  ›  专栏  ›  技术社区  ›  Eric Ouellet

当不在主窗口线程上时,调用需要hWnd的Win32 api的最佳方式是什么?

  •  0
  • Eric Ouellet  · 技术社区  · 6 年前

    我尝试从工作线程调用2个Win32 API函数:

    • SetforeGroundindow
    • FlashWindowEx

    这两个Win32函数都需要hWnd作为参数。我尝试了两种不同的方法来获得有效的hWnd:

    • HwndSource=(HwndSource)HwndSource。FromVisual(窗口); IntPtr hWnd=源。手柄
    • WindowInteropHelper WindowInteropHelper=新的WindowInteropHelper(窗口); IntPtr hwnd=windowInteropHelper。手柄

    从工作线程调用时,我收到:

    System.InvalidOperationException: 'The calling thread cannot access this object because a different thread owns it.'
    

    在里面net Core、WPF、作为“Dispatcher”属性的窗口,但Dispatcher没有CheckAccess或VerifyAccess。

    所以我有几个问题:

    • 我想要使用的2 Win32 Api不需要从主窗口线程调用。有没有办法让hWnd直接给他们打电话而不用进行线程检查?
    • 为什么调度器上没有CheckAccess或VerifyAccess,以及在中是什么替代了这两个选项。net核心WPF(与.net framework WPF的区别)?
    • 我获取hWnd的两种方法有什么区别?最好的方法是什么?
    • 做我想做的事最好的方法是什么?

    作为参考,这是我的代码。注释显示异常发生的位置:

    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Windows;
    using System.Windows.Interop;
    
    namespace UnmanagedCore.WindowEx
    {
        public static class WindowExtension
        {
            [DllImport("USER32.DLL")]
            public static extern bool SetForegroundWindow(IntPtr hWnd);
    
            public static bool SetForegroundWindow(this Window window)
            {
                // WindowInteropHelper windowInteropHelper = new WindowInteropHelper(window);
                // IntPtr hwnd = windowInteropHelper.Handle;
    
                HwndSource source = (HwndSource)HwndSource.FromVisual(window);    // System.InvalidOperationException
                IntPtr hWnd = source.Handle;
                return SetForegroundWindow(hWnd);
            }
    
            public static T RunSafeWindowAction<T>(this Window window, Func<T> func)
            {
                // Missing code here ... waiting answer from StackOverflow to write proper code
                return func();
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct FLASHWINFO
            {
                public UInt32 cbSize;
                public IntPtr hwnd;
                public UInt32 dwFlags;
                public UInt32 uCount;
                public UInt32 dwTimeout;
            }
    
            public enum FlashWindow : uint
            {
                /// <summary>
                /// Stop flashing. The system restores the window to its original state.
                /// </summary>    
                FLASHW_STOP = 0,
    
                /// <summary>
                /// Flash the window caption
                /// </summary>
                FLASHW_CAPTION = 1,
    
                /// <summary>
                /// Flash the taskbar button.
                /// </summary>
                FLASHW_TRAY = 2,
    
                /// <summary>
                /// Flash both the window caption and taskbar button.
                /// This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags.
                /// </summary>
                FLASHW_ALL = 3,
    
                /// <summary>
                /// Flash continuously, until the FLASHW_STOP flag is set.
                /// </summary>
                FLASHW_TIMER = 4,
    
                /// <summary>
                /// Flash continuously until the window comes to the foreground.
                /// </summary>
                FLASHW_TIMERNOFG = 12
            }
    
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            static extern bool FlashWindowEx(ref FLASHWINFO pwfi);
    
            /// <summary>
            /// Flashes a window
            /// </summary>
            /// <param name="hWnd">The handle to the window to flash</param>
            /// <returns>whether or not the window needed flashing</returns>
            public static bool FlashWindowEx(IntPtr hWnd)
            {
                FLASHWINFO fInfo = new FLASHWINFO();
    
                fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo));
                fInfo.hwnd = hWnd;
                fInfo.dwFlags = (int)FlashWindow.FLASHW_ALL;
                fInfo.uCount = UInt32.MaxValue;
                fInfo.dwTimeout = 0;
    
                return FlashWindowEx(ref fInfo);
            }
    
            /// Minor adjust to the code above
            /// <summary>
            /// Flashes a window until the window comes to the foreground
            /// Receives the form that will flash
            /// </summary>
            /// <param name="hWnd">The handle to the window to flash</param>
            /// <returns>whether or not the window needed flashing</returns>
            public static bool FlashWindowEx(this Window window)
            {
                HwndSource source = (HwndSource)HwndSource.FromVisual(window);
                IntPtr hWnd = source.Handle;
                FLASHWINFO fInfo = new FLASHWINFO();
    
                fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo));
                fInfo.hwnd = hWnd;
                fInfo.dwFlags = (int)(FlashWindow.FLASHW_ALL | FlashWindow.FLASHW_TIMERNOFG);
                fInfo.uCount = UInt32.MaxValue;
                fInfo.dwTimeout = 0;
    
                return FlashWindowEx(ref fInfo);
            }
        }
    }
    
    0 回复  |  直到 6 年前