在Windows窗体应用程序中将第三方对话框设置为前台



早上好。

我非常期待一个非常棘手的问题的解决方案;希望有人能分享一些经验。

我正在开发一种OCR软件;为了与文档扫描仪通信,我使用了良好的NTwain库
当扫描仪驱动程序有事情要告诉(发生错误、卡纸、进纸器空等等)时,它本身会引发对话框,所以您无法控制它们
问题是这些消息仍然在后台,被我的应用程序主窗体隐藏,我不知道如何将它们放在前台。

使用user32.dll互操作方法是一种选择,但我可以弄清楚引发扫描仪驱动程序对话框的过程;为用户提供了由不同制造商使用不同型号的可能性,我不能依赖对话框标题或类似内容,因为它们因型号而异。

有人有主意吗
在Windows中,有一个C:WindowsTWAIN.dllC:Windowstwain_32.dll,让O.s.与扫描仪驱动程序通信:有了user32.dll,就可以像处理进程一样,查找从特定.dll打开的窗口?

我在祈祷:)
再见Nando

我终于找到了一个棘手的/部分的问题解决方案
与之前所说的不同,(至少对于佳能扫描仪)似乎驱动程序对话框消息框是我的主进程窗口的子窗口;通过一些User32.dll互操作黑魔法和计时器,我终于把那些该死的小窗口移到了前台,让用户阅读它们并选择要做什么。

这是代码。

#region Usings
using System;
using System.Collections;

#endregion

namespace EProm.Common.PInvoke
{
    /// <summary>
    /// Catch process child windows, setting them in foreground.
    /// <see cref="http://stackoverflow.com/questions/28559726/set-to-foreground-a-third-party-dialog-in-a-windows-form-application"/>
    /// </summary>
    public class DialogsCatcher
    {
        #region Fields
        private readonly ILog _log;
        private readonly int _processId;
        private readonly Timer _timer;
        private readonly IntPtr _windowHandle;
        #endregion

        #region Constructors
        public DialogsCatcher(int processId, int interval, IntPtr windowHandle)
        {
            _log = LogManager.GetLogger(GetType().Name);
            _processId = processId;
            _windowHandle = windowHandle;
            _timer = new Timer();
            _timer.Elapsed += new ElapsedEventHandler(CatchDialogs);
            _timer.Enabled = true;
            _timer.Interval = interval;
            _log.Debug("DialogsCatcher initialized.");
        }
        #endregion

        #region Public Methods
        public void StartMonitoring()
        {
            _timer.Start();
            _log.Debug("DialogsCatcher started.");
        }
        public void StopMonitoring()
        {
            _timer.Stop();
            _log.Debug("DialogsCatcher stopped.");
        }
        #endregion

        #region Private Methods
        private void CatchDialogs(object sender, EventArgs e)
        {
            GetProcessOpenedWindowsByProcessId(_processId, _windowHandle);
        }
        //nando20150219: meaningful names, you're doin' it right! :)
        private void GetProcessOpenedWindowsByProcessId(int processId, IntPtr windowHandle)
        {
            var shellWindowHandle = User32.GetShellWindow();
            var windows = new Dictionary<IntPtr, string>();
            EnumWindowsProc filter = (windowHandle, lp) =>
            {
                int length = User32.GetWindowTextLength(windowHandle);
                var windowText = new StringBuilder(length);
                User32.GetWindowText(windowHandle, windowText, length + 1);
                windows.Add(windowHandle, windowText.ToString());
                var isWindowVisible = User32.IsWindowVisible(windowHandle);
                if (windowHandle == shellWindowHandle)
                {
                return true;
                }
                if (!isWindowVisible)
                {
                    return true;
                }
                if (length == 0)
                {
                    return true;
                }
                uint windowPid;
                User32.GetWindowThreadProcessId(windowHandle, out windowPid);
                if (windowPid != processId)
                {
                    return true;
                }
                if (windowHandle != windowHandle)
                {
                    //nando20150218: set window to foreground
                    User32.SetForegroundWindow(windowHandle);
                    _log.DebugFormat("Window "{0}" moved to foreground.", windowText);
                }
                return true;
            };
            User32.EnumWindows(filter, 0);
#if DEBUG
            //foreach (var dictWindow in windows)
            //{
            //  _log.DebugFormat("WindowHandle: {0} - WindowTitle: {1}", dictWindow.Key, dictWindow.Value);
            //}
#endif 
        }
        #endregion
    }

    #region Delegates
    public delegate bool EnumWindowsProc(IntPtr windowHandle, IntPtr lp);
    public delegate bool EnumedWindow(IntPtr windowHandle, ArrayList windsowHandles);
    #endregion

    /// <summary>
    /// Windows User32.dll wrapper
    /// </summary>
    /// <see cref="http://pinvoke.net/"/>
    public class User32
    {
        #region Public Methods
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool IsWindowVisible(IntPtr hWnd);
        [DllImport("user32.dll", EntryPoint = "GetWindowText", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount);
        [DllImport("user32.dll", SetLastError = true)]
        public static extern uint GetWindowThreadProcessId(IntPtr hwnd, out uint lpdwProcessId);
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetForegroundWindow(IntPtr hWnd);
        [DllImport("user32.DLL")]
        public static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam);
        [DllImport("user32.DLL")]
        public static extern int GetWindowTextLength(IntPtr hWnd);
        [DllImport("user32.DLL")]
        public static extern IntPtr GetShellWindow();
        #endregion
    }
}

再见风滚草……:)

最新更新