Как правильно получить дескриптор окна из функции EnumWindows WinAPI? - PullRequest
0 голосов
/ 26 января 2019

Я пытаюсь перевести часть кода C # на C ++. Исходный код C # находит окно, которое при рисовании будет отображаться под значками на рабочем столе, то есть в основном, а точнее вместо обоев. Однако я не могу понять, как вернуть дескриптор конкретного окна из функции EnumWindows() и его обратный вызов для рисования на нем.

Сейчас я пытаюсь передать указатель дескриптора окна, который приведен к LPARAM:

HWND workerw;
EnumWindows((WNDENUMPROC)EnumWindowsProc, (LPARAM)&workerw);

А затем в функции обратного вызова я привел параметр LPARAM обратно к дескриптору окна:

(HWND)workerw = FindWindowEx(0,hwnd,"WorkerW",0);

Однако, когда я запускаю программу, ничего не происходит, что заставляет меня предположить, что я не рисую в правильное окно ..

Это весь файл:

#include <iostream>
#include <windows.h>

using namespace std;

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);

int main(int argc, char *argv[]){
    Sleep(2000);
    HWND progman = FindWindow("ProgMan", NULL);

    // Send 0x052C to Progman. This message directs Progman to spawn a
    // WorkerW behind the desktop icons. If it is already there, nothing
    // happens.
    SendMessageTimeout(progman,0x052C,0,0,SMTO_NORMAL,1000,nullptr);

    HWND workerw;
    EnumWindows((WNDENUMPROC)EnumWindowsProc, (LPARAM)&workerw);

    HDC hdc = GetDC(workerw);
    if (hdc != NULL){
        TextOut(hdc, 20, 20, "hello world", 30);
    }else{
        cout << "error" << endl;
        return 0;
    }

    RECT r = {0, 0, 1000, 1000};
    RedrawWindow(workerw, &r, NULL, RDW_NOERASE | RDW_INVALIDATE | RDW_UPDATENOW);
    ReleaseDC(workerw, hdc);
    return 0;
}

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM workerw)
{
    HWND p = FindWindowEx(hwnd,0,"SHELLDLL_DefView",0);
    if (p != 0){
        // Gets the WorkerW Window after the current one.
        (HWND)workerw = FindWindowEx(0,hwnd,"WorkerW",0);
    }
    return true;
}

И это соответствующая часть исходного файла C #, который я получил от здесь :

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DrawBehindDesktopIcons
{
    class Program
    {
        static void Main(string[] args)
        {
            // Fetch the Progman window
            IntPtr progman = W32.FindWindow("Progman", null);

            IntPtr result = IntPtr.Zero;

            // Send 0x052C to Progman. This message directs Progman to spawn a
            // WorkerW behind the desktop icons. If it is already there, nothing
            // happens.
            W32.SendMessageTimeout(progman,
                                0x052C,
                                new IntPtr(0),
                                IntPtr.Zero,
                                W32.SendMessageTimeoutFlags.SMTO_NORMAL,
                                1000,
                                out result);

            IntPtr workerw = IntPtr.Zero;

            // We enumerate all Windows, until we find one, that has the SHELLDLL_DefView
            // as a child.
            // If we found that window, we take its next sibling and assign it to workerw.
            W32.EnumWindows(
                new W32.EnumWindowsProc((tophandle, topparamhandle) =>
                {
                    IntPtr p = W32.FindWindowEx(tophandle,
                                                IntPtr.Zero,
                                                "SHELLDLL_DefView",
                                                IntPtr.Zero);

                    if (p != IntPtr.Zero)
                    {
                        // Gets the WorkerW Window after the current one.
                        workerw = W32.FindWindowEx(IntPtr.Zero,
                                                    tophandle,
                                                    "WorkerW",
                                                    IntPtr.Zero);
                    }

                    return true;
                }),
                IntPtr.Zero);

            // We now have the handle of the WorkerW behind the desktop icons.
            // We can use it to create a directx device to render 3d output to it,
            // we can use the System.Drawing classes to directly draw onto it,
            // and of course we can set it as the parent of a windows form.

            // Get the Device Context of the WorkerW
            IntPtr dc = W32.GetDCEx(workerw, IntPtr.Zero, (W32.DeviceContextValues)0x403);
            if (dc != IntPtr.Zero)
            {
                for (int i = 0; i < 20000; i++)
                {
                    // Create a Graphics instance from the Device Context
                    using(Graphics g = Graphics.FromHdc(dc))
                    {
                        g.FillRectangle(new SolidBrush(Color.White), 0, 0, 500, 500);
                    }
                }
                // make sure to release the device context after use.
                W32.ReleaseDC(workerw, dc);
            }
        }
    }
} // namespace DrawBehindDesktopIcons

Когда я компилирую и запускаю версию C #, она работает нормально.

Конечно, поскольку я вообще ничего не знаю о C #, вполне возможно, что я упускаю что-то совершенно очевидное, если это так, я извиняюсь.

Я надеюсь, что кто-то может помочь мне заставить это работать, это сделало бы возможным много интересных вещей!

В конце я хочу использовать распознавание лиц и opencv, чтобы создать иллюзию глубины на фоне рабочего стола, что-то вроде окна.

...