Windows 7 edit control, vertical scroll does not work - winapi

I have an application that compiles ok (mingw) and runs ok, however the edit control that is created has scroll bars but the vertical scroll bar doesn't do anything. The same executable works fine on WinXP. Also, the edit control has both vertical and horizontal scroll bars, the horizontal works just fine, but vertical does not. The vertical scroll bar is visible and clickable, but nothing happens...
Following code is used when creating the edit control:
HWND hwndEdit = CreateWindow(TEXT("EDIT"), TEXT("Edit control"),
WS_OVERLAPPED | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | ES_LEFT | ES_MULTILINE |
ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_READONLY | WS_SIZEBOX,
1000, 480, 400, 500, NULL, 0, GetModuleHandle(NULL), NULL);
SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM) TEXT(""));
SendMessage(hwndEdit, EM_LIMITTEXT, 0, 0);
Following code is used repeatedly to add text to edit control:
char test[] = "test";
SendMessage(hWndDbg, EM_SETSEL, 0x7FFFFFFF, 0x7FFFFFFF); // Undo any selection and move to end.
SendMessage(hWndDbg, EM_REPLACESEL, 0, (LPARAM) temp);

Finally found the fix. It seems in WinXP the edit control does not have to have a parent window defined, in Win7 it is required for the vertical scroll bar to work, horizontal scroll bar works in Win7 even without parent window defined.

Note that vertical scroll bars even make sense on single-line edit controls. In this case, WM_VSCROLL must be set, and ES_AUTOVSCROLL not. (EM_AUTOVSCROLL means EM_AutoHIDEVScroll.) The alternative UpDown control makes more programming efford than capturing VM_VSROLL messages, and then changing the (typically numerical) value inside the edit control.
Unluckily, the MS Visual Studio built-in Resource Editor won't let you add WM_VSROLL to single-line edits! You must do this by adding this bit by editing the .RC file in text mode.
Similar to the fact that this Resource Editor won't let you add a default text to the control, which is still supported by the resource loader.

Use GetDesktopWindow() as hWndParent parameter. It works on Win7.

Related

How to clear an HWND so that it will show everything underneath?

I'm trying to make an application which will grey out all the windows except for ones that have focus. I've seen one out there but it expects that the one with focus is above all the rest, which is not the case (using focus follows mouse mode).
So, I'm thinking that this would be straight forward, and I can brush up on some of my old WinAPI skills. I create a standard Windows Desktop Application in VS2017, and modify the InitInstance() function
Creating the window:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd = CreateWindowEx(
WS_EX_COMPOSITED | WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOPMOST
| WS_EX_TOOLWINDOW
, szWindowClass, szTitle
, NULL // no style
, 0, 0, 640, 480 // initial window rect
, NULL // parent window (desktop)
, NULL // no menu
, GetModuleHandle(NULL), 0);
Remove title bar, grips and such:
SetWindowLong(hWnd, GWL_STYLE, 0);
I want it to be opaque, but with alpha blended transparency:
SetLayeredWindowAttributes(hWnd, 0, 255, LWA_ALPHA);
So, now I get a white window popup. It has no titlebar or menu and sits above all my other windows and is ignored when I click on it, allowing access to the windows underneath. If I set the opacity to something lower than 255, I can see through the window.
However, I can't seem to keep it from being white. I just want to have it blank so that when I draw on it, it will show what I draw, with the appropriate alpha blended attributes.
Looking around, I found How to "Clear" a WinAPI Transparent Window, but that is for controls on a window, not the window itself. So I don't think it really applies. Also, I don't really want to do the work of iterating over all the windows and bliting the contents onto a memory DC and then bliting that onto my window DC. That seems silly. There must be some way of clearing the DC, but how?
Edit
Other things I've tried is:
In the MyRegisterClass() function, I've set WNDCLASSEXW::hbrBackground to (HBRUSH)NULL_BRUSH.
In the WM_PAINT message handler, I've set the PAINTSTRUCT::fErase to TRUE before calling EndPaint().
Neither of these helped.

Change style of maximized window

I want a window which behaves identically to normal Overlapped window, except it does not have capton bar when maximized (to make more room for the client area).
I can remove WS_CAPTION|WS_SYSMENU from the window style.
However, I cannot find way to get window position and size right:
A normal window is maximized by expanding work area rectangle with border width. This makes border to "hang" outside. When I remove WS_CAPTION, the border is different (3 vs 4 pixels in my case) so I have to reposition the window somehow.
What I have tried:
First change style, then maximize: this does not maximize to work area, but to full screen instead. Looks like this is a feature of window manager that relies on WS_CAPTION style. Other than that, the border is "hanging" correctly.
First maximize, then change style, position and size:
I can't find API to get the maximized size and position. However, work area of closest monitor looks good to me.
I can't find API to expand window rect with appropriate "hanging border". AdjustWindowRectEx is almost there, however non-client area is not the same as border (obviously it also includes caption and menu). I also tried to do the math myself using GetSystemMetrics values, but it seems too unpredictable. The border could be SM_CXSIZEFRAME, or SM_CXSIZEFRAME+SM_CXPADDEDBORDER, or SM_CXFIXEDFRAME, and maybe this depends on OS version, theme and whatever.
Is it possible to do this in a robust, "official" way?
I put my own answer below but it is too hacked.
You are already removing the caption. If you don't want to show the borders, then remove the borders as well. Get ready to restore the border later. Find the desktop rectangle, and position the window in to that rectangle. The full screen window can have WS_OVERLAPPED or WS_POPUP flag with no caption and no borders. Example:
void switch_view()
{
RECT rc;
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
if(style & WS_CAPTION)
{
SetWindowLongPtr(hwnd, GWL_STYLE, WS_OVERLAPPED);
SetWindowLongPtr(hwnd, GWL_EXSTYLE, 0);
SetWindowPos(hwnd, NULL, 0, 0, rc.right, rc.bottom,
SWP_SHOWWINDOW | SWP_FRAMECHANGED);
}
else
{
SetWindowLongPtr(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
}
}
This is what I get after many attempts.
The border problem is solved. As suggested by others, I remove border together with caption. Therefore no need to calculate it. There is also no need to calculate border for captioned window with border, because this is special-cased by window manager.
To obtain and maintain the right size, I use MonitorFromWindow and GetMonitorInfo. The position and size are applied together with style change (both ways) and also in WM_SIZE handler. Watching WM_SIZE allows to recover from external minimize-restore events, as well as TaskBar change etc.
For unknown reason, moving with Win+Arrow keys does not work. This issue only exists when the window is in maximized state and without caption. Using this workaround:
in WM_WINDOWPOSCHANGING set WS_CAPTION style. This allows window to move correctly. Afterwards, the WM_SIZE handler applies the right style/position/size again.
Approach that failed: use restored window rather than maximized. In this case there is too much going wrong in restore-move-maximize-restore lifecycle (either restore or maximize goes to wrong monitor).

Fullscreen vs Borderless window

My goal is to create an OpenGL application. I've seen many games that let the user decide if the "game window" will be "fullscreen" or "borderless". What's the difference? How do I implement each method?
I heard that fullscreen windows are just windows with WS_POPUP style that are set to be the width and height of the screen. Is this true for only one of the approaches I mentioned above?
What's the difference between "Borderless" and "Fullscreen" here? (screenshot taken from LoL)
You just need WS_POPUP and full screen width & height to hide the task bar. Here is example of changing window style after window is already shown:
if (msg == WM_LBUTTONDOWN)
{
if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_POPUP)
{
SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_OVERLAPPEDWINDOW);
SetWindowPos(hwnd, NULL, 0, 0, 600, 400, SWP_FRAMECHANGED);
}
else
{//show full-screen
int w = GetSystemMetrics(SM_CXSCREEN);
int h = GetSystemMetrics(SM_CYSCREEN);
SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
SetWindowPos(hwnd, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED);
}
}
Or to show with initial full-screen size:
int w = GetSystemMetrics(SM_CXSCREEN);
int h = GetSystemMetrics(SM_CYSCREEN);
HWND hmain = CreateWindow(L"className", L"title", WS_POPUP, 0, 0, w, h, 0, 0, hInst, 0);
ShowWindow(hmain, SW_SHOW);
Windows are either WS_OVERLAPPED, WS_POPUP, or WS_CHILD. These three flags can't be combined with each other, but they can be combined with other WS_XXXX flags.
Top windows are either WS_OVERLAPPED or WS_POPUP Different styles for main window include:
Normal window: WS_OVERLAPPED, shown with ShowWindow(hwnd, SW_SHOW)
Maximized window: WS_OVERLAPPED, shown with ShowWindow(hwnd, SW_MAXMIZE) covers the whole screen, not including the taskbar
Fullscreen: WS_POPUP flag, with width & height set to SM_CXSCREEN/SM_CYSCREEN, covers the whole screen, it goes over the task bar
All these windows can have WS_BORDER or not. Or they may have WS_THICKFRAME for resizing border. In fullscreen mode, the window usually has no border. In maximized mode, the borders fall outside the view area.
More details: Window Styles
'Fullscreen' mode is a special mode where the game takes over the entire display and doesn't attempt to cooperate with other windows in any way. It's how all games used to work, is more flexible (your game resolution doesn't have to match your desktop resolution) and in theory faster. In practice it can cause a lot of problems when you alt-tab and suchlike. You can in some situations end up with the game window still showing when you should be using another application.
'Borderless' makes a normal window but with no title bar or border that takes up the whole screen. Visually this should be the same as Fullscreen, but avoids the interoperating problems. You can have other things on top of it (eg. taskmanager), you can alt-tab quite happily. The downside is that it may be slower because Windows gets involved in the drawing process, and you're stuck with the user's desktop resolution.
'Windowed' is a normal Windows window which always has a title bar, and may have resizing handles, minimise button and so on. This might also take up the whole screen when maximised, but the actual usable area is smaller because you lose some space to the title bar/close buttons/border.
Screen modes are generally Windows level things, rather than openGL.
To get Windowed mode you use CreateWindowEx() and pass the WS_OVERLAPPED style.
To get Borderless you use the same function with WS_POPUP style. In theory, anyway. I've seen video drivers give you Fullscreen anyway.
To get Fullscreen you generally apply ChangeDisplaySettings(blah,CDS_FULLSCREEN) to switch to your desired video mode.

Remove border from win32 button

I have a button which is created in the WM_CREATE function of a Win32 Application with the following code:
hChangeWorldButton = CreateWindowEx(NULL,
"BUTTON",
"OK",
WS_CHILD | WS_VISIBLE | BS_FLAT | BS_BITMAP,
2,
2,
25,
25,
hWnd,
(HMENU)CHANGEWORLD_BUTTON,
GetModuleHandle(NULL),
NULL);
SendMessage(hChangeWorldButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)worldBmp);
I would like the button to show only the image. Not the background and border.
How can I do this? I have tried many different button styles from MSDN but nothing seems to fit my needs. I was thinking of using BS_OWNERDRAW but it seems a bit overkill. Or is it the only solution?
Finally, how can I change the cursor to be a hand when it's hovering over the button?
No button style is available that results in the visual representation you are after. You would have to go with BS_OWNERDRAW here.
As an alternative you could use a Static Control with the SS_NOTIFY style instead. A static control allows you to get the visual representation you want, and the SS_NOTIFY styles allows you to respond to mouse input. However, you will not be able to implement a keyboard interface.
While I have not tried this myself, it may also be possible to get the desired effect by using a Command Link (BS_COMMANDLINK), and setting the caption to an empty string.
To eliminate the button's background and border simply make the button smaller than the bitmap.

change color in progress bar win 32

I am trying to change the color of background and bar in a win 32 progress bar in the following way :
HWND hwndPB =CreateWindowEx(0, PROGRESS_CLASS, NULL,
WS_CHILD | WS_VISIBLE |PBS_SMOOTHREVERSE | PBS_MARQUEE ,
20, 50, 275, 20,
hwndDlg, NULL,NULL , NULL);
SetWindowLongPtr(hwndDlg,GWLP_USERDATA,reinterpret_cast<LONG_PTR>(hwndPB));
SendMessage(hwndPB,(UINT)PBM_SETBKCOLOR,0,RGB(200,200,200));
SendMessage(hwndPB,(UINT) PBM_SETBARCOLOR,0,(LPARAM)RGB(100,100,100));
SendMessage(hwndPB,(UINT) PBM_SETMARQUEE,(WPARAM) TRUE,(LPARAM)50 );
I guess this is not working because of the visual themes being enabled. Can anybody suggest me a way to get it done or disable the visual styles. I am using VS 2008. Also, its a non mfc application.
You can disable themes for an individual control by calling SetWindowTheme. For your progress bar, disable the theming like this:
SetWindowTheme(hwndPB, "", "");
Once you have disabled the theming, you'll be able to control the colors.

Resources