如何正确地从EnumWindows WinAPI函数获取窗口句柄?

时间:2019-01-25 22:06:28

标签: c# c++ .net windows winapi

我正在尝试将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;
}

这是我从here获得的原始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在我的桌面背景中创建深度幻觉,这是一种实际的窗口之类的东西。

0 个答案:

没有答案