My Question is: In the below C++ code, why does clicking on the button do nothing while it is supposed to call MessageBox from WndProc1?
P.S: After compiling, I got some errors like the following:
"C:\Windows\SysWOW64\ntdll.dll", Can't find or open PDB file.
Code:
#include <Windows.h>
LRESULT CALLBACK WndProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
LONG WINAPI WndProc1(
_In_ HWND hwnd_button,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
//Точка входа в программу
int WINAPI WinMain
(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
//Создаем класс окна
WNDCLASS WindowClass;
//Заполняем структуру
WindowClass.style = 0;
WindowClass.lpfnWndProc = (WNDPROC)WndProc;
WindowClass.cbClsExtra = 0;
WindowClass.cbWndExtra = 0;
WindowClass.hInstance = hInstance;
WindowClass.hIcon = LoadIcon(hInstance,
(LPCTSTR)IDI_APPLICATION);
WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WindowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
WindowClass.lpszMenuName = 0;
WindowClass.lpszClassName = TEXT("Class");
//Зарегистируем класс окна
RegisterClass(&WindowClass);
//Создаем переменную, в которой поместим идентификатор окна
HWND hWnd;
hWnd = CreateWindow(TEXT("Class"), TEXT("ClickTest"),
WS_OVERLAPPEDWINDOW, 0, 0, 500, 300, NULL, NULL, hInstance, NULL);
//Создаем кнопку
HWND hWnd_button;
hWnd_button = CreateWindow(TEXT("button"), TEXT("Click me"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 10, 80, 30, hWnd, (HMENU)10000, hInstance, NULL);
//показать окно
ShowWindow(hWnd, nCmdShow);
//обновить содержимое окна
UpdateWindow(hWnd);
//Создадим переменную для храненния сообщений
MSG msg;
//Создадим цикл обработки сообщений
while(GetMessage(&msg, NULL,0 ,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LONG WINAPI WndProc1(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{
switch (Message){
case WM_COMMAND:
if(LOWORD(wparam)==10000)
{
MessageBox(hwnd, TEXT("Button Pressed"), TEXT(""), 0);
}
return 0;}}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT PS;
switch(message)
{
case WM_CREATE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
BeginPaint(hWnd, &PS);
EndPaint(hWnd, &PS);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Now working, just added button function as one of the cases to WndProc (WndProc1 deleted)
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lParam)
{
PAINTSTRUCT PS;
switch(message)
{
case WM_CREATE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
BeginPaint(hWnd, &PS);
EndPaint(hWnd, &PS);
break;
case WM_COMMAND:
if(LOWORD(wparam)==10000)
{
MessageBox(hWnd, TEXT("Button Pressed"), TEXT(""), 0);
}
default:
return DefWindowProc(hWnd, message, wparam, lParam);
}
return 0;
}
One final newbie question: what's the difference between LRESULT CALLBACK and LONG WINAPI then?
Do this modification on WndProc:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT PS;
switch(message)
{
case WM_COMMAND:
if(LOWORD(wParam)==10000)
{
MessageBox(hWnd, TEXT("Button Pressed"), TEXT(""), 0);
}
break;
case WM_CREATE:
break;
// ...
I added WM_COMMAND in the switch/case of WndProc.
How do you expect WndProc1 to be called? It isn't associated to any window class... You have to handle the WM_COMMAND inside WndProc (buttons, as well as other common controls, notify their parent of their events via WM_COMMAND).
Related
I Was working on a win32 project which uses the WM_MOVING message from WndProc to detect the new position where window is moved. but when i try to snap the window to left side the LPARAM gives wrong values for just a millisecond and gives the real value after that.
Please have a look into the output:
Left: 0, Right:683
Left: -205, Right:295
Left: 0, Right:683
Left: -205, Right:295
Left: 0, Right:683
Left: -205, Right:295
The real output is -205 but in between I get zero which cause the content of my window to flicker. In my case the position of the content is depend on the window position, so it causes flicker if I receive a wrong value.
Here is what i am trying to achieve : Manually creating acrylic effect
When ever I move the window in this mode (just before the aero snap mode) the value will get changed to zero.
This is only affecting The Top and Left coordinates of the window and also flickers when aero snapping to any sides.
Here is a simple reproduceable example:
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <stdio.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
RECT* hostRect;
char buffer[200];
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(0,CLASS_NAME,L"Learn to Program Windows",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
if (hwnd == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_MOVING:
{
hostRect = reinterpret_cast<RECT*>(lParam);
sprintf_s(buffer, "Left: %d, Top:%d, Right:%d, Bottom:%d\n", hostRect->left, hostRect->top, hostRect->right, hostRect->bottom);
OutputDebugStringA(buffer);
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Run this program and check the value in output while you move the window to any side for aero snap.
Note: In my case i will not be able to use GetWindowRect() in WM_MOVING, because calling GetWindowRect() slow down the render() function (just a directx painting) in my window.
You can try to make temporary changes to the style of the window.
Here is an example:
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <stdio.h>
#define WM_RESTOREORIGINALSTYLE WM_USER + 1
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
RECT* hostRect;
char buffer[200];
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(0, CLASS_NAME, L"Learn to Program Windows", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if (hwnd == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_MOVING:
{
hostRect = reinterpret_cast<RECT*>(lParam);
sprintf_s(buffer, "Left: %d, Top:%d, Right:%d, Bottom:%d\n", hostRect->left, hostRect->top, hostRect->right, hostRect->bottom);
OutputDebugStringA(buffer);
break;
}
case WM_SYSCOMMAND:
{
if (wParam == (SC_MOVE | 2)) wParam = SC_SIZE | 9;
if ((wParam & 0xFFE0) == SC_SIZE && (wParam & 0x000F)) // handles MOVE and SIZE in one "if"
{
long int oldStyle = GetWindowLongW(hwnd, GWL_STYLE);
PostMessageW(hwnd, WM_RESTOREORIGINALSTYLE, GWL_STYLE, oldStyle);
SetWindowLongW(hwnd, GWL_STYLE, oldStyle & 0xFEFEFFFF); // disable WS_MAXIMIZE and WS_MAXIMIZEBOX
DefWindowProcW(hwnd, WM_SYSCOMMAND, wParam, lParam);
return 0;
}
return DefWindowProcW(hwnd, WM_SYSCOMMAND, wParam, lParam);
}
case WM_RESTOREORIGINALSTYLE:
{
if ((long int)wParam == GWL_STYLE)
SetWindowLongW(hwnd, GWL_STYLE, lParam);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
More reference : Win32 prevent window “snap”
This question already has answers here:
Read access violation using m_pRenderTarget with winapi due to non-NULL pointer
(2 answers)
Closed 2 years ago.
I am trying to learn the win32 api using the Microsoft documentation. I have gotten to chapter 4, and I seem to have run into an issue that I am struggling to debug. The dialogue box triggered by the about button throws an exception:
Exception thrown at 0x773BDCFF (ntdll.dll) in practice.exe: 0xC0000005: Access violation reading location 0x00905A4C.
Here is the declaration of the WndProc and About callbacks:
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
Here is the code for the implementation of the WndProc and About callbacks:
LRESULT CALLBACK App::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
App* pApp;
if (message == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
pApp = (App*)pcs->lpCreateParams;
::SetWindowLongPtrW(hWnd, GWLP_USERDATA, PtrToUlong(pApp));
return TRUE;
}
else
{
pApp = reinterpret_cast<App*>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA)));
if (!pApp)
return DefWindowProc(hWnd, message, wParam, lParam);
}
int wmld, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(pApp->getInstance(), MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, pApp->About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK App::About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
I hope the error is within these snippets. If not, I would be happy to provide more code. I have done research, and I truly have very little idea what the problem is. I know that the callback for the about function must be static, which I believe it is. Apart from that, I don't know what would cause it to throw an exception. Thank you for any help you can give me.
Fail to reproduce this issue using your presented code. The following is an example based on your code piece and it works for me. You can refer to.
App.h
class App
{
public:
App(HINSTANCE hInstance, CONST WCHAR* clsName);
private:
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
ATOM MyRegisterClass(HINSTANCE hInstance, CONST WCHAR* clsName);
};
App.cpp
#include "App.h"
App::App(HINSTANCE hInstance, CONST WCHAR* clsName)
{
App::MyRegisterClass(hInstance, clsName);
}
ATOM App::MyRegisterClass(HINSTANCE hInstance, CONST WCHAR* clsName)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = App::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DIALOGBOXEXCEPTION));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_DIALOGBOXEXCEPTION);
wcex.lpszClassName = clsName;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
LRESULT CALLBACK App::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
App* pApp;
if (message == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
pApp = (App*)pcs->lpCreateParams;
::SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pApp);
return TRUE;
}
else
{
pApp = reinterpret_cast<App*>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA)));
if (!pApp)
return DefWindowProc(hWnd, message, wParam, lParam);
}
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(NULL, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, pApp->About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK App::About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
Create the main window:
App pApp = App(hInst, szWindowClass);
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, &pApp);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
I want to make WndProc a class member function and I found this article, so I tried to apply it to the simplest Win32 program, which does nothing but creating a blank window, the very first step of Win32.
int Myclass::Start(HINSTANCE hInstance, int nCmdShow)
{
if (FAILED(InitWindow(hInstance, nCmdShow)))
return 0;
MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;;
}
LRESULT Myclass::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
Myclass* pThis = nullptr;
if (message == WM_NCCREATE) {
LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
pThis = static_cast<Myclass*>(lpcs->lpCreateParams);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
}
else {
pThis = reinterpret_cast<Myclass*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
}
if(pThis)
return pThis->RealWndProc(hWnd, message, wParam, lParam);
return DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT Myclass::RealWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
It runs well, but when I close the window the program stays in the message loop and doesn't quit.
I found out that WM_DESTROY is not delivered to RealWndProc(), so PostQuitMessage() is not called.
If I insert if(WM_DESTROY == message) { PostQuitMessage(0); return 0; } right before the last line of StaticWndProc, then the program quits. But I'm not sure if this is a good way to do it.
How can I make WM_DESTROY consumed by RealWndProc()?
Like this is how I did it.. Works just fine.. The only problem I can think of in your code is one of two:
You missed the calling convention for the WindowProcedure.
You forgot to pass "this" to CreateWindowEx.
And the code:
#include <windows.h>
class Window
{
public:
Window(LPCTSTR Title, LPCTSTR Class, DWORD dwStyleEx = 0, DWORD dwStyle = WS_OVERLAPPEDWINDOW,
POINT Location = {CW_USEDEFAULT, CW_USEDEFAULT}, int Width = CW_USEDEFAULT,
int Height = CW_USEDEFAULT, HWND Parent = HWND_DESKTOP, HMENU Menu = nullptr);
int Loop();
private:
HWND WindowHandle;
static LRESULT __stdcall WindowProcedure(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam);
LRESULT RealWindowProcedure(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam);
};
Window::Window(LPCTSTR Title, LPCTSTR Class, DWORD dwStyleEx, DWORD dwStyle, POINT Location, int Width, int Height, HWND Parent, HMENU Menu)
{
WNDCLASSEX WndClass =
{
sizeof(WNDCLASSEX), CS_DBLCLKS, Window::WindowProcedure,
0, 0, GetModuleHandle(nullptr), LoadIcon(nullptr, IDI_APPLICATION),
LoadCursor(nullptr, IDC_ARROW), HBRUSH(COLOR_BACKGROUND),
nullptr, Class, LoadIcon(nullptr, IDI_APPLICATION)
};
if(RegisterClassEx(&WndClass))
{
WindowHandle = CreateWindowEx(dwStyleEx, Class, Title, dwStyle, Location.x, Location.y, Width, Height, Parent, Menu, GetModuleHandle(nullptr), this);
}
}
LRESULT __stdcall Window::WindowProcedure(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
Window* Data = nullptr;
switch(Msg)
{
case WM_NCCREATE:
{
CREATESTRUCT* pCreate = reinterpret_cast<CREATESTRUCT*>(lParam);
Data = static_cast<Window*>(pCreate->lpCreateParams);
SetWindowLongPtr(Hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(Data));
break;
}
default:
{
Data = reinterpret_cast<Window*>(GetWindowLongPtr(Hwnd, GWLP_USERDATA));
break;
}
}
return Data ? Data->RealWindowProcedure(Hwnd, Msg, wParam, lParam) : DefWindowProc(Hwnd, Msg, wParam, lParam);
}
LRESULT Window::RealWindowProcedure(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch(Msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(Hwnd, Msg, wParam, lParam);
}
return 0;
}
int Window::Loop()
{
MSG Messages = {nullptr};
ShowWindow(WindowHandle, SW_SHOW);
while(GetMessage(&Messages, nullptr, 0, 0))
{
TranslateMessage(&Messages);
DispatchMessage(&Messages);
}
return Messages.wParam;
}
int main()
{
Window w("TItle", "Class");
return w.Loop();
}
You should catch WM_CLOSE and have it call DestroyWindow() to trigger WM_DESTROY:
case WM_CLOSE:
DestroyWindow(hWnd);
break;
Also, your StaticWndProc() method is using the wrong calling convention. It must use the __stdcall calling convention, which is wrapped by WINAPI and CALLBACK macros, eg:
LRESULT CALLBACK Myclass::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
If I create a child window (In this case window "About") to the main window, the dialog box for some reason is not called. If you do not the child window is a dialog box called normal and works fine. GetLastError returns the error number 1812 (The specified image file did not contain a resource section.). But from a resource file everything is fine. And as I said, if you do not create a child window then everything works fine. What's the problem?
#include <windows.h>
#include "resource.h"
LONG WINAPI WndProc(HWND, UINT, WPARAM,LPARAM);
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK PointsProc(HWND hPoints, UINT message, WPARAM wParam,LPARAM lParam);
HINSTANCE hInst;
HWND hPoints;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
hInst = hInstance;
HWND hwnd;
MSG msg;
WNDCLASS w;
memset(&w,0,sizeof(WNDCLASS));
w.style = CS_HREDRAW | CS_VREDRAW;
w.lpfnWndProc = WndProc;
w.hInstance = hInstance;
w.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
w.lpszClassName = L"My Class";
RegisterClass(&w);
hwnd = CreateWindow(L"My Class", L"My title", WS_OVERLAPPEDWINDOW,
300, 200, 200, 180, NULL, NULL, hInstance, NULL);
HMENU main_menu = CreateMenu();
AppendMenu(main_menu, MF_STRING, 1111, L"Box");
WNDCLASS w2;
memset(&w2, 0, sizeof(WNDCLASS));
w2.lpfnWndProc = (WNDPROC)PointsProc;
w2.hInstance = hInst;
w2.lpszClassName = L"About";
w2.hCursor = LoadCursor(NULL, IDC_ARROW);
w2.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(111, 111, 111));
RegisterClass(&w2);
hPoints = CreateWindowEx(0, L"About", (LPCTSTR) NULL,
WS_CHILD | WS_BORDER | WS_VISIBLE | WS_DISABLED, 10, 10,
100, 100, hwnd, (HMENU)1112, hInst, NULL);
ShowWindow(hPoints,SW_NORMAL);
UpdateWindow(hPoints);
SetMenu(hwnd, main_menu);
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{
switch (Message)
{
case WM_COMMAND:
switch(LOWORD(wparam))
{
case 1111:
DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hwnd, About);
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, Message, wparam, lparam);
}
return 0;
}
LRESULT CALLBACK PointsProc(HWND hPoints, UINT message, WPARAM wParam,LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
break;
default:
return DefWindowProc(hPoints, message, wParam, lParam);
}
return 0;
}
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
The dialog box is called, only it takes a long time because PointsProc() is looping...
The problem was the break; while handling WM_PAINT in PointsProc() -- it then skips calling DefWindowProc(), so the window keeps getting WM_PAINT messages because the window remains invalid.
// case WM_PAINT:
// break;
I have read and read, trying to find how to put text on a custom control. I have found stuff, but none of it has been clean and simple.
So how do I draw text on a custom control? here is code...
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam);
LRESULT CALLBACK CustProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam) ;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
wchar_t * windowname = L"window Class";
wchar_t * cust = L"custctrl";
WNDCLASS wc = {0};
wc.lpszClassName = windowname;
wc.lpfnWndProc = WindowProc;
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(
0,
windowname,
L"app",
WS_VISIBLE | WS_THICKFRAME| WS_OVERLAPPEDWINDOW ,
50, 50,
500, 500,
NULL,
NULL,
hInstance,
NULL
);
WNDCLASS button = {0};
button.lpfnWndProc = CustProc;
button.lpszClassName = cust;
button.hInstance = hInstance;
button.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
button.hCursor = LoadCursor(NULL, IDC_HAND);
RegisterClass(&button);
HWND click = CreateWindowEx(
WS_EX_CLIENTEDGE,
cust,
L"Custom Control", //doesnt show up on the window, not to my suprise
WS_VISIBLE | WS_CHILD ,
0, 0,
500, 500,
hwnd,
NULL,
hInstance,
NULL
);
//all the rest...
}
LRESULT CALLBACK CustProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam) {
switch(uMsg) {
case WM_CREATE:
SetWindowText(hwnd, L"button"); //also doesn't work, also not to my suprise
case WM_LBUTTONDOWN: {
MessageBox(hwnd, L"you clicked the custom button", L"cool", 0); // works fine
break;
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wparam, lparam);
}
You can catch the WM_PAINT message in your CustProc function and draw the text yourself.
You can get a drawing context by calling BeginPaint, draw the text and close the drawing context by calling EndPaint. You can draw text with the TextOut function. Here is an example from MSDN:
LRESULT APIENTRY WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 0, 0, "Hello, Windows!", 15);
EndPaint(hwnd, &ps);
return 0L;
// Process other messages.
}
}
Full example here.