so a quick rundown of the Win32 app I'm making. It's basically supposed to change refresh rate between 60 and 144 Hz based on whether or not the laptop is plugged in. When I launch the app, the GUI starts but it crashes. I'll post the code and debug below.
#ifndef UNICODE
#define UNICODE
#define UNICODE_WAS_UNDEFINED
#endif
#include <Windows.h>
#ifdef UNICODE_WAS_UNDEFINED
#undef UNICODE
#endif
#include <iostream>
using namespace std;
BOOL checked = FALSE;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MSG msg;
WNDCLASS wc = { 0 };
wc.lpszClassName = L"autoRefresh";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClass(&wc);
HWND hWnd = CreateWindowW(wc.lpszClassName, L"Refresh Changer", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 860, 540, 500, 150, 0, 0, hInstance, 0);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
RegisterPowerSettingNotification(hWnd, &GUID_ACDC_POWER_SOURCE, DEVICE_NOTIFY_WINDOW_HANDLE);
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
DEVMODE dm;
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm);
switch (msg) {
case WM_CREATE: {
CreateWindow(TEXT("button"), TEXT("Enable automatic refresh rate changer (Will run at startup)"), WS_VISIBLE | WS_CHILD | BS_CHECKBOX, 20, 20, 500, 35, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
CheckDlgButton(hwnd, 1, BST_UNCHECKED);
break;
}
case WM_COMMAND: {
OutputDebugStringW(L"WM_COMMAND case\n");
checked = IsDlgButtonChecked(hwnd, 1);
if (checked) {
OutputDebugStringW(L"Box unchecked\n");
CheckDlgButton(hwnd, 1, BST_UNCHECKED);
checked = FALSE;
}
else {
OutputDebugStringW(L"Box checked\n");
CheckDlgButton(hwnd, 1, BST_CHECKED);
checked = TRUE;
}
break;
}
case WM_POWERBROADCAST: {
OutputDebugStringW(L"WM_BROADCAST case\n");
if (checked) {
OutputDebugStringW(L"WM_BROADCAST checked is TRUE\n");
//std::wstring progPath = L"C:\\Users\\user\\AppData\\Roaming\\Microsoft\\Windows\\RefreshChanger.exe";
//HKEY hkey = NULL;
//LONG createStatus = RegCreateKey(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", &hkey); //Creates a key
//LONG status = RegSetValueEx(hkey, L"RefreshChanger", 0, REG_SZ, (BYTE*)progPath.c_str(), (progPath.size() + 1) * sizeof(wchar_t));
SYSTEM_POWER_STATUS powerStatus;
GetSystemPowerStatus(&powerStatus);
if (powerStatus.ACLineStatus == 1) {
OutputDebugStringW(L"Refresh rate before changing: " + dm.dmDisplayFrequency);
dm.dmDisplayFrequency = 144;
LONG ret = ChangeDisplaySettingsEx(NULL, &dm, NULL, 0, NULL);
OutputDebugStringW(L"ChangeDisplaySettingsEx returned " + ret);
if (0 != EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm)) {
OutputDebugStringW(L"Refresh rate after changing: " + dm.dmDisplayFrequency);
}
switch (ret) {
case DISP_CHANGE_SUCCESSFUL:
OutputDebugStringW(L"Display successfully changed\n");
break;
case DISP_CHANGE_BADDUALVIEW:
OutputDebugStringW(L"The settings change was unsuccessful because the system is DualView capable\n");
break;
case DISP_CHANGE_BADFLAGS:
OutputDebugStringW(L"An invalid set of flags was passed in.\n");
break;
case DISP_CHANGE_BADMODE:
OutputDebugStringW(L"The graphics mode is not supported.\n");
break;
case DISP_CHANGE_BADPARAM:
OutputDebugStringW(L"An invalid parameter was passed in. This can include an invalid flag or combination of flags.\n");
break;
case DISP_CHANGE_FAILED:
OutputDebugStringW(L"The display driver failed the specified graphics mode.\n");
break;
case DISP_CHANGE_NOTUPDATED:
OutputDebugStringW(L"Unable to write settings to the registry.\n");
break;
case DISP_CHANGE_RESTART:
OutputDebugStringW(L"The computer must be restarted for the graphics mode to work.\n");
break;
}//switch
}
else {
OutputDebugStringW(L"WM_BROADCAST checked is FALSE\n");
OutputDebugStringW(L"Refresh rate before changing: " + dm.dmDisplayFrequency);
dm.dmDisplayFrequency = 60;
LONG ret = ChangeDisplaySettingsEx(NULL, &dm, NULL, 0, NULL);
OutputDebugStringW(L"ChangeDisplaySettingsEx returned " + ret);
if (0 != EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm)) {
OutputDebugStringW(L"Refresh rate after changing: " + dm.dmDisplayFrequency);
}
switch (ret) {
case DISP_CHANGE_SUCCESSFUL:
OutputDebugStringW(L"Display successfully changed\n");
break;
case DISP_CHANGE_BADDUALVIEW:
OutputDebugStringW(L"The settings change was unsuccessful because the system is DualView capable\n");
break;
case DISP_CHANGE_BADFLAGS:
OutputDebugStringW(L"An invalid set of flags was passed in.\n");
break;
case DISP_CHANGE_BADMODE:
OutputDebugStringW(L"The graphics mode is not supported.\n");
break;
case DISP_CHANGE_BADPARAM:
OutputDebugStringW(L"An invalid parameter was passed in. This can include an invalid flag or combination of flags.\n");
break;
case DISP_CHANGE_FAILED:
OutputDebugStringW(L"The display driver failed the specified graphics mode.\n");
break;
case DISP_CHANGE_NOTUPDATED:
OutputDebugStringW(L"Unable to write settings to the registry.\n");
break;
case DISP_CHANGE_RESTART:
OutputDebugStringW(L"The computer must be restarted for the graphics mode to work.\n");
}//switch
}//if/else
}//if checked
}//case
case WM_DESTROY: {
OutputDebugStringW(L"WM_DESTROY case\n");
PostQuitMessage(0);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
And here's a screenshot of the debug console:
When I unplug the charger, the GUI crashes. It will run from being unplugged, but it also crashes when I plug the charger in. The refresh rate isn't changed and WM_DESTROY gets called, even though I'm not clicking the X at the top of the window. I'm super new to Win32 so I'm sorry if I'm missing something super simple. My background is primarily in Android development. Thanks for any help!
You're not breaking out of your outer switch/case so you're falling through into the WM_DESTROY case.
Related
I am testing out a thoery for the Combobox for win32. Many things have been tried but I am not understanding how to make it do what I want it to do. When the selection is made in the combo box I want it to print into the edit box. I believe this would be done through the handle maybe.
So if I add it to my button 1 through a cast for button 1 how do you get it to print out to the edit field??
My code is below. I left in some of the things I tried but commented it out. The problem is in add controls and I am thinking my switch and case.
I am missing that one part that populate the text to the edit box.
I am not so much new to programming so much as new to this type of programming. I am looking for a simple approach. Thanks in advance for your time.
Below is the updated code and what I got for now. I followed the guidelines for unicode. I even made friends with visual studio c++(I think).
#include <windows.h>
#include <tchar.h>
#include <iostream>
using namespace std;
#define OPTINBT1 1
#define OPTINBT2 2
#define COMBO1 3
HWND hWnd, hComboOne;
void addControl(HWND);
LPCWSTR egClassName = L"myWindowClass";
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int nCmdShow)
{
WNDCLASSW wc = { 0 };
wc.lpszClassName = egClassName;
wc.lpfnWndProc = WindowProcedure;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hInstance = hInst;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
if (!RegisterClassW(&wc))
{
const wchar_t Error01[] = L"Register Issue To Check On : ";
const wchar_t Error01_Caption[] = L"Error 01";
MessageBoxW(hWnd, Error01, Error01_Caption, MB_OK | MB_ICONERROR);
return 0;
}
LPCWSTR parentWinTitle = L"My Window";
hWnd = CreateWindowW(egClassName, parentWinTitle, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 500, 500, NULL, NULL, NULL, NULL);
if (hWnd == NULL)
{
const wchar_t Error02[] = L"Window Creation Issue To Check On : ";
const wchar_t Error02_Caption[] = L"Window Creation Issue To Check On : ";
MessageBoxW(hWnd, Error02, Error02_Caption, MB_OK | MB_ICONERROR);
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_CREATE:
addControl(hWnd);
break;
case WM_COMMAND:
if (HIWORD(wp) == CBN_SELCHANGE)
{
if (LOWORD(wp) == COMBO1)
{
HWND hcombo = (HWND)lp;
LRESULT index = SendMessageW(hcombo, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
wchar_t buf[256];
SendMessageW(hcombo, (UINT)CB_GETLBTEXT, (WPARAM)index, (LPARAM)buf);
MessageBoxW(hWnd, buf, L"Good Example", 0);
}
break;
}
switch (LOWORD(wp))
{
case OPTINBT1:
MessageBoxW(hWnd, L"This is Radio button1: ", L"Radio Button 2 is good", MB_OK);
break;
case OPTINBT2:
MessageBoxW(hWnd, L"This is Radio button2: ", L"Radio Button 1 is good", MB_OK);
break;
default:break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wp, lp);
}
return 0;
}
void addControl(HWND hWnd)
{
HWND OptBt1, OptBt2;
const LPCWSTR cont1 = L"STATIC";
const LPCWSTR cont2 = L"COMBOBOX";
const LPCWSTR cont3 = L"BUTTON";
const LPCWSTR emptyS = L"";
const LPCWSTR bl = L"RButton 1";
const LPCWSTR b2 = L"RButton 2";
//Option buttons
OptBt1 = CreateWindowW(cont3, bl, WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON, 24, 8, 90, 25, hWnd, (HMENU)OPTINBT1, NULL, NULL);
OptBt2 = CreateWindowW(cont3, b2, WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON, 24, 40, 90, 25, hWnd, (HMENU)OPTINBT2, NULL, NULL);
SendMessage(OptBt1, BM_SETCHECK, BST_CHECKED, 0);
hComboOne = CreateWindowW(cont2, emptyS, WS_VISIBLE | WS_CHILD | CBS_DROPDOWN | CBS_HASSTRINGS | WS_VSCROLL, 77, 70, 150, 150, hWnd, (HMENU)COMBO1, 0, 0);
LPCWSTR ComboBoxItems[] = { L"Subject1", L"Subject2", L"Subject3",
L"Subject4", L"Subject5" };
/** Or the array way */
SendMessageW(hComboOne, CB_ADDSTRING, 0, (LPARAM)ComboBoxItems[0]);
SendMessageW(hComboOne, CB_ADDSTRING, 0, (LPARAM)ComboBoxItems[1]);
SendMessageW(hComboOne, CB_ADDSTRING, 0, (LPARAM)ComboBoxItems[2]);
SendMessageW(hComboOne, CB_ADDSTRING, 0, (LPARAM)ComboBoxItems[3]);
SendMessageW(hComboOne, CB_ADDSTRING, 0, (LPARAM)ComboBoxItems[4]);
}
WM_CREATE should be inserted before addControl.
In WM_COMMAND respond to CBN_SELCHANGE notification to detect combobox selection change.
When you show a message box you can use the handle of your own window MessageBox(hWnd,...). If you supply NULL as the handle then the message box becomes the child of desktop window, it behaves as if it is displayed in modeless mode.
switch(msg)
{
case WM_CREATE:
addControl(hWnd);
break;
case WM_COMMAND:
if(HIWORD(wp) == CBN_SELCHANGE)
{
if(LOWORD(wp) == COMBO1)
{
HWND hcombo = (HWND)lp;
int index = SendMessage(hcombo, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
char buf[256];
SendMessage(hcombo, (UINT)CB_GETLBTEXT, (WPARAM)index, (LPARAM)buf);
MessageBox(hWnd, buf, 0, 0);
}
break;
}
switch(LOWORD(wp))
{
case OPTINBT1:
MessageBox(hWnd, "This is Radio button1: ", "ComboBox Working??", MB_OK);
break;
case OPTINBT2:
MessageBox(hWnd, "This is Radio button2: ", "ComboBox Working??", MB_OK);
break;
default:break;
}
break;
Not related to your problem, but you are mixing Unicode (example L"EDIT") with ANSI (example "EDIT").
Window functions like CreateWindow are macros. In ANSI it is CreateWindowA, and in Unicode it is the wide function CreateWindowW
You are compiling your program in old ANSI mode. CreateWindow is a macro to CreateWindowA which needs ANSI input. CreateWindow("EDIT",...)
If you compile your program in Unicode, CreateWindow is a macro for the wide function CreateWindowW which uses Unicode parameter CreateWindow(L"EDIT",...)
If you create a project in Visual Studio it will default to the new Unicode standard. Use wide char (L"Text") and Unicode functions everywhere. I would recommend compiling the program with warning level 4. Make sure the program compiles with zero warnings.
You want to respond to the CBN_SELCHANGE message that is sent to your window procedure. In the case of WM_COMMAND the low word of wParam will contain the control ID, the high word will contain an optional command code.
That command code is critical for properly responding to combo box messages. You will want to respond to the CBN_SELCHANGE message by sending the combo box a CB_GETCURSEL and then CB_GETLBTEXTLEN and CB_GETLBTEXT, after that you can send your edit control a WM_SETTEXT with the retrieved text.
Alright so this code is pretty long over a short problem so I will kinda use <--- arrows to point it out for you, but down in my switch case WM_COMMAND:
I am kinda confused on using the return 0/ break.
return 0; seems to jump me outside of the whole WndProc function (skips over some code)
break; just breaks out of the switch statement but continues.
So does that mean I should use return 0; at the very end of my switch statement to prevent from moving on? Or is there something just wrong with my WM_MAXMININFO, because I never had that problem until after I changed the return 0 to break; The reason I ask is because once it hits WM_MAXMININFO I get a Access Violation. (That may be that cause of all of this).
// Win32Project2.cpp : Defines the entry point for the application.
#include "stdafx.h"
#include "Win32Project2.h"
#include <Windows.h>
#include <Windowsx.h>
#include <shellapi.h>
#include "ProcessFind.h"
#include <WinUser.h>
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#define BUTTON L"button"
#define szDefault L"Awaiting Commands..."
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdShow, int iCmdLine)
{
wchar_t szAppName[] = L"Game Launcher";
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hInstance = hInstance;
wndclass.lpszClassName = szAppName;
wndclass.lpszMenuName = NULL;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wndclass);
hwnd = CreateWindow(szAppName, L"GameLauncher v1.0", WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, 375, 100, NULL, NULL, hInstance, 0);
ShowWindow(hwnd, iCmdLine);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
static HWND hUserBox;
static HWND hWindowButton;
HBITMAP hImage = (HBITMAP)LoadImage(NULL, L"?C:\\Users\\chaos\\Desktop\\Capture.PNG", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_LOADTRANSPARENT);
switch (message)
{
case WM_CREATE:
CreateWindowEx(NULL, BUTTON, L"Check for process", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX , 5, 35, 150, 25, hwnd, (HMENU)2, NULL, NULL);
CreateWindow(BUTTON, L"Minecraft", WS_CHILD | WS_VISIBLE, 250, 5, 100, 25, hwnd, (HMENU)1, NULL, NULL);
CreateWindow(BUTTON, L"Options", WS_CHILD | WS_VISIBLE | WS_DISABLED, 250, 30, 100, 25, hwnd, (HMENU)3, NULL, NULL);
hUserBox = CreateWindow(L"static", L"Awaiting Commands...", WS_CHILD | WS_VISIBLE | WS_BORDER, 5, 5, 240, 25, hwnd, (HMENU) 2, NULL, NULL);
return 0;
case WM_COMMAND:
switch (LOWORD(wparam))
{
case 1:
{
wchar_t* szProccessToKill = new wchar_t[20];
GetWindowText(hUserBox, szProccessToKill, 20);
// Checking checked status on checkbox. (Say that 5 times fast lol)
if (IsDlgButtonChecked(hwnd, 2) == BST_CHECKED)
{
ProcessFind testFunction;
SetWindowText(hUserBox, L"Ending process");
Sleep(1000);
testFunction.EndProcess(L"java.exe");
SetWindowText(hUserBox, L"Launching Minecraft...");
Sleep(1000);
ShellExecute(NULL, L"open", L"MinecraftLauncher", NULL, L"C:\\Program Files (x86)\\Minecraft", 6);
SetWindowText(hUserBox, L"Minecraft has launched sucessfully!");
Sleep(1000);
SetWindowText(hUserBox, szDefault);
}
else if (IsDlgButtonChecked(hwnd, 2) == BST_UNCHECKED)
{
SetWindowText(hUserBox, L"Launching Minecraft...");
HINSTANCE ErrorCode = ShellExecute(NULL, L"open", L"C:\\Program Files (x86)\\Minecraft\\MinecraftLauncher", NULL, NULL, 1);
int ErrorCodeInt = (int)ErrorCode;
switch (ErrorCodeInt)
{
case 0:
MessageBox(NULL, L"The operating system is out of memory or resources.", L"Error", MB_OK | MB_ICONERROR);
break;
case ERROR_FILE_NOT_FOUND:
MessageBox(NULL, L"The specified file was not found.", L"Error", MB_OK | MB_ICONERROR);
break;
case ERROR_PATH_NOT_FOUND:
MessageBox(NULL, L"The specified path was not found.", L"Error", MB_OK | MB_ICONERROR);
break;
default:
SetWindowText(hUserBox, L"Minecraft has launched successfully");
Sleep(1500);
break;
}
SetWindowText(hUserBox, szDefault);
}
delete[] szProccessToKill;
break; <--- **If this is not a return 0;**
}
case 3:
{
break;
}
default:
break;
}
//Set Min / Max Width/Height size.
case WM_GETMINMAXINFO: <-- It will jump down here and give me an access violation error:
{
MINMAXINFO* MMI = (MINMAXINFO*)lparam;
MMI->ptMaxTrackSize.x = 375;
MMI->ptMaxTrackSize.y = 100;
MMI->ptMinTrackSize.x = 375;
MMI->ptMinTrackSize.y = 100;
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, message, wparam, lparam);
}
return 0;
}
I will kinda shorten it up straight to the problem for you guys:
SetWindowText(hUserBox, szDefault);
}
delete[] szProccessToKill;
break; <--- **If this is not a return 0;**
}
case 3:
{
break;
}
default:
break;
}
//Set Min / Max Width/Height size.
case WM_GETMINMAXINFO: <-- It will jump down here and give me an access violation error:
{
MINMAXINFO* MMI = (MINMAXINFO*)lparam;
MMI->ptMaxTrackSize.x = 375;
MMI->ptMaxTrackSize.y = 100;
MMI->ptMinTrackSize.x = 375;
MMI->ptMinTrackSize.y = 100;
return 0;
}
I'm a newbie to c++, and I'm stuck on displaying the window. I'm not getting any errors, but my Window is not displaying on the desktop. When I open the task manager, it appears under the 'Proccesses' tab. I haven't been finding any solutions to this problem, so any help is appreciated. Thanks! :)
**Note: I'm using Microsoft Visual Studio 2012
**Note: Not exactly a newbie to c++, but more to creating a win32 application
#include <Windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
static TCHAR WindowClass[] = L"Window";
LRESULT CALLBACK WindowProc(
HWND WinH,
UINT Msg,
WPARAM wParam,
LPARAM lParam
)
{
switch (Msg)
{
PAINTSTRUCT pntStruct;
static HDC hdc;
case WM_PAINT:
{
BeginPaint(
WinH,
&pntStruct
);
TextOut(hdc,
5, 5,
L"Hello, World!", _tcslen(L"Hello, World!"));
//pntStruct.rcPaint
EndPaint(
WinH,
&pntStruct
);
} break;
case WM_SIZE:
{
} break;
case WM_MOVE:
{
} break;
case WM_DESTROY:
{
} break;
case WM_CLOSE:
{
} break;
default:
{
return DefWindowProc(WinH, Msg, wParam, lParam);
} break;
case WM_ACTIVATEAPP:
{
if (WM_ACTIVATEAPP)
{
OutputDebugStringA("WM_ACTIVEAPP->TRUE");
}
else
{
OutputDebugStringA("WM_ACTIVEAPP->FALSE");
}
} break;
}
return 0;
};
int WINAPI WinMain(
HINSTANCE Window,
HINSTANCE PrevInstance,
LPSTR Cmd,
int CmdShow
)
{
WNDCLASSEX wclass;
//wclass.cbSize = sizeof(WNDCLASS);
wclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wclass.lpfnWndProc = WindowProc;
wclass.cbClsExtra = 0;
wclass.cbWndExtra = 0;
wclass.hInstance = Window;
//wclass.hIcon; TODO: CREATE ICON
//wclass.hCursor;
//wclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wclass.lpszMenuName = NULL;
wclass.lpszClassName = (LPCTSTR)WindowClass;
// HICON hIconSm;
RegisterClassEx(&wclass);
HWND CreateWin = CreateWindow(
WindowClass,
L"NAME OF WINDOW",
WS_VISIBLE | WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,//WIDTH:[TODO]->Make custom width to fit window
CW_USEDEFAULT,//HEIGHT:[TODO]->Make custom width to fit window
0,
0,
Window,
0
);
ShowWindow(CreateWin, CmdShow);
UpdateWindow(CreateWin);
MSG message;
while (GetMessage(&message, NULL, 0, 0) > 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
};
return 0;
};
There are lots of things wrong with this code.
You are declaring WindowClass as a TCHAR[], but initializing it with a wchar_t[]. Same thing with the lpString parameter of TextOut(). That will only work if UNICODE is defined for the project, otherwise you will get a compiler error. When you use TCHAR, you need to wrap string literals with the TEXT() macro so they use the correct character type. Otherwise, stop using TCHAR and just use Unicode APIs for everything. You only need to use TCHAR if your code needs to support both ANSI (Win9x/ME) and Unicode (NT4+) compilations. Nobody really supports Win9x/Me anymore, so new code should focus on just Unicode APIs.
You are not zeroing the contents of the WNDCLASSEX structure, so all of the fields that you have intentionally commented out and not assigned values to (most importantly, the cbSize field) will contain random values from the stack. That is likely to cause RegisterClassEx() to fail, which you are not checking for. To avoid this problem, ALWAYS zero out API structures before using them. This is especially important for structures that grow in size over time (when newer Windows releases introduce new structure fields). Such structures typically have a cbSize field so the API knows which version of the structure you are using, so you must provide an accurate value. And you need to zero out any unused fields so you do not get unexpected behavior from the API.
You are not checking if CreateWindow() fails, such as a side effect of RegisterClassEx() failing.
Your WindowProc() is supposed to pass unhandled messages to DefWindowProc(), but you are not doing that. Most of your case blocks are simply discarding messages so Windows cannot process them. Is that what you really want? I doubt it. In particular, the default behavior of DefWindowProc() for WM_CLOSE is to destroy the window, triggering the WM_DESTROY message.
Your WM_DESTROY handler is not calling PostQuitMessage() to put a WM_QUIT message into the calling thread's message queue so GetMessage() can return 0 to break your message loop and let the app exit.
Your WM_PAINT handler is not using the HDC that BeginPaint() provides to you, you are drawing using an uninitialized HDC variable.
With all of that said, try something more like this:
#include <Windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h> // Or: remove this
static TCHAR WindowClass[] = TEXT("Window");
// or: static WCHAR WindowClass[] = L"Window";
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_PAINT:
{
static const TCHAR* HelloWorld = TEXT("Hello, World!");
// or: const WCHAR* HelloWorld = L"Hello, World!";
PAINTSTRUCT pntStruct = {0};
HDC hdc = BeginPaint(hWnd, &pntStruct);
TextOut(hdc, 5, 5, HelloWorld, _tcslen(HelloWorld));
// or: TextOutW(hdc, 5, 5, HelloWorld, lstrlenW(HelloWorld));
EndPaint(hWnd, &pntStruct);
break;
}
case WM_SIZE:
{
//...
break;
}
case WM_MOVE:
{
//...
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
case WM_CLOSE:
{
//...
break;
}
case WM_ACTIVATEAPP:
{
if (WM_ACTIVATEAPP)
{
OutputDebugString(TEXT("WM_ACTIVEAPP->TRUE"));
// or: OutputDebugStringW(L"WM_ACTIVEAPP->TRUE");
}
else
{
OutputDebugString(TEXT("WM_ACTIVEAPP->FALSE"));
// or: OutputDebugStringW(L"WM_ACTIVEAPP->FALSE");
}
break;
}
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wclass = {0}; // Or: WNDCLASSEXW
wclass.cbSize = sizeof(wclass);
wclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wclass.lpfnWndProc = &WindowProc;
wclass.cbClsExtra = 0;
wclass.cbWndExtra = 0;
wclass.hInstance = hInstance;
wclass.hIcon = NULL; // TODO: CREATE ICON
wclass.hCursor = NULL;
wclass.hbrBackground = NULL;//(HBRUSH)(COLOR_WINDOW+1);
wclass.lpszMenuName = NULL;
wclass.lpszClassName = WindowClass;
wclass.hIconSm = NULL;
if (!RegisterClassEx(&wclass)) // Or: RegisterClassExW()
{
// error! Use GetLastError() to find out why...
return 0;
}
HWND hCreateWin = CreateWindow( // Or: CreateWindowW()
WindowClass,
TEXT("NAME OF WINDOW"), // Or: L"NAME OF WINDOW"
WS_VISIBLE | WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,//WIDTH:[TODO]->Make custom width to fit window
CW_USEDEFAULT,//HEIGHT:[TODO]->Make custom width to fit window
0,
0,
hInstance,
0
);
if (!hCreateWin)
{
// error! Use GetLastError() to find out why...
return 0;
}
ShowWindow(hCreateWin, nCmdShow);
UpdateWindow(hCreateWin);
MSG message;
while (GetMessage(&message, NULL, 0, 0) > 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
};
return 0;
};
i've created s simple W32 application to cicle through two applications(hard coded window classes atm).
When i call the start button (IDC_Start) everything works fine, but when i change the focus to
hwnd the application hangs an cannot be closed. I just need a simple and clean method to
stop the loop, that start when calling IDC_Start. Any Help would be greatly apreciated!
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <resource.h>
#include <iostream>
using namespace std;
BOOL CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
HWND hwnd1,hwnd2;
hwnd1 = FindWindow("Notepad++",0);
hwnd2 = FindWindow("Notepad",0);
BOOL bDone;
switch(Message)
{
case WM_INITDIALOG:
// This is where we set up the dialog box, and initialise any default values
{
SetDlgItemInt(hwnd, IDC_NUMBER, 5, FALSE);
HICON hIcon, hIconSm;
hIcon = (HICON)LoadImage(NULL, "e32.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
if(hIcon)
SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
else
MessageBox(hwnd, "Could not load large icon!", "Error", MB_OK | MB_ICONERROR);
hIconSm = (HICON) LoadImage(NULL, "e16.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
if(hIconSm)
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);
else
MessageBox(hwnd, "Could not load small icon!", "Error", MB_OK | MB_ICONERROR);
}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_START:
{
BOOL bSuccess;
int nDelay = GetDlgItemInt(hwnd, IDC_NUMBER, &bSuccess, FALSE);
nDelay= nDelay*1000;
int i=1;
ShowWindow(hwnd,SW_MINIMIZE);
if(bSuccess)
{
if (hwnd1 != 0&&hwnd2 != 0)
{
SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
while(i)
{
if(bDone!=TRUE)
{
SetDlgItemInt(hwnd, IDC_SHOWCOUNT, nDelay/1000, FALSE);
Sleep(nDelay);
SetForegroundWindow(hwnd1);
Sleep(nDelay);
SetForegroundWindow(hwnd2);
i++;
}
else
{
SetThreadExecutionState(ES_CONTINUOUS);
MessageBox(hwnd, "Stopped", "Warning", MB_OK);
break;
}
}
}
else
{
MessageBox(hwnd,"Cannot find suitable Window","AppDia",MB_OK);
}
}
else
{
MessageBox(hwnd, "Number not identified", "Warning", MB_OK);
}
}
break;
case IDC_STOP:
bDone==TRUE;
break;
}
break;
case WM_CLOSE:
EndDialog(hwnd, 0);
break;
default:
return FALSE;
}
return TRUE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
return DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, DlgProc);
}
Your logic loops with Sleeps, it doesn't give the dialog box a way to process it's messages, so it seems to hang -- try using a Timer instead, with something like:
static BOOL bWnd1 = TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{ case IDC_START:
{ int nDelay = GetDlgItemInt(hwnd, IDC_NUMBER, &bSuccess, FALSE);
nDelay= nDelay*1000;
ShowWindow(hwnd,SW_MINIMIZE);
SetTimer(hwnd, 1, nDelay, NULL);
break;
}
case IDC_STOP:
KillTimer(hwnd, 1);
break;
}
break;
case WM_TIMER:
{ HWND hwnd = (bWnd1 ? FindWindow("Notepad++",0) : FindWindow("Notepad",0));
SetForegroundWindow(hwnd);
bWnd1 = !bWnd1;
break;
}
case WM_CLOSE:
KillTimer(hwnd, 1);
EndDialog(hwnd, 0);
break;
default:
return FALSE;
This is just a sample code, you'll need to add error checking to it...
I am attempting to write a slot machine Win32 App that uses images to display the result of the spins. I know how to display an image on a normal LRESULT CALLBACK frame, but i'm lost when it comes to displaying images on a dialog. Could anyone help me by explaining(in-depth) how i would go about displaying images? I really appreciate it.
My current Dialog callback:
BOOL CALLBACK DlgProc(HWND hwnd, UINT message,WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG: //dialog created
g_hbmObject = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_OBJECT));
//initialize slotmachine class
Machine.Initialize(time(0));
if(g_hbmObject == NULL) //test if object is loaded correctly
std::cerr << "Could not load ball..";
break;
case WM_COMMAND: //switch command
switch(LOWORD(wParam))
{
case IDC_SPIN: //slot machine spins
//put spin function, decide what to display
//do i put the display image command here? or where?
break;
case IDC_EXIT: //exit button
DeleteObject(g_hbmObject);
EndDialog(hwnd, 0);
break;
}
break;
case WM_CLOSE:
case WM_DESTROY: //case program is exited
DeleteObject(g_hbmObject);
PostQuitMessage(0);
break;
default:
return FALSE;
}
return TRUE;
}
The following code registers a "REEL" window class: a control that displays a spinning reel for a slot machine. You can create multiple instances of it on a dialog using resource statements like:
CONTROL "",IDC_REEL1,"REEL",0,14,50,40,40
CONTROL "",IDC_REEL2,"REEL",0,70,50,40,40
The reel spins endlessly, but you can easily add private messages to start and stop it.
As explained in the comments, it expects a bitmap representing a reel with resource ID IDB_REEL.
HBITMAP g_hbmpReel;
LRESULT CALLBACK ReelWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
const int ReelTimerId = 5;
switch (message)
{
case WM_CREATE:
SetTimer(hWnd, ReelTimerId, 10, 0);
break;
case WM_DESTROY:
KillTimer(hWnd, ReelTimerId);
break;
case WM_SIZE:
SetWindowPos(hWnd, 0, 0, 0, 40, 40, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
break;
case WM_TIMER:
if (wParam == ReelTimerId)
{
int offset = GetWindowLong(hWnd, 0);
offset = (offset + 5) % 120;
SetWindowLong(hWnd, 0, offset);
InvalidateRect(hWnd, 0, FALSE);
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
HDC hdcReel = CreateCompatibleDC(hdc);
HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcReel, g_hbmpReel);
int offset = GetWindowLong(hWnd, 0);
BitBlt(hdc, 0, 0, 40, 40, hdcReel, 0, offset, SRCCOPY);
SelectObject(hdcReel, hbmpOld);
DeleteDC(hdcReel);
EndPaint(hWnd, &ps);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
ATOM RegisterReel(HINSTANCE hInstance)
{
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = ReelWndProc;
// Window data used to hold the position of the reel
wcex.cbWndExtra = sizeof(int);
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszClassName = L"REEL";
// IDB_REEL is a 40x160 bitmap representing a reel with THREE 40x40 symbols.
// The bottom 40x40 square should be the same as the topmost.
g_hbmpReel = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_REEL));
return RegisterClassEx(&wcex);
}