Related
I'm working in Windows 10 and I am trying to write a C++ program that intercepts all touch screen input, however some input is still getting through.
My code calls RegisterPointerInputTarget with PT_TOUCH to intercept touch input. This mostly seems to work, however the results are inconsistent. As a test I have added code that uses SendInput to move the mouse slowly to the right whenever touch input is detected. With my program running I can, for example, open up MS Paint and touch the screen. So long as I hold my finger still on the cursor moves slowly to the right as expected. The moment I move my finger however, the cursor snaps to the position under my finger, just as it would if my program were not running at all.
To give another example, if I try the same thing in visual studio, again the cursor moves slowly to the right until I move my finger at which point the cursor follows my fingers' movement but slowly, lagging be behind it with a significant delay.
The code to set up my window looks like this;
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
static const char* class_name = "DUMMY_CLASS";
WNDCLASSEX wx = {};
wx.cbSize = sizeof(WNDCLASSEX);
wx.lpfnWndProc = WndProc; // function which will handle messages
wx.hInstance = hInst;
wx.lpszClassName = class_name;
HWND hWnd = 0;
if (RegisterClassEx(&wx)) {
hWnd = CreateWindowEx(0, class_name, "dummy_name", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
}
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
if (RegisterTouchWindow(hWnd, 0) &&
RegisterPointerInputTarget(hWnd, PT_TOUCH))
{
...
and my message handling code looks like this;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_TOUCH:
{
INPUT Inputs[1] = { 0 };
Inputs[0].type = INPUT_MOUSE;
Inputs[0].mi.dx = 1;
Inputs[0].mi.dy = 0;
Inputs[0].mi.dwFlags = MOUSEEVENTF_MOVE;
SendInput(1, Inputs, sizeof(INPUT));
Ideally this test code would simply move the cursor for any touch input. Any help in fixing or just understanding this would be greatly appreciated!
I have made some progress with this but have hit other, related, problems I will ask about in a separate question. I will add a comment here when that question is live. The key to sorting out this initial issue however was to make sure I am returning 0, without calling DefWindowProc from all WM_POINTERENTER, WM_POINTERLEAVE, WM_POINTERUP, WM_POINTERDOWN, WM_POINTERUPDATE and WM_TOUCH messages, and to put my SendInput call into the code processing the WM_UPDATE message.
So far I got this partially working capturing function in C#:
/// <summary>
/// Captures a HWND, using a WM_PRINT windows message to draw into a memory DC.
/// Pro: Does also work if the HWND is not positioned inside the visible screen.
/// Con: Does only work if the target handle supports WM_PRINT and WM_PRINTCLIENT.
/// TODO: Subclass the target handle and hack the WM_PRINT support for various systems, including Windows 7.
/// Example for Windows 2000 see http://www.fengyuan.com/article/wmprint.html.
/// </summary>
/// <param name="hWnd">The HWND.</param>
/// <returns>Bitmap of the captured visual window, if the operation succeeds. Null, if the operation fails.</returns>
public static Bitmap CaptureHWnd_WM_PRINT(UIntPtr hWnd)
{
Bitmap bitmap = null;
UIntPtr hDC = User32.GetWindowDC(hWnd); //Get the device context of hWnd
if (hDC != UIntPtr.Zero)
{
UIntPtr hMemDC = Gdi32.CreateCompatibleDC(hDC); //Create a memory device context, compatible with hDC
if (hMemDC != UIntPtr.Zero)
{
RECT rc; MyGetWindowRect(hWnd, out rc); //Get bounds of hWnd
UIntPtr hbitmap = Gdi32.CreateCompatibleBitmap(hDC, rc.Width, rc.Height); //Create a bitmap handle, compatible with hDC
if (hbitmap != UIntPtr.Zero)
{
UIntPtr hOld = Gdi32.SelectObject(hMemDC, hbitmap); //Select hbitmap into hMemDC
//#also tried: User32.SendMessage(hWnd, WM.PRINT, hMemDC, (UIntPtr)(DrawingOptions.PRF_CLIENT | DrawingOptions.PRF_CHILDREN | DrawingOptions.PRF_NONCLIENT | DrawingOptions.PRF_OWNED));
User32.DefWindowProc(hWnd, WM.PRINT, hMemDC, (UIntPtr)(DrawingOptions.PRF_CLIENT | DrawingOptions.PRF_CHILDREN | DrawingOptions.PRF_NONCLIENT | DrawingOptions.PRF_OWNED));
bitmap = Image.FromHbitmap(hbitmap.ToIntPtr()); //Create a managed Bitmap out of hbitmap
Gdi32.SelectObject(hMemDC, hOld); //Select hOld into hMemDC (the previously replaced object), to leave hMemDC as found
Gdi32.DeleteObject(hbitmap); //Free hbitmap
}
Gdi32.DeleteDC(hMemDC); //Free hdcMem
}
User32.ReleaseDC(hWnd, hDC); //Free hDC
}
return bitmap;
}
The problem is, that it can only work if hWnd handles the WM_PRINT and WM_PRINTCLIENT messages correctly.
For example, one can test it sucessfully using
UIntPtr hWndMyButton = User32.CreateWindowEx(
WS_EX.NONE, "Button", " HELLO WORLD! :) ", WS.CHILD,
5000, 5000,
200, 30, User32.GetDesktopWindow(), (UIntPtr)0x8807, UIntPtr.Zero, UIntPtr.Zero);
Bitmap capture = CaptureHWnd_WM_PRINT(hWndMyButton);
, but for the most cases it only results in a black image of the size of hWnd. Note that hWndMyButton is far outside the screen bounds (at position {X=5000,Y=5000}), but can still get captured. That is the reason I need WM_PRINT.
The questions is now, how can I force hWnd to handle the print messages correctly on at least Windows 7?
So far, I found this solution for Windows 2000 and would like to get a similar solution for Windows 7, or preferred a generic solution for all Windows systems that support WM_PRINT.
Unfortunately I could not find anything for other systems than Windows 2000.
What is wrong with the following code? Why does PrintWindow return 0?
HWND hwnd = GetDesktopWindow();
CHK(hwnd);
HDC hdc = GetWindowDC(hwnd);
CHK(hdc);
if (hdc)
{
HDC hdcMem = CreateCompatibleDC(hdc);
CHK(hdcMem);
if (hdcMem)
{
RECT rc;
CHK(GetWindowRect(hwnd, &rc));
HBITMAP hbitmap = CreateCompatibleBitmap(hdc, rc.right-rc.left, rc.bottom-rc.top);
CHK(hbitmap);
if (hbitmap)
{
SelectObject(hdcMem, hbitmap);
CHK(PrintWindow(hwnd, hdcMem, 0)); //HERE return 0
DeleteObject(hbitmap);
}
DeleteObject(hdcMem);
}
ReleaseDC(hwnd, hdc);
}
PrintWindow is a fairly thin operation. What it really does is post a WM_PRINTmessage to the queue for the window in question, in this case the desktop, and hopes that that window will respond to WM_PRINT correctly if at all (see here and here).
I repro'd your behavior but I'm not 100% sure why it's failing either. Perhaps you cannot call PrintWindow on an HWND that your process does not own, or perhaps the desktop does not respond to WM_PRINT messages.
The second link above includes a comment about using BitBlt instead:
Try getting a handle (HWND) to the
desktop window - and use BitBlt to
capture all the contents. Mind you -
you'll only capture what is visible on
the screen.
Maybe this helps.
It looks like GetDesktopWindow() returns a virtual HWND whose value is universally 0x0010010 on all Windows machines. This virtual HWND does not conform to usual PrintWindow behavior so the PrintWindow() returns FALSE, and GetLastError() reports no error code on this PrintWindow call.
To make PrintWindow() work, you can instead use the HWND from GetShellWindow(), which has the title "Program Manager" from the WinSpy++ figure below.
Replace:
HWND hwnd = GetDesktopWindow();
With:
HWND hwnd = GetDesktopWindow();
hwnd = FindWindowEx( hwnd, 0, _T("Progman"), _T("Program Manager") );
I'm not sure whether this gets what you want though. If you want to take a screenshot of the entire current desktop (including whatever top level windows are visible) then BitBlt is the route you want to take.
If you want to get the taskbar as well, you can still use this method but you'll have to take 2 screenshots and stitch the results together.
Can we change/increase the size of console output to view large size of data in console application at once?
There seem to be different ways to Rome:
This should be the recommended way I would think, cause the name says it all: GetConsoleWindow as is demonstrated here.
A quick hack might be the windows API function SendInput. If you simulate Alt+Enter, you could probably fullscreen the active window.
Here are some propositions using API calls from user32.dll
Check out the SetConsoleScreenBufferInfoEx API. It takes a CONSOLE_SCREEN_BUFFER_INFOEX as input and that has a dwSize member which contains the size of the console screen buffer, in character columns and rows.
MSDN for SetConsoleScreenBufferInfoEx Function: http://msdn.microsoft.com/en-us/library/ms686039(v=VS.85).aspx
I once used a small hack that is first setting the console's output buffer and then trying to find the console window and resize it. It worked well on XP, I never tested it on newer Windows versions.
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
SMALL_RECT sr;
sr.Top = 0;
sr.Left = 0;
sr.Bottom = 10;
sr.Right = 79;
SetConsoleWindowInfo(h, TRUE, &sr);
TCHAR title[512];
GetConsoleTitle(title, 512);
HWND hWnd = FindWindow(NULL, title);
if(hWnd != NULL) {
HWND hWndInsertAfter = NULL;
UINT nFlags = SWP_NOSIZE | SWP_NOZORDER;
#if 0 // Don't move?
nFlags |= SWP_NOMOVE;
#endif
SetWindowPos(hWnd, hWndInsertAfter , 40, 350, 0, 0, nFlags);
SetForegroundWindow(hWnd);
}
If you are using the command prompt window, right click it's label on the task bar and click the Properties option.
Am i allowed to use a DC outside of a paint cycle?
Is my window's DC guaranteed to be valid forever?
i'm trying to figure out how long my control's Device Context (DC) is valid.
i know that i can call:
GetDC(hWnd);
to get the device context of my control's window, but is that allowed?
When Windows sends me a WM_PAINT message, i am supposed to call BeginPaint/EndPaint to properly acknowledge that i've painted it, and to internally clear the invalid region:
BeginPaint(hWnd, {out}paintStruct);
try
//Do my painting
finally
EndPaint(hWnd, paintStruct);
end;
But calling BeginPaint also returns me a DC inside the PAINTSTRUCT structure. This is the DC that i should be painting on.
i cannot find anything in the documentation that says that the DC returned by BeginPaint() is the same DC that i would get from GetDC().
Especially now, in the days of Desktop Composition, is it valid to paint on a DC that i obtain outside of BeginPaint?
There seem to be 2 ways i can get a DC to paint on during a paint cycle:
dc = GetDC(hWnd);
BeginPaint(&paintStruct);
There is a 3rd way, but it seems to be a bug with the Borland Delphi that i develop with.
During WM_PAINT processing, Delphi believes that the wParam is a DC, and proceeds to paint on it. Whereas the MSDN says that the wParam of a WM_PAINT message is unused.
The Why
My real goal is to try to keep a persistent GDI+ Graphics object against an HDC, so that i can use some better performing features of GDI+ that depend on having a persistent DC.
During the WM_PAINT message handling i want to draw a GDI+ image to the canvas. The following nieve version is very slow:
WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(m_hwnd, ps);
Graphics g = new Graphics(ps.hdc);
g.DrawImage(m_someBitmap, 0, 0);
g.Destroy();
EndPaint(h_hwnd, ps);
}
GDI contains a faster performing bitmap, a CachedBitmap. But using it without thinking gives no performance benefit:
WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(m_hwnd, ps);
Graphics g = new Graphics(ps.hdc);
CachedBitmap bm = new CachedBitmap(m_someBitmap, g);
g.DrawCachedBitmap(m_bm, 0, 0);
bm.Destroy();
g.Destroy();
EndPaint(h_hwnd, ps);
}
The performance gain comes from creating the CachedBitmap once, so on program initialization:
m_graphics = new Graphics(GetDC(m_hwnd));
m_cachedBitmap = new CachedBitmap(b_someBitmap, m_graphcis);
And now on the paint cycle:
WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(m_hwnd, ps);
m_graphics.DrawCachedBitmap(m_cachedBitmap, 0, 0);
EndPaint(h_hwnd, ps);
}
Except now i'm trusting that the DC i obtained after program initializtion will be the same DC for my window as long as the application is running. This means that it survives through:
fast user switches
composition enabled/disabled
theme switching
theme disabling
i find nothing in MSDN that guarantees that the same DC will be used for a particular window for as long as the window exists.
Note: i am not using double-buffering, because i want to be a good developer, and do the right thing. *
Sometimes that means you double-buffering is bad.
There are exceptions, but in general, you may get a different DC each time you call GetDC or BeginPaint. Thus you shouldn't try to save state in the DC. (If you must do this for performance, there are special DCs you can create for a class of windows or a particular window instance, but it doesn't sound like that's what you really need or want.)
Most of the time, however, those DCs will be compatible. They will represent the same graphics mode, so your compatible bitmap should work, even if you get a different DC.
There are Windows messages that tell you when the graphics mode changes, like WM_DISPLAYCHANGE and WM_PALETTECHANGED. You can listen for these, and recreate your cached bitmap. Since those are rare events, you won't have to worry about the performance impact of recreating your cached bitmap at that point.
You can also get notifications for things like theme changes. Those don't change the graphics mode--they're a higher level concept--so your cached bitmap should still be compatible with any DC you get. But if you want to change bitmap when the theme changes, you can listen for WM_THEMECHANGED as well.
The only way I know of that may (or may not) do what you are looking for is to create the window with the CS_OWNDC class style.
What that does is allocates a unique device context for each window in the class.
Edit
From the linked MSDN article:
A device context is a special set of
values that applications use for
drawing in the client area of their
windows. The system requires a device
context for each window on the display
but allows some flexibility in how the
system stores and treats that device
context.
If no device-context style is
explicitly given, the system assumes
each window uses a device context
retrieved from a pool of contexts
maintained by the system. In such
cases, each window must retrieve and
initialize the device context before
painting and free it after painting.
To avoid retrieving a device context
each time it needs to paint inside a
window, an application can specify the
CS_OWNDC style for the window class.
This class style directs the system to
create a private device context — that
is, to allocate a unique device
context for each window in the class.
The application need only retrieve the
context once and then use it for all
subsequent painting.
Windows 95/98/Me: Although the
CS_OWNDC style is convenient, use it
carefully, because each device context
uses a significant portion of 64K GDI
heap.
Perhaps this example will illustrate the use of CS_OWNDC better:
#include <windows.h>
static TCHAR ClassName[] = TEXT("BitmapWindow");
static TCHAR WindowTitle[] = TEXT("Bitmap Window");
HDC m_hDC;
HWND m_hWnd;
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static PAINTSTRUCT ps;
switch (msg)
{
case WM_PAINT:
{
BeginPaint(hWnd, &ps);
if (ps.hdc == m_hDC)
MessageBox(NULL, L"ps.hdc == m_hDC", WindowTitle, MB_OK);
else
MessageBox(NULL, L"ps.hdc != m_hDC", WindowTitle, MB_OK);
if (ps.hdc == GetDC(hWnd))
MessageBox(NULL, L"ps.hdc == GetDC(hWnd)", WindowTitle, MB_OK);
else
MessageBox(NULL, L"ps.hdc != GetDC(hWnd)", WindowTitle, MB_OK);
RECT r;
SetRect(&r, 10, 10, 50, 50);
FillRect(m_hDC, &r, (HBRUSH) GetStockObject( BLACK_BRUSH ));
EndPaint(hWnd, &ps);
return 0;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
WNDCLASSEX wcex;
wcex.cbClsExtra = 0;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.cbWndExtra = 0;
wcex.hbrBackground = (HBRUSH) GetStockObject( WHITE_BRUSH );
wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
wcex.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wcex.hIconSm = NULL;
wcex.hInstance = hInstance;
wcex.lpfnWndProc = WndProc;
wcex.lpszClassName = ClassName;
wcex.lpszMenuName = NULL;
wcex.style = CS_OWNDC;
if (!RegisterClassEx(&wcex))
return 0;
DWORD dwExStyle = 0;
DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
m_hWnd = CreateWindowEx(dwExStyle, ClassName, WindowTitle, dwStyle, 0, 0, 300, 300, NULL, NULL, hInstance, NULL);
if (!m_hWnd)
return 0;
m_hDC = GetDC(m_hWnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
The CS_OWNDC flag is not to be confused with the CS_CLASSDC flag which:
Allocates one device context to be shared by all windows in the class. Because window classes are process specific, it is possible for multiple threads of an application to create a window of the same class. It is also possible for the threads to attempt to use the device context simultaneously. When this happens, the system allows only one thread to successfully finish its drawing operation.
If all else fails just reconstruct the CachedBitmap.
When you construct a CachedBitmap object, you must pass the address of a Graphics object to the constructor. If the screen associated with that Graphics object has its bit depth changed after the cached bitmap is constructed, then the DrawCachedBitmap method will fail, and you should reconstruct the cached bitmap. Alternatively, you can hook the display change notification message and reconstruct the cached bitmap at that time.
I'm not saying that CS_OWNDC is the perfect solution, but it is one step towards a better solution.
Edit
The sample program seemed to retain the same DC during screen resolution / bit depth change testing with the CS_OWNDC flag, however, when that flag was removed, the DC's were different (Window 7 64-bit Ultimate)(should work the same over differn OS versions... although it wouldn't hurt to test).
Edit2
This example doesn't call GetUpdateRect to check if the window needs to be painted during the WM_PAINT. That is an error.
You can draw onto whichever window dc pleases you. They're both valid. A window does not have just one dc that can represent it at a time. So each time you call GetDC - and BeginPaint internally does so, you will get a new, unique dc, that nonetheless represents the same display area.
Just ReleaseDC (or EndPaint) when you're done with them. In the days of Windows 3.1 device contexts were a limited, or very expensive system resource, so applications were encouraged to never hold onto them, but to retrieve them from the GetDC cache. nowadays its perfectly acceptable to create a dc at window creation, and cache it for the life of the window.
The only "problem" is, when handling WM_PAINT, the dc returned by BeginPaint will be clipped to the invalid rect, and the saved one will not.
I don't however understand what you are attempting to achieve with gdiplus. Usually, if an object is ... selected into a dc for a long period of time, that dc is a memory dc, not a window dc.
Each time GetDC is called you WILL get a new HDC representing a distinct device context with its own state. So, objects, background colors, text modes etc. set on one DC will NOT effect that state of another DC retrieved by a different call to GetDC or BeginPaint.
The system cannot randomly invalidate HDCs retrieved by the client, and actually does a lot of work in the background to ensure that HDCs retrieved before a display mode switch, continue to function. Even changing the bit depth, that technically makes the dc's incompatible, will not, in any way, prevent an application from continuing to use an hdc to blit.
That said, it is wise to watch at LEAST for WM_DISPLAYCHANGE, release any cached DCs and device bitmaps, and recreate them.