I have dialog window specified via a *.rc file that doesn't render properly on the screen. It exhibits the following set of anomalies:
The dialog window is white.
The dialog window title bar is absent.
All GUI objects are rendered two times -- once at position (X,Y) specified by the *.rc file and a 2nd time at position (X+3,Y+23). Pushbuttons at position (X,Y) are alive. The "echoes" at (X+3,Y+23) are non-functional.
The pushbutton object specified as DEFPUSHBUTTON is not the default pushbutton, and the pushbutton object specified as PUSHBUTTON is the default pushbutton.
Other than the default pushbutton anomaly and the weird appearance, the Dialog window operates as it should, as does the callback function -- SelectPuzzle() -- that it invokes. The source code for SelectPuzzle() is not enclosed but is available upon request as are screen shots.
This code is virtually identical to code I have used successfully in other projects. Why it doesn't work here remains a mystery. Can anyone help?
I've tried everything I can think of to diagnose this bug but without success, e.g.:
In place of DialogBoxParam(), I tried using DialogBox() with variable PuzzleDB supplied as a global. Same result.
I tried stripped-down, simplified versions both of the resource file and of the SelectPuzzle() function,
-- i.e., a DIALOGEX resource with just a "Cancel" pushbutton and a SelectPuzzle() function with just an empty WM_INITDIALOG section and a WM_COMMAND case to support the Cancel pushbutton. Same result.
I verified consistent use of the IDD_SELECTPUZZLE constant in MainApp and in resource file. I also tried different numeric values for IDD_SELECTPUZZLE.
Same result.
The following code excerpts are relevant:
MainApp.h (included in stdafx.h)
.
.
#define IDD_SELECTPUZZLE 9500
#define IDM_SelectPuzzle 9510
#define ID_CurrentPuzzle 9521
#define ID_SelectedPuzzle 9522
#define ID_PuzzleSelStatus 9523
.
.
PuzzleDB.h (included in stdafx.h)
//=======================================================================
// PuzzleDB.h : Defines the entry point for the application.
//=======================================================================
#pragma once
typedef struct {
int NumberOfPuzzles;
int *PuzzleNumbers;
int ndxCurrentPuzzleNumber;
clasPuzzle *Puzzle;
} PuzzleSelectionData, *pPuzzleSelectionData;
clasPuzzle *ResetPuzzle(
clasPuzzle *Puzzle
);
char *LoadPuzzle(
char *tstr
, int ndxSelectedPuzzle
, pPuzzleSelectionData pPuzzleDB );
MainApp.cpp,
#include "stdafx.h"
.
.
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK SelectPuzzle(HWND, UINT, WPARAM, LPARAM);
.
.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
.
.
static PuzzleSelectionData PuzzleDB;
.
.
switch (message)
.
.
case WM_COMMAND:
switch (wParam)
.
.
//*****WM_COMMAND********************************************
case IDM_SelectPuzzle:
k = PuzzleDB.ndxCurrentPuzzleNumber;
DialogBoxParam(
hInst
, MAKEINTRESOURCE(IDD_SELECTPUZZLE)
, hWnd, SelectPuzzle
, (unsigned long)(&PuzzleDB));
if (PuzzleDB.ndxCurrentPuzzleNumber != k)
SendMessage(hWnd,WM_COMMAND,IDM_LoadPuzzle,0L);
break;
.
.
AppName.rc
.
.
//**** BEGIN Application specific resources *********************************
//--------------------------------------------------------------------------------
// Application specific resource.
// Menu Dialog item "Select Puzzle"
//--------------------------------------------------------------------------------
IDD_SELECTPUZZLE DIALOGEX 4, 4, 126, 74 // Position w.r.t. parent window.
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Select Puzzle"
FONT 10, "MS Shell Dlg"
BEGIN
ICON IDR_MAINFRAME , IDC_STATIC ,14,14, 21,20
LTEXT "Use Mouse Wheel to Select Puzzle." , IDC_STATIC , 8, 4,118,12,SS_NOPREFIX
LTEXT "Current Puzzle: " , IDC_STATIC , 8,16, 52,12,SS_NOPREFIX
LTEXT "New Selection: " , IDC_STATIC , 8,28, 52,12,SS_NOPREFIX
PUSHBUTTON "Accept" , ID_OK , 8,40, 52, 4,WS_GROUP
DEFPUSHBUTTON "CANCEL" , ID_CANCEL ,66,40, 52, 4,WS_GROUP
LTEXT " " , ID_CurrentPuzzle ,66,16, 52,12,SS_NOPREFIX
LTEXT " " , ID_SelectedPuzzle ,66,28, 52,12,SS_NOPREFIX
LTEXT " " , ID_PuzzleSelStatus, 8,60,110,12,SS_NOPREFIX
END
//**** END Application specific resources ***********************************
The main problem is that you return TRUE from the dialog procedure for all messages. Except for a handful of special messages, this indicates that you don't want default handling. Thus things that should be done, are not being done.
Tip for dialogs: seriously underdocumented, but where you need to return some specific value for some specific message, use SetDlgMsgResult from <windowsx.h>, or equivalent code.
In passing, the code can be greatly simplified and improved by
removing use of Visual C++ non-standard semantics precompiled headers (for standard-conformance and maintainability),
removing use of Visual C++ non-standard tWinMain, just use standard main,
removing use of Windows 9x support (the unmentionably silly Microsoft T stuff for strings),
using std::wstring instead of C library string handling,
and using wide string literals instead of narrow ones plus conversion,
etc.
A particularly bad apple, in the tWinMain function this code:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
InitInstance only makes sense for 16-bit Windows.
passing nCmdShow around only makes sense for 16-bit Windows (in 32-bit Windows it is ignored by the first ShowWindow call).
Returning FALSE here erroneously indicates success, when it is a failure.
I have seen essentially this code many times, even in the D language's Windows support, and I suspect that it originates with Microsoft.
Anyway, wherever you got that from, that source is seriously outdated and unreliable, to be treated only as a source of bad programming habits and ingenious ways to introduce bugs.
Related
This question already has answers here:
Access a variable from a different switch case (from WM_CREATE to WM_CTLCOLORSTATIC in the WinApi)
(2 answers)
Closed last month.
I have created a basic button in case: WM_CREATE in the windows procedure with the following.
/*The "new_game_button" is declared as type HWND at the
start of the windows procedure function but not initialized.*/
new_game_button = CreateWindow ( "BUTTON", "New Game",
WS_CHILD | WS_BORDER ,
50, 50, 100, 100,
hwnd, NULL, NULL, NULL);
My intent is to create an instructions and "start new game" button as the first thing in my simple tictactoe app. It will immediately show as expected if I give the parameter WS_VISIBLE.
Further in the same case:WM_CREATE if I use the lines
if (!start_Game){ //global variable default is false
ShowWindow( new_game_button, SW_SHOW);
}
The button will show as expected.
Outside of those two cases I cannot get the button to show at a later stage.
Further, if I use one of those two methods to show the button I can never get it to go away using
ShowWindow ( new_game_button, SW_HIDE);
Once the button is showing, it stays for the duration of the programs execution. Doesn't matter which case. Command/Create/Paint
I have tried using
if (start_Game){
ShowWindow( new_game_button, SW_HIDE);
UpdateWindow ( new_game_button );
//UpdateWindow ( hwnd ); tried this as well
}
inside case WM_CREATE.
I have also tried the same SW_HIDE line inside case: WM_COMMAND where a new game is generated (compiles but doesn't hide the button.)
I have tried declaring the button child window outside the WM_CREATE inside the windows procedure function. Then using WM_CREATE to show the window - works -- still WM_COMMAND will not hide the window.
I have also tried creating the button window inside of case:WM_PAINT which works to show the button but not to get rid of it. I have even tried DestroyWindow which just fails. [returns 0]
In trying to understand the behaviour of the button window - I have found that I cannot get
ShowWindow( new_game_button, SW_SHOW);
to work in the case:WM_COMMAND.
You said (in a code comment in the question).
new_game_button is declared as type HWND at the start of the windows procedure function but not initialized.
Each incoming message means a new call to your window procedure. Variables which are local to a function don't retain their value between calls unless they are marked static.
When your window procedure returned from processing WM_CREATE, you lost the value of new_game_button. When you try to use it during WM_COMMAND processing later, it is uninitialized and your program causes undefined behavior by passing it to ShowWindow.
Every comment helped me solve this which I appreciate. I am too new to give reputation sadly.
case WM_CREATE:
{
new_game_button = CreateWindow ("BUTTON", "New Game",
WS_CHILD | WS_BORDER ,
50, 50, 100, 100,
hwnd, (HMENU) 1, NULL, NULL);
if (!start_Game){
ShowWindow( new_game_button, SW_SHOW);
}
}
break;
After I had an ID for the dialog I am able to use GetDlgItem function to show or hide as I please.
new_game_button = GetDlgItem (hwnd, 1);
ShowWindow( new_game_button, SW_HIDE);
Now I want to dynamically modify the GUI of a running WINDOWS program(assume this program is written in win32 API/MFC), for example, add a button to it's specific position.
But I'm not familiar with WINDOWS GUI programming.
So I want to ask if there is any normal way to implement this feature using win32 API or MFC.
If not, do I need any hacking tips?
You can dynamically create any Windows component by utilizing the CreateWindow function when processing (for example) a WM_COMMAND message inside your WndProc callback function. Or any other message for that matter. Provided that you have a button with an ID of IDC_BUTTON you can create a new button when clicked.
case WM_COMMAND: // process commands
switch (LOWORD(wParam))
{
case IDC_BUTTON: //check for our button ID
HWND hwndButton = CreateWindow(
L"BUTTON", // predefined class name
L"OK", // button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
10, // y position
75, // width
24, // height
hWnd, // parent handle
(HMENU)IDC_BUTTON2, // button ID
hInst, // module instance
NULL); // lparam, pointer not needed
break;
}
I'm creating a small WinAPI application in C++. I am trying to create a button on my form by using the code:
HWND hwndButton = CreateWindow(
TEXT("BUTTON"),
TEXT("Click Here"),
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, // Styles
10,
10,
100,
30,
hwnd,
NULL,
(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
NULL);
This code is based off of an MSDN sample. My issue is that it uses a bold font on the button like this:
When I want to use the standard font like this:
I already have the preprocessor directive at the top of my file to enable visual styles.
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
What steps should I take to use the standard system wide font?
Thanks
GetStockObject isn't the recommended way of retrieving the GUI font (it doesn't take themes into account, and different fonts can be chosen for buttons, menus, etc). Instead you should use SystemParametersInfo (see Remarks section of GetStockObject).
It is not recommended that you employ this method to obtain the current font used by dialogs and windows. Instead, use the SystemParametersInfo function with the SPI_GETNONCLIENTMETRICS parameter to retrieve the current font. SystemParametersInfo will take into account the current theme and provides font information for captions, menus, and message dialogs.
NONCLIENTMETRICS metrics = {};
metrics.cbSize = sizeof(metrics);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
HFONT guiFont = CreateFontIndirect(&metrics.lfCaptionFont);
// When you're done with the font, don't forget to call
DeleteObject(guiFont);
There's no such thing as default system wide font for controls, initially you get a control created with "System" font, that's what you see on first picture. When button is created as part of a dialog, it uses a font from dialog template, so using something like "MS Shell Dlg" with appropriate size + WM_SETFONT on a button should give you the same result as on picture 2. Note that there's no physical MS Shell Dlg font on a system, it's mapped to particular font according to registry settings.
Common control manifest has nothing to do with this, behavior has not changed with comctl32 version 6.
The default GUI font is stored in DEFAULT_GUI_FONT, and can be retrieved via
GetStockObject(DEFAULT_GUI_FONT);
To set the font of the button you can use:
HWND yourButton; // use CreateWindow or anything else to get this
SendMessage(yourButton, WM_SETFONT, (LPARAM)GetStockObject(DEFAULT_GUI_FONT), true);
A convenient way of doing this without calling SendMessage on every single child window manually is to use the EnumChildWindows function with the following callback function -
Create the callback function EnumChildProc:
BOOL CALLBACK EnumChildProc(
HWND hWnd,
LPARAM lParam
)
{
HFONT hfDefault = *(HFONT *) lParam;
SendMessageW(hWnd, WM_SETFONT, (WPARAM) hfDefault, MAKELPARAM(TRUE, 0));
return TRUE;
}
At the start of your (w)WinMain function, add the code:
NONCLIENTMETRICSW ncm;
HFONT hfDefault;
ZeroMemory(&ncm, sizeof(NONCLIENTMETRICSW));
ncm.cbSize = sizeof(NONCLIENTMETRICSW);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, FALSE);
hfDefault = CreateFontIndirectW(&ncm.lfMessageFont);
Then, after the ShowWindow call, add this line:
EnumChildWindows(hWnd, EnumChildProc, (LPARAM)&hfDefault);
I've been googling for a while and I found nothing working for me so I'm here asking you folks this question.
I've already tried with SendMessage, SetWindowText and much more.
What I am trying to do is output a text in a textbox ( TEXT("edit") ... ).
The messages I have to display are: "You win", "You lose" or "Draw".
What do you suggest me to do?
(I'm using DEV C++)
Thanks everybody!
Your code snippet:
HWND hwndbutton[2];
switch (message) /* handle the messages */
{
case WM_CREATE:
hwndbutton[0] = CreateWindow(TEXT("edit"),TEXT(""), WS_VISIBLE | WS_CHILD |
WS_BORDER,10,10,50,30, hwnd, (HMENU)11,0,0);
looks like it is inside a window procedure - first problem is that the value in hwndbutton[0] will be lost (it's on the stack) when the procedure is called again. You could, for example, make it static:
static HWND hwndbutton[2];
Tracing through your debugger should show you this.
There is a similar question here but I'm looking for a C++ version.
I want to create a .rs file with a DialogBox that uses a string as a variable instead a " " so I can change it in the program.
For example: In
DEFPUSHBUTTON "Hello World", IDOK, 8, 24, 75, 14
the "Hello World" would become a variable name, which I can 'define' or set in the program.
Why? I'm trying to make a DialogBox, like a 'template', and make many instances around the program with different Text in but same buttons in them.
Hope my gibberish is understanded.
Unfortunately, this is not possible. The caption text for a control must be a constant string because the resource file is actually compiled separately from your application and has no knowledge of variables defined elsewhere in your program's code.
Resource files do support string tables, but even these require the strings to be constant values. The advantage is that you can modify the resource file without access to the rest of the source code, which makes things like localization possible, even by outside translators.
So you're stuck hard-coding the initial caption of your DEFPUSHBUTTON. It can be an empty string or whatever value you want; you just need a placeholder. And you can put all of the possible captions in a string table (which I would recommend), but you cannot link the two using any automated mechanism.
You need to write the code to do this yourself. You could certainly dynamically generate resources, but that's quite a bit of trouble. I think the simplest way of doing this is just to create the dialog (using your "template" resource file), retrieve the handle of the controls whose caption text you want to change, and send them a WM_SETTEXT message with the new string. In fact, the SetDlgItemText function will do exactly this for you.
Perhaps that would be easier to explain with some code. Assume that you have a dialog resource defined, including all of your controls. All of the controls you wish to modify will need to have a unique ID assigned to each of them so that you can distinguish between them at runtime. It doesn't matter what the initial values you assign in the resource file are, as you're going to be changing them right off the bat. It might look like this:
IDD_TEMPLATE DIALOG DISCARDABLE 0, 0, xx, xx
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
CAPTION "Dialog Template"
FONT 8, "MS Sans Serif"
BEGIN
CTEXT "Placeholder text", IDC_MESSAGE, xx, xx, xx, xx
DEFPUSHBUTTON "Placeholder", IDOK, xx, xx, xx, xx
PUSHBUTTON "Cancel", IDCANCEL, xx, xx, xx, xx
END
Then, in your dialog procedure (DialogProc), handle the WM_INITDIALOG message as follows:
INT_PTR CALLBACK TemplateDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
// Load the caption strings you want to use from the string table
// in the resource file, or get them from wherever you want.
// These are the "variables" you wanted to use in the question.
TCHAR* pszMessage;
LoadString(hInstance, /* instance handle for app or resource DLL */
IDS_MESSAGE, /* ID of the string resource to load */
reinterpret_cast<LPTSTR>(&pszMessage),
0);
TCHAR* pszOkBtn;
LoadString(hInstance, IDS_OKBUTTON, reinterpret_cast<LPTSTR>(&pszOkBtn), 0);
// ...etc.
// Set the caption text for each control.
SetDlgItemText(hwndDlg, /* handle to the dialog box window */
IDC_MESSAGE, /* ID of the control to modify */
pszMessage); /* variable containing text to set */
SetDlgItemText(hwndDlg, IDOK, pszOkBtn);
// ...etc.
// And, if you want to set some other properties, you can do that too.
// For example, you might set the caption of the dialog itself.
TCHAR* pszTitle;
LoadString(hInstance, IDS_DLGCAPTION, reinterpret_cast<LPTSTR>(&pszTitle), 0);
SetWindowText(hwndDlg, pszTitle);
// ...etc.
return TRUE; // set the default focus
}
// ...process other messages as necessary
}
return FALSE; // we did not process the message
}
While I think Cody Gray's answer is better, there is always the option of creating your dialog template in-memory, and modifying it as you create new instances of the dialog. I wouldn't recommend it unless you find this kind of thing fun (I'm one of those people). I certainly wouldn't recommend it for what you're asking, but it is technically an option...
DialogBoxIndirect takes a pointer to a structure that is made up of a header (DLGTEMPLATE) that describes the dialog box itself, followed by the specified number of controls (DLGITEMTEMPLATE).
Effectively you can use the above to build a new in-memory dialog template each time you want a DialogBox with different text on the button. However, that's a little extreme if all you really want to do is change some text, which as Cody says, you can do with SetDlgItemText.
If you're really curious, here's an example.