Remove the standard window frame in C++ Win32 - c++

I saw this documentation on MSDN.
I am trying to remove the standard frame of the window. I successfully extended the frame into client area, but the following snippet does not work. My window looks exactly the same as without it....
if (message == WM_CREATE)
{
RECT rcClient;
GetWindowRect(hWnd, &rcClient);
// Inform the application of the frame change.
SetWindowPos(hWnd,
NULL,
rcClient.left, rcClient.top,
(rcClient.right - rcClient.left), (rcClient.bottom - rcClient.top),
SWP_FRAMECHANGED);
}
Could anybody help me please?

I think you can do it by passing WS_OVERLAPPED (not WS_OVERLAPPEDWINDOW) as the dwStyle parameter to CreateWindowEx when creating the window.

It's really simple, just go to your window procedure, then the message WM_NCCALCSIZE and return 0 when WPARAM is TRUE
// Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_NCCALCSIZE:
if (wparam == TRUE) return 0;
break;
}
...
}
As a clarification the code that you showed serves to force the previous code

Related

How to detect mouse cursor is outside a windows?

I've written a code that dynamically creates a POPUP style window when the user clicks inside my main app window. Now I'd like the POPUP window to be automatically destroyed when the mouse cursor goes out of the POPUP wnd region. I know that i have probably handle the WM_MOUSEMOVE message but how to do that? Please provide a simple code for that if You can...
Use the WM_MOUSELEAVE message instead. However, note that this message has to be explicitly requested via TrackMouseEvent(), which your window can call when it receives its first WM_MOUSEMOVE message.
As #Remy Lebeau said, the following is the code implementation.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL Tracing = FALSE;
switch (message)
{
case WM_MOUSELEAVE:
{
DestroyWindow(hWnd);
break;
}
case WM_MOUSEMOVE:
{
if (!Tracing)
{
Tracing = TRUE;
TRACKMOUSEEVENT tme{};
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hWnd;
TrackMouseEvent(&tme);
}
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
you can compare the event.target and event.currentTarget, if both are same then you are out side of popup window else in side the popup window.

CListCtrl select multiple lines with the mouse

There is a CListCtrl with SetExtendedStyle (LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT), a single selection is false. I want to be able to select multiple lines with the mouse.
When starting selection from an empty area, it works:
It does not work if I start the selection not from an empty area. Selection frame does not appear:
How to make it work?
It is not really a good idea to change how a common control works because users expect them to function like they do in all other applications.
The ListView (CListCtrl) does not support this feature but if you don't care about making non-dragging selections you can subclass the control and sort-of make it work:
WNDPROC g_OrgWndProc = 0;
static LRESULT CALLBACK LVSubClass(HWND hWnd, UINT Msg, WPARAM wp, LPARAM lp)
{
if (Msg == WM_LBUTTONDOWN)
{
UINT oldexstyle = (UINT) ListView_SetExtendedListViewStyleEx(hWnd, LVS_EX_FULLROWSELECT, 0);
LRESULT oldcolw = ListView_GetColumnWidth(hWnd, 0);
ListView_SetColumnWidth(hWnd, 0, 0);
PostMessage(hWnd, WM_APP, oldexstyle, oldcolw); // Restore delay
return CallWindowProc(g_OrgWndProc, hWnd, Msg, wp, lp);
}
if (Msg == WM_APP)
{
ListView_SetExtendedListViewStyleEx(hWnd, LVS_EX_FULLROWSELECT, (UINT) wp);
ListView_SetColumnWidth(hWnd, 0, (UINT) lp);
}
return CallWindowProc(g_OrgWndProc, hWnd, Msg, wp, lp);
}
...
g_OrgWndProc = (WNDPROC) SetWindowLongPtr(listviewhandle, GWLP_WNDPROC, (LONG_PTR) LVSubClass);
This code removes the full-row-select style and makes the first column "invisible" when the listview handles the initial mouse down message so that the internal listview hit-testing returns LVHT_NOWHERE and marquee-selection can start. You should consider this to be a ugly hack and I would recommend that you only intercept WM_LBUTTONDOWN when Control or Shift is down...

How to block mouse input from transparent window with Win32 API?

I have a main window in a process that is not owned by the program I'm creating. I'm using a Windows Hook to inject a DLL into this process for the purpose of adding a child window to this main window.
My end goal was to create a WS_EX_LAYERED window that allows me to create an internal colored border but allow the center portion to be transparent and allow mouse clicks through. This part works perfectly.
WNDCLASS wndClass = {};
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = OverlayProc;
wndClass.hInstance = g_TargetInstance;
wndClass.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 255, 255));
wndClass.lpszClassName = "OVERLAY";
RegisterClass(&wndClass);
g_Window = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, "OVERLAY", nullptr,
WS_CHILDWINDOW, rect.left, rect.top, rect.right+1, rect.bottom+1, data->hwnd, nullptr, g_TargetInstance, nullptr);
SetLayeredWindowAttributes(g_Window, RGB(0, 255, 255), 0, LWA_COLORKEY);
ShowWindow(g_Window, SW_SHOW);
UpdateWindow(g_Window);
The 2nd part to this is a I wanted to conditionally block all mouse input to the parent window. I couldn't do this with the transparent portion of the WS_EX_LAYERED window so I tried creating a 2nd transparent STATIC control as a child of the main window but this doesn't block mouse input either.
I'm also sending simulated mouse clicks to the parent window through calls to PostMessage, passing WM_LBUTTONDOWN and WM_LBUTTONUP. How could I block all mouse input to the parent window via a transparent window?
It appears this is not possible to do with a simple transparent window drawn over sibling controls. What I ended up doing was using SetWindowHookEx to add a WH_GETMESSAGE hook into the process from which I use to replace the main window's WndProc function and intercept mouse messages. I tag my simulated mouse messages with a specific value in the wParam argument so the proc will now it was simulated and removes that value, passing it along to the parent window.
If it does not detect my "tag" value in the click message, it will swallow the mouse message and not pass it along to the original WndProc function.
Injected WndProc replacement
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_LBUTTONDOWN:
wParam -= 11141008;
if (wParam != MK_LBUTTON && !g_Paused)
return 0;
break;
case WM_LBUTTONUP:
wParam -= 11141008;
if (wParam != 0 && !g_Paused)
return 0;
break;
case WM_MOUSEHOVER:
case WM_MOUSEMOVE:
if (!g_Paused)
return 0;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
Snippet from Windows Hook function
//...
switch (data->message)
{
case (WM_USER + 1):
{
g_Paused = FALSE;
//...
SetWindowSubclass(data->hwnd, WndProc, 1, 0);
break;
}
case (WM_USER + 2):
{
RemoveWindowSubclass(data->hwnd, WndProc, 1);
//...
break;
}
}
//...
The code inside the window hook function is used to subclass the main process window and inject my own WndProc function which in turn processes mouse input the way I want.
This is the code used to "simulate" mouse clicks without physically clicking in the window. Note the added value to wParam to identify this click as simulated and not generated by the user.
void Window::LeftClick(DWORD x, DWORD y, DWORD delayMillis)
{
LPARAM lparam = MAKELPARAM(x, y);
lock_guard<mutex> lock(this->m_ClickMutex);
PostMessage(this->m_Window, WM_LBUTTONDOWN, 11141008 + MK_LBUTTON, lparam);
this_thread::sleep_for(std::chrono::milliseconds(delayMillis));
PostMessage(this->m_Window, WM_LBUTTONUP, 11141008, lparam);
}
Also, just for the person in the comments who was ridiculing my choice of the word simulated and the added criticism for using PostMessage to simulate keyboard input, here is my keyboard input test method which (for my purposes) works flawlessly and very reliably
void GameWindow::KeyPress(UINT vkCode) const
{
UINT scanCode = MapVirtualKey(vkCode, MAPVK_VK_TO_VSC);
LPARAM lparam1 = MAKELPARAM(1, scanCode);
LPARAM lparam2 = MAKELPARAM(1, 0xC000 | scanCode);
PostMessage(this->m_Window, WM_KEYDOWN, vkCode, lparam1);
this_thread::sleep_for(chrono::milliseconds(25));
PostMessage(this->m_Window, WM_KEYUP, vkCode, lparam2);
}

Windows API: How to Draw Text to Child Window? [duplicate]

This question already has answers here:
How can I change the background color of a button WinAPI C++
(4 answers)
Closed 7 years ago.
I have recently started learning windows API and would like to make more interactive GUI applications. All code is written in C++.
What I have done is made a custom button window, not using the built in button class. I want each button to have different text and would like to set this in the parent window.
So I create the button and save the handle:
hNavBtnNews = CreateWindow(szUW_NAV_BTN, "News", WS_CHILD | WS_VISIBLE, 540, 0, 100, HEADER_HEIGHT, header, NULL, NULL, NULL);
Then to make sure this hasn't failed I check the handle and attempt drawing text:
if(hNavBtnNews == NULL){
printf("\nFailed to Create Window Nav Button \n");
}else{
printf("\nCreated Window Nav Button");
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
hdc = BeginPaint(hNavBtnNews, &ps);
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, BG_TXT_COLOR);
GetClientRect(hNavBtnNews, &rect);
DrawText(hdc, "News", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hNavBtnNews, &ps);
}
This is all done in the WM_CREATE case of the parent window procedure (which itself works just fine). The text is a light grey color and the background of the button is a dark blue. Except the text is not being drawn. There are no compiler warnings or errors either. Perhaps subclassing built in controls would be better for this, though I don't know how. Any help in solving this issue would be greatly appreciated.
Consider the following brief snippet as an example of how simple sub-classing can be:
LRESULT CALLBACK myDrawButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_PAINT:
onBtnPaint(hWnd, wParam, lParam);
return TRUE;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
BOOL CALLBACK DlgMain(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
{
HWND button = GetDlgItem(hwndDlg, IDC_BUTTON_TO_SUBCLASS);
SetWindowSubclass(button, myDrawButtonProc, 0, 0);
}
return TRUE;
...
...
...

Changing HWND Window Procedure in runtime

I'm working in an IDE which creates a hwnd and its respective WndProc LRESULT CALLBACK. I need to change the WndProc to a custom one.
I've read that SetWindowLong would do the job, but I can't find any working example. For example:
HWND hwnd; //My window
SetWindowLong(hwnd, GWL_WNDPROC, myNewWndProc);
The third parameter for SetWindowLong is a Long as the name of the function names it. How can I make a reference from my WndProc function to a Long?
My WndProc:
LRESULT CALLBACK WndProcedure(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
msg_dev(toString(uMsg));
switch(uMsg){
case WM_MOUSEMOVE:
SetCursor(LoadCursor(NULL, IDC_HAND));
break;
case WM_LBUTTONDOWN:
msg_dev("Button down!");
break;
default:
DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
};
You need to use something like this:
WNDPROC prevWndProc;
...
prevWndProc = (WNDPROC) SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR)&myNewWndProc);
...
LRESULT CALLBACK myNewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
msg_dev(toString(uMsg));
switch(uMsg)
{
case WM_MOUSEMOVE:
SetCursor(LoadCursor(NULL, IDC_HAND));
break;
case WM_LBUTTONDOWN:
msg_dev("Button down!");
break;
}
return CallWindowProc(prevWndProc, hwnd, uMsg, wParam, lParam);
}
See this article:
When you subclass a window, it's the original window procedure of the window you subclass you have to call when you want to call the original window procedure
That being said, you should use SetWindowSubclass() instead of SetWindowLongPtr(). Let it handle this for you. See this article for more details:
Safer subclassing
For example:
#define MY_SUBCLASS_ID 1
SetWindowSubclass(hwnd, &mySubClassProc, MY_SUBCLASS_ID, 0);
...
LRESULT CALLBACK mySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
msg_dev(toString(uMsg));
switch(uMsg)
{
case WM_MOUSEMOVE:
SetCursor(LoadCursor(NULL, IDC_HAND));
break;
case WM_LBUTTONDOWN:
msg_dev("Button down!");
break;
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, &mySubClassProc, uIdSubclass);
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
A simple cast does the job.
SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR)&myNewWndProc);
Otherwise It would be incompatible types: LRESULT and LONG.
The MSDN documentation for SetWindowLong() states that GWL_WNDPROC
Sets a new address for the window procedure.
This means that your third parameter should be a pointer to a function. Your SetWindowLong() call should therefore look like this:
SetWindowLong(hwnd, GWL_WNDPROC, (LONG_PTR)&myNewWndProc);
Note also the Remarks section that states:
An application must pass any messages not processed by the new window procedure to the previous window procedure by calling CallWindowProc.
You can use setWindowLong to address your problem.
setWindowLong(hwnd,GWL_WNDPROC,(LONG)newWindowProcedure);
However you would be setting the window procedure twice. Once with the IDE default and then to yours. What you need to dobis set the window procedure when the window is being REGISTERED.
#include <windows.h>
void registerWindow();
void createWindow();
void messageLoop();
int main()
{
registerWindow();
createWindow();
messageLoop();
}
LRESULT CALLBACK myWindowProcedure(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
{
return DefWindowProc(hwnd,msg,wparam,lparam);
}
void registerWindow()
{
/** This is the important part.
* Find this part in your code.
* Set WNDCLASS::lpfnWndProc to what ever
* window procedure you want.
**/
WNDCLASS wc = {};
wc.lpfnWndProc = myWindowProcedure;
wc.hInstance = hInstance;
wc.lpszClassName = "CLASS NAME";
RegisterClass(&wc);
// WARNING: Your app will crash at runtime if the
// windows procedure is "NOT PROPER"
}
void createWindow()
{
auto hwnd = CreateWindowEx(
0, // Optional window styles.
"CLASS NAME", // Window class
"Learn to Program Windows", // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, // Parent window
NULL, // Menu
HINSTANCE(), // Instance handle
NULL // Additional application data
);
ShowWindow(hwnd, nCmdShow
}
void messageLoop()
{
MSG msg;
while( GetMessage(&msg, NULL, 0, 0) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
You have to use SetWindowLongPtr (which on 32-bit is a macro but a separate function on 64-bit) to ensure compatibility with both 32- and 64-bit systems.
Syntax would be as follows:
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)&myNewWndProc);
Note SetWindowLongPtr is used instead of SetWindowLong, and GWLP_WNDPROC is used as the nIndex constant.