问题
I need to capture a winlogon screen in WinXP/Win7/10. For WinXP I'm using a mirror driver and a standard methodic like this:
...
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;
}
And luckily it works on WinXP. But in case of win7/win10 I've a quite different situation:
SetThreadDesktop function after switching to winlogon always returns FALSE with an error 5 ( access denied ) I tried to change a strategy:
- First of all program creates a list of all of existing window stations and their desktops.
After that program "polls" all of WINSTAs and HDESKs and saves screenshots on a disk.
I tried to launch this program under 3 modes:
- as an Administrator
- as a service with enabled desktop interaction.
- at winlogon desktop using CreateProcess flags ( in this case program simply crashes )
And result was the same. What I'm doing wrong? Should I try a Desktop Duplication API?
Thanks in advance for your responses!
回答1:
As Winlogon is a secure desktop you have to run your application under LOCAL_SYSTEM account to access it.
Example: a windows service that runs under LOCAL_SYSTEM that launches an user application (that captures the screen) in a console session.
In your code there is no check for the return value of OpenInputDesktop which may be NULL with error code 5 (access denied).
Check this answer as well for more information
来源:https://stackoverflow.com/questions/43520385/winlogon-screen-capturing-in-windows-7-10