C++: A Lingering 'ghost' window appears..? - c++

My program - among other things - changes the console window appearance (mainly the window size and border).
Now on my computer, everything is working perfectly at the moment, but when I run the application in VirtualBox, or on a different computer, I get the following:
The window on the top-left corner of the image is not actually a window. It's an image of a window, that you can't click. (mouse clicks go through it)
You can get rid of it by stretching the selection rectangle on the desktop over it, or if you highlight (for example) a button that is under it. Also, you can move a window over it, which makes it disappear completely.
The black rectangle on the bottom-right corner of the image is my console window, which is displayed correctly.
My question is, how to get rid of the 'ghost' window with C++?
I tried Googling a bit, but all I could find was ChangeDisplaySettings(0, 0);, which on my computer doesn't do anything (probably because I don't even have this problem on my computer), and in VirtualBox, it first appears to momentarily make the console window fullscreen and then back to the way it was. (the screen flickers the first time you run the application)
Although it does remove the ghost window, I don't want the screen to flicker like that, so this is not what I'm looking for.
EDIT:
As I can't really figure out what would be relevant code for this problem, I'll just dump pretty much all the code that has anything to do with changing the window itself in my program.
CSBIEx.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
GetConsoleScreenBufferInfoEx(hCon, &CSBIEx);
CSBIEx.dwSize.X = 49;
CSBIEx.dwSize.Y = 21;
SetConsoleScreenBufferInfoEx(hCon, &CSBIEx);
srWnd.Bottom = 20;
srWnd.Left = 0;
srWnd.Right = 48;
srWnd.Top = 0;
SetConsoleWindowInfo(hCon, TRUE, &srWnd);
GetClientRect(hWnd, &rClnt);
rClnt.top += 1;
rClnt.bottom -= 2;
rClnt.right -= 1;
SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP);
exStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
exStyle &= ~WS_EX_CLIENTEDGE;
SetWindowLongPtr(hWnd, GWL_EXSTYLE, exStyle);
BringWindowToTop(hWnd);
SetWindowPos(hWnd, HWND_TOPMOST, ((rScr.right / 2) - rClnt.right / 2) - 1, (rScr.bottom / 2) - rClnt.bottom / 2, 0, 0, SWP_FRAMECHANGED | SWP_DRAWFRAME | SWP_NOSIZE);
SetWindowRgn(hWnd, CreateRectRgnIndirect(&rClnt), 1);
ShowWindow(hWnd, SW_SHOWNORMAL);
//ChangeDisplaySettings(0, 0);
2ND EDIT:
I don't know if it's of any help, but I noticed that if I use ChangeDisplaySettings(NULL, 0); instead of ChangeDisplaySettings(0, 0); it doesn't do anything. That's pretty weird considering that NULL is #defined 0..
If no one can figure anything out, I'll probably just end up using ChangeDisplaySettings(0, 0);.

InvalidateRect(NULL, NULL, TRUE);
Was the thing that I was looking for.

Are you running an "Aero" theme on your computer? If so, switch to the classic theme. Betcha you will see the problem manifest itself. I think your app is not handling the WM_PAINT message properly. The Aero themes send far fewer WM_PAINT messages. The OS does the painting with bitmaps that it saves.
EDIT: Try calling these with the new dimensions:
BOOL WINAPI SetConsoleDisplayMode(
_In_ HANDLE hConsoleOutput,
_In_ DWORD dwFlags,
_Out_opt_ PCOORD lpNewScreenBufferDimensions
);
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033%28v=vs.85%29.aspx
BOOL WINAPI SetConsoleWindowInfo(
_In_ HANDLE hConsoleOutput,
_In_ BOOL bAbsolute,
_In_ const SMALL_RECT *lpConsoleWindow
);
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686125%28v=vs.85%29.aspx
You can also try sending yourself a WM_PAINT message with DispatchMessage.

Related

How do I get the handle of a chrome window

Sorry is this is a basic question but I can't wrap my head around this. I am trying to maximize a new chrome window, but I cant seem to find the handle to it. Here is the code I wrote so far to try to debug it but...
LPCWSTR window = L"chrome.exe";
HWND hWND = FindWindow(NULL, window);
SetWindowPos(
hWND,
HWND_TOPMOST,
10,
10,
10,
10,
SWP_SHOWWINDOW
);
The values were set to 10 just to see if it would move.
a) how do i get the handle of a specific window (in this case a new window of chrome)
b) is there a faster way to maximize a window than SetWindowPos()

Draw on Windows 10 wallpaper in C++

Is there a way to get an handle to Windows's wallpaper (behind icons) in C++ in order to draw on it?
That would allow to make an active desktop (discontinued after Windows XP) equivalent, a Wallpaper Engine equivalent, or any other similar tool. (Temperature and resources usage monitoring on the wallpaper in my case).
Note: the handle returned by GetDesktopWindow() returns the window at desktop icons level, not behind it.
Solutions from similar questions aren't working for me.
Specifically i tried VLC media player's wallpaper mode code.
Key code is:
hwnd = FindWindow( _T("Progman"), NULL );
if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, _T("SHELLDLL_DefView"), NULL );
if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, _T("SysListView32"), NULL );
if( !hwnd )
{
msg_Warn( p_vout, "couldn't find \"SysListView32\" window, "
"wallpaper mode not supported" );
return;
}
But it will not draw on the wallpaper.
Credits to this draw behind desktop icons C# page as reference. The article explains the theory behind the solution, which applies regardless of the programming language being used.
Long story short, the smooth fading animation you see on Windows 10 when changing wallpaper is achieved by creating a new window that does exactly what you're asking for, drawing under the icons. That window achieves the fade-in effect for the new wallpaper, and is created by the Program Manager.
In the mentioned article you can see together with C# implementation an explanation of every step. Here i'll write a C++ equivalent keeping comments from the source.
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
HWND p = FindWindowEx(hwnd, NULL, L"SHELLDLL_DefView", NULL);
HWND* ret = (HWND*)lParam;
if (p)
{
// Gets the WorkerW Window after the current one.
*ret = FindWindowEx(NULL, hwnd, L"WorkerW", NULL);
}
return true;
}
HWND get_wallpaper_window()
{
// Fetch the Progman window
HWND progman = FindWindow(L"ProgMan", NULL);
// Send 0x052C to Progman. This message directs Progman to spawn a
// WorkerW behind the desktop icons. If it is already there, nothing
// happens.
SendMessageTimeout(progman, 0x052C, 0, 0, SMTO_NORMAL, 1000, nullptr);
// We enumerate all Windows, until we find one, that has the SHELLDLL_DefView
// as a child.
// If we found that window, we take its next sibling and assign it to workerw.
HWND wallpaper_hwnd = nullptr;
EnumWindows(EnumWindowsProc, (LPARAM)&wallpaper_hwnd);
// Return the handle you're looking for.
return wallpaper_hwnd;
}
The C-like casts can be replaced with reinterpret_casts, according to your coding preferences.
One note that isn't mentioned in the article:
Since when changing wallpaper a new WorkerW window is generated to achieve the fading effect, if the user tries to change wallpaper while your program is actively drawing and refreshing your instance of WorkerW, the user set background will be placed on top of your drawing, start fading in until it reaches 100% opacity, and lastly be destroyed, leaving your WorkerW still running.

Click-through Transparent window, no dragging allowed [C++]

There are several ways to do this using .NET (take this for instance), yet I wasn't able to reproduce the same thing using only C++ win32.
My approach was to use WS_EX_LAYERED and then SetLayeredWindowAttributes to have some control over the opacity, but I read more and I found out that WS_EX_TRANSPARENT is 'better'- it allows click-through.
However, using
hWnd = CreateWindowEx(WS_EX_TRANSPARENT, fooName, fooName, WS_OVERLAPPEDWINDOW | WS_POPUP | WS_CLIPSIBLINGS, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
doesn't seem to do the trick. There is also another thing: once I get the click-through window working, can I use
PostMessage(hWnd, WM_LBUTTONUP, 0, MAKELPARAM(GET_X_LPARAM(lParam) ,GET_Y_LPARAM(lParam)));
to block the dragging state from passing through?
Note: the dragging state is produced using a touchpad device.
The click-through part:
Indeed, WS_EX_TRANSPARENT by itself is a big lie; so I used WS_EX_COMPOSITED | WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOPMOST instead.
I have control over the opacity using SetLayeredWindowAttributes(hWnd, 0, (255 * opacity) / 100, LWA_ALPHA); (quite unorthodox, but it works) and I also use
SetCapture(hWnd);
ShowCursor(false);
to grab the mouse focus as the top level window doesn't let go and hides the cursor.
I also tried to force the focus on the window adding WM_NCACTIVATE and WM_ACTIVEAPP:
case WM_MOUSEMOVE:
fprintf(stdout, "Mouse move [%d][%d]\n", GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
SetForegroundWindow(hWnd);
break;
case WM_LBUTTONDOWN:
printf("Mouse click\n");
SetForegroundWindow(hWnd);
break;
case WM_NCACTIVATE:
return false;
case WM_ACTIVATEAPP:
wActive = (bool)wParam;
if(wActive == false)
return 0;
else
return DefWindowProc(hWnd, message, wParam, lParam);
The dragging part:
In my particular case I wanted to 'poke' the window underneath (child window) without losing focus; unfortunately, any mouse click event will change the focus to that child window - a solution would be to:
set a timer (SetTimer, WM_TIMER) and check whether your application lost focus or not
set a hook to your window and reply to a WM_KILLFOCUS message with a WM_SETFOCUS message
I have been lately working on creating windows with transparency and click-through properties and I just tried this:
HWND hWnd = CreateWindowEx(WS_EX_LAYERED|WS_EX_TRANSPARENT, cName, wTitle, NULL, 0, 0, 640, 480, NULL, 0, GetModuleHandle(NULL), 0);
You can't close it, minimize it, drag it, etc - every click you make goes straight through as if it didn't exist.
Then just change transparency using:
SetLayeredWindowAttributes(hWnd, 0, 100, LWA_ALPHA);
It achieves everything that in your question, if I understood it correctly.
Your approach might have not worked because WS_EX_LAYERED must be defined if you use WS_EX_TRANSPARENT.

C++: Setting the console window as a WS_POPUP

I'm trying to create a borderless console window.
I was able to set the windowstyle to WS_POPUP, which removed the borders, but there were some glitches;
It seems that there are some parts on the console window that didn't get redrawn, or something like that, but I've tried using InvalidateRect() on the whole window, and other redrawing functions, but they don't seem to work.
Someone suggested using SetWindowPos() (with SWP_FRAMECHANGED), but that doesn't do anything either.
I have been fiddling with this probelm for a while now, and am pretty sure it has something to do with the clientarea not drawing properly (don't quote me on this)
Also the bottom glitchy part will turn black/transparent when I first scroll down and then up, but the text in my program sometimes isn't shown under it, which to my knowledge would suggest that it has no background, so it has sort of a 'chameleon' effect.
Any ideas?
I finally figured it out. (Big thanks to Maximus)
I had to use SetWindowRgn(), just like he suggested.
The final code would look something like this:
HWND hWnd = GetConsoleWindow();
RECT rcScr, rcWnd, rcClient;
GetWindowRect(hWnd, &rcWnd);
GetWindowRect(GetDesktopWindow(), &rcScr);
GetClientRect(hWnd, &rcClient);
MoveWindow(hWnd, (rcScr.right / 2) - 330, (rcScr.bottom / 2) - 180, rcWnd.right - rcWnd.left, rcWnd.bottom - rcWnd.top, 1);
SetWindowLong(hWnd, GWL_STYLE, WS_POPUP);
SetWindowRgn(hWnd, CreateRectRgn(rcClient.left + 2, rcClient.top + 2, rcClient.right + 2, rcClient.bottom + 2), TRUE);
ShowWindow(hWnd, 1);

Custom back ground for owner drawn menu

Im using mfc to draw a custom menu except it has a nasty looking border around it. How do i get rid of the border or draw over it?
For example:
(the white border around the edge)
Edit:
i know its only three hours left but none of the things below work. I have tried them using the following code:
HWND hwnd = m_pParent->getBrowserHWND();
uint32 style = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, style&~WS_BORDER);
SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED);
HookHwnd hook(hwnd);
int res = TrackPopupMenu((HMENU)menu.GetHMenu(), TPM_LEFTALIGN|TPM_RIGHTBUTTON|TPM_RETURNCMD|TPM_RECURSE, xPos, yPos, 0, hwnd, NULL);
SetWindowLong(hwnd, GWL_STYLE, style);
Actually further to freefallr's advice it may well just be a simple WS_BORDER.
Try removing it using:
ModifyStyle( WS_BORDER, 0, SWP_FRAMECHANGED );
I only use WTL for UI coding, it's been years since I've looked at MFC, but it's also very close to the Windows API. You might check the creation flags for the menu.
Call GetWindowLong and specifically, check GWL_EXSTYLE for WS_EX_CLIENTEDGE; this may be the cause of your problem. You can always OR it out and call SetWindowLong and redraw the menu to test.
Hope this is of some help!
Update:
I wonder if the frame isn't being updated. Try:
ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);