我需要在WinXP / Win7 / 10中捕获一个Winlogon屏幕。
对于WinXP,我使用的是镜像驱动程序和标准方法,如下所示:

...
extern "C" __declspec(dllexport) void SetActiveDesktop() {
    if ( currentDesk != NULL )
        CloseDesktop( currentDesk );

    currentDesk = OpenInputDesktop( 0, FALSE, GENERIC_ALL );
    BOOL ret = SetThreadDesktop( currentDesk );
    int LASTeRR = GetLastError();
}

extern "C" __declspec(dllexport) HBITMAP CaptureAnImage(
    int width,
    int height,
    int bitsPerPixel )
{
    HBITMAP hbmScreen;
    LPTSTR bih = NULL;
    HDC hdcMemDC = NULL;

    int colorDepth = GetCurrentColorDepth();

    if ( bitsPerPixel > colorDepth && colorDepth > 0 )
        bitsPerPixel = colorDepth;

    // Checks a current HDC
    if ( currHdc == NULL ) {
        SetActiveDesktop();
        currHdc = GetDcMirror();
    }

    if ( prevHdc != currHdc ) {
        prevHdc = currHdc;
    }

    // Check an application instance handler
    if ( appInstance == NULL )
        appInstance = GetModuleHandle(NULL);

    // Creates a compatible DC which is used in a BitBlt from the window DC
    hdcMemDC = CreateCompatibleDC( currHdc );

    if( hdcMemDC == NULL )
    {
        return NULL;
    }

    // Defines bitmap parameters
    bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bi.bmiHeader.biWidth = width;
    bi.bmiHeader.biHeight = height;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = bitsPerPixel;

    // Creates a bitmap with defined parameters
    hbmScreen = CreateDIBSection( hdcMemDC, &bi, DIB_RGB_COLORS, (VOID**)&lpBitmapBits, NULL, 0 );

    if ( hbmScreen == NULL ) {
        return NULL;
    }

    // Select the compatible bitmap into the compatible memory DC.
    SelectObject(hdcMemDC,hbmScreen);

    // Bit block transfer into our compatible memory DC.
    if(!BitBlt(hdcMemDC,
        0,0,
        width, height,
        currHdc,
        0,0,
        SRCCOPY))
    {
        SetActiveDesktop();
        currHdc = GetDC(NULL);//GetDcMirror();
        hdcMemDC = CreateCompatibleDC( currHdc );

        // Creates a bitmap with defined parameters
        hbmScreen = CreateDIBSection( hdcMemDC, &bi, DIB_RGB_COLORS, (VOID**)&lpBitmapBits, NULL, 0 );

        if(!BitBlt(hdcMemDC,
            0,0,
            width, height,
            currHdc,
            0,0,
            SRCCOPY ))
        {
            DeleteDC( hdcMemDC );
            return hbmScreen;
        }
    }

    if (DeleteDC( hdcMemDC ) == FALSE ) {
        return NULL;
    }

    return hbmScreen;
}

幸运的是,它可以在WinXP上运行。但是在win7 / win10的情况下,情况就完全不同了:

切换到winlogon后,SetThreadDesktop函数始终返回FALSE,错误5(访问被拒绝)
我试图改变策略:
  • 首先,程序创建所有现有窗口站及其桌面的列表。
  • 之后,该程序会“轮询”所有WINSTA和HDESK,并将屏幕截图保存在磁盘上。

    我试图以3种模式启动该程序:
  • 作为管理员
  • 作为已启用桌面交互的服务。
  • 在Winlogon桌面上使用CreateProcess标志创建
  • (在这种情况下,程序只是崩溃了)

  • 结果是一样的。
    我做错了什么?我应该尝试桌面复制API吗?

    预先感谢您的回复!

    最佳答案

    由于Winlogon是安全桌面,因此您必须以LOCAL_SYSTEM帐户运行应用程序才能访问它。

    示例:在LOCAL_SYSTEM下运行的Windows服务,该服务在控制台 session 中启动用户应用程序(捕获屏幕)。

    在您的代码中,没有检查OpenInputDesktop的返回值,该返回值可能为NULL,错误代码为5(访问被拒绝)。

    还要检查this answer以获取更多信息

    09-06 06:52