Win32 CTRL-ALT-DEL -> task manager kills OpenGL somehow - c

WINAPI: I have a simple Win32 application and an OpenGL context.
CAUSE) If I do CTRL-ALT-DELETE and click task manager ...
EFFECT) the application window is black until it is resized. OpenGL will not render.
With a great deal of experimentation, I have largely overcome this huge annoyance ...
Unlikable partial solution --- I cheat resizing the window with no redraw as such, "mostly" tricking Windows
Code:
case WM_SYNCPAINT:
SetWindowPos (hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOOWNERZORDER |
SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE | SWP_HIDEWINDOW);
RedrawWindow (hwnd, NULL, 0, RDW_NOERASE );
SetWindowPos (hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOOWNERZORDER |
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
break;
D) However, it is still a suboptimal solution with some minor side effects.
QUESTION 1: Why is my OpenGL getting killed, recreating the context doesn't even work.
QUESTION 2: There has to be a real way to solve this problem without hiding the window and showing it again which causes some repainting side-effects ... does anyone have a solution.
Although not directly related, SDL2 has this problem as well and I often cross-check against their code for winapi messaging/drawing issues like this and their codebase doesn't have a solution and I see this issue posted around the internet for other things like Glut and such. This seems to be a problem that rears its ugly head even in common OpenGL toolkits and such.

Related

Why is ID2D1Factory::GetDesktopDpi obsolete?

I'm following a direct2d tutorial and when I compile the code I get an error that a function is obsolete and that I should replace it, I look for ways to replace the function with the solutions that visual studio gives me (before publishing in stackoverflow) but it doesn't work, or I don't know how to call them.
main.cpp
// Because the CreateWindow function takes its size in pixels,
// obtain the system DPI and use it to scale the window size.
FLOAT dpiX, dpiY;
// The factory returns the current system DPI. This is also the value it will use
// to create its own windows.
m_pDirect2dFactory->GetDesktopDpi(&dpiX, &dpiY);
// Create the window.
m_hwnd = CreateWindow(
L"D2DDemoApp",
L"Direct2D Demo App",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
static_cast<UINT>(ceil(640.f * dpiX / 96.f)),
static_cast<UINT>(ceil(480.f * dpiY / 96.f)),
NULL,
NULL,
HINST_THISCOMPONENT,
this
);
error
1>------ Build started: Project: entt, Configuration: Debug x64 ------
1>Using triplet "x64-windows-static" from "C:\Users\Jule\vcpkg\installed\x64-windows-static\"
1>main.cpp
1>C:\Users\Jule\source\repos\entt\entt\main.cpp(154,27): error C4996: 'ID2D1Factory::GetDesktopDpi': Deprecated. Use DisplayInformation::LogicalDpi for Windows Store Apps or GetDpiForWindow for desktop apps.
1>Done building project "entt.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
tutorial: https://learn.microsoft.com/en-us/windows/win32/direct2d/direct2d-quickstart
I just went through this tutorial myself and ran into the same issue. The solution provided by #Julio Enrique in the comments is correct. However, I didn't realize at first he replaced both dpiX and dpiY with x, so it didn't work for me. As a result, I found an even simpler drop and replacement fix for this example tutorial. For others experiencing this issue, try the following fix:
// obtain the system DPI and use it to scale the window size.
FLOAT dpiX, dpiY;
// The following will return the current system DPI. This is the value used
// to create a window with the correct dimensions.
dpiX = (FLOAT) GetDpiForWindow (GetDesktopWindow ());
dpiY = dpiX;
// Create the window.
m_hwnd = CreateWindow(
L"D2DDemoApp",
L"Direct2D Demo App",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
static_cast<UINT>(ceil(640.f * dpiX / 96.f)),
static_cast<UINT>(ceil(480.f * dpiY / 96.f)),
NULL,
NULL,
HINST_THISCOMPONENT,
this
);
hr = m_hwnd ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
ShowWindow(m_hwnd, SW_SHOWNORMAL);
UpdateWindow(m_hwnd);
}
Also pointed out by #Julio Enrique, make sure to link the required Direct2D library (i.e. d2d1.lib) either in the Visual Studio linker options or via the following pragma:
#pragma comment(lib, "d2d1.lib")
Going forward, in order to prevent others from experiencing this issue in the future when reading the posted tutorial documentation, I have submitted a Pull Request to fix the documentation on the Microsoft website.

How can two different WPF application communicate each other being in same machine

Would like to have some insights on how can one wpf application activate another running application and send text messages.
Thank you all for the responses.
In fact I was successful in pointing an answer for self. PFB the steps.
To communicate between two WPF apps without any service connectivity I made use of ClipBoard facility available in Windows
The first WPF app will insert the value which needs to be passed in ClipBoard as below and later will activate the other WPF app who is running in the tray..
Process[] pname = Process.GetProcessesByName("APPNAME");
Clipboard.SetText("TEXT TO BE PASSED");
//Activation
Process[] processes = Process.GetProcessesByName(proc);
if (pname.Length != 0)
{
IntPtr hWnd = processes[0].MainWindowHandle;
SetForegroundWindow(hWnd);
SetWindowPos(p.MainWindowHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
Later in the activated app..through the activated method we could read the value as below
string clipboardText = System.Windows.Clipboard.GetText();
and then clear the clip
System.Windows.Clipboard.Clear();
Hopefully this will help someone. Thanks a lot.

Adding custom border to another application with Win32 API

I'd like to add my custom border rectangle to another application window like this:
I wrote this code by surfing from google but didn't help me:
HWND hWndX;
HRGN hRegX;
HDC hdc;
hWndX = FindWindow(NULL, "Untitled - Notepad");
hdc = GetDC(hWndX);
if (hWndX)
{
hRegX = CreateRectRgn(10, 10, 200, 200);
SetWindowLong(hWndX, GWL_STYLE, GetWindowLong(hWndX, GWL_STYLE));
SetWindowPos(hWndX, hWndX, 0, 0, 100, 100, SWP_FRAMECHANGED);
SetWindowRgn(hWndX, hRegX, true);
}
else
MessageBox(hWndX, "Cant find the window handle", "Error!", 0);
This kind of thing /might/ have worked in the old Win16/Windows 95 era, but these days, the OS protects one program from affecting the other. To change the border of another process, you will need to inject your code (as a dll) into the other process (assuming you have the correct security level). It's not that it is impossible, but it's not the sort of thing a beginner coder would be able to do.

GDI Leak Problem

I'm experiencing memory leaks while running the following GDI code:
HDC hdcScreen = GetDC(NULL);
HDC hdcMem = CreateCompatibleDC(hdcScreen);
HBITMAP hbmpOld = (HBITMAP) SelectObject(hdcMem, hBmp); // apparently here is the leak
// do something
SelectObject(hdcMem, hbmpOld); //placing the old object back. The return object is handled elseware
DeleteDC(hdcMem); // after CreateCompatibleDC
ReleaseDC(NULL, hdcScreen); // after GetDC
I already looked at similar threads, such as this but I couldn't find the problem.
Any help would be appreciated.
DeleteDC, ReleaseDC return value was checked to be true (no errors).
Thanks,
Tal.
Solved.
The problem was hBmp wasn't correctly initialized, so there was a crash at the SelectObject - no error, just the function exited, skipping the "//do something" and the releases part.
For future reference, a very useful free tool is NirSoft GDIView which displays GDI usage per process and tracks changes (handle leaks) while it runs. So you can perform operations in your app and keep checking GDIView until you see the counter increasing, and then repeat the operations until you pinpoint which one is causing the unwarranted handle increase.

Programmatically press a button on another application (C, Windows)

I'm trying to use the following code to press a button on my other application:
HWND ButtonHandle;
if( (wnd = FindWindow(0, "Do you want to save?")) )
{
ButtonHandle = FindWindowEx(wnd, 0, "SaveButton", "&Save");
SendMessage(wnd, WM_COMMAND, MAKEWORD(GetDlgCtrlID(ButtonHandle), BN_CLICKED ), (LPARAM)ButtonHandle);
}
It doesn't work. I tried passing different handles to MAKEWORD and to change the WPARM and LPARAM but nothing.
Any ideas on how to click a button on another application's window?
Code is appreciated.
Thanks.
EDIT:
The reason it doesn't seem to work permissions. I sent a PostMessage() and the result was an error with GetLastError() = 5 (or Access Denied).
Any ideas?
EDIT2 I don't mean to be rude but please please please, I already searched all the API's including getting and setting the regions for the button and then sending a button down and button up, getting the control ID, getting the class ID and a zillion more.
The reason I asked the question here in the first place is because I already exhausted my search on the internet.
If you know the answer PLEASE POST CODE, do not suggest an API and that's it, show me how does that API solves the problem. It's not hard.
thank you.
EDIT 3: The question's answer was selected automatically when the bounty finished. The question still remains without an answer.
Are you sure that "SaveButton" class name is valid? Do you get the button
handle?
Try to send messages to ButtonHandle window (directly to the button).
Update: I believe this should work,
SendMessage(ButtonHandle, BM_CLICK, 0, 0);
See the following solution, also you can use
SendMessage(ButtonHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(ButtonHandle, WM_LBUTTONUP, 0, 0);
Or
SendMessage(ButtonHandle, BM_CLICK, 0, 0);
HWND buttonHandle = 0;
BOOL CALLBACK GetButtonHandle(HWND handle, LPARAM)
{
char label[100];
int size = GetWindowTextA(handle,label,sizeof(label));
if(strcmp(label,"&Save") == 0)
{
buttonHandle = handle;
return false;
}
return true;
}
void main()
{
HWND windowHandle = FindWindowA(NULL,"Do you want to Save?");
if(windowHandle != 0)
{
BOOL ret = EnumChildWindows(windowHandle,GetButtonHandle,0);
if(buttonHandle != 0)
{
LRESULT res = SendMessage(buttonHandle,BM_CLICK,0,0);
//SendMessage(buttonHandle,WM_LBUTTONDOWN,0,0);
//SendMessage(buttonHandle,WM_LBUTTONUP,0,0);
}
}
}
Note:
Getting sure from the window text,button text (check if there is space at the end of the window title)
SendMessage(btnHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(btnHandle, WM_LBUTTONUP, 0, 0);
SendMessage(btnHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(btnHandle, WM_LBUTTONUP, 0, 0);
You have to send a button click twice. Not sure why (maybe the first click only activates the window of the button), but I'm using this code for a long time and it always worked for me.
maybe this can help:
http://www.cplusplus.com/forum/beginner/8806/
Access Denied errors on SendMessage or PostMessage make no sense unless the process sending the message is running at a lower integrity level than the target process.
This should not be happening unless the process that owns the target window is being run "asAdministrator" or is a service. And its damn hard for services to create windows on the interactive desktop with Windows 6 and up.
You can do some reading about Integrity Levels Here if they apply even remotely to this situation. Internet Explorer is about the only other application that 'opts in' to the integrity security model by purposely lowering the integrity level of itself in order to sandbox itself more effectively.
If you can raise the window containing the button you can send raw mouse event to a position within the boundaries of button.
There are two function to simulate mouse event SendInput and mouse_event. I recommend using mouse_event function. To raise a window you can use ShowWindow. I don't know how to get the handle of a button, but if you have its hWnd its easy to find its absolute position using GetWindowRect function. Try using these, if you run into any problems I will be glad to help.
Or define a custom WM within your application window to handle save request. WM_CUSTOM or WM_USER (cant remember which) marks the start of user defined window messages.
When I have to do these kind of things I use SendKeys. It is VB-ish and C# provides a nice interface to use but for C/C++ you'll have to do it <this way>. What is nice with it is that you could write scripts and run them instead of hard coding it in your code.
Microsoft is now pushing Active Accessibility (MSAA) for UI Automation,
(It has been renamed a number of times over the years)
see
UI Automation and Microsoft Active Accessibility
Using UI Automation for Automated Testing
UI Automation Clients for Managed Code
Sorry I don’t have any simple code to get you started. As “SendMessage()” does not seem to be working for you, I don’t know of another option apart from “UI Automation”
I am assuming you have check with Spy++ (installed with MsDev) that you message are being send to the correct button etc – and that the button is a standard windows buttons. My first instant would say use “SendMessage()" or "PostMessage()” but given the numbers of answers about “SendMessage()” and the fact it is not working for you. I expect someone is going on…
//Send digit 4 to the already opened calc.exe
HWND windowHandle;
windowHandle = FindWindowA(NULL,"Calculator");
if(windowHandle != 0)
ret = EnumChildWindows(windowHandle,GetButtonHandle,0);
BOOL CALLBACK GetButtonHandle(HWND handle, LPARAM)
{
char label[100];
int size = GetWindowTextA(handle,label,sizeof(label));
if(strcmp(label,"4") == 0)
{
PostMessage(handle ,WM_LBUTTONDOWN,(WPARAM)0x0001,0);
PostMessage(handle ,WM_LBUTTONUP,(WPARAM)0x0001,0);
PostMessage(handle ,WM_LBUTTONDOWN,(WPARAM)0x0001,0);
PostMessage(handle ,WM_LBUTTONUP,(WPARAM)0x0001,0);
return false;
}
return true;
}
You can use sendkeys (as tr3 said) to send mouse clicks, which is different than using SendMessage. It is also less direct and more hack-ish, but is useful for automation (in VBS).
Also, just a guess but the problem could be that your message handling is broken somewhere by not calling the base class member. Example:
void CMyClass::OnMessageY(CWnd *cwnd)
{
CBaseClass::OnMessageY(cwnd);
//... my code
}
if you sure ButtonHandle are valid handle you can use pair WM_LBUTTONDOWN and WM_LBUTTONUP message instead of BN_CLICKED
HWND ButtonHandle;
if( (wnd = FindWindow(0, "Do you want to save?")) )
{
SendMessage(ButtonHandle, WM_LBUTTONDOWN, MK_LBUTTON, 0);
SendMessage(ButtonHandle, WM_LBUTTONUP, MK_LBUTTON, 0);
}
A non-C approach: Use Java and the java.awt.Robot class to move the mouse around perform real clicks (I guess there is something in the Windows World for this, too).
Problem: You have to know where your button is :D

Resources