WM_GETTEXT returning only single character - c++

I'm a chemist new to coding and am working on a script to help me automatically process some of my data. The code I'm working on right now involves using WM_GETTEXT to grab the title of a window handle. However, right now the char buffer is only grabbing a single character, rather than the whole title. It looks like someone several years ago had a similar problem (link: http://www.cplusplus.com/forum/beginner/58207/), which suggests the issue may be related to mixing data types. I tried switching to a TCHAR as suggested, but cannot compile on doing so (receive error that I cannot convert from "const char[1] to TCHAR[254]). Here's the code I'm using:
int textLen = (int)SendMessage(windowHandle, WM_GETTEXTLENGTH, 0, 0);
std::cout << "The handle length is: " << textLen << std::endl;
const int bufferSize = 254;
char textBuffer[bufferSize] = "";
SendMessage(windowHandle, WM_GETTEXT, (WPARAM)bufferSize, (LPARAM)textBuffer);
std::cout << "The handle title is: " << textBuffer << std::endl;
Does anyone have any suggestions? I'm working in Microsoft Visual Studio, which I think may be part of the problem, but I'm not sure how to fix it.

Try calling SendMessageA instead of SendMessage - that indicates you are using char not WCHAR (i.e. what TCHAR really might have been).
Alternatively, use wide-character versions of std::cout, which is std::wcout and use TCHAR/WCHAR throughout (including textBuffer declaration).
In essence, you're mixing wide strings with old-school strings.

The other answer is correct, but you might want to consider using GetWindowText instead of sending the message.
With GetWindowText, whether you use the -A or -W suffix, you'd get some type safety, which might have helped you avoid this problem in the first place.
In some cases, GetWindowText can return the title even if the process that owns the target window is hung or not responding to messages in a timely fashion.

Related

Cannot fix an "invalid handle" error in WinAPI when trying to do anything requiring it

I am trying to play around with WinAPI to be able to manipulate the console, mostly just be able to write whatever I want, wherever I want without having to rewrite the whole console. I remember that I once got it to work earlier but that was long ago and I seem to have lost that code... whoops.
Anyway, I remember, that I succeeded with much less effort than what it is taking me now.
I am using this MS Docs page for reference and I remember using it earlier, successfully.
Right now, there is truly only a couple of lines that I am trying to get to work:
#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
HANDLE hndl = GetStdHandle(STD_INPUT_HANDLE);
if (hndl == INVALID_HANDLE_VALUE)
{
cout << "Invalid handle, error " << GetLastError();
return 0;
}
long unsigned int *chars_written = new long unsigned int;
if (!WriteConsoleOutputCharacter(hndl, "mystring", 8, {20, 30}, chars_written))
{
cout << "Could not write, error " << GetLastError();
return 0;
}
return 0;
}
The result is the console window displaying "Could not write, error 6" and then ending the application.
Error 6, according to System Error Codes is "the handle is invalid".
What am I doing wrong? I must be missing something.
It seems to be important that I am trying to work in Code::Blocks.
BONUS: I tried MS Visual Studio with the full WinAPI SDK (some important parts seem to be missing in Code::Blocks) and, while the main problem is the same, the functions in MS Visual Studio don't seem to all fit the official reference I am using, e.g. WriteConsoleOutputCharacter requires an LPCWSTR as its 2nd argument instead of a LPCSTR as mentioned in the source and as works in Code::Blocks. Windows Data Types
Edit: I found that WriteConsoleOutputCharacter is a macro actually, and is defined differently between Code::Blocks and MS Visual Studio, as two different, existing in both versions functions: WriteConsoleOutputCharacterA() and WriteConsoleOutputCharacterW(), which sadly, is not mentioned in the MS Docs.
Thank you in advance,
Maurice.
First of all WriteConsoleOutputCharacter() requires a wide string as argument, while you're passing a normal string "mystring" as argument. To make it a wide literal, you just add the letter L as a prefix - e.g: L"mystring". And the program is giving you an error because the handle you're retrieving is an input handle (STD_INPUT_HANDLE). Meanwhile, if you want to output to the console through a handle you need to retrieve an output handle (STD_OUTPUT_HANDLE).

Printing UTF8 characters to linux console using C++

I am trying to get the unicode character macron (U+00AF), i.e., an overscore, to print consistently on various linux consoles. So far, some consoles work (e.g., putty ssh), others do not (e.g., ubuntu shell), and I have not been able to figure out what I am doing right in one case (probably luck) and wrong in the other.
I do know the basics of Unicode and Utf8, but I have not been able to figure out how to consistently get consoles to display the appropriate characters.
Any suggestions? Note that this is explicitly for unix consoles - all of the similar questions I have found focused on Windows-specific console commands.
Here is what I would effectively like to get working:
wchar_t post = L'¯'; //0xC2AF
std::wcout << post << std::endl;
Unfortunately nothing I tried or could find in the way of suggestions consistently displayed the appropriate character, so I ended up using an ASCII hyphen '-' as a close enough match.
The solution is to put it into stream as a multicharacter string:
std::string s = "\uC2AF";
std::cout << s << std::endl;
or to set a locale using
char* setlocale( int category, const char* locale);
function:
std::locale old_locale; // current locale
setlocale(LC_ALL, "en_US.UTF-8");
wchar_t w = 0xC2AF;
std::wcout << w << std::endl;
setlocale(LC_ALL, old_locale.name().c_str()); // restore locale
The final result is however dependent on many user settings (console, fonts, etc.), so there is no guarantee that it will be OK.

Adding a string to a listbox results in weird characters

I have made a function that send strings to listbox using WIN32
char data[] = "abcd";
addToList(hWnd,data);
void addToList(HWND hWnd,char data[] ){
SendMessage(GetDlgItem(hWnd,IDC_LISTBOX),LB_ADDSTRING,0,(LPARAM)data);
}
when I execute this it's send data to list box but the problem they appeared in weird characters, I have tried wchar_t also but the problem still issued
First of all, you should be checking your API calls for errors. You need to check the return values of all your calls to API functions.
That said, given the code in the question,
SendMessage(GetDlgItem(hWnd,IDC_LISTBOX),LB_ADDSTRING,0,(LPARAM)data);
If that results in an item being added to the list box, then it means that GetDlgItem did indeed return a valid window handle, and data did indeed point to valid memory. In which case the only explanation for what you report is that the text encoded did not match.
So, we can assume that the SendMessage macro evaluates to SendMessageW. And since you are passing ANSI encoded text, that mismatch explains the symptoms. The function treats the text as UTF-16 encoded.
One obvious solution is to use SendMessageA instead. However, a better solution, in my view, would be to pass UTF-16 encoded data.
wchar_t data[] = L"abcd";
....
void addToList(HWND hWnd, const wchar_t *data)
{
SendMessage(GetDlgItem(hWnd,IDC_LISTBOX), LB_ADDSTRING, 0, (LPARAM)data);
}
Obviously your code would add in the error checking that I mentioned at the start.

CreateProcess and CreatePipe to execute a process and return output as a string in VC++

I am trying to use CreateProcess and CreatePipe to execute a process from within a Windows Forms C++/CLR application in Visual Studio 2010.
From within my Windows forms app I want to execute a child process (console app) and return the output as a std::string, std::wstring, or System::String^ within my Windows forms app. Additionally, I do not want the newly created child process to spawn a window.
The console application is of my own creation, so I have control of it's source too.
I have seen the following examples, but I do not understand how to modify the code to accomplish what I am trying to do:
MSDN
kgui
A simpler MFC based function
The MSDN code appears to be written as two console apps, one calling the other. The code is confusing to me. I've only been working in C++ for about 4 months, so I still don't understand everything. It appears to reference a text file, which I don't need to do.
Is there a simpler way to do this than MSDN's 200+ lines of code or kgui's 300+ lines of code?
The answer here was helpful, but over simplistic. I was hoping to see a basic source example (one that doesn't involve hundreds of lines of complex code would be preferable). I would have used the MFC code, but I had difficulty adapting it to my purposes (I'm not using MFC).
Following is my adaptation of the code from Code Project:
string ExecuteExternalFile(string csExeName, string csArguments)
{
string csExecute;
csExecute=csExeName + " " + csArguments;
SECURITY_ATTRIBUTES secattr;
ZeroMemory(&secattr,sizeof(secattr));
secattr.nLength = sizeof(secattr);
secattr.bInheritHandle = TRUE;
HANDLE rPipe, wPipe;
//Create pipes to write and read data
CreatePipe(&rPipe,&wPipe,&secattr,0);
//
STARTUPINFO sInfo;
ZeroMemory(&sInfo,sizeof(sInfo));
PROCESS_INFORMATION pInfo;
ZeroMemory(&pInfo,sizeof(pInfo));
sInfo.cb=sizeof(sInfo);
sInfo.dwFlags=STARTF_USESTDHANDLES;
sInfo.hStdInput=NULL;
sInfo.hStdOutput=wPipe;
sInfo.hStdError=wPipe;
//Create the process here.
CreateProcess(0,(LPWSTR)csExecute.c_str(),0,0,TRUE,NORMAL_PRIORITY_CLASS|CREATE_NO_WINDOW,0,0,&sInfo,&pInfo);
CloseHandle(wPipe);
//now read the output pipe here.
char buf[100];
DWORD reDword;
string m_csOutput,csTemp;
BOOL res;
do
{
res=::ReadFile(rPipe,buf,100,&reDword,0);
csTemp=buf;
m_csOutput+=csTemp;
}while(res);
return m_csOutput;
}
I have tried using this from within my Windows Forms app, and while it compiles ok and doesn't cause any errors, it doesn't seem to work either. I have no idea why.
This is how I executed the above code:
std::string ping = ExecuteExternalFile("ping.exe", "127.0.0.1");
It did not appear to do anything, except that on the first execution it give a very strange 3 characters as an output, then on subsequent executions, nothing.
You are not making correct use of the ::ReadFile() function.
Read about it here: http://msdn.microsoft.com/en-us/library/ms891445.aspx
Basically, you want to fail with an error if the function ever does not return TRUE, and you want to keep looping until it yields a zero reDword.
Also, ::ReadFile() will not zero-terminate your data for you, so you have to do it yourself, like this: buf[reDword] = '\0'; (make sure your buf is 101 chars long before doing that.)
EDIT:
Since I was asked to provide some example code, here it is, though I have not gone through the trouble of actually compiling it to make sure it works, so please beware of syntax errors, and generally consider it only as a rough pointer to the direction in which it should be done:
#define BUFFER_SIZE 100
string csoutput;
for( ;; )
{
char buf[BUFFER_SIZE+1];
DWORD redword;
if( !::ReadFile(rPipe,buf,BUFFER_SIZE,&redword,0) )
{
DWORD error = ::GetLastError();
//throw new Exception( "Error " + error ); //or something similar
}
if( redword == 0 )
break;
buf[redword] = '\0';
string cstemp = buf;
csoutput += cstemp;
}
return csoutput;
Thanks to Hans Passant for the lead that got me to this clear and simple piece of code that does exactly what I was looking for.
/// this namespace call is necessary for the rest of the code to work
using namespace System::Diagnostics;
using namespace System::Text;/// added for encoding
Process^ myprocess = gcnew Process;
Encoding^ Encoding;/// added for encoding
Encoding->GetEncoding(GetOEMCP());/// added for encoding
myprocess->StartInfo->FileName = "ping.exe";
myprocess->StartInfo->Arguments = "127.0.0.1";
myprocess->StartInfo->UseShellExecute = false;
/// added the next line to keep a new window from opening
myprocess->StartInfo->CreateNoWindow = true;
myprocess->StartInfo->RedirectStandardOutput = true;
myprocess->StartInfo->StandardOutputEncoding = Encoding;/// added for encoding
myprocess->Start();
String^ output = gcnew String( myprocess->StandardOutput->ReadToEnd() );
myprocess->WaitForExit();
/// OutputBox is the name of a Windows Forms text box in my app.
OutputBox->Text = output;
EDIT: Added encoding information. See above code.

Opening Unicode text files in C++ and displaying their contents

Currently I am attempting to open a text file that was saved in Unicode format, copy it's contents to a wstring, and then display it on the console. Because I am trying to understand more about working with strings and opening files, I'm experimenting with it in a simple program. Here is the source.
int main()
{
std::wfstream myfile("C:\\Users\\Jacob\\Documents\\openfiletest.txt");
if(!myfile.is_open())
{
std::cout << "error" << std::endl;
}
else
{
std::cout << "opened" << std::endl;
}
std::wstring mystring;
myfile >> mystring;
std::wcout << mystring << std::endl;
system("PAUSE");
}
When I try to display it on the console it displays  ■W H Y when it should display WHY (really it's "WHY WONT YOU WORK", but ill worry about why it's incomplete later I guess).
In all honesty, using Unicode is not very important to me because this isn't a program that I will be selling (more for just my self). I do want to get familiar with it though because eventually I do plan on needing to knowledge of using Unicode in C++. I am also using boost file-system for working with directories and multithreading while using C++/cli for the GUI. My question(s): Should I really bother using Unicode if I don't need it at this point in time, If so how do I fix this problem, and are there and cross platform libraries for dealing with strings and files that use different Unicode encodings (windows with UTF-16 and Linux with UTF-32).
Also, any articles on Unicode in C++ or Unicode in general would be appreciated. Here is one that I found and it helped a little.The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
Thanks.
EDIT: Here is another arcticle I just found that was useful Reading UTF-8 Strings with C++
That's a byte order mark. If you find one at the beginning of the file, just strip it.
And the spaces in between letters are probably because the console isn't very wide char friendly.
It displays just one word because myfile is a stream and operator>> extracts just one string separated by whitespaces from the stream. You might want to try the getline function.