I've created in plain win32 c++ an options menu with an edit box using embedded resources. The edit box ID_EDIT_OPTIONS_BOX has a default value of 30. I can change to value in the edit box to eg 10. I've used the OK-button the place the code for reading and writing the editbox. After I click OK, this new value is stored in my variable INT testInt. But when i re-open the options menu, the edit box still reflects the default value as stored in the resource file.
The basic code I use is this:
testInt = GetDlgItemInt(hDlg, ID_EDIT_OPTIONS_BOX, NULL, FALSE);
SetDlgItemInt(hDlg, ID_EDIT_OPTIONS_BOX, testInt, FALSE);
Do I need to refresh the window or am I missing something really trivial? Below I've listed the full program code, resource header and file.
The program code:
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include "resource.h"
#define WIN32_LEAN_AND_MEAN
// Global variables
static TCHAR szWindowClass[] = _T("DesktopApp");
static TCHAR szTitle[] = _T("Windows Desktop Guided Tour Application");
HINSTANCE hInst;
int testInt;
// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK CheckOptionsProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
)
{
WNDCLASSEX 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, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,
_T("Call to RegisterClassEx failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
// Store instance handle in our global variable
hInst = hInstance;
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 100,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
{
MessageBox(NULL,
_T("Call to CreateWindow failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
ShowWindow(hWnd,
nCmdShow);
UpdateWindow(hWnd);
// Main message loop:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_FILE_EXIT:
PostMessage(hWnd, WM_CLOSE, 0, 0);
break;
case ID_EDIT_OPTIONS:
DialogBox(hInst, MAKEINTRESOURCE(ID_EDIT_OPTIONS), hWnd, (DLGPROC)CheckOptionsProc);
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
LRESULT CALLBACK CheckOptionsProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_EDIT_OPTIONS_OK:
testInt = GetDlgItemInt(hDlg, ID_EDIT_OPTIONS_BOX, NULL, FALSE);
SetDlgItemInt(hDlg, ID_EDIT_OPTIONS_BOX, testInt, FALSE);
EndDialog(hDlg, IDOK);
break;
}
}
return 0;
}
The resource header
#define IDR_MENU 10
#define ID_FILE_EXIT 20
#define ID_EDIT_OPTIONS 30
#define ID_EDIT_OPTIONS_BOX 40
#define ID_EDIT_OPTIONS_OK 50
And resource file
#include "resource.h"
#include <windows.h>
IDR_MENU MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", ID_FILE_EXIT
END
POPUP "&Edit"
BEGIN
MENUITEM "&Options...", ID_EDIT_OPTIONS
END
END
ID_EDIT_OPTIONS DIALOGEX 0, 0, 260, 128
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Options"
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
FONT 9, "SEGOE UI"
BEGIN
CONTROL "&OK", ID_EDIT_OPTIONS_OK, BUTTON, BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 145, 110, 50, 11
CONTROL "30", ID_EDIT_OPTIONS_BOX, EDIT, ES_RIGHT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 200, 13, 18, 10
END
Use SetDlgItemInt when dialog received WM_INITDIALOG message:
LRESULT CALLBACK CheckOptionsProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
SetDlgItemInt(hDlg, ID_EDIT_OPTIONS_BOX, testInt, FALSE);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_EDIT_OPTIONS_OK:
testInt = GetDlgItemInt(hDlg, ID_EDIT_OPTIONS_BOX, NULL, FALSE);
EndDialog(hDlg, IDOK);
break;
}
}
return 0;
}
and remember to initialize testInt:
int testInt = 30;
Related
In my WinAPI application, I have a series of edit controls in a child window. I would like the user to be able to move between them by pressing on the tab key to go forward and shift-tab to go back, but I can't seem to figure out how to use WS_TABSTOP with child windows. What I intend to have happen is that when the user clicks the tab key, the subsequent edit control is selected. However, when I click the tab in the window of the following code the cursor simply disappears.
Here is a minimal reproducible example:
//libraries
#pragma comment ("lib", "Comctl32.lib")
#pragma comment ("lib", "d2d1.lib")
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
#include <CommCtrl.h>
// C RunTime Header Files
#include <vector>
#include <string>
#define IDS_APP_TITLE 103
#define IDI_PRACTICE 107
#define IDI_SMALL 108
#define IDC_PRACTICE 109
#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
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK WndProcChild(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
ATOM MyRegisterClass(HINSTANCE hInstance);
HWND childHWND;
HWND InitInstance(HINSTANCE hInstance, int nCmdShow);
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_PRACTICE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
// Perform application initialization:
HWND hWnd = InitInstance(hInstance, nCmdShow);
if(!hWnd)
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PRACTICE));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
if (!IsDialogMessage(hWnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProcChild(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
HWND edit1 = CreateWindow(WC_EDIT, L"", WS_CHILD | WS_BORDER | WS_VISIBLE | WS_TABSTOP, 100, 100, 100, 100, hWnd, (HMENU)1, hInst, NULL);
HWND edit2 = CreateWindow(WC_EDIT, L"", WS_CHILD | WS_BORDER | WS_VISIBLE | WS_TABSTOP, 300, 100, 100, 100, hWnd, (HMENU)2, hInst, NULL);
break;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
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_PRACTICE));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(GetStockObject(WHITE_BRUSH));
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_PRACTICE);
wcex.lpszClassName = L"Parent";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
//Child wnd class
WNDCLASSEXW wcexChild;
wcexChild.cbSize = sizeof(WNDCLASSEX);
wcexChild.style = CS_HREDRAW | CS_VREDRAW;
wcexChild.lpfnWndProc = WndProcChild;
wcexChild.cbClsExtra = 0;
wcexChild.cbWndExtra = 0;
wcexChild.hInstance = hInstance;
wcexChild.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PRACTICE));
wcexChild.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcexChild.hbrBackground = (HBRUSH)(GetStockObject(WHITE_BRUSH));
wcexChild.lpszMenuName = MAKEINTRESOURCEW(IDC_PRACTICE);
wcexChild.lpszClassName = L"Child";
wcexChild.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcexChild) && RegisterClassExW(&wcex);
}
HWND InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(L"Parent", L"PARENT", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);
childHWND = CreateWindowW(L"Child", L"", WS_CHILD | WS_VISIBLE | WS_EX_CONTROLPARENT,
0, 0, 700, 700, hWnd, nullptr, hInstance, nullptr);
if (!hWnd)
{
return NULL;
}
ShowWindow(childHWND, nCmdShow);
UpdateWindow(childHWND);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return hWnd;
}
Problem here is that if (!IsDialogMessage(hWnd, &msg)) gets called on the wrong window.
Replacing the line with if (!IsDialogMessage(childHWND, &msg)) gets TAB navigation to work.
From the IsDialogMessage documentation:
Although the IsDialogMessage function is intended for modeless dialog boxes, you can use it with any window that contains controls, enabling the windows to provide the same keyboard selection as is used in a dialog box.
In the posted code, the "window that contains controls" is the direct parent of the edit controls, which is childHWND.
[ EDIT ] One other problem pointed out in the comments (thanks #IInspectable) is that the extended style WS_EX_CONTROLPARENT is mistakenly passed with the style flags, instead of the extended style flags. To fix that, the call to childHWND = CreateWindowW(L"Child", L"", WS_CHILD | WS_VISIBLE | WS_EX_CONTROLPARENT, ... should be changed to childHWND = CreateWindowExW(WS_EX_CONTROLPARENT, L"Child", L"", WS_CHILD | WS_VISIBLE, ... instead.
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.
I am doing a school project and i want to set it up so when the user presses a button a dialog box pops up and allows users to input data. How should I implement this? I use resedit if that matters.
I wrote a simple demo, you can refer to the following code
Compiler tool: VS2017
// WindowsProject29.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "WindowsProject29.h"
#define MAX_LOADSTRING 100
#define IDB_ONE 133
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
HWND hWnd;
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
ATOM MyRegisterClass_1(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
void DisplayModelDialog(HWND hParent);
LRESULT CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM 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_WINDOWSPROJECT29, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
MyRegisterClass_1(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT29));
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_WINDOWSPROJECT29));
wcex.hCursor = LoadCursor(nullptr, MAKEINTRESOURCE(IDC_CURSOR1));
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOWSPROJECT29);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
ATOM MyRegisterClass_1(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = DialogProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWSPROJECT29));
wcex.hCursor = LoadCursor(nullptr, MAKEINTRESOURCE(IDC_CURSOR1));
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOWSPROJECT29);
wcex.lpszClassName = TEXT("Dialog");
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 = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
// DisplayModelDialog(hWnd);
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_CREATE:
{
CreateWindow(L"Button", L"Click", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
35, 10, 120, 60, hWnd, (HMENU)IDB_ONE, hInst, NULL);
}
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;
case IDB_ONE:
DisplayModelDialog(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
void DisplayModelDialog(HWND hParent)
{
EnableWindow(hParent, FALSE);
HWND hDlg = CreateWindow(
TEXT("Dialog"),
TEXT("Dialog"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
500,
300,
hParent,
NULL,
(HINSTANCE)GetWindowLong(hParent, GWL_HINSTANCE),
NULL);
HWND EDIT= CreateWindow(L"edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER,
20, 20, 200, 50, hDlg, NULL, NULL, NULL);
ShowWindow(hDlg, SW_SHOW);
UpdateWindow(hDlg);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
EnableWindow(hParent, TRUE);
SetForegroundWindow(hParent);
}
LRESULT CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
Debug Result:
More details, such as the need to save the text of the edit box and so on, can be added according to the actual situation.
I have the main window open. It was created for me using visual studio. What I am attempting to do is have a main screen with 9 to 12 buttons. These buttons will then open up other windows. I am attempting with one button currently the "InventoryBtn". The inventory window open up and I am able to close it. The second time I try to open the window I get an error. It seems the window is already registered and cant be recreated. What am I doing incorrectly? I stepped thru it and aw that "Destroy:" is being called. The second time I try to show the inventory window the handle is uninitialized.
#include "stdafx.h"
#include "VehManager.h"
#include "M_Inventory.h"
#define MAX_LOADSTRING 100
#define InvWindowBtn 101
#define InvBtn 103
using namespace boost::gregorian;
HINSTANCE hInst;
WCHAR szTitle[MAX_LOADSTRING];
WCHAR szWindowClass[MAX_LOADSTRING];
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK InvWindowProcess(HWND, UINT, WPARAM, LPARAM);
HWND handleforInvWin;
WNDCLASSEX wxInv;
void CreateInventoryWindow();
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_VEHMANAGER, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE (IDC_VEHMANAGER));
MSG msg;
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_VEHMANAGER));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_VEHMANAGER);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance;
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
MessageBoxA(NULL, "Main window creation failed.", "904.VehicleManager", MB_OK | MB_ICONINFORMATION);
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HFONT hfDefault;
switch (message)
{
case WM_CREATE:
{
HWND hInvBtn = CreateWindowEx(NULL, L"Button", L"INVENTORY", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
50, 220, 100, 24, hWnd, (HMENU)InvBtn, GetModuleHandle(NULL), NULL);
if (hInvBtn == NULL)
MessageBoxA(hWnd, "Could not create inventory button", "904.VehcleManager", NULL);
hfDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
SendMessage(hInvBtn, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0));
}
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
switch (wmId)
{
case InvBtn:
{
CreateInventoryWindow();
break;
}
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_RBUTTONDOWN:
MessageBox(NULL, L"Right button mouse clicks not allowed.", L"904.VehicleManager", NULL);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
void CreateInventoryWindow()
{
ZeroMemory(&wxInv, sizeof(WNDCLASSEX));
wxInv.cbClsExtra = NULL;
wxInv.cbSize = sizeof(WNDCLASSEX);
wxInv.cbWndExtra = NULL;
wxInv.hbrBackground = (HBRUSH)COLOR_WINDOW;
wxInv.hCursor = LoadCursor(NULL, IDC_ARROW);
wxInv.hIcon = NULL;
wxInv.hIconSm = NULL;
wxInv.hInstance = hInst;
wxInv.lpfnWndProc = (WNDPROC)InvWindowProcess;
wxInv.lpszClassName = L"Inventory";
wxInv.lpszMenuName = NULL;
wxInv.style = CS_HREDRAW | CS_VREDRAW;
if (!RegisterClassEx(&wxInv))
{
int nResult = GetLastError();
MessageBox(NULL, L"Inventory window class registration failed.", L"904.VehicleManager", MB_ICONEXCLAMATION);
return;
}
handleforInvWin = CreateWindowEx(NULL, wxInv.lpszClassName, L"Open Window 2", WS_OVERLAPPEDWINDOW,
200, 170, 640, 480, NULL, NULL, hInst, NULL);
if (!handleforInvWin)
{
MessageBox(NULL, L"Error with the inventory window handle.", L"904.VehManager", MB_ICONEXCLAMATION);
return;
}
ShowWindow(handleforInvWin, SW_SHOWNOACTIVATE);
UpdateWindow(handleforInvWin);
}
LRESULT CALLBACK InvWindowProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HFONT hfDefault;
switch (message)
{
case WM_CREATE:
{
HWND hInvBtn = CreateWindowEx(NULL, L"Button", L"Close", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
50, 220, 100, 24, hwnd, (HMENU)InvBtn, GetModuleHandle(NULL), NULL);
if (hInvBtn == NULL)
MessageBoxA(hwnd, "Could not create inventory button", "904.VehcleManager", NULL);
hfDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
SendMessage(hInvBtn, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0));
break;
}
case WM_DESTROY:
{
break;
}
case WM_COMMAND:
case InvBtn:
{
DestroyWindow(hwnd);
break;
}
break;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
I writing Hook Mouse system-wide (when mouse over any components in screen, Handle, classname, wndproc of it will display in my program).
But system-wide hook in my program not run when move mouse outside main program
I create DLL file successfully, but dont understand why it ONLY run as local hook (it run good in local my program - SCREEN AREA of my program).
This is source of hookDLL.cpp (DLL file):
#include "stdafx.h"
#include "Win32_Iczelion_HookDLL.h"
#define WM_MOUSEHOOK WM_USER+10
HINSTANCE hInstance;
HHOOK hHook;
HWND hWnd;
EXPORT HHOOK CALLBACK InstallHook(HWND);
EXPORT void CALLBACK UninstallHook(void);
EXPORT LRESULT CALLBACK MouseProc(int, WPARAM, LPARAM);
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hInstance = hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
EXPORT HHOOK CALLBACK InstallHook(HWND hwnd)
{
hWnd = hwnd;
hHook = SetWindowsHookEx (WH_MOUSE, (HOOKPROC)MouseProc, hInstance, NULL);
return hHook;
}
EXPORT void CALLBACK UninstallHook()
{
UnhookWindowsHookEx(hHook);
}
EXPORT void test()
{
MessageBox(NULL, L"yeah", L"yeah", MB_OK);
}
EXPORT LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CallNextHookEx(hHook, nCode, wParam, lParam);
POINT pt = {0};
GetCursorPos(&pt);
HANDLE handle = WindowFromPoint(pt);
PostMessage(hWnd, WM_MOUSEHOOK, (WPARAM)handle, 0);
return 0;
}
And this is source of hook.cpp (main program):
#include "stdafx.h"
#include "Win32_Iczelion_Hook.h"
#include "Win32_Iczelion_HookDLL.h"
#define WM_MOUSEHOOK WM_USER+10
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
HWND hWndEHandle;
HWND hWndEClassName;
HWND hWndEWndProc;
HWND hWndBHook;
HWND hWndBExit;
HHOOK hHook;
BOOL HookFlag = 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 _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WIN32_ICZELION_HOOK, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32_ICZELION_HOOK));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX 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_WIN32_ICZELION_HOOK));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32_ICZELION_HOOK);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 600, 300, NULL, NULL, hInstance, NULL);
hWndEHandle = CreateWindowEx(NULL, L"Edit", NULL,
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL,
100,35,345,25,hWnd,(HMENU)IDC_HANDLE,hInstance,NULL);
hWndEClassName = CreateWindowEx(NULL, L"Edit", NULL,
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL,
100,65,200,25,hWnd,(HMENU)IDC_CLASSNAME,hInstance,NULL);
hWndEWndProc = CreateWindowEx(NULL, L"Edit", NULL,
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL,
100,95,200,25,hWnd,(HMENU)IDC_WNDPROC,hInstance,NULL);
hWndBHook = CreateWindowEx(NULL, L"Button", L"Hook",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
305,65,140,25,hWnd,(HMENU)IDC_HOOK,hInstance,NULL);
hWndBExit = CreateWindowEx(NULL, L"Button", L"Exit",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
305,95,140,25,hWnd,(HMENU)IDC_EXIT,hInstance,NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
LPWSTR buffer = 0;
RECT rect;
switch (message)
{
case WM_CREATE:
GetWindowRect(hWnd, &rect);
SetWindowPos(hWnd, HWND_TOPMOST, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW);
break;
case WM_CLOSE:
if (HookFlag==TRUE)
UninstallHook();
DestroyWindow(hWnd);
case WM_MOUSEHOOK:
{
wchar_t buffer[256];
wsprintfW(buffer, L"%p", wParam);
SetDlgItemText(hWnd, IDC_HANDLE, buffer);
GetClassName((HWND)wParam, buffer, 128);
SetDlgItemText(hWnd, IDC_CLASSNAME, buffer);
DWORD buffer2 = GetClassLong((HWND)wParam,GCL_WNDPROC);
wsprintfW(buffer, L"%p", buffer2);
SetDlgItemText(hWnd, IDC_WNDPROC, buffer);
break;
}
case WM_COMMAND:
{
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
if (wmEvent==BN_CLICKED)
{
if (wmId==IDC_HOOK)
{
if (HookFlag==FALSE)
{
if (InstallHook(hWnd))
{
HookFlag = TRUE;
SetDlgItemText(hWnd, IDC_HOOK, L"Un hook");
}
}
else
{
UninstallHook();
SetDlgItemText(hWnd,IDC_HOOK,L"Hook");
HookFlag = FALSE;
SetDlgItemText(hWnd,IDC_CLASSNAME,NULL);
SetDlgItemText(hWnd,IDC_HANDLE,NULL);
SetDlgItemText(hWnd,IDC_WNDPROC,NULL);
}
}
else if (wmId==IDC_EXIT)
{
SendMessage(hWnd,WM_CLOSE,0,0);
}
}
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);
}
break;
}
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Anyone can help me.
Last EDIT : corrected code.
The DLL is loaded, by Windows, in other processes, if they have the same bitness as your main process (and if they get the mouse). Consequence: the global hWnd variable in your Dll is always NULL and PostMessage fails.
Advices:
1 Always check the API's return code. You should have noticed that PostMessage failed.
2 When you are about to PostMessage in your DLL, if you see a NULL hWnd, use FindWindow to get the HWND and store it in hWnd for next time.
New version of the MouseProc DLL CallBack:
EXPORT LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if ( nCode >= 0 ) {
PMOUSEHOOKSTRUCT pmhs = reinterpret_cast<PMOUSEHOOKSTRUCT>( lParam );
if ( hWnd == NULL ) hWnd = FindWindow( L"WIN32_ICZELION_HOOK", NULL );
if ( hWnd ) PostMessage(hWnd, WM_MOUSEHOOK, (WPARAM)pmhs->hwnd, 0);
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
EDIT: make sure you run your progam (EXE) from a folder where the DLL has been rebuild). Create an empty solution (SLN) and add the 2 projects in it (vcxproj). Delete all "old" EXE and DLL. Rebuild.
EDIT added ScreenShot:
The EXE showing the class name of the Explorer folder bar
When DLL is loaded from another program (when you mouse over outside main program), hWnd is NULL, so you have to use FindWindow to get hWnd value of main program before PostMessage.