Before beginning to read the problem please note i read Petzold's book (windows programming 5th edition)!
In form.h i have declared the custom message named CMessage (it stand for "custom message", which later calls the method for creating a button), in formbutton.cpp i am sending message from its constructor to the main window which is created in form.cpp. I found out from getLastError method in my helper class that send message fails because of invalid window handle, it is strange because if i use isWindow(forms.mainWindowHandle) before sending the message i got messagebox that shows "operation completed successfully". The same design worked before splitting whole code into multiple headers and cpps, now its broken.
******
step by step debugging :
form myform(hInstance);
form::form(HINSTANCE hInstanceForm);
HWND form::Createform(HWND handle, HINSTANCE hInstance, int xPos , int yPos , int xSize , int ySize);
Formbutton::Formbutton(BOOL create);
form::form();
SendMessage(forms.mainWindowHandle, CMessage,0 ,0);//error
//rest of the code and main window is shown but not the button
******
formbutton.cpp
#pragma once
#include "FormButton.h"
#include "Form.h"
#include "helper.h"
Formbutton::Formbutton(){}
Formbutton::Formbutton(BOOL create)
{
helper help;
form forms;
if (create)
{
SendMessage(forms.mainWindowHandle, CMessage,0 ,0); //same with PostMessage
help.getLastError();
}
}
HWND Formbutton::createButton(HWND button, HWND parent)
{
button = CreateWindow(TEXT("Button"), // window class name
TEXT("Button"), // window caption
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP, // window style
500, // initial x position
500, // initial y position
300, // initial x size
500, // initial y size
parent, // parent window handle
NULL, // window menu handle
(HINSTANCE)GetWindowLongPtr(parent, -6), // program instance handle
NULL); // creation parameters
ShowWindow(button, SW_SHOW);
return button;
}
form.h
#pragma once
#include <Windows.h>
#define CMessage (WM_USER+0x0001)
class form
{
private:
HWND Createform(HWND handle, HINSTANCE hInstance, int xPos = CW_USEDEFAULT, int yPos = CW_USEDEFAULT, int xSize = GetSystemMetrics(SM_CXFULLSCREEN), int ySize = GetSystemMetrics(SM_CYFULLSCREEN));
MSG msg;
WNDCLASS wndclass;
protected:
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
public:
HWND mainWindowHandle;
form::form();
form::form(HINSTANCE hInstanceForm);
form::~form();
WPARAM updateForm();
};
form.cpp
#pragma once
#include "Form.h"
#include "FormButton.h"
LRESULT CALLBACK form::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
Formbutton fb;
switch (message)
{
case WM_CREATE:
return 0;
case WM_PAINT:
InvalidateRect(hwnd, &rect, TRUE);
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
SetBkMode(hdc, TRANSPARENT);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case CMessage: //this is the custom message
fb.createButton(fb.buttonHandle, hwnd);
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
HWND form::Createform(HWND handle, HINSTANCE hInstance, int xPos , int yPos , int xSize , int ySize)
{
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = TEXT("Framework");
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
TEXT("Framework"), MB_ICONERROR);
}
handle = CreateWindow(TEXT("Framework"), // window class name
TEXT("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX | WS_HSCROLL | WS_VSCROLL, // window style
xPos, // initial x position
yPos, // initial y position
xSize, // initial x size
ySize, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters
//ShowWindow(handle, SW_SHOWMAXIMIZED);
UpdateWindow(handle);
return handle;
}
WPARAM form::updateForm()
{
ShowWindow(mainWindowHandle, 10);
UpdateWindow(mainWindowHandle);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
form::form()
{
}
form::form(HINSTANCE hInstanceForm)
{
mainWindowHandle = Createform(mainWindowHandle, hInstanceForm);
}
form::~form()
{
}
helper.cpp
#pragma once
#include "helper.h"
#include <strsafe.h>
void helper::getLastError()
{
wchar_t buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, NULL);
MessageBox(NULL, buf, TEXT("error"), MB_OK);
}
source.cpp
#pragma once
#include <Windows.h>
#include "Form.h"
#include "FormButton.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
form myform(hInstance);
Formbutton btn(true);
myform.updateForm();
}
You are creating two instances of form: one in your WinMain() and one in your Formbutton constructor. You want to add your button to the former, but you are really adding it to the latter, and the latter ceases to exist once the constructor returns.
I'm not sure how you want to structure your program, but my suggestion is to pass the correct parent form as a form * parameter to the Formbutton constructor.
Related
I am new to using international languages in my win32 program in C++. I have a simple window created with an edit field inside. I want to set a chinese hardcoded text into the edit field. I am using SetWindowText but the output has only question marks and | character. What am I missing? My code file is pasted below. I have tried WM_SETTEXT but no luck.
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <strsafe.h>
#include <iostream>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"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
);
if (hwnd == NULL)
{
return 0;
}
HWND edit = CreateWindowEx(0, L"Edit", L"", WS_CHILD | WS_VISIBLE | WS_BORDER, 0, 0, 200, 50, hwnd, NULL, hInstance, NULL);
SetWindowTextW(edit, L"銷售回扣");
//SendMessage(edit, WM_SETTEXT, 0, (LPARAM)(L"銷售回扣"));
ShowWindow(hwnd, nCmdShow);
// Run the message loop.
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_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// All painting occurs here, between BeginPaint and EndPaint.
FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1));
EndPaint(hwnd, &ps);
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
In my program I am trying to create a child window (via CreateWindow("STATIC", ...)) to contain some other controls such as edit boxes and buttons. However, I want the background for this static control to be a gradient.
My goal is to have something that looks like this as a child window:
My efforts so far have yielded the window being created with controls visible but as soon as it is redrawn with WM_ERASEBKGND, the controls are hidden behind the drawn gradient.
I can find plenty of examples on drawing a gradient (or other such graphic backgrounds) and also, independently, creating a window with controls. But I have yet to find any resource of having both at the same time.
Here is my example code:
#include <windows.h>
#pragma comment( lib, "Msimg32" ) // load that dll for GradientFill
// Global macros
inline COLOR16 ToColor16(BYTE byte) { return byte << 8; }
inline COLOR16 RVal16(COLORREF color) { return ToColor16(GetRValue(color)); }
inline COLOR16 GVal16(COLORREF color) { return ToColor16(GetGValue(color)); }
inline COLOR16 BVal16(COLORREF color) { return ToColor16(GetBValue(color)); }
// Global variables
HINSTANCE hInst;
// Forward declarations
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// Entry point
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
// Register the window class.
const TCHAR CLASS_NAME[] = "mcvewinapi";
WNDCLASS wc = { };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
"MCVE WINAPI", // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
300, //horizontal position
50, //vertical position
700, //width
500, //height
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
hInst = hInstance;
if (hwnd == NULL) {
return 0;
}
ShowWindow(hwnd, nCmdShow);
// Run the message loop.
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
// vill geven area with vertical gradient
void VerticalGradient(HDC hDC, const RECT &RectToFill, COLORREF rgbTop, COLORREF rgbBottom) {
GRADIENT_RECT gradRect;
TRIVERTEX TriVert[2];
// references for the verticies
gradRect.UpperLeft = 0; // point to TriVert[0]
gradRect.LowerRight = 1; // point to TriVert[1]
//setup top of gradient attributes
TriVert[0].x = RectToFill.left - 1;
TriVert[0].y = RectToFill.top - 1;
TriVert[0].Red = RVal16(rgbTop);
TriVert[0].Green = GVal16(rgbTop);
TriVert[0].Blue = BVal16(rgbTop);
TriVert[0].Alpha = 0x0000;
//setup bottom of gradient attributes
TriVert[1].x = RectToFill.right;
TriVert[1].y = RectToFill.bottom;
TriVert[1].Red = RVal16(rgbBottom);
TriVert[1].Green = GVal16(rgbBottom);
TriVert[1].Blue = BVal16(rgbBottom);
TriVert[1].Alpha = 0x0000;
// draw the shaded rectangle
GradientFill(hDC, TriVert, 2, &gradRect, 1, GRADIENT_FILL_RECT_V);
}
// discover area to fill with gradient
void vFill(HWND ctrlhwnd) {
HDC gBoxDC;
HWND gBoxH;
RECT gBoxR;
POINT xWhere;
// get rectangle from control
gBoxH = ctrlhwnd;
GetWindowRect(gBoxH, &gBoxR);
// get DC for control
gBoxDC = GetDC(gBoxH);
// load up RECT from POINT
xWhere = { gBoxR.left, gBoxR.top };
ScreenToClient(gBoxH, &xWhere);
gBoxR.left = xWhere.x + 2;
gBoxR.top = xWhere.y + 2;
// load up RECT from POINT
xWhere = { gBoxR.right, gBoxR.bottom };
ScreenToClient(gBoxH, &xWhere);
gBoxR.right = xWhere.x - 1;
gBoxR.bottom = xWhere.y - 1;
//paint area
VerticalGradient(gBoxDC, gBoxR, RGB(250, 191, 145), RGB(191, 191, 191));
ReleaseDC(gBoxH, gBoxDC);
}
// Processes messages for the main window.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_CREATE:
struct wAnchor {
int udPos;
int lrPos;
int width;
int height;
};
wAnchor Section1[4], TextLine;
unsigned int LineHeight, k;
HWND FillBox;
LineHeight = 24;
Section1[1].lrPos = 5;
Section1[1].udPos = 20;
Section1[1].width = 325;
Section1[1].height = 360;
TextLine.lrPos = Section1[1].lrPos + 5;
TextLine.udPos = Section1[1].udPos + 5;
TextLine.width = 0;
TextLine.height = LineHeight;
k = 1;
FillBox = CreateWindow("STATIC",
"",
WS_VISIBLE | WS_CHILD | WS_BORDER | WS_EX_CLIENTEDGE,
Section1[1].lrPos,
Section1[1].udPos,
Section1[1].width,
Section1[1].height,
hWnd, // child of parent
(HMENU)8200,
hInst,
NULL);
CreateWindow("STATIC",
"Section title",
WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER | WS_EX_CLIENTEDGE,
TextLine.lrPos,
TextLine.udPos + (TextLine.height * k++),
TextLine.width + 315,
TextLine.height,
FillBox, // child of FillBox
(HMENU)8201,
hInst,
NULL);
CreateWindow("STATIC",
"Entry:",
WS_VISIBLE | WS_CHILD | WS_BORDER | WS_EX_CLIENTEDGE,
TextLine.lrPos,
TextLine.udPos + (TextLine.height * k),
TextLine.width + 75,
TextLine.height,
FillBox, // child of FillBox
(HMENU)8202,
hInst,
NULL);
CreateWindow("EDIT", // edit bos
"109",
WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP | ES_MULTILINE,
TextLine.lrPos + 75,
TextLine.udPos + (TextLine.height * k),
TextLine.width + 35,
TextLine.height,
FillBox, // child of FillBox
(HMENU)8203,
hInst,
NULL);
CreateWindow(
"BUTTON", // Predefined class; Unicode assumed
"test", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
50, // x position
150, // y position
50, // Button width
30, // Button height
FillBox, // child of FillBox
(HMENU)8204, // No menu
hInst,
NULL); // Pointer not needed
UpdateWindow(FillBox);
break;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
break;
case WM_ERASEBKGND:
vFill(GetDlgItem(hWnd, 8200)); //fill background with gradient
return 1L;
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Initially, no gradient is drawn until I resize the window, then the gradient covers the controls. Of course, I would like the gradient to be redrawn as needed, but the controls to remain visible.
How do I accomplish this?
You can add the WS_CLIPCHILDREN style to the parent window:
FillBox = CreateWindow(TEXT("STATIC"),
TEXT(""),
WS_VISIBLE | WS_CHILD | WS_BORDER | WS_EX_CLIENTEDGE | WS_CLIPCHILDREN,
Section1[1].lrPos,
Section1[1].udPos,
Section1[1].width,
Section1[1].height,
hWnd, // child of parent
(HMENU)8200,
hInst,
NULL);
This will not include its child windows when drawing the parent window, which works for me:
If you're going to create a window to act as a container for some controls, the obvious choice is usually to create a dialog. It already (automatically) handles most of what you're doing right now, and a few things you might want to (like using the tab to move between controls) but haven't yet.
So, for example, starting from a generic Windows app, I changed the default About box to host roughly the controls you wanted, then popped it up as a modeless dialog when the application initialized.
// frame.cpp : Defines the entry point for the application.
//
#include "framework.h"
#include "frame.h"
#pragma comment( lib, "Msimg32" ) // load that dll for GradientFill
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_FRAME, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_FRAME));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_FRAME));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_FRAME);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND dialog;
switch (message)
{
case WM_CREATE:
dialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
ShowWindow(dialog, SW_SHOW);
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
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;
}
inline COLOR16 ToColor16(BYTE byte) { return byte << 8; }
inline COLOR16 RVal16(COLORREF color) { return ToColor16(GetRValue(color)); }
inline COLOR16 GVal16(COLORREF color) { return ToColor16(GetGValue(color)); }
inline COLOR16 BVal16(COLORREF color) { return ToColor16(GetBValue(color)); }
// Message handler for about box.
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_ERASEBKGND: {
COLORREF rgbTop(RGB(250, 191, 145));
COLORREF rgbBottom(RGB(191, 191, 191));
RECT RectToFill;
GetClientRect(hDlg, &RectToFill);
GRADIENT_RECT gradRect;
TRIVERTEX TriVert[2];
// references for the verticies
gradRect.UpperLeft = 0; // point to TriVert[0]
gradRect.LowerRight = 1; // point to TriVert[1]
//setup top of gradient attributes
TriVert[0].x = RectToFill.left - 1;
TriVert[0].y = RectToFill.top - 1;
TriVert[0].Red = RVal16(rgbTop);
TriVert[0].Green = GVal16(rgbTop);
TriVert[0].Blue = BVal16(rgbTop);
TriVert[0].Alpha = 0x0000;
//setup bottom of gradient attributes
TriVert[1].x = RectToFill.right;
TriVert[1].y = RectToFill.bottom;
TriVert[1].Red = RVal16(rgbBottom);
TriVert[1].Green = GVal16(rgbBottom);
TriVert[1].Blue = BVal16(rgbBottom);
TriVert[1].Alpha = 0x0000;
HDC dc = GetDC(hDlg);
GradientFill(dc, TriVert, 2, &gradRect, 1, GRADIENT_FILL_RECT_V);
ReleaseDC(hDlg, dc);
return 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 didn't really complete the transformation from it being a modal dialog to modeless (e.g., a modeless dialog usually won't have an OK button, or code to handle its being pressed, but it's still enough to get the idea of how it can look:
I am trying to create a listview in C++ with the win32 api, however the code supplied on mdsn is giving me an error.
HWND CreateListView (HWND hwndParent)
{
INITCOMMONCONTROLSEX icex; // Structure for control initialization.
icex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&icex);
RECT rcClient; // The parent window's client area.
GetClientRect (hwndParent, &rcClient);
// Create the list-view window in report view with label editing enabled.
HWND hWndListView = CreateWindow(WC_LISTVIEW, //ERROR red line under create window
L"",
WS_CHILD | LVS_REPORT | LVS_EDITLABELS,
0, 0,
rcClient.right - rcClient.left,
rcClient.bottom - rcClient.top,
hwndParent,
(HMENU)IDM_CODE_SAMPLES, //ERROR IDM CODE SAMPLES undefined
g_hInst, //ERROR
NULL);
return (hWndListView);
}
This example is strait from mdsn and I have no idea why it is not working. I am getting IDM_CODE_SAMPLES Undefined, and something wrong with createwindow. Please help me to get this working it would be really helpful.
IDM_CODE_SAMPLES is the ID you want to assign to your control. You can either define the symbol to a numeric value, or use the numeric value directly (choose 100, for example). The ID is useful if you want to reference a particular control, although its HWND is equally useful as an ID.
g_hInst is presumably a global variable of type HMODULE, initialized from WinMain. If you don't want to use the global variable, you can call GetModuleHandle(nullptr) in its place, provided that you are compiling an .exe as opposed to a .dll.
You'll get a lot of helpful information when working through Intro to Win32 programming in C++.
I am now getting an error (1 unresolved externals)
We can find from InitCommonControlsEx function.
Ensures that the common control DLL (Comctl32.dll) is loaded, and
registers specific common control classes from the DLL.
Add:
#include <commctrl.h>
#pragma comment(lib,"Comctl32.lib")
Minimal code example:
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <commctrl.h>
#pragma comment(lib,"Comctl32.lib")
#define IDM_CODE_SAMPLES 101
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HWND CreateListView(HWND hwndParent);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"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
);
CreateListView(hwnd);
if (hwnd == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
// Run the message loop.
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_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
HWND CreateListView(HWND hwndParent)
{
INITCOMMONCONTROLSEX icex; // Structure for control initialization.
icex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&icex);
RECT rcClient; // The parent window's client area.
GetClientRect(hwndParent, &rcClient);
// Create the list-view window in report view with label editing enabled.
HWND hWndListView = CreateWindow(WC_LISTVIEW, //ERROR red line under create window
L"",
WS_CHILD | LVS_REPORT | LVS_EDITLABELS,
0, 0,
rcClient.right - rcClient.left,
rcClient.bottom - rcClient.top,
hwndParent,
(HMENU)IDM_CODE_SAMPLES, //ERROR IDM CODE SAMPLES undefined
GetModuleHandle(nullptr), //ERROR
NULL);
return (hWndListView);
}
Just in case someone else is having issues around SysListView32:
#include <Ole2.h>
OleInitialize(NULL);
#include <commctrl.h>
#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "comctl32.lib")
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwICC = ICC_LISTVIEW_CLASSES;
InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
BOOL bRet = InitCommonControlsEx(&InitCtrls);
...
For reference: fully working example with bells and whistles: https://github.com/jjYBdx4IL/Win32-List-View
I'm trying to add thumbnail buttons to a window, but there is no error and no thumbnail button is shown. I read the following pages for reference:
Your First Windows Program;
ITaskbarList3::ThumbBarAddButtons method;
some code on github.
Environment: win10 64bit, vs2015
// function WindowProc and wWinMain are copied from msdn directly.
#include "stdafx.h"
#include <windows.h>
#include "shobjidl.h"
#include <exception>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HRESULT addThumbnailButtons(HWND hwnd) {
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr)) {
ITaskbarList4* ptbl = nullptr;
HRESULT hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&ptbl));
if (SUCCEEDED(hr)) {
// create 2 buttons
THUMBBUTTON thmb[2] = {};
thmb[0].dwMask = THB_TOOLTIP;
thmb[0].iId = 0;
wcscpy_s(thmb[0].szTip, L"Button 1");
thmb[1].dwMask = THB_TOOLTIP;
thmb[1].iId = 1;
wcscpy_s(thmb[1].szTip, L"Button 2");
//ptbl->HrInit();
hr = ptbl->ThumbBarAddButtons(hwnd, ARRAYSIZE(thmb), thmb);
ptbl->Release();
return hr;
}
else {
throw std::exception("createInstance failed");
}
}else{
throw std::exception("coinitialize failed");
}
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"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
);
if (hwnd == NULL)
{
return 0;
}
HRESULT hr = addThumbnailButtons(hwnd);
if (FAILED(hr)) {
throw std::exception("addbuttons failed");
}
ShowWindow(hwnd, nCmdShow);
// Run the message loop.
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_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);
}
Per the ITaskBarList3 documentation:
When an application displays a window, its taskbar button is created by the system. When the button is in place, the taskbar sends a TaskbarButtonCreated message to the window. Your application should call RegisterWindowMessage(L"TaskbarButtonCreated") and handle that message in its wndproc. That message must be received by your application before it calls any ITaskbarList3 method.
You must wait for that message before calling addThumbnailButtons(), eg:
UINT uMsgTaskbarCreated;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
uMsgTaskbarCreated = RegisterWindowMessage(L"TaskbarButtonCreated");
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"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
);
if (hwnd == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
// Run the message loop.
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_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;
}
default:
if ((uMsg == uMsgTaskbarCreated) && (uMsgTaskbarCreated != 0))
{
HRESULT hr = addThumbnailButtons(hwnd);
if (FAILED(hr)) {
...;
}
}
break;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Hello all I have been trying to paint to my child window outside of WM_PAINT and Instead of painting on the child window it paints off of the window onto the screen I think it may be because of the location of x and y but shouldn't point (0,0) be the top left of the child window not of my actual screen?
Here is what the code I wrote to try to paint onto the child window:
#pragma warning(disable:4996)
#pragma comment(lib, "Ws2_32.lib")
#include <Windows.h>
#define WIDTH 800
#define HEIGHT 600
#define CLASS_NAME "Class"
#define IDC_MAIN_EDIT 101
#define IDC_WINDOW 102
int x = 0, y = 0;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void print_line(HWND hwnd, char *Msg);
void Println();
int Run();
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcex = { 0 };
MSG msg;
HWND hwnd = NULL;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = CLASS_NAME;
wcex.hInstance = hInstance;
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wcex))
{
MessageBoxA(NULL, "Failed to register class", "Error", MB_OK | MB_ICONERROR);
return -1;
}
hwnd = CreateWindow(CLASS_NAME //Name of the window class
, CLASS_NAME//Title of the window
, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN// the window style
, 0 //x Postition of the window
, 0// y position of the windpo
, WIDTH, HEIGHT, // Width and Height
NULL,//Parent window(we have no parent window)
NULL,//Menu(we are not using menu's)
hInstance,//application handle
NULL);//Creates the window
if (!hwnd)
{
MessageBoxA(NULL, "Failed to register class", "Error", MB_OK | MB_ICONERROR);
return -2;
}
ShowWindow(hwnd, nCmdShow);
return Run();
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HWND hEdit = NULL;
HWND hWindow = NULL;
#define Print(msg2) print_line(hWindow, msg2)
switch (msg)
{
case WM_CREATE:
hWindow = CreateWindowEx(WS_EX_CLIENTEDGE, "Window", "",
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOHSCROLL | WS_CLIPSIBLINGS,
0, 0, WIDTH, HEIGHT - 25, hwnd, (HMENU)IDC_WINDOW, GetModuleHandle(NULL), NULL);
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "",
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOHSCROLL,
0, 535, WIDTH, 25, hwnd, (HMENU)IDC_MAIN_EDIT, GetModuleHandle(NULL), NULL);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
Print("Hello");
break;
default:
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
}
int Run()
{
MSG msg = { 0 };
WSAData wsa;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsa) != 0) return -1;
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
void print_line(HWND hwnd, char *Msg)
{
HDC hdc;
hdc = GetDC(hwnd);
TextOut(hdc,
x,
y,
Msg,
strlen(Msg));
ReleaseDC(hwnd, hdc);
}
void Println()
{
x = 0;
y += 20;
}
Yes I know there are other questions concerning this topic but none of them seemed to answer my question or address any of the problems I have been experiencing while trying to paint on the child window.
It Seems to me you create your windows in WndProc, but they do not get returned, so both windows created in WndProc end up being NULL when WM_CREATE returns (AS the are only declared in WndProc).
Perhaps you need to set these both to globals, the use for example GetDC(hEdit) to draw to them. Overall it still looks like an odd bit of code.
It seems to me that you want to write text to the edit control you created with id=IDC_MAIN_EDIT by manually drawing the text into the control?
Try
case WM_COMMAND:
//Print("Hello");
hEdit = GetDlgItem(hwnd, IDC_MAIN_EDIT); // get handle to edit window
if (hEdit != NULL) // did we get a handle to the edit window?
{
int len = GetWindowTextLength(hEdit);
SendMessage(hEdit , EM_SETSEL, len, len); // select end of contents
SendMessage(hEdit , EM_REPLACESEL, 0, (LPARAM)"Hello"); // replace end with new textt
}
break;
and the edit control will draw the text for you.
If you want to manually write the text to the window created by you modify the Print macro as follows:
#define Print(msg2) print_line(hwnd, msg2)