I am a little new to C++, so I am starting out with a text editor program. I am developing this project in NetBeans IDE. Currently the application is all in the main source file. When I compile and run the project, I get no errors and the project proceeds to function.
However, I have some sort of error or bug that lies within the application as it is running. This bug is associated with the Edit Control and the GetWindowText() method. The problem is located in the saveFile() function. What I am making of the GetWindowText() function is to test to see if I can retrieve text from the Edit Control and use it for my needs. I tried to emulate it through a simple MessageBox() function, and I got nothing.
Source code [FULL]:
/*
* File: main.cpp
* Author: CA1K
*
* Created on November 1, 2015, 9:58 PM
*/
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <string>
using namespace std;
// [ PROGRAM PROCEDURES ]
//=========================================================
/*Really what these are used for is to address conditions to
*the WS_COMMAND case, these are registered as integers
*/
#define IDC_MAIN_EDIT 0//edit ID
#define EXIT_PROC 1//the exit procedure
#define ABOUT_PROC 2//the trigger for the "about" window
#define CLONE_PROC 3//spawn a new window
#define SAVE_PROC 4//save procedure
#define OPEN_PROC 5//copy procedure
//=========================================================
// [ DEVELOPER FRIENDLY VARIABLES ]
//=========================================================
const char g_szClassName[] = "CPadx1"; //window class name
const char g_Title[] = "CPad"; //window title
const char g_About[] = "CPad is a program developed by CA1K. It is entirely made from the win32 API. For more programs, go to ca1k.xkotto.com.";
int dim = 600;//window dimensions(square)
TCHAR buffer[512];
//=========================================================
// [ OBJECT BUILDING ]
//=========================================================
void makeMenu(HWND hwnd){
HMENU hMenubar;
HMENU hMenu;
HMENU hMenu2;
hMenubar = CreateMenu();
hMenu = CreateMenu();
hMenu2 = CreateMenu();
AppendMenuW(hMenu, MF_STRING, SAVE_PROC, L"&Save/Save as");
AppendMenuW(hMenu, MF_STRING, OPEN_PROC, L"&Open file");
AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
AppendMenuW(hMenu, MF_STRING, CLONE_PROC, L"&New Window");
AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
AppendMenuW(hMenu, MF_STRING, ABOUT_PROC, L"&About");
AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR)hMenu, L"&File");
AppendMenuW(hMenu2, MF_STRING, EXIT_PROC, L"&Exit");
AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR)hMenu2, L"&Config");
SetMenu(hwnd, hMenubar);
}
void dispWnd(HWND hwnd){//this function spawns a new window
HINSTANCE hInstance;
HWND newChild = CreateWindowEx(0, g_szClassName, g_Title, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, dim, dim, hwnd, NULL, hInstance, NULL);
HWND GetParent(HWND hwnd);
ShowWindow(newChild, 1);
UpdateWindow(newChild);
}
void makeEdit(HWND hwnd, HWND hEdit){//this function creates the edit
HINSTANCE hInstance;
RECT rect;
int pwidth;
int pheight;
if(GetWindowRect(hwnd, &rect))
{
pwidth = rect.right - rect.left;
pheight = rect.bottom - rect.top;
}
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT","",
WS_CHILD|WS_VISIBLE|ES_AUTOVSCROLL|ES_AUTOHSCROLL|ES_MULTILINE,
0,0,pwidth,pheight,hwnd,(HMENU)IDC_MAIN_EDIT,
hInstance,NULL);
}
void saveFile(HWND hEdit){
GetWindowText(hEdit, buffer, 512);
MessageBox(NULL, buffer, "Test", MB_ICONINFORMATION);
}
//=========================================================
// [ SOFTWARE PROCESSING ]
//=========================================================
// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HWND winEdit;
switch(msg)
{
/*WINDOW ACTIONS*/
case WM_CREATE:{//on window creation
makeMenu(hwnd);
makeEdit(hwnd,winEdit);
}
break;
case WM_SIZE:
makeEdit(hwnd,winEdit);
break;
case WM_COMMAND://window actions
switch(LOWORD(wParam))
{
case ABOUT_PROC:
MessageBox(NULL, g_About, "About", MB_ICONINFORMATION);
break;
case EXIT_PROC:
PostQuitMessage(0);//exit program
break;
case CLONE_PROC:
dispWnd(hwnd);
break;
case SAVE_PROC:
saveFile(winEdit);
break;
}
break;
case WM_CLOSE://on window close
DestroyWindow(hwnd);
break;
case WM_DESTROY://on window destroy
PostQuitMessage(0);
break;
default://default method
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
g_Title,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, dim, dim,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
//=========================================================
I am questioning whether I have the scopes wrong, or something else. Feed back would be much appreciated.
-CA1K
You need to make winEdit a static variable. This is because you use it in more than one message, like WM_CREATE and WM_COMMAND. Then, you need to pass a pointer to an HWND to your makeEdit function:
makeEdit(hwnd, &winEdit);
So your overall window procedure should look like this:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND winEdit;
switch(msg)
{
/*WINDOW ACTIONS*/
case WM_CREATE:{//on window creation
makeMenu(hwnd);
makeEdit(hwnd, &winEdit);
}
break;
case WM_SIZE:
makeEdit(hwnd,winEdit);
break;
case WM_COMMAND://window actions
switch(LOWORD(wParam))
{
case ABOUT_PROC:
MessageBox(NULL, g_About, "About", MB_ICONINFORMATION);
break;
case EXIT_PROC:
PostQuitMessage(0);//exit program
break;
case CLONE_PROC:
dispWnd(hwnd);
break;
case SAVE_PROC:
saveFile(winEdit);
break;
}
break;
case WM_CLOSE://on window close
DestroyWindow(hwnd);
break;
case WM_DESTROY://on window destroy
PostQuitMessage(0);
break;
default://default method
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
Related
I have a simple example for creating popup menu. I want to close this menu programmatically when pressing on button, is there any possibility to do that? Or maybe I should use different class?
I need to open this menu when button is pressed and close it the same way when pressing the button. Here is simple code example that I have.
#define MAX_LOADSTRING 100
#define IDM_FILE_NEW 1
#define IDM_FILE_OPEN 2
#define IDM_FILE_QUIT 3
#define BUTTON_ID 1
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
HWND gButton = NULL;
HWND mainHwnd = NULL;
HMENU hMenu;
bool gMenuHidden = false;
// 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);
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_POPUPMENU, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_POPUPMENU));
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;
}
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_POPUPMENU));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
mainHwnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!mainHwnd)
{
return FALSE;
}
ShowWindow(mainHwnd, nCmdShow);
UpdateWindow(mainHwnd);
return TRUE;
}
HMENU CreateAndInitializeMenu()
{
HMENU menu = CreatePopupMenu();
AppendMenuW(menu, MF_STRING, IDM_FILE_NEW, L"&New");
AppendMenuW(menu, MF_STRING, IDM_FILE_OPEN, L"&Open");
AppendMenuW(menu, MF_SEPARATOR, 0, NULL);
AppendMenuW(menu, MF_STRING, IDM_FILE_QUIT, L"&Quit");
return menu;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_COMMAND:
{
if (wParam == BUTTON_ID)
{
//gMenuHidden = !gMenuHidden;
if (gMenuHidden)
{
hMenu = CreateAndInitializeMenu();
TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, 150, 250, 0, mainHwnd, NULL);
DestroyMenu(hMenu);
}
else
{
// TODO:
}
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_CREATE:
{
gButton = CreateWindowW(L"button", L"Show/Hide menu", WS_VISIBLE | WS_CHILD, 100, 120, 120, 25, hWnd, (HMENU)BUTTON_ID, NULL, NULL);
break;
}
}
return DefWindowProcW(hWnd, message, wParam, lParam);
}
Maybe the right way is to always create menu when button is pressed and destroy it right after that? But in that case we should create menu all the time when pressing the button. I was trying to create the menu once and show it when we need it. Also the menu is not shown right now. Trying to figure out why.
Thanks in advance.
First, you can certainly avoid repeating the creation/destruction of your popup menu: just create it (once) on window creation (by handling the WM_CREATE message) and destroy it when handling WM_DESTROY. But note: you will need to make your hMenu a static variable, so that its value is maintained across multiple calls of your WndProc function.
As for hiding the menu programmatically – you can do this by sending the parent window the WM_CANCELMODE message, as suggested in this related question: How to CLOSE a context menu after a timeout?
You can keep a 'flag' variable (also must be static) to keep track of the current display status of the popup menu: if this is not shown, call TrackPopupMenu; if it is shown, send the WM_CANCELMODE message. You will also need to add the TPM_RETURNCMD flag in your call to TrackPopupMenu, so that you can reset the flag if/when the user selects a command from the menu.
Here's a version of your WndProc function that implements this approach:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HMENU hMenu; // Make "static" so we can reuse across calls
static bool hasMenu = false; // Flag to indicate current menu status
POINT point;
switch (msg) {
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDM_FILE_NEW:
case IDM_FILE_OPEN:
MessageBeep(MB_ICONINFORMATION);
break;
case IDM_FILE_QUIT:
SendMessage(hwnd, WM_CLOSE, 0, 0);
break;
}
break;
case WM_CREATE:
// Create the menu (once only) on window creation...
hMenu = CreatePopupMenu();
AppendMenuW(hMenu, MF_STRING, IDM_FILE_NEW, L"&New");
AppendMenuW(hMenu, MF_STRING, IDM_FILE_OPEN, L"&Open");
AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
AppendMenuW(hMenu, MF_STRING, IDM_FILE_QUIT, L"&Quit");
hasMenu = false; // Reset here in case of multiple uses.
break;
case WM_RBUTTONUP:
if (!hasMenu) { // Only show menu if it's not already active...
hasMenu = true;
point.x = LOWORD(lParam);
point.y = HIWORD(lParam);
ClientToScreen(hwnd, &point);
// Add the "TPM_RETURNCMD" flag so we can reset "hasMenu" when a command is sselected (return non-zero):
BOOL cmd = TrackPopupMenu(hMenu, TPM_RIGHTBUTTON | TPM_RETURNCMD, point.x, point.y, 0, hwnd, NULL);
if (cmd) {
hasMenu = false;
SendMessage(hwnd, WM_COMMAND, cmd, 0); // Send the command (not done automatically with TPM_RETURNCMD)
}
}
else {
hasMenu = false;
SendMessage(hwnd, WM_CANCELMODE, 0, 0);
}
break;
case WM_DESTROY:
DestroyMenu(hMenu); // Destroy the menu.
PostQuitMessage(0);
break;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
When I add a menubar to a window, the window didn't resize accordingly because the top portion is hidden by the menubar. I want to resize the window while taking account of menubar's height. This is what I tried.
/* g++ test.cpp -o test -Wl,-subsystem,windows */
#include <Windows.h>
#define ID_OPEN 0
#define ID_EXIT 1
#define ID_ABOUT 2
const int width = 500;
const int height = 400;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szWndClassName[] = TEXT("hellowin");
HWND hWnd;
MSG msg;
WNDCLASS wndclass;
//Step 1: Registering the Window Class
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) COLOR_BACKGROUND;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szWndClassName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program only works in Windows NT or greater!"), TEXT("Hey dude!"), MB_OK | MB_ICONERROR);
return 1;
}
// Step 2: Creating the Window
hWnd = CreateWindow(szWndClassName, /* window class name */
TEXT("Hey!"), /* window title (or caption) */
WS_OVERLAPPEDWINDOW, /* window style */
CW_USEDEFAULT, /* initial x position */
CW_USEDEFAULT, /* initial y position */
width, /* initial window width */
height, /* initial window height */
NULL, /* parent window handle */
NULL, /* window menu handle */
hInstance, /* program instance handle */
NULL); /* creation parameters */
if (hWnd == NULL)
{
MessageBox(NULL, TEXT("Window Creation Failed!"), TEXT("Error!"),
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd);
// Step 3: The Message Loop (heart)
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
// Step 4: the Window Procedure (brain)
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
HMENU hMenuBar = CreateMenu();
HMENU hFile = CreatePopupMenu();
HMENU hHelp = CreatePopupMenu();
AppendMenu(hMenuBar, MF_POPUP, (UINT_PTR) hFile, "File");
AppendMenu(hMenuBar, MF_POPUP, (UINT_PTR) hHelp, "Help");
AppendMenu(hFile, MF_STRING, ID_OPEN, "Open");
AppendMenu(hFile, MF_STRING, ID_EXIT, "Exit");
AppendMenu(hHelp, MF_STRING, ID_ABOUT, "About");
SetMenu(hWnd, hMenuBar);
PMENUBARINFO pmbi;
GetMenuBarInfo(hWnd, OBJID_MENU, 0, pmbi);
RECT menuRect;
RECT windRect;
GetWindowRect(pmbi->hwndMenu, &menuRect);
GetWindowRect(hWnd, &windRect);
int width = menuRect.right - menuRect.left;
int height = (menuRect.bottom - menuRect.top) + (windRect.bottom - windRect.top);
SetWindowPos(hWnd,
0,
0,
0,
width,
height,
SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER);
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT rect;
GetClientRect(hWnd, &rect);
DrawText(hdc, TEXT("Hello World!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hWnd, &ps);
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
I tried to retrieve rectangles of both menubar and the window and calculate the new dimension like this
int width = menuRect.right - menuRect.left;
int height = (menuRect.bottom - menuRect.top) + (windRect.bottom - windRect.top);
Unfortunately the code crashes. I have no idea which part I did wrong. Any ideas?
pmbi is an uninitialised pointer variable. Passing it to GetMenuBarInfo is therefore the likely cause of your crash. If that doesn't crash, then attempting to access pmbi->hwndMenu probably will.
Instead, you want:
MENUBARINFO mbi;
mbi.cbSize = sizeof (mbi); // see documentation
GetMenuBarInfo(hWnd, OBJID_MENU, 0, &mbi);
...
which tells GetMenuBarInfo to fill in the (stack-based) variable mbi.
Then replace pmbi->hwndMenu with mbi.hwndMenu and that should fix your problem.
I'm trying to add some application controls into my Windows API code (Note: I am using Visual Studio) I am experiencing a problem where I try to add in a CreateWindowW() function that generates text and a field ("static" and "edit") and a menu at the same time. The menu works fine on its own ("Calculations"):
However, adding the CreateWindow() function "erases" the menu entirely but yields the CreateWindowW() outputs (also flickers a bit):
The code I have right now is this (the menu function and the CreateWindowW() functions are at the bottom):
#define MAX_LOADSTRING 100
#define FILE_MENU_DESTROY 1
#define FILE_MENU_ABOUT 2
// 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);
//Custom Application Function Forwrd Declarations
void WinControls(HWND);
void WinMenu(HWND);
HMENU hMenu;
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_RANKTOOLADVANCED, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance); //Generates an instance of a window class
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_RANKTOOLADVANCED));
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)//Class properties of the window
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc; //assigns a window to the instance of the class
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance; //creates an instance
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_RANKTOOLADVANCED));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); //defines a type of cursor (arrow, help, cross, etc.)
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_RANKTOOLADVANCED);
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)
{//initializes instance of window class (invocation)
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, L"test", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 900, 600, 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)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{/*
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
case FILE_MENU_NEW:
{
MessageBox(hWnd, L"task failed successfully", L"you done goofed", MB_OK | MB_ICONEXCLAMATION);
break;
}*/
case FILE_MENU_DESTROY:
{
DestroyWindow(hWnd);
break;
}
case FILE_MENU_ABOUT:
{
MessageBox(hWnd, L"about", L"About", MB_OK);
break;
}
break;
}
}
case WM_CREATE:
{
WinControls(hWnd);
WinMenu(hWnd);
break;
}/*
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
TextOut(hdc, 10, 10, rekt, _tcslen(rekt));
TextOut(hdc, 10, 40, reverse, _tcslen(reverse));
EndPaint(hWnd, &ps);
break;
}*/
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
void WinMenu(HWND hWnd) {
hMenu = CreateMenu();
HMENU hFileMenu = CreateMenu();
HMENU hSubMenu = CreateMenu();
HMENU hSubMenu2 = CreateMenu();
//XP Calculations
AppendMenuW(hSubMenu, MF_STRING, NULL, L"Rank -> XP");
AppendMenuW(hSubMenu, MF_STRING, NULL, L"XP -> Rank");
//Credit Calculations
AppendMenuW(hSubMenu2, MF_STRING, NULL, L"Rank -> Cred");
AppendMenuW(hSubMenu2, MF_STRING, NULL, L"Cred -> Rank");
AppendMenuW(hFileMenu, MF_POPUP, (UINT_PTR)hSubMenu, L"Points"); //option that popups submenu of hSubMenu
AppendMenuW(hFileMenu, MF_POPUP, (UINT_PTR)hSubMenu2, L"Credits"); //option that popups submenu of hSubMenu
AppendMenuW(hFileMenu, MF_SEPARATOR, NULL, NULL); // separator
AppendMenuW(hFileMenu, MF_STRING, FILE_MENU_ABOUT, L"About");
AppendMenuW(hFileMenu, MF_STRING, FILE_MENU_DESTROY, L"Exit"); // option
AppendMenuW(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, L"Calculations"); //popups up submenu of hFileMenu
SetMenu(hWnd, hMenu);
}
void WinControls(HWND hWnd) {
CreateWindowW(L"Static", L"Enter text here: ", WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER, 400, 100, 100, 50, hWnd, NULL, NULL, NULL);
CreateWindowW(L"Edit", L"...", WS_VISIBLE | WS_CHILD, 400, 155, 100, 50, hWnd, NULL, NULL, NULL);
}
Please do note that the setup is the Visual Studio basic setup for the program.
Any help is appreciated!
I have done some debugging and figured out it was that the CreateWindowW() I used for the static and edit controls was conflicting with the definition of the window properties.
Since the window was defined by WNDCLASSEXW wcex, I just had to change the CreateWindowW() with CreateWindowExW().
Only new problem is that the static control (and the others) works but not the edit control, which kills the menu.
I am learning how to use WinAPI with C++, and am creating an application which at the moment just has a basic edit control for someone to enter their username.
void AddMenus(HWND hWnd)
{
hMenu = CreateMenu();
hSubMenu = CreateMenu();
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hSubMenu, L"File");
AppendMenu(hSubMenu, MF_STRING, FILE_MENU_EXIT, L"Exit");
SetMenu(hWnd, hMenu);
}
void AddControls(HWND hWnd)
{
hUNameS = CreateWindowW(L"static", L"Username: ", WS_VISIBLE | WS_CHILD | ES_CENTER,
100, 50, 100, 25, hWnd, NULL, NULL, NULL);
hUName = CreateWindowW(L"edit", L" ", WS_VISIBLE | WS_CHILD | WS_BORDER,
202, 50, 100, 25, hWnd, NULL, NULL, NULL);
}
When using the following block of code to create the window, both the controls and the menu don't appear.
case WM_CREATE:
AddControls(hWnd);
AddMenus(hWnd);
break;
If I comment out the AddControls, then the menu appears fine, but if I leave them both as shown, then the menu doesn't appear. Nothing changes if I swap the order of the function calls.
Both the menu and the controls appear if I set the second parameter of the edit control to NULL, but then I get a different problem, where any text I type in the control is invisible until I click it, and then disappears again when I continue to type. The only way I have found to fix this is by having a placeholder which then removes the menu.
TLDR: I can't get both the menu and controls to appear at the same time, and without the second parameter of the edit control being set, then text is invisible to start with.
The code of your first question:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case FILE_MENU_DESTROY:
{
DestroyWindow(hWnd);
break;
}
case FILE_MENU_ABOUT:
{
MessageBox(hWnd, L"about", L"About", MB_OK);
break;
}
break; //this break will not break outside case WM_COMMAND, but only break outside the switch (wmId).
}
}
case WM_CREATE:
AddControls(hWnd);
AddMenus(hWnd);
break;
...
}
need to move the break; above the WM_CREATE to break WM_COMMAND case. Otherwise, when you createwindow and receive WM_COMMAND, WinMenu(AddMenus for this case) will be executed multiple times. I can reproduce with this code.
Modify to:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case FILE_MENU_DESTROY:
{
DestroyWindow(hWnd);
break;
}
case FILE_MENU_ABOUT:
{
MessageBox(hWnd, L"about", L"About", MB_OK);
break;
}
}
}
break;
case WM_CREATE:
AddControls(hWnd);
AddMenus(hWnd);
break;
...
}
This works for me, and the whole project:
#define MAX_LOADSTRING 100
#define FILE_MENU_DESTROY 1
#define FILE_MENU_ABOUT 2
// 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);
//Custom Application Function Forwrd Declarations
void WinControls(HWND);
void WinMenu(HWND);
HMENU hMenu;
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_RANKTOOLADVANCED, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance); //Generates an instance of a window class
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_RANKTOOLADVANCED));
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)//Class properties of the window
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc; //assigns a window to the instance of the class
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance; //creates an instance
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_RANKTOOLADVANCED));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); //defines a type of cursor (arrow, help, cross, etc.)
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_RANKTOOLADVANCED);
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)
{//initializes instance of window class (invocation)
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, L"test", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 900, 600, 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
//
//
void AddMenus(HWND hWnd)
{
hMenu = CreateMenu();
HMENU hSubMenu = CreateMenu();
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hSubMenu, L"File");
AppendMenu(hSubMenu, MF_STRING, FILE_MENU_DESTROY, L"Exit");
SetMenu(hWnd, hMenu);
}
void AddControls(HWND hWnd)
{
HWND hUNameS = CreateWindowW(L"static", L"Username: ", WS_VISIBLE | WS_CHILD | ES_CENTER,
100, 50, 100, 25, hWnd, NULL, NULL, NULL);
HWND hUName = CreateWindowW(L"edit", L" ", WS_VISIBLE | WS_CHILD | WS_BORDER,
202, 50, 100, 25, hWnd, NULL, NULL, NULL);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{/*
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
case FILE_MENU_NEW:
{
MessageBox(hWnd, L"task failed successfully", L"you done goofed", MB_OK | MB_ICONEXCLAMATION);
break;
}*/
case FILE_MENU_DESTROY:
{
DestroyWindow(hWnd);
break;
}
case FILE_MENU_ABOUT:
{
MessageBox(hWnd, L"about", L"About", MB_OK);
break;
}
}
}
break;
case WM_CREATE:
AddControls(hWnd);
AddMenus(hWnd);
break;
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
I am new to Win32 API and trying to learn it. I was successful to create a window and it works perfectly.
I added a button to it and want to show a message box when clicked. The button works perfectly but the message box in WM_COMMAND does not appear at all and the code below message box does not get executed as well.
I have checked online for how to do it and it seems to work for them but not me.
Here is the code
#include <Windows.h>
#include <tchar.h>
#include <stdlib.h>
#include <string.h>
WNDCLASSEX wcex;
static TCHAR szWindowClass[] = _T("DesktopApp");
static TCHAR szTitle[] = _T("First Application");
HINSTANCE hInst;
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int CALLBACK WinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPSTR lpCmdLine,_In_ int nCmdShow)
{
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, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL, _T("Call to Register Failed"), _T("Windows Desktop Guided Tour"), NULL);
return 1;
}
hInst = hInstance;
HWND hwnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, NULL, NULL, hInstance, NULL);
if (!hwnd)
{
MessageBox(NULL, _T("Failed to create a window"), _T("Windows Desktop Guided Tour"), NULL);
return 1;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
HWND button;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Hello world! This is the first ever application window created by dumb Bhavin.");
switch (message)
{
case WM_CREATE:
button = CreateWindow(_T("BUTTON"),_T("1") ,WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 100, 40, 50, 30, hWnd, (HMENU)1, NULL, NULL);
break;
//////////////////////////////////THIS IS WHERE THE ISSUE IS///////////////////////////////////////////
case WM_COMMAND:
{
if (LOWORD(wParam) == 1)
{
OutputDebugString(_T("The compiler executes this! That means the button is working"));
MessageBox(NULL, L"Here it is", L"ok", NULL); //Message box does not appear at all. The code below it does not execute at all.
OutputDebugString(_T("The compiler DOES NOT execute this!"));
}
break;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
case WM_PAINT:
// hdc = BeginPaint(hWnd, &ps);
// TextOut(hdc, 5, 5, greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
Edit 1:
Here is a small video of what exactly happens.
Error Video
Note : I passed hWnd parameter in this instead of NULL. Passing hWnd as first Parameter does not help either.
The issue was my half-implemented WM_Paint. Uncommenting the BeginPaint line solves the problem.
or, passing it directly to DefWindowProc as return DefWindowProc(hWnd, message, wParam, lParam); works too.