Session 0 capture screen - c++

Tried https://stackoverflow.com/a/30138664/533237 and able to capture screen.
But I want to capture screen from an application running in session 0 or another user.Introduced a 10 sec sleep before capturing and switched to another user.
Also tried PsExec.exe -h -s E:\sc.exe. Both throws error
C:\Users\unity\Documents\Visual Studio 2015\Projects\ConsoleApplication2\Debug>sc.exe
FAILURE 0x8876086C (-2005530516)
line: 60 file: 'c:\users\unity\documents\visual studio 2015\projects\consoleapplication2\consoleapplication2\consoleapplication2.cpp'
expr: 'd3d->GetAdapterDisplayMode(adapter, &mode)'
C:\Users\unity\Documents\Visual Studio 2015\Projects\ConsoleApplication2\Debug>PsExec.exe -h -s E:\sc.exe -w E:\
PsExec v2.11 - Execute processes remotely
Copyright (C) 2001-2014 Mark Russinovich
Sysinternals - www.sysinternals.com
FAILURE 0x8876086C (-2005530516)
line: 60 file: 'c:\users\unity\documents\visual studio 2015\projects\consoleapplication2\consoleapplication2\consoleapplication2.cpp'
expr: 'd3d->GetAdapterDisplayMode(adapter, &mode)'
Commented out GetAdapterDisplayMode and hardcoded height and width but CreateDevice failed
FAILURE 0x8876086A (-2005530518)
line: 76 file: 'c:\users\unity\documents\visual studio 2015\projects\consoleapplication2\consoleapplication2\consoleapplication2.cpp'
expr: 'd3d->CreateDevice(adapter, D3DDEVTYPE_HAL, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &parameters, &device)'
Edited:
Idea is to have a single app running in background and capture anything getting displayed irrespective of the user logged in or even if no one is logged in (lock/login screen)

There are two levels of problems with this.
On one level, while a lot of GDI will work, session 0 is not linked to a functional display device, certainly not one that is capable of D3D.
On another level, while things like the DWM have been introduced, the Windows API has always presented a display model where invisible screen pixels simply don't exist. The entire windows display model is built around getting windows to co-operative paint to a shared display surface, and any parts of a window that are uncovered are repainted on demand by the desktop composition system.
This means, in a very fundamental way, you cannot screen capture anything from session 0 as, in order to do so, session 0 would have to be attached to the active display device.

Related

Crashing when calling QTcpSocket::setSocketDescriptor()

my project using QTcpSocket and the function setSocketDescriptor(). The code is very normal
QTcpSocket *socket = new QTcpSocket();
socket->setSocketDescriptor(this->m_socketDescriptor);
This coding worked fine most of the time until I ran a performance testing on Windows Server 2016, the crash occurred. I debugging with the crash dump, here is the log
0000004f`ad1ff4e0 : ucrtbase!abort+0x4e
00000000`6ed19790 : Qt5Core!qt_logging_to_console+0x15a
000001b7`79015508 : Qt5Core!QMessageLogger::fatal+0x6d
0000004f`ad1ff0f0 : Qt5Core!QEventDispatcherWin32::installMessageHook+0xc0
00000000`00000000 : Qt5Core!QEventDispatcherWin32::createInternalHwnd+0xf3
000001b7`785b0000 : Qt5Core!QEventDispatcherWin32::registerSocketNotifier+0x13e
000001b7`7ad57580 : Qt5Core!QSocketNotifier::QSocketNotifier+0xf9
00000000`00000001 : Qt5Network!QLocalSocket::socketDescriptor+0x4cf7
00000000`00000000 : Qt5Network!QAbstractSocket::setSocketDescriptor+0x256
In the stderr log, I see those logs
CreateWindow() for QEventDispatcherWin32 internal window failed (Not enough storage is available to process this command.)
Qt: INTERNAL ERROR: failed to install GetMessage hook: 8, Not enough storage is available to process this command.
Here is the function, where the code was stopped on the Qt codebase
void QEventDispatcherWin32::installMessageHook()
{
Q_D(QEventDispatcherWin32);
if (d->getMessageHook)
return;
// setup GetMessage hook needed to drive our posted events
d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId());
if (Q_UNLIKELY(!d->getMessageHook)) {
int errorCode = GetLastError();
qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %s",
errorCode, qPrintable(qt_error_string(errorCode)));
}
}
I did research and the error Not enough storage is available to process this command. maybe the OS (Windows) does not have enough resources to process this function (SetWindowsHookEx) and failed to create a hook, and then Qt fire a fatal signal, finally my app is killed.
I tested this on Windows Server 2019, the app is working fine, no crashes appear.
I just want to know more about the meaning of the error message (stderr) cause I don't really know what is "Not enough storage"? I think it is maybe the limit or bug of the Windows Server 2016? If yes, is there any way to overcome this issue on Windows Server 2016?
The error ‘Not enough storage is available to process this command’ usually occurs in Windows servers when the registry value is set incorrectly or after a recent reset or reinstallations, the configurations are not set correctly.
Below is verified procedure for this issue:
Click on Start > Run > regedit & press Enter
Find this key name HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\LanmanServer\Parameters
Locate IRPStackSize
If this value does not exist Right Click on Parameters key and Click on New > Dword Value and type in IRPStackSize under the name.
The name of the value must be exactly (combination of uppercase and lowercase letters) the same as what I have above.
Right Click on the IRPStackSize and click on Modify
Select Decimal enter a value higher than 15(Maximum Value is 50 decimal) and Click Ok
You can close the registry editor and restart your computer.
Reference
After researching for a few days I finally can configure the Windows Server 2016 setting (registry) to prevent the crash.
So basically it is a limitation of the OS itself, it is called desktop heap limitation.
https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/desktop-heap-limitation-out-of-memory
(The funny thing is the error message is Not enough storage is available to process this command but the real problem came to desktop heap limitation. )
So for the solution, flowing the steps in this link: https://learn.microsoft.com/en-us/troubleshoot/system-center/orchestrator/increase-maximum-number-concurrent-policy-instances
I increased the 3rd parameter of SharedSection to 2048 and it fix the issue.
Summary steps:
Desktop Heap for the non-interactive desktops is identified by the third parameter of the SharedSection= segment of the following registry value:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SubSystems\Windows
The default data for this registry value will look something like the following:
%SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,3072,512 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ProfileControl=Off MaxRequestThreads=16
The value to be entered into the Third Parameter of the SharedSection= segment should be based on the calculation of:
(number of desired concurrent policies) * 10 = (third parameter value)
Example: If it's desired to have 200 concurrent policy instances, then 200 * 10 = 2000, rounding up to a nice memory number gives you 2048as the third parameter resulting in the following update to be made to the registry value:
SharedSection=1024,3072,2048

Strange OpenXR Behaviour on xrEndFrame

Firstly: Context is VR with HP Reverb G2, WMR runtime, DX12.
We're seeing some unexplained behaviour across developer machines when working with OpenXR. It looks as thought the OpenXR runtime is changing the way it presents depending on the machine setting for preferred GPU.
More specifically, we noticed that depending on the machines setting for preferred GPU, we are seeing a different method used when XrEndFrame is called. This is a big deal as the different method results in a blank screen being drawn into our current renderTarget!
The difference is that when the preferred device is an Nvidia GPU, xrEndFrame looks like this in PIX (in a graphics queue that is separate to our main render):
Index Global ID Name EOP to EOP Duration (ns) Execution Start Time (ns)
2 8063 Signal(pFence:obj#20, Value:62)
3 8064 Wait(pFence:obj#36, Value:31)
5 8065 CopyTextureRegion(pDst:{pResource:obj#4083, Type:D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, SubresourceIndex:0}, DstX:0, DstY:0, DstZ:0, pSrc:{pResource:obj#4084, Type:D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, SubresourceIndex:0}, pSrcBox:{left:0, top:0, front:0, right:2088, bottom:2036, back:1})
6 8066 CopyTextureRegion(pDst:{pResource:obj#4083, Type:D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, SubresourceIndex:1}, DstX:0, DstY:0, DstZ:0, pSrc:{pResource:obj#4085, Type:D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, SubresourceIndex:0}, pSrcBox:{left:0, top:0, front:0, right:2088, bottom:2036, back:1})
8 8067 Signal(pFence:obj#20, Value:63)
9 8068 Signal(pFence:obj#21, Value:31)
and when it isn't, (i.e. somehow maybe picking up Intel onboard?) it looks like this:
Index Global ID Name EOP to EOP Duration (ns) Execution Start Time (ns)
0 8064 Wait(pFence:obj#45, Value:21)
2 8065 ClearRenderTargetView(RenderTargetView:res#4008, ColorRGBA:{Element:0, Element:0, Element:0, Element:0}, NumRects:0, pRects:nullptr)
15 8066 DrawIndexedInstanced(IndexCountPerInstance:4, InstanceCount:2, StartIndexLocation:0, BaseVertexLocation:0, StartInstanceLocation:0)
17 8067 Signal(pFence:obj#22, Value:23)
18 8068 Signal(pFence:obj#23, Value:21)
The latter is clearing the current renderTargetView and drawing a quad over the top that is the dimensions of the headset display.
Yet- we've checked the rendering code and it is definitely not selecting the Intel graphics device. However the second behaviour goes away if we set 'preferred graphics processor' to nvidia gpu in nvidia control panel.
We can also see that the above behaviour is the result of a call to XrEndFrame, and that our rendering code is identical otherwise.
Any clue as to what part of the runtime might be looking at or influenced by this setting?
Unfortunately (fortuitously?) we found we need to work on the rendering code to be able to swap runtimes to say SteamVR, so right now we can't swap out the runtime.
Obviously we have a workaround, which is to set the preferred device. But understanding how/why this issue is occurring would be great.
So this was finally tracked down to an error on our part.
In our case we were using xrGetD3D12GraphicsRequirementsKHR to get the minimum graphics requirements for openxr.
This has an adapterLuid identifier in the structure XrGraphicsRequirementsD3D12KHR which we should have been using to select the GPU in the graphics API, but weren't.

TouchPanelSetCalibration not updating calibration

Problem
Our product is providing a wizard to calibrate the touch screen. A special requirement is that I need to verify every new calibration which is made by this wizard. The verification is quite simple tho. After the touch screen has been calibrated a new screen containing 4 touch targets (buttons) is shown, if the user is able to hit each target within a given time frame the calibration is considered successful. If time runs out, the calibration data in the registry shall be restored and the touch driver shall be restored without restarting.
Approach
Backup of HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\TOUCH\CalibrationData
Show Windows CE built-in calibration UI using: TouchCalibrate()
Show custom verification screen as described above.
If verification failed restore registry and call TouchPanelSetCalibration(...) using old calibration data.
When calling TouchPanelSetCalibration(...) I get the following output:
Maximum Allowed Error 54:
Calibration Results:
Screen => Mapped
( 240, 136) => ( 240, 130)
( 96, 54) => ( 93, 57)
( 96, 218) => ( 99, 218)
( 384, 218) => ( 381, 220)
( 384, 54) => ( 387, 55)
Maximum error (square of Euclidean distance in screen units) = 36
The registry is properly restored and considering the output I'm assuming the calibration data is also properly forwarded to the driver.
But somehow the touch calibration is not restored without restarting the system.
Do I need to signal this change somehow by sending a message or firing an event? Do I need to make any additional API calls?
...Any help is appreciated
Thanks.
~Sambuca
I also posted this question on MSDN forums. Here's the answer I got there:
The Touch Driver Entrypoint TouchPanelSetCalibration must be called
by GWES to get the calibration data updated. When called from a user
application, the API would only update data held inside the
application process.
But there is an other approach to implement your touch calibration
wizard.
The Touch Calibration UI (calibrui) shown by TouchCalibrate() can be
customized. Basically, you'd need to replace the default confirmation
screen with your own implementation.
The instructions on how to clone the default CalibrUi can be found:
For Windows CE 5.0 in MSDN: http://msdn.microsoft.com/en-us/library/aa452834.aspx
For CE 6.0 and Compact 7: http://guruce.com/blogpost/cloning-calibrui-in-windows-ce-60

Linux - Detecting idleness

I need to detect when a computer is idle for a certain time period. My definition of idleness is:
No users logged in, either by remote methods or on the local machine
X server inactivity, with no movement of mouse or key presses
TTY keyboard inactivity (hopefully)
Since the majority of distros have now moved to logind, I should be able to use its DBUS interface to find out if users are logged in, and also to monitor logins/logouts. I have used xautolock to detect X idleness before, and I could continue using that, but xscreensaver is also available. Preferably however I want to move away from any specific dependencies like the screensaver due to different desktop environments using different components.
Ideally, I would also be able to base idleness on TTY keyboard inactivity, however this isn't my biggest concern. According to this answer, I should be able to directly query the /dev/input/* interfaces, however I have no clue how to go about this.
My previous attempts at making such a monitor have used Bash, due to the ease of changing a plain text script file, howver I am happy using C++ in case more advanced methods are required to accomplish this.
From a purely shell standpoint (since you tagged this bash), you can get really close to what you want.
#!/bin/sh
users_are_logged_in() {
who |grep -q .
return $?
}
x_is_blanked() {
local DISPLAY=:0
if xscreensaver-command -time |grep -q 'screen blanked'; then
return 0 # we found a blanked xscreensaver: return true
fi
# no blanked xscreensaver. Look for DPMS modes
xset -q |awk '
/DPMS is Enabled/ { dpms = 1 } # DPMS is enabled
/Monitor is On$/ { monitor = 1 } # The monitor is on
END { if(dpms && !monitor) { exit 0 } else { exit 1 } }'
return $? # true when DPMS is enabled and the monitor is not on
}
nobody_here() {
! users_are_logged_in && x_is_blanked
return $?
}
if nobody_here; then
sleep 2m
if nobody_here; then
# ...
fi
fi
This assumes that a user can log in in two minutes and that otherwise, there is no TTY keyboard activity.
You should verify that the who |grep works on your system (i.e. no headers). I had originally grepped for / but then it won't work on FreeBSD. If who has headers, maybe try [ $(who |grep -c .) -gt 1 ] which will tell you that the number of lines that who outputs is more than one.
I share your worry about the screensaver part; xscreensaver likely isn't running in the login manager (any other form of X would involve a user logged in, which who would detect), e.g. GDM uses gnome-screensaver, whose syntax would be slightly different. The DPMS part may be good enough, giving a far larger buffer for graphical logins than the two minutes for console login.
Using return $? in the last line of a function is redundant. I used it to clarify that we're actually using the return value from the previous line. nobody_here short circuits, so if no users are logged in, there is no need to run the more expensive check for the status of X.
Side note: Be careful about using the term "idle" as it more typically refers to resource (hardware, that is) consumption (e.g. CPU load). See the uptime command for load averages for the most common way of determining system (resource) idleness. (This is why I named my function nobody_here instead of e.g. is_idle)

How to refresh logon screensaver parameter changes?

I have a Windows service that may change the timeout on the logon screensaver in Windows (as described here.) To do that I change the following registry key to the timeout in seconds:
HKEY_USERS\.DEFAULT\Control Panel\Desktop\ScreenSaveTimeOut
The issue is that how do I make OS "read" or refresh the actual screensaver timeout after a change in the registry key above?
My practice shows that it is refreshed (for sure) only when I reboot the system, but in my case I need it to be applied without the reboot.
EDIT_1: After suggestion below I tried, as it seems to me, all possible combinations of the flags for the following:
DWORD bsmInfo1 = BSM_ALLDESKTOPS;
DWORD dwFlgs = BSF_FORCEIFHUNG | BSF_IGNORECURRENTTASK | BSF_NOTIMEOUTIFNOTHUNG | BSF_SENDNOTIFYMESSAGE;
int nbsm1 = ::BroadcastSystemMessage(dwFlgs, &bsmInfo1, WM_SETTINGCHANGE, 0, (LPARAM)L"Windows");
DWORD bsmInfo2 = BSM_ALLDESKTOPS;
int nbsm2 = ::BroadcastSystemMessage(dwFlgs, &bsmInfo2, WM_SETTINGCHANGE, 0, (LPARAM)L"WindowsThemeElement");
to no avail :( I receive 1 as a result from both calls but it has no effect.
I was able to resolve this.-.-.
If your service is running in the same session as the logon screensaver then you can call SystemParametersInfo with the SPI_SETSCREENSAVETIMEOUT flag.
SystemParametersInfo broadcasts the WM_SETTINGCHANGE message to all top level windows to indicate that a parameter has changed. If your code isn't running in the correct session then you could use BroadcastSystemMessage with the BSM_ALLDESKTOPS flag to deliver the WM_SETTINGCHANGE message. However, this does require the SE_TCB_NAME privilege, so your code would have to be running as SYSTEM.
I haven't actually tried this cross-session, so I can't guarantee that it works.