Use A Parameter In A .rs Resource File C++ Console - c++

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.

Related

C++ Winapi HWND Get element by Name

Is there a way I can get a HWND by it's property "name"? I know that every IDE has its own properties for HWND elements but those properties are applied to the HWND.
I'm not working in Visual Studio, this is just a case. I want to get HWNDs by Name in C++ without VS Libraries.
For example:
HWND button = GetHwndByName("button1"); //Example
Property "name" is button1
I'm going to assume you're either trying to access your GUI controls in code or some other program's GUI controls.
As some people have mentioned, the (name) property in the properties editor is just the variable name used for that control. Your screenshot shows Visual Studio editing a .net program. In the case of .net, the (name) field is the name of the class member of the window class that represents the control. So if (name) is button1 then Visual Studio might generate code like
// pseudo-C++/C#-like
class Form1 : public System.Windows.Forms.Form {
private:
System.Windows.Forms.Button *button1;
...
};
The idea here is that you would have event handlers as part of your Form1 class:
void Form1::onButton1Clicked(void)
{
this->button1->SetText("You clicked me!");
}
As such, the (name) is not an intrinsic property of the window from Windows's point of view.
I don't know what CA Plex's GUI editor looks like, but I would assume, given you said you were using C++, that it either
a) produces a class like the one I pasted above, in which case you would just use the (name) directly as members, or
b) produces a header file with each of those control names as global HWND variables
Either way, you can just use them directly from within your code. Perhaps have something like
void doToAllButtons(void (*f)(HWND, LPARAM), LPARAM lParam)
{
(*f)(button1, lParam);
(*f)(button2, lParam);
(*f)(button3, lParam);
}
and simply write an appropriate function to call via this one.
If you need to interface with another program and want to use its variable names, then you're out of luck. You'll need to find the windows you want some other way, such as with FindWindow().

c++ Dialog box doesn't render properly on PC screen

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.

GetDlgItemInt returns 0

I have a dialog and a picture control inside of it. During OnInitDialog I try to obtain the text part of the picture control like this
CWnd *dialogHandle; // Handle of the dialog
CWnd *itemHandle; // Handle of the picture control
BOOL error;
dialogHandle->GetDlgItemInt(itemHandle->GetDlgCtrlID(), &error, 0);
however GetDlgItemInt function set error to 0 which says there is an error
here is the resource line
CONTROL 65443, IDC_PICTURE, "Static", SS_BITMAP, 13, 13, 40, 40
I want this number 65443
You want GetWindowLong(hWnd, GWL_ID); (or the MFC equivalent).
GetDlgItemInt() is simply an atoi() wrapper around GetDlgItemText(), which reads the label of the control, not its ID.
GetDlgItemInt() is supposed to get a text out of control. The second parameter is referred to as 'translated' flag and not an 'error' flag. Is this realy the method you are looking for? I think you need something else.

How to create controls at runtime?

How to create dynamic MFC controls and handle message maps of the controls at runtime?
It really depends on which controls do you want to create, especially if you want to know which flags should you set. In general it goes down to this:
Normally a CWnd-derived control is created using Create or CreateEx. For a CButton, for instance:
CButton button;
button.Create("Button text", WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | DT_CENTER, CRect(5, 5, 55, 19), this, nID);
where the CRect specifies the button position, this is a pointer to the parent window, and nID is the control ID.
If the control doesn't come out as expected, it's probably because some flags are missing. I suggest you draw a sample control in design mode, check out the code for that control in the RC file, and copy the flags to the Create caller.
As for the message maps, they are normally routed to the parent window. The nID value you used in Create is important here, because it will be the number that identifies the control in the message map. If you have a fixed number of controls, you can hard-code the nID numbers for your controls (starting at 10000, for instance); if not, you'll have to provide a way for the parent window to identify them. Then you just add the message map entries.
ON_BN_CLICKED(10000, OnBnClicked)
ON_CONTROL_RANGE(BN_CLICKED, 10010, 10020, OnBtnsClicked)
You can use the ON_CONTROL_RANGE message map to map a range of IDs to the same function.

Reading from a text field in another application's window

Is there a way for a Windows application to access another applications data, more specifically a text input field in the GUI, and grab the text there for processing in our own application?
If it is possible, is there a way to "shield" your application to prevent it?
EDIT: The three first answers seem to be about getting the another applications window title, not a specific text input field in that window.
I'm no Windows API expert, so could you be more exact how do I find a certain text field in that window, what are the prerequisites for it (seems like knowing a window handle something is required, does it require knowing the text field handle as well? How do I get that? etc...)
Code snippets in C++ really would be really appreciated. MSDN help is hard to browse since Win32-API has such horrible naming conventions.
Completed! See my answer below for a how-to in C++.
For reading text content from another application's text box you will need to get that text box control's window handle somehow. Depending on how your application UI is designed (if it has a UI that is) there are a couple of different ways that you can use to get this handle. You might use "FindWindow"/"FindWindowEx" to locate your control or use "WindowFromPoint" if that makes sense. Either way, once you have the handle to the text control you can send a "WM_GETTEXT" message to it to retrieve its contents (assuming it is a standard text box control). Here's a concocted sample (sans error checks):
HWND hwnd = (HWND)0x00310E3A;
char szBuf[2048];
LONG lResult;
lResult = SendMessage( hwnd, WM_GETTEXT, sizeof( szBuf ) / sizeof( szBuf[0] ), (LPARAM)szBuf );
printf( "Copied %d characters. Contents: %s\n", lResult, szBuf );
I used "Spy++" to get the handle to a text box window that happened to be lying around.
As for protecting your own text boxes from being inspected like this, you could always sub-class your text box (see "SetWindowLong" with "GWL_WNDPROC" for the "nIndex" parameter) and do some special processing of the "WM_GETTEXT" message to ensure that only requests from the same process are serviced.
OK, I have somewhat figured this out.
The starting point is now knowing the window handle exactly, we only know partial window title, so first thing to do is find that main window:
...
EnumWindows((WNDENUMPROC)on_enumwindow_cb, 0);
...
which enumerates through all the windows on desktop. It makes a callback with each of these window handles:
BOOL CALLBACK on_enumwindow_cb(HWND hwndWindow, LPARAM lParam) {
TCHAR wsTitle[2048];
LRESULT result;
result = SendMessage(hwndWindow, WM_GETTEXT, (WPARAM) 2048, (LPARAM) wsTitle);
...
and by using the wsTitle and little regex magic, we can find the window we want.
By using the before mentioned Spy++ I could figure out the text edit field class name and use it to find wanted field in the hwndWindow:
hwndEdit = FindWindowEx(hwndWindow, NULL, L"RichEdit20W", NULL);
and then we can read the text from that field:
result = SendMessage(hwndEdit, WM_GETTEXT, (WPARAM) 4096, (LPARAM) wsText);
I hope this helps anyone fighting with the same problem!
Look at AutoHotkey. If you need an API for your application, look at their sources.
To prevent it, use a custom widget instead of WinForms, MFC or Win32 API. That is not foolproof, but helps.
Yes it is possible in many ways (one way is to use WINAPI GetWindow and GetWindowText).
First, get a handle to the textbox you want to retrieve text from (using FindWindow, EnumChildWindows and other APIs), then:
Old VB6-codeexample, declaration of API:
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Code to extract text:
Dim MyStr As String
MyStr = String(GetWindowTextLength(TextBoxHandle) + 1, Chr$(0))
GetWindowText TextBoxHandle, MyStr, Len(MyStr)
MsgBox MyStr
About how to shield the application to prevent it, you could do many things.
One way would be to have a own control to handle text input that build up the text from lets say a couple of labels placed where the text would be, or that draws the text graphically.
You can also get text from a richedit control with EM_GETTEXTRANGE message, but it works only in the same process in which the control was created.