I'm trying to get a semi transparent window with the Win32 API and C++. Despite the fact, that there
are around a million results trying to answer that question, none of those seem to have worked for my case.
I have a native Win32 window with a hosted WPF content inside it. Because I'm trying to create a custom
window frame (and that also works by now), I want the top part of the self drawn frame to be semi
transparent, possibly also applying the acrylic blur.
Looking at WPF, I could archive my goal using AllowTransparency = True on the window and with a
transparent background. Now I need a way to replicate that behavior with the Win32 API.
Technically, I can make the entire main window transparent (because the main window is the frame entirely
and the WPF hosted content is the client area), but even that didn't work (no transparency).
For reference, here is how I'm creating my window:
WNDCLASSEXW window_class_ex = {
sizeof(WNDCLASSEXW),
CS_HREDRAW | CS_VREDRAW,
window_callback,
0,
0,
application_instance,
nullptr,
LoadCursorW(nullptr, IDC_ARROW),
CreateSolidBrush(RGB(0, 0, 0)),
nullptr,
window_class,
nullptr
};
const HWND window_handle = CreateWindowExW(
0,
window_class,
L"WinSoup",
WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_EX_LAYERED,
CW_USEDEFAULT, CW_USEDEFAULT, 100, 100,
nullptr,
nullptr,
application_instance,
reinterpret_cast<LPVOID>(owner)
);
I have seen that I should use WS_EX_LAYERED, but also that didn't have the desired effect.
Of course the WPF content itself should not be transparent!
Ok, so, despite all the answers telling me to read the documentation and look at other
examples... turns out, I misplaced the WS_EX_LAYERED.
const HWND window_handle = CreateWindowExW(
WS_EX_LAYERED, // Needs to be placed here (extended style)
window_class,
L"WinSoup",
WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX, // Not here!
CW_USEDEFAULT, CW_USEDEFAULT, 100, 100,
nullptr,
nullptr,
application_instance,
reinterpret_cast<LPVOID>(owner)
);
Your question says
The WPF content itself should not be transparent!
You can use Set/UpdateLayeredWindowAttributes, but the opacity for your WPF content will change too.
If you really want to create a high-performance transparent/semi-transparent window, you need to specify the WS_EX_NOREDIRECTIONBITMAP flag instead of WS_EX_LAYERED. Then use DirectComposition with another graphics API to render your content.
Look at https://msdn.microsoft.com/magazine/dn745861.aspx for more details.
Related
I'm having trouble getting my Rich Edit control to accept the zoom ratio I specify when sending it the EM_SETZOOM message. I create the control using the following line of code:
editWrap = CreateWindowEx(0, MSFTEDIT_CLASS, nullptr, ES_EX_ZOOMABLE | ES_MULTILINE |
WS_VISIBLE | WS_CHILD | WS_VSCROLL | ES_AUTOVSCROLL | ES_DISABLENOSCROLL, 0, 0, 0, 0,
hwnd, nullptr, appInstance, nullptr);
Whenever I try to send it the EM_SETZOOM message the return value is always FALSE no matter what I specify as the WPARAM and LPARAM. I also tried putting ES_EX_ZOOMABLE as the first parameter of the CreateWindowEx call with the same results.
Zooming with the mouse works as expected. That's not the issue here. I'm trying to set the zoom programmatically.
I'm using the following code to send the message:
SendMessage(getCurrentEditor(), EM_SETZOOM, MAKEWPARAM(64, 0), MAKELPARAM(1, 0));
You are passing in the ES_EX_ZOOMABLE in the wrong parameter of CreateWindowEx(). You are passing it in the dwStyle parameter, but it is an extended window style so it needs to be passed in the dwExStyle parameter instead, eg:
editWrap = CreateWindowEx(ES_EX_ZOOMABLE, MSFTEDIT_CLASS, nullptr, ES_MULTILINE |
WS_VISIBLE | WS_CHILD | WS_VSCROLL | ES_AUTOVSCROLL | ES_DISABLENOSCROLL, 0, 0, 0, 0,
hwnd, nullptr, appInstance, nullptr);
Note that the EM_SETZOOM message is only supported on Windows Vista and later, in RichEdit 3.0 and later (you are using 4.1). You didn't indicate which Windows version you are using, or what your ratio values are set to. So it is hard to diagnose why exactly EM_SETZOOM returns FALSE. All that means is that the ratio wasn't accepted, but not WHY it wasn't accepted. Are you able to zoom the RichEdit with the mouse using Ctrl+MouseWheel? That will tell you whether ES_EX_ZOOMABLE is taking effect or not.
On a separate note: you are creating your RichEdit with a width and height of 0! Are you sure that is what you really want?
It turns out that the control won't accept a zoom factor of 64/1. I found that out by reading the Windows Forms documentation on the RichTextBox control. The Win32 API documentation just said the zoom factor had to be a number between 1/64 and 64. The Windows Forms documentation says it has to be "between 1/64 and 64.0, not inclusive". When I changed my test code to send 63/1 to the control, it worked as expected.
I want to make a custom border or simply remove the border for another window (another application). However the way I've done it currently (with GetWindowLong, SetWindowLong & SetWindowPos functions) removing the border causes graphical issues for one program (cmd.exe) and does nothing at all for another (heroes of might and magic II).
I'm not very familiar with C++ yet and don't know how to go about doing this. I want simple and clean-cut borders so I for example could place a cmd.exe on the taskbar or play HoMM2 in borderless full screen.
Anyone knows how this can be achieved?
Here's my current function:
void noBorder(HWND win)
{
LONG style = GetWindowLong(win, GWL_STYLE);
style &= ~(WS_CAPTION | WS_SYSMENU | WS_THICKFRAME |
WS_MINIMIZE | WS_MAXIMIZEBOX | WS_BORDER);
SetWindowLong(win, GWL_STYLE, style);
style = GetWindowLong(win, GWL_EXSTYLE);
SetWindowLong(win, GWL_EXSTYLE, style | WS_EX_DLGMODALFRAME);
SetWindowPos(win, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE |
SWP_NOSIZE | SWP_FRAMECHANGED);
}
I'm currently using the SkeletonBasics-D2D library. I would like to give a presentation with the skeleton but need make the window fullscreen. Here are the notes I currently worked through and my next step is potentially modifying the .rc file to work with the full screen windowed app; however, I'd like to ask first is anyone knows another way.
Potentially it could just be manipulating this code in my SkeletonBasics.rc file :
IDD_APP DIALOGEX 0, 0, 512, 424
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_CONTROLPARENT | WS_EX_APPWINDOW
CAPTION "Skeleton Basics"
CLASS "SkeletonBasicsAppDlgWndClass"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "",IDC_VIDEOVIEW,"Static",SS_BLACKFRAME,0,0,512,384
LTEXT "Click 'Seated' to change skeletal pipeline type!",IDC_STATUS,0,413,511,11,SS_SUNKEN,WS_EX_CLIENTEDGE
CONTROL "Seated",IDC_CHECK_SEATED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,238,391,55,8
END
Notes from code :
creating a window causes different signals to be generated than a dialog
where a dialog expects WM_INITDIALOG on create, a window should expect WM_NCCREATE
the dialog's DLGPROC was being set with CreateDialogParamW(). The window's WNDPROC is set within a WNDCLASS structure and then registered before CreateWindow()
the window's class name is important, as it's referred to in the SkeletonBasics.rc file wc.lpszClassName = L"SkeletonBasicsAppDlgWndClass";
need to determine all messages sent to the window and handle them appropriately
This tutorial is a great example of full screen and have used it to convert my application into full screen.
To get there, I needed to change the dialog proc to a window.
http://www.directxtutorial.com/Lesson.aspx?lessonid=11-4-4
I created an edit control by the following code:
hWnd = CreateWindowExW( 0, // extended styles
L"EDIT",
L"Text in edit.",
ES_LEFT | WS_VISIBLE | WS_CHILD,
10, // x
50, // y
30, // width
100, // height
hWndMainWindow,
NULL,
hInstance,
NULL);
My edit control looks like this:
But most edit controls I see in Windows have a 3D look like in the image below:
I tried several extended and normal window styles, but the didn't do any good. How do I make my edit control look like in the second image?
Some quick links that may help you to take reference:
Window Styles
Extended Window Styles
Edit Styles
You need to include the WS_EX_CLIENTEDGE extended window style.
You say that you have already tried including WS_EX_CLIENTEDGE without success. I'm going to take a wild guess that you have been trying to include it in the window style rather than the extended window style. Your code should look like this:
hWnd = CreateWindowExW(
WS_EX_CLIENTEDGE, // extended styles
L"EDIT",
...
);
I create the static control with the code below:
hWnd = CreateWindowExW( 0,
L"STATIC",
Content.c_str(),
SS_LEFT | WS_VISIBLE | WS_CHILD /*| SS_SUNKEN*/,
200,
120,
120,
40,
hWndParent,
NULL,
hInstance,
NULL);
If I enable the SS_SUNKEN style in the creation code above, the created static control appears sunken successfully.
But, what I'm trying to do is the change the control style after its creation.
I tried this:
void BaseWindowClass::AddStyle(DWORD NewStyle)
{
// NewStyle = 0x00001000 = SS_SUNKEN
LONG oldstyle, changedstyle;
oldstyle=SetWindowLongW(hWnd, GWL_STYLE, changedstyle=GetWindowLongW(hWnd, GWL_STYLE) | NewStyle);
UpdateWindowStyles();
// oldstyle = 0x50000000
// changedstyle = 0x50001000 (everything looks normal)
}
void BaseWindowClass::UpdateWindowStyles()
{
BOOL success;
success=SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
// success = 0x00000001 (non-zero: SetWindowPos sucseeded)
}
Documentation:
SetWindowLong()
SetWindowPos()
I call SetWindowPos() after calling SetWindowLongW() because in the documentation of SetWindowLong, it says:
Certain window data is cached, so changes you make using SetWindowLong will not take effect until you call the SetWindowPos function. Specifically, if you change any of the frame styles, you must call SetWindowPos with the SWP_FRAMECHANGED flag for the cache to be updated properly.
And, in the documentation of SetWindowPos, it says:
If you have changed certain window data using SetWindowLong, you must call SetWindowPos for the changes to take effect. Use the following combination for uFlags: SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED.
Even after changing SetWindowLongW() and SetWindowPos() the style of my static control does not change.
What am I doing wrong, or what am I missing?
SS_SUNKEN effectively sets WS_EX_STATICEDGE in the extended styles (GWL_EXSTYLE) window long, so you can update GWL_EXSTYLE appropriately and reposition as you're currently doing.
Even though SS_SUNKEN does affect the frame of a static control, it isn't one of the "frame styles" that note is referring to.
That note refers to generic frame styles that affect all windows like WS_BORDER or WS_EX_CLIENTEDGE - styles that require a recalculation of a window's non-client area when changed.
Many of the system controls cache their styles upon creation and don't update the cache even if you change the styles via SetWindowLong. I would guess that's what's happening here - if you don't create the static control with SS_SUNKEN, you can't add it later. Your best option would be to simply destroy and recreate the control with the new style.