0

我试图通过在我的应用程序表单的构造函数中调用本机 GetForegroundWindow WinAPI 函数来获取 C#/Net 2.0/WinForms 中前景窗口的句柄。

当我直接从 Windows Explorer 或 Total Commander 运行程序时,它会正确识别 Windows Explorer 或 Total Commander 窗口。

但是,如果我在桌面上为我的程序创建一个快捷方式并为该快捷方式设置一个快捷键(比如说 Ctrl+Alt+X),当我使用该快捷方式运行我的程序时,前台窗口被标识为“Shell_TrayWnd窗口”(句柄 0x00010064),而不是实际的窗口。(假设我在顶部运行 Firefox,当我按 Ctrl+Alt+X 时,我的程序启动并说前台窗口不是 Firefox,它应该说它是任务栏 - Shell_TrayWnd。)

    public MainForm()
    {
        this.InitializeComponent();

        IntPtr handle = WinAPI.GetForegroundWindow();
        this.Text = handle.ToString();
        StringBuilder title = new StringBuilder(255);
        if (WinAPI.GetWindowText(handle, title, 255) > 0)
        {
            this.Text += title.ToString();
        }
    }

我怎样才能得到真正的前景窗口?我应该(也)使用 GetWindow 等其他功能吗?

谢谢

4

3 回答 3

1

请注意,调用GetForegroundWindow时任务栏可能是真正的前台窗口,因为它是Explorer在处理快捷键,并且任务栏属于Explorer(Shell_TrayWnd是任务栏的窗口类)。

如果你想对全局活动窗口做一些事情,你最好启动你的应用程序并让它在后台等待。然后,您可以在应用程序运行时处理按键操作,因此 Explorer 不会干扰。

不知何故,这让我想起了Raymond Chen的一篇文章。

于 2010-04-21T16:17:20.503 回答
0

我认为您正在尝试和我做同样的事情——在当前路径从 Explorer 中打开一个 shell。

我遇到了完全相同的问题。这是一个对我有用的程序。它用于EnumWindows搜索所有可见窗口,直到找到标题为真实路径的窗口。

using System;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;

public class ShellHere
{
    // Thanks to pinvoke.net for the WinAPI stuff

    [DllImport("user32.dll")]
    private static extern int EnumWindows(CallBackPtr callPtr, int lPar); 

    [DllImport("user32.dll")]
    static extern int GetWindowText(int hWnd, StringBuilder text, int count);

    [DllImport("user32.dll", EntryPoint="GetWindowLong")]
    private static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, GWL nIndex);

    [DllImport("user32.dll", EntryPoint="GetWindowLongPtr")]
    private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, GWL nIndex);

    public delegate bool CallBackPtr(int hwnd, int lParam);
    private static CallBackPtr _callBackPtr;

    // This static method is required because Win32 does not support
    // GetWindowLongPtr directly
    public static IntPtr GetWindowLongPtr(IntPtr hWnd, GWL nIndex)
    {
        if (IntPtr.Size == 8)
            return GetWindowLongPtr64(hWnd, nIndex);
        else
            return GetWindowLongPtr32(hWnd, nIndex);
    }

    public static bool FindPathInTitle( int hwnd, int lparams )
    {
        const int nChars = 256;
        StringBuilder buffer = new StringBuilder( nChars );

        IntPtr result = GetWindowLongPtr( new IntPtr(hwnd), GWL.GWL_STYLE );

        // ignore invisible windows
        if ( (result.ToInt64() & WS_VISIBLE) != 0 )
        {
            if ( GetWindowText( hwnd, buffer, nChars ) > 0 )
            {
                string title = buffer.ToString();

                // ignore the taskbar
                if ( title.ToLower() != "start" && Directory.Exists( title ) )
                {
                    _folder = title;
                    return false;
                }
            }
        }

        return true;
    }

    private static string _folder;

    public static void Main()
    {
        _callBackPtr = new CallBackPtr( FindPathInTitle );
        EnumWindows( _callBackPtr, 0 );

        Process shell = new Process();
        shell.StartInfo.FileName = "cmd.exe";
        if ( !string.IsNullOrEmpty( _folder ) )
            shell.StartInfo.WorkingDirectory = _folder;
        shell.Start();
    }

    public enum GWL
    {
        GWL_WNDPROC =    (-4),
        GWL_HINSTANCE =  (-6),
        GWL_HWNDPARENT = (-8),
        GWL_STYLE =      (-16),
        GWL_EXSTYLE =    (-20),
        GWL_USERDATA =   (-21),
        GWL_ID =     (-12)
    }

    // Window Styles 
    const UInt32 WS_VISIBLE = 0x10000000;
}

到目前为止它对我有用(Win7-64)。请注意,您不必直接在“资源管理器”窗口上即可工作 - 它会使用 Tab 键顺序中的下一个窗口。

于 2010-09-23T05:37:09.000 回答
0

我不确定你需要前景窗口做什么,所以这可能会或可能不会有帮助:

您可能可以通过以下方式检测到您是通过快捷方式启动的:

在这种情况下,您可能会尝试获取按 Z 顺序排列的前一个窗口,或者在桌面窗口的顶部。

于 2010-09-23T08:47:55.187 回答