I'm fairly new to C++. I tried practicing my code but I hit an error I'm not sure how to fix:
Error: expression cannot be used as a function
switch (message)
{
case WM_CREATE:
TextBox = CreateWindow("EDIT",
"",
WS_VISIBLE|WS_CHILD|WS_BORDER,
10,10,80,20,
hwnd,NULL,NULL,NULL);
BUTTON = CreateWindow("BUTTON",
"GO",
WS_VISIBLE|WS_CHILD|WS_BORDER,
100,10,70,20,
hwnd,(HMENU)1,NULL,NULL);
break;
case WM_COMMAND:
case 1:
int gwtstat=0;
//char *t=&textSaved[0];
gwtstat=GetWindowText(TextBox,&textSaved[0], 50);
::MessageBox(
hwnd,
"I am" ()textSaved "and i am Beautiful!",
"smile",
MB_YESNO);
The issue is here:
"I am" ()
The expression "I am" is of type char const[5] which doesn't support function call syntax. What you intended to do is probably string interpolation. For that you can use std::format starting with C++20.
The following solves the immediate issue:
::MessageBox(
hwnd,
std::format("I am {} and i am Beautiful!", textSaved).c_str(),
"smile",
MB_YESNO);
There are lots of other issues with the code, some less fatal than others:
Use of the ANSI API as opposed to the Unicode API. The latter is strongly recommended, as it allows use of the entire set of Unicode code points (and has less overhead)
Assigning terribly low IDs to controls (0 and 1, respectively) (see Why do dialog editors start assigning control IDs with 100? for details)
Defining a variable in a case label; your compiler warned you about this
Failure to extract the control ID from the WM_COMMAND message handler
A more appropriate implementation could look like this:
// Declare symbolic constants for control IDs
constexpr int TextBoxId = 100;
constexpr int GoButtonId = 101;
// ...
switch (message)
{
case WM_CREATE:
TextBox = ::CreateWindowW(L"EDIT",
L"",
WS_VISIBLE|WS_CHILD|WS_BORDER,
10,10,80,20,
hwnd,(HMENU)TextBoxId,NULL,NULL);
BUTTON = ::CreateWindowW(L"BUTTON",
L"GO",
WS_VISIBLE|WS_CHILD|WS_BORDER,
100,10,70,20,
hwnd,(HMENU)GoButtonId,NULL,NULL);
break;
case WM_COMMAND:
// Evaluate control ID of the sender
switch(LOWORD(wParam)) {
case GoButtonId: {
// ^ Introduce new scope for automatic
// lifetime management of local variables
// Retrieve text from text box
size_t const length = ::GetWindowTextLengthW(TextBox);
std::wstring text(length, L'\0');
::GetWindowTextW(TextBox, text.data(), text.length() + 1);
::MessageBoxW(
hwnd,
std::format(L"I am {} and i am Beautiful!", text).c_str(),
L"smile",
MB_YESNO);
// ...
}
break;
While this implementation reads the edit control's contents into a std::wstring variable the following will work as well, and doesn't require C++20 (compiles with C++98):
::MessageBoxW(
hwnd,
(L"I am " + text + L" and i am Beautiful!").c_str(),
L"smile",
MB_YESNO);
Related
I was wondering if it were possible to take text input from a text box (CreateWindowEx "EDIT") and store it as a string or even better a vector
I need to have a textbox that the user can enter or paste text and when I click a button it will alphabetize the words and count unique words etc...
so far I have it reading it in as characters (i dont know how to make it a string) and alphabetizes the characters
so if I type in: how now brown cow
it will output: bchnnoooorwwww
instead of: brown cow how now
my code under the WM_COMMAND case is
int length;
length = GetWindowTextLength(textbox) + 1;
vector<wchar_t> list(length);
GetWindowText(textbox, &list[0], length);
wstring stxt = &list[0];
wstring str(stxt);
sort(str.begin(), str.end());
SetWindowText(sortedOutput, &str[0]);
This answer may be of use to you in devising a solution. I don't really know of one that is not hacky, but it can be done casting of the constness of c_string() from std::string.
https://stackoverflow.com/a/1986974/128581
A std::string's allocation is not guaranteed to be contiguous under the C++98/03 standard, but C++11 forces it to be. In practice, neither I nor Herb Sutter know of an implementation that does not use contiguous storage.
Notice that the &s[0] thing is always guaranteed to work by the C++11 standard, even in the 0-length string case. It would not be guaranteed if you did str.begin() or &*str.begin(), but for &s[0] the standard defines operator[] as:
Returns: *(begin() + pos) if pos < size(), otherwise a reference to an object of type T with value charT(); the referenced value shall not be modified
Continuing on, data() is defined as:
Returns: A pointer p such that p + i == &operator for each i in [0,size()].
(notice the square brackets at both ends of the range)
Thus it follows you can do something like this:
int len = GetWindowTextLength(hwnd) + 1;
std::string s;
s.reserve(len);
GetWindowText(hwnd, const_cast<char*>(s.c_str()), len - 1);
Which is pretty ugly. Welcome any more "correct" answers, though.
Regarding when unicode is enabled on your build, you have to use a wstring or equivalent. Testing that out just a moment ago, this works:
std::wstring title;
title.reserve(GetWindowTextLength(m_window_handle) + 1);
GetWindowText(m_window_handle, const_cast<WCHAR *>(title.c_str()), title.capacity());
In general, regarding the windows api its useful to google their all caps typedefs and figure out what they really are.
Regarding splitting strings, std::string isn't particular good at this kind of manipulation. This is where std::stringstream (or wstringstream for unicode) comes in handy. I am fairly certain stringstream is not guaranteed to be contiguous in memory, so you can't really go around writing directly into its buffer.
// Initialize a stringstream so we can extract input using >> operator
std::wstringstream ss;
ss.str(title);
// Make a vector, so we can store our words as we're extracting them
// and so we can use sort later, which works on many stl containers
std::vector<std::wstring> words;
std::wstring word;
// This will evaluate to false and thus end the loop when its done
// reading the string word by word
while(ss >> word)
{
words.push_back(word);
}
Then proceed with your sorting, but on the new vector words.
Your problem is not a winapi problem. While not the only way, you found a solution to transfer a string back and forth to your edit box.
How to turn that string into a list/vector of strings, with words being the elements of that list/vector is in fact an STL problem.
Basically, you are looking for the C++ equivalent of the C# function String.Split().
And there is already a good question and answer for that, here:
Most elegant way to split a string?
So, all you have to do is a sort of round trip:
Get string from TextBox
Convert string to a std::vector<string>, using your split function (see the other question for how to do that).
Sort the vector in the usual way.
Convert the vector back to a string, which is the inverse of your split function (Hint: std::ostringstream).
Set the resulting string as the text of your TextBox.
Depending on your preferences regarding multi character strings and globalization, you might decide to stick to the ASCII versions at first. On windows, you can compile to MBCS or ASCII. The respective string types are then respectively (TCHAR and LPCTSTR or WCHAR and LPCWSTR or CHAR and LPCSTR). All win32 functions come in two flavors, distinguished by a trailing A or W at the end of the function name, respectively.
AFAIK, while there is std::string and std::wstring, there is no standard implementation for std::basic_string<TCHAR>, which would work along with your compile options.
As for the window handling, here some code example (snippets):
In InitInstance(), I created the dialog (IDD_FORMVIEW) with my input edit box, my button and my static output area as a child window of the main application window:
//
// 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 hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
HWND hWndChild = CreateDialogW(hInstance, MAKEINTRESOURCE(IDD_FORMVIEW), hWnd, dlgProc);
if (NULL == hWndChild)
{
DWORD lastError = GetLastError();
wchar_t msg[100];
swprintf_s(msg, _countof(msg), L"error code: 0x%0X\n", lastError);
OutputDebugString(msg);
}
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
ShowWindow(hWndChild, SW_SHOW);
UpdateWindow(hWnd);
return TRUE;
}
CreateDialogW() takes as the last parameter a pointer to the dialog handler function, which is called dlgProc() in this example.
This is how that dlgProc() function looks like:
// Message handler for our menu which is a child window of the main window, here.
static INT_PTR CALLBACK dlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
BOOL processed = false;
switch (uMsg)
{
case WM_INITDIALOG:
break;
case WM_NOTIFY:
break;
case WM_COMMAND:
{
auto sourceId = LOWORD(wParam);
auto code = HIWORD(wParam);
if (IDC_BUTTON1 == sourceId)
{
if (BN_CLICKED == code)
{
wchar_t text[1024];
GetDlgItemText(hwndDlg, IDC_EDIT1, text, _countof(text));
// TODO: do your string processing here (string -> string)
SetDlgItemText(hwndDlg, IDC_STATIC, text);
processed = TRUE;
}
}
}
break;
default:
break;
}
return processed;
}
I have just mixed a few lines of code to convert wchar_t to wstring to std::string. Here you go!
string GetWindowStringText(HWND hwnd)
{
int len = GetWindowTextLength(hwnd) + 1;
vector<wchar_t> buf(len);
GetWindowText(hwnd, &buf[0], len);
wstring wide = &buf[0];
string s(wide.begin(), wide.end());
return s;
}
This has a vector so you'll need to include it.
I am currently making a Win32 DLL project with WinAPI, with a User Interface.
I am confused on how I get a textbox's text in C++. Here is what a bit of my code looks like.
case Execute:
char text[256];
TCHAR TextBuffer[_MAX_PATH];
LRESULT result = SendMessage(Pointers::ExecuteBar, WM_GETTEXT, 256, LPARAM(text));
HandleCommands(std::string(text));
std::string UserInput = (std::string)(char*)TextBuffer;
if (Enabled)
{
HandleCommands(UserInput);
}
else
{
PushMessage(L"Not Initialized.", RGB(255, 140, 0));
};
break;
};
break;
that's my case Execute function.
Here's my WinApi Button for Execute.
HWND ExecuteButton = CreateWindow(L"BUTTON", L"EXE", (WS_CHILD | WS_VISIBLE),
340, 380, 60, 20, Pointers::Window, (HMENU)Execute, DllModule, NULL);
I need help because whenever I try and type in something it goes to a message that I put in to notify the user if they typed in something wrong.
If you want to get the text of a window just use the GetWindowText() function
1st param is the handle to the window you want to copy its text.
2nd param is the char that must be previously defined .
3rd param is the max number of chars you will copy.
Example:
char copy[ ] = " ";
GetWindowText(hWndTextBox, ©[0], sizeof(copy)-1);
Here the 3rd param will give it an unlimited numbers of chars to get copied you can set it to any integer number like 20
I have spent today searching everywhere for a concrete explanation or example of coloring the thumb on a trackbar (slider) in win32 C++. Everything I've found has been partially explained, and in trying every conceivable variation I have come up blank.
The control I have been focused on is defined in my rc file as
CONTROL "",IDC_PLAYSLIDER,"msctls_trackbar32",TBS_NOTICKS | WS_TABSTOP,5,22,187,15
Essentially, my message handling of NM_CUSTOMDRAW comes down to the following. I have no confidence on my color/hdc handling, but the lack of messages is my primary problem.
INT_PTR CALLBACK dialogproc(HWND h, UINT m, WPARAM w, LPARAM l)
{
switch (m) {
case WM_NOTIFY:
{
switch (((LPNMHDR)l)->code) {
case NM_CUSTOMDRAW:
{
LPNMCUSTOMDRAW lpNMCD = (LPNMCUSTOMDRAW)l;
UINT idc = lpNMCD->hdr.idFrom;
switch (lpNMCD->dwDrawStage) {
case CDDS_PREPAINT:
return CDRF_NOTIFYSUBITEMDRAW;
break;
case CDDS_SUBITEM | CDDS_ITEMPREPAINT:
{
switch (lpNMCD->dwItemSpec)
{
case TBCD_THUMB:
HGDIOBJ old_pen = SelectObject(lpNMCD->hdc, penSlider);
HGDIOBJ old_brush = SelectObject(lpNMCD->hdc, brushSlider);
return CDRF_NEWFONT;
}
}
break;
}
What I am getting at runtime is a CDDS_PREPAINT on the correct control, but no matter what I have tried, I have had no further CDDS_ drawStage messages.
If anyone has done this on a trackbar (most examples are list controls) and is willing to share their message handler code, or can otherwise shed light on my confusion, that would be greatly appreciated.
From the docs for NM_CUSTOMDRAW:
If this message is handled in a dialog procedure, you must set the
return value as part of the window data before returning TRUE. For
more information, see DialogProc.
The DialogProc docs say:
If the dialog box procedure processes a message that requires a
specific return value, the dialog box procedure should set the desired
return value by calling SetWindowLong(hwndDlg, DWL_MSGRESULT, lResult)
immediately before returning TRUE
Note that with the advent of 64-bit windows it is better practice to use SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, lResult).
I am new here and hope to learn a lot from a great community.
I am beginning to learn some GUI C++ pogramming, but only the basics. I have made one win32 GUI app before using mingw and creating my own resource and header file. All I need the program to do at this point is get text from a text box.
With mingw, I would use a callback function like this, using GetDigItem() to get user input from a text box when a certain button is clicked.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
{
char szFileName[MAX_PATH];
HINSTANCE hInstance = GetModuleHandle(NULL);
GetModuleFileName(hInstance, szFileName, MAX_PATH);
MessageBox(hwnd, szFileName, "This program is:", MB_OK | MB_ICONINFORMATION);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_FILE_EXIT:
DestroyWindow(hwnd);
break;
case ID_STUFF_GO:
break;
case REG_BUTTON:
char NameInput[MAX_PATH];
// Gets inputted info from text boxes
// this is what I want to do in vc++
GetWindowText(GetDlgItem(hwnd, NAME_BOX), NameInput, MAX_PATH);
break;
case WM_CREATE:
{
CreateWindow (TEXT("EDIT"), TEXT("Name Here"), WS_VISIBLE | WS_CHILD | WS_BORDER, 10, 10, 230, 20, hwnd, (HMENU) NAME_BOX, NULL, NULL);
CreateWindow (TEXT("EDIT"), TEXT("Number Here"), WS_VISIBLE | WS_CHILD | WS_BORDER, 10, 35, 230, 20, hwnd, (HMENU) SERIAL_BOX, NULL, NULL);
CreateWindow (TEXT(button), TEXT(button1), WS_VISIBLE | WS_CHILD, 75, 60, 90, 20, hwnd, (HMENU) REG_BUTTON, NULL, NULL);
I've noticed the code is a little different in VC++. I created a button and text box from the Windows Form Designer. I have managed to manipulate inputted info, and have it displayed on the text box, but I need to get inputted info and have it returned as a char, std::string, etc. Here is the code in question that I have, which does not compile as is.
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
// Storage buffer for serial and name
std::string test;
// Upon button click, this will transfer inputted text to the label next to it
label1->Text = textBox1->Text;
// this does not compile
test = textBox1->Text;
// Gets inputted info from text boxes
// This does not compile either
//GetWindowText(GetDlgItem(NULL, textBox1), NameInput, MAX_PATH);
//GetWindowText(GetDlgItem(NULL, textBox2), SerialInput, MAX_PATH);
Does anyone have any ideas on how to get the inputted information in text box to return as a char, char*, (std::)string, or other type for further manipulation? Thanks.
EDIT-
I figured out where in mingw I can use GetDigItem() to return user input, I do that in VC++ by using a System::String^ as indicated in the code below.
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
label1->Text = textBox1->Text;
//char SerialInput[MAX_PATH];
//test -> textBox1->Text
// The following compiles and works to retrieve input
// as a System::String^
System::String^ userinput;
textBox1->Text = userinput;
// However this yields 2 compiler error
// error C2065: 'marshal_as' : undeclared identifier
// error C2275: 'std::string' : illegal use of this type as an expression
std::string stdString = marshal_as<std::string>(newer);
// Forgive any spacing errors, this 4 space indent to repr code
// isn't working with my long expressions
The problem now seems to be getting the System::String^ to something I can work with. My attempts to convert it to an std::string aren't working as I showed, I also included in my stdafx.h. A char or anything would be great. Any ideas?
EDIT 2:
I need to convert a SYstem::String^ to whatever else I can (preferably std::string or char). Here is what I have tried, and the compiler errors recieved.
System::String^ userinput;
userinput = textBox1->Text;
// method 1
const __wchar_t __pin * str1 = PtrToStringChars(userinput);
// error recieved
error C4980: '__pin' : use of this keyword requires /clr:oldSyntax command line option
// method 2
char* str2 = (char*)(void*)Marshal::StringToHGlobalAnsi(str);
// error recieved
error C2653: 'Marshal' : is not a class or namespace name
error C3861: 'StringToHGlobalAnsi': identifier not found
// method 3
// #include <atlstr.h>
// CString str3(userinput);
// error recieved
fatal error C1083: Cannot open include file: 'atlstr.h': No such file or directory
// Where can I get this header file from?
I feel like there's something obvious I"m not doing...
P.S - It's very misleading of Microsoft to call this Visual C++, as this is not C++!
P.S.S - For any c++ coders reading this, VC++ has standards and languages all of it's own, completely different than traditional C++ and even the win api. It's over complication at it's finest - do yourself and your clients a favor and stick to QT for win guis!
You should indicate which framework you're using (e.g., MFC or WTL), and give the specific compiler error rather than simply saying it doesn't compile. Without more information, I'm guess this is the problem:
std::string test;
test = textBox1->Text;
The Text field is probably a wide character string. (Windows uses UTF-16 internally, so--on Windows--a std::wstring is a string of 16-bit character values. Most Windows functions handle surrogates to access characters beyond the BMP. On other OSes, a std::wstring is often a string of 32-bit character values.)
You cannot assign a wide character string to a std::string without a conversion. Your choices are to use a wide string (e.g., std::wstring) or to apply a conversion.
For conversions, Windows has a WideCharToMultibyte function you could use. C++ has std::codecvt.
I am writing my first simple program in C++/WINAPI, with a lot of check boxes and a few edit fields, which will set up some calculations on a button press. All of my check boxes work/store info through individual cases, ie
switch (msg)
{
...
case WM_COMMAND:
{
switch (wParam)
{
case IDBC_BoxCheck1:
{...}
case IDBC_BoxCheck2:
{...}
...
} ...
...but I assumed edit fields didn't work as a case statement like a button press, since the value has to be read at the end once it has been changed as many times as the user wants. I looked online and attempted to use the SendMessage(hwnd, ...) and GetWindowText(hwnd, ...) functions to send a WM_GETTEXT command to the edit field and store it to a lpstr string, but I ran into the same problem with both of them - the hwnd for the edit fields aren't declared in the scope where the WM_GETTEXT command is being sent from, and I'm not sure how to get it there. Here is an overview of the structure being used in my program, which comes from a mix of some tutorials I was working with:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
return OnCreate(hwnd, reinterpret_cast<CREATESTRUCT*>(lParam));
// OnCreate is a sub function that handles the creation of all the buttons/controls,
// since there are so many of them, with the format:
// HWND editControl1 = CreateControl(...); // CreateControl being another sub fnct
// that creates edit field ctrls
// editControl1 is the hwnd I'm trying
// to read the value from
// HWND checkControl1 = CreateButton(...); // Creates button ctrls, including ck box
...
}
...
case WM_COMMAND:
{
switch (wParam)
{
case IDBC_BoxCheck1: // These control IDs are defined at the top of the file
{
LPSTR Check1;
StoreInfo(Check1); // Just a sub fnct to store info for later calculations
}
case IDBC_BoxCheck2:
{
LPSTR Check2;
StoreInfo(Check2);
} // etc... there are 20 or so check boxes/buttons
case IDBC_Calculate:
{
LPSTR edit1;
GetWindowText(editControl1, edit1, 100); // or SendMessage(editControl1, ...)
// This kicks out the error of editControl1 not being declared in this scope
StoreInfo(edit1);
// Calculation function goes here
} ...
} ....
}
default: DefWindowProc(hwnd, msg, wParam, lParam);
}
}
IDBC_Calculate is the final button pressed before the calculations run. I figured the best place to read and store the values from the edit fields would be after this button is pressed, right before the calculation function is called, but tied to the same command. This is where the hwnd editControl1 is undefined, but I don't know how to send the definition to this scope, or where else I should be reading and storing the edit field values.
Any help or pointers on getting the values from these edit fields to my other functions would be appreciated! I've seen many different ways to check button states in various tutorials/lessons, so I'd love to know if there's a better way to do what I've written above in general.
Your edit fields have IDs right? Then you can use GetDlgItem.
editControl1 = GetDlgItem(hwnd, CONTROL_ID_1);
GetDlgItem is badly named, it doesn't just work in dialog boxes. It gets the handle of any child window from a parent window, using the ID of the child window.
And what Anders K says is correct. The way you are using GetWindowText will crash your program.