Получить дескриптор на рабочий стол / окно оболочки - PullRequest
5 голосов
/ 03 декабря 2011

В одной из моих программ мне нужно проверить, фокусирует ли пользователь в настоящий момент окно рабочего стола / оболочки. В настоящее время я использую GetShellWindow () из user32.dll и сравниваю результат с GetForegroundWindow ().

Этот подход работает до тех пор, пока кто-то не изменит обои рабочего стола, но как только обои будут изменены, дескриптор GetShellWindow () больше не будет совпадать с дескриптором GetForegroundWindow (), и я не совсем понимаю, почему это так. ( ОС: Windows 7 32bit)

Есть ли лучший способ проверить, сфокусирован ли рабочий стол? Желательно тот, который не сломается, если пользователь поменяет обои?

РЕДАКТИРОВАТЬ: Я разработал обходной путь: я тестирую дескриптор, чтобы иметь дочерний элемент класса "SHELLDLL_DefView". Если это так, рабочий стол находится в фокусе. Хотя он работает на моем ПК, это не значит, что он будет работать постоянно ...

Ответы [ 2 ]

6 голосов
/ 19 февраля 2012

Ситуация немного изменилась, поскольку в Windows 7 в качестве обоев доступны слайд-шоу. Вы работаете с WorkerW, но это работает только с обоями, для которых установлен эффект слайд-шоу.

Когда установлен режим обоев для слайд-шоу, вам нужно найти окно класса WorkerW и проверить детей, есть ли SHELLDLL_DefView.Если слайд-шоу нет, вы можете использовать старый добрый GetShellWindow().

У меня была такая же проблема несколько месяцев назад, и я написал функцию для получения нужного окна.К сожалению, я не могу найти это.Но следующее должно работать.Отсутствуют только импорт Win32:

public enum DesktopWindow
{
    ProgMan,
    SHELLDLL_DefViewParent,
    SHELLDLL_DefView,
    SysListView32
}

public static IntPtr GetDesktopWindow(DesktopWindow desktopWindow)
{
    IntPtr _ProgMan = GetShellWindow();
    IntPtr _SHELLDLL_DefViewParent = _ProgMan;
    IntPtr _SHELLDLL_DefView = FindWindowEx(_ProgMan, IntPtr.Zero, "SHELLDLL_DefView", null);
    IntPtr _SysListView32 = FindWindowEx(_SHELLDLL_DefView, IntPtr.Zero, "SysListView32", "FolderView");

    if (_SHELLDLL_DefView == IntPtr.Zero)
    {
        EnumWindows((hwnd, lParam) =>
        {
            if (GetClassName(hwnd) == "WorkerW")
            {
                IntPtr child = FindWindowEx(hwnd, IntPtr.Zero, "SHELLDLL_DefView", null);
                if (child != IntPtr.Zero)
                {
                    _SHELLDLL_DefViewParent = hwnd;
                    _SHELLDLL_DefView = child;
                    _SysListView32 = FindWindowEx(child, IntPtr.Zero, "SysListView32", "FolderView"); ;
                    return false;
                }
            }
            return true;
        }, IntPtr.Zero);
    }

    switch (desktopWindow)
    {
        case DesktopWindow.ProgMan:
            return _ProgMan;
        case DesktopWindow.SHELLDLL_DefViewParent:
            return _SHELLDLL_DefViewParent;
        case DesktopWindow.SHELLDLL_DefView:
            return _SHELLDLL_DefView;
        case DesktopWindow.SysListView32:
            return _SysListView32;
        default:
            return IntPtr.Zero;
    }
}

В вашем случае вы бы позвонили GetDesktopWindow(DesktopWindow.SHELLDLL_DefViewParent);, чтобы получить окно верхнего уровня для проверки, является ли оно окном переднего плана.

4 голосов
/ 18 июля 2013

Вот обходной путь, который использует GetClassName(), чтобы определить, активен ли рабочий стол:

  • Когда Windows запускается впервые, класс рабочего стола «Progman»
  • После измененияДля рабочего стола класс рабочего стола будет «WorkerW»

. Вы можете проверить их, чтобы убедиться, что рабочий стол сфокусирован.

[DllImport("user32.dll")]
static extern int GetForegroundWindow();

[DllImport("user32.dll")]
static extern int GetClassName(int hWnd, StringBuilder lpClassName, int nMaxCount);

public void GetActiveWindow() {
    const int maxChars = 256;
    int handle = 0;
    StringBuilder className = new StringBuilder(maxChars);

    handle = GetForegroundWindow();

    if (GetClassName(handle, className, maxChars) > 0) {
        string cName = className.ToString();
        if (cName == "Progman" || cName == "WorkerW") {
            // desktop is active
        } else {
            // desktop is not active
        }
    }
}
...