how do I get a windows text winapi c++? - c++

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, &copy[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

Related

How to get input into a messageBox

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);

Crash after SendMessage to TEdit

I'm trying to get data from another program. And... it's giving me an error all the time! Is there something wrong?
HWND hWnd = FindWindow(NULL, L"MyProgram");
if (hWnd)
{
HWND TPageControl = FindWindowEx(hWnd, NULL, L"TPageControl", NULL);
TPageControl = FindWindowEx(hWnd, TPageControl, L"TPageControl", NULL);
HWND TTabSheet = FindWindowEx(TPageControl, NULL, L"TTabSheet", NULL);
HWND TEdit = FindWindowEx(TTabSheet, NULL, L"TEdit", NULL);
int editlength = SendMessage(TEdit, WM_GETTEXTLENGTH, 0, NULL);
TCHAR* Targets = new TCHAR( editlength + 1 );
int count = SendMessage(TEdit, EM_GETLINE, editlength + 1, (LPARAM) Targets);
std::wcout << Targets << "\n";
//delete Targets;
}
but if i'm debugging, it's working.
You are not following the documentation for EM_GETLINE. The first parameter specifies the line index. I'm assuming you are sending this message to a single-line edit control, and it simply gets ignored. The second parameter must hold the length of the buffer:
Before sending the message, set the first word of this buffer to the size, in TCHARs, of the buffer.
The remarks for edit controls are also relevant:
The copied line does not contain a terminating null character.
While parameters for EM_GETLINE get automatically marshaled across process boundaries (like all message parameters for messages in the range 0 to W_USER-1), you might want to consider sending WM_GETTEXT instead, if you are dealing with a single-line edit control:
int editlength = SendMessage(TEdit, WM_GETTEXTLENGTH, 0, NULL);
TCHAR* Targets = new TCHAR[editlength + 1];
int count = SendMessage(TEdit, WM_GETTEXT, editlength + 1, (LPARAM) Targets);
// NUL-terminate buffer in case the text did not fit
Targets[count] = _T('\0');
std::wcout << Targets << "\n";
If you are sending WM_GETTEXT to a hung application your application will hang as well. Call GetWindowText to work around this. The secret life of GetWindowText has additional background information.
If you need to retrieve a specific line from a multi-line edit control the following is more appropriate. In contrast to your code it sends an EM_LINEINDEX and EM_LINELENGTH message to retrieve the appropriate buffer size:
int characterIndex = SendMessage(TEdit, EM_LINEINDEX, lineIndex, 0);
int lineLength = SendMessage(TEdit, EM_LINELENGTH, characterIndex, 0);
TCHAR* pBuffer = new TCHAR[lineLength + 1];
// Set the size of the buffer
*(WORD*)pBuffer = lineLength + 1;
// Retrieve the line
int characterCount = SendMessage(TEdit, EM_GETLINE, lineIndex, (LPARAM)pBuffer);
// NUL-terminate buffer
pBuffer[characterCount] = _T('\0');
A word on why the initial code appears to work when run under a debugger: It's not the debugger, that makes a difference. It's the Debug Build that does. A debug configuration will fill allocated memory with specific byte patterns (0xCD for operator new[]()). The effect of this is that the buffer passed when sending EM_GETLINE is interpreted as having size 0xCDCD (52685 in decimal). In a release configuration on the other hand, the buffer contents are usually 0x00, i.e. the buffer is interpreted as having size 0. This is not to say that the debug build works. It merely masks an error.
I used GetWindowText, works like a sharm I did't want to use fancy calculations. The error really only appears on multiline text, since the buffer size would be calculated correctly.
MS Documentation GetWindowText

TabCtrl_GetItem macro not working as expected

I'm creating a basic notepad program, and when the user clicks close, I want it to ask the user if they want to save the current document opened. I'm using a tabbed interface, and trying to retrieve the filename ( text on tab ) so I have a MessageBox that says "Would you like to save: untitled.txt" or similar. I'm having trouble getting the file name. This is what I currently have:
case ID_FILE_CLOSE: // When the close button is clicked
{
HWND hEdit, hTabs;
hTabs = GetDlgItem( hwnd, IDC_MAIN_TAB );
int curTab = TabCtrl_GetCurSel( hTabs );
TCITEM curtitem;
TabCtrl_GetItem( hTabs, curTab, &curtitem );
// Check for file name
MessageBox( hwnd, curtitem.pszText, "Test", MB_OK );
}
break;
This is the error I keep getting in a popup box with Break, Continue, Ignore buttons:
Unhandled exception at 0x7597d298 in notepadpremium.exe: 0xC0000005: Access violation reading location 0xcccccccc.
I'm using MS Visual C++ Express 2010.
I also have a listbox with the filenames that also show the extension ( almost like notepad++ document switcher ) and tried LB_GETITEMDATA through a message, but that always returned blank. I think that was because I use LB_ADDSTRING to add it to the listbox. ( the listbox and tabs are interconnected, when you click on a file in the listbox, it changes to the corresponding tab ). Why isnt my code working the way it should?
Read the documentation:
pitem
Type: LPTCITEM
Pointer to a TCITEM structure that specifies the information to retrieve and receives information about the tab. When the message is sent, the mask member specifies which attributes to return. If the mask member specifies the TCIF_TEXT value, the pszText member must contain the address of the buffer that receives the item text, and the cchTextMax member must specify the size of the buffer.
You are not initializing the TCITEM at all. You need to tell TabCtrl_GetItem() what data to retrieve, and more importantly what buffer you provide to receive that data into. You are not doing any of that, you are passing random data to TabCtrl_GetItem(), which is why it crashes.
Try this instead:
case ID_FILE_CLOSE: // When the close button is clicked
{
HWND hTabs = GetDlgItem( hwnd, IDC_MAIN_TAB );
int curTab = TabCtrl_GetCurSel( hTabs );
TCHAR szFileName[MAX_PATH+1] = {0};
TCITEM curtitem = {0};
curitem.mask = TCIF_TEXT;
curitem.pszText = szFileName;
curitem.cchTextMax = MAX_PATH;
if (TabCtrl_GetItem( hTabs, curTab, &curtitem ))
{
// also from the documentation:
//
// "the control may change the pszText member of the structure
// to point to the new text instead of filling the buffer with
// the requested text. The control may set the pszText member
// to NULL to indicate that no text is associated with the item."
//
// which means you cannot rely on the szFileName[] buffer actually
// containing the filename, you have to use whatever buffer the
// TCITEM is actually pointing at, which may or may not be the
// szFileName buffer...
MessageBox( hwnd, curitem.pszText, TEXT("Test"), MB_OK );
}
}
break;
As for your ListBox issue, you said you are using LB_ADDSTRING to add strings to the ListBox, but are using LB_GETITEMDATA to retrieve them. That is wrong. You need to use LB_GETTEXTLEN and LB_GETTEXT instead. LB_GETITEMDATA is used to retrieve user-defined data that was added to the ListBox using LB_SETITEMDATA.

c++ winapi, get listview header text

I created a listview and after that I would like to get the header text, something like this:
HWND hwndHD = ListView_GetHeader(hListView);
HDITEM hdi;
Header_GetItem(hwndHD, 2, (LPHDITEMA) &hdi);
unsigned char HDtext[lMAX];
hdi.pszText = (LPSTR)HDtext;
SendMessage(hListView, HDM_GETITEM, (WPARAM) 0, (LPARAM) &hdi);
std::string str(HDtext, HDtext + sizeof(HDtext));
MessageBox(hwnd, str.c_str() , "CreateFile", MB_OK);
But it didn't work, what am I do wrong?
You have to initialise the HDITEM parameter before you call the Header_GetItem. You must specify in the mask which information you are requesting.
In your case you want to do it like this:
char HDtext[lMAX];
HWND hwndHD = ListView_GetHeader(hListView);
HDITEM hdi = { 0 };
hdi.mask = HDI_TEXT;
hdi.pszText = HDtext;
hdi.cchTextMax = lMAX;
Header_GetItem(hwndHD, 2, &hdi);
You have also completely neglected to include error checking in your code. You should add it.
You need to check the return value of every API call. Consult the documentation on MSDN to know how to interpret it.
Using the code above as an example, you would write:
HWND hwndHD = ListView_GetHeader(hListView);
if (hwndHD == NULL) {
// handle error
}
....
if (!Header_GetItem(hwndHD, 2, &hdi)) {
// handle error
}

Obtaining input from textbox Visual C++ 2010 Express

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.