Crash after SendMessage to TEdit - c++

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

Related

how do I get a windows text winapi 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

In Windows, Does SetCurrentConsoleFontEx change console's font size?

Other guys recommend the SetCurrentConsoleFontEx function but I don't know how to apply it to my project.
I want to change the font size of only some texts, not all texts.
Does SetCurrentConsoleFontEx() change the console's font size?
Or are there other ways to change it?
If there is, please show me the console function and a simple example.
Here is an example of using SetCurrentConsoleFontEx to change the console's font size. This affects the entire console window -- so like Joachim Pileborg already said, if you want mixed font sizes in a single console window, this won't help you.
#define _WIN32_WINNT 0x500
#include <Windows.h>
// PrintChars sends ASCII characters to console output
// for demonstration purposes.
// depends only on Win32 API
static void PrintChars() {
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD num_written;
static const char* cr_lf = "\r\n";
for(char c=' '; c<'\x7f'; ++c) {
WriteFile(hStdout, &c, 1, &num_written, NULL);
if(c % 16 == 15) WriteFile(hStdout, cr_lf, 2, &num_written, NULL);
}
WriteFile(hStdout, cr_lf, 2, &num_written, NULL);
}
// WaitEnter blocks execution until the user
// presses the enter key.
// depends only on Win32 API
static void WaitEnter() {
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
char buffer;
DWORD num_read;
do {
num_read = 0;
ReadFile(hStdin, &buffer, 1, &num_read, NULL);
} while(num_read && buffer != '\n');
}
int main() {
// Display some example characters
PrintChars();
// Wait for the user to see how the current font looks
WaitEnter();
// Get a handle to the current console screen buffer
HANDLE hcsb = CreateFileA("CONOUT$", GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
CONSOLE_FONT_INFOEX cfi = {sizeof(cfi)};
// Populate cfi with the screen buffer's current font info
GetCurrentConsoleFontEx(hcsb, FALSE, &cfi);
// Modify the font size in cfi
cfi.dwFontSize.X *= 2;
cfi.dwFontSize.Y *= 2;
// Use cfi to set the screen buffer's new font
SetCurrentConsoleFontEx(hcsb, FALSE, &cfi);
// Wait for the user to see the difference before exiting
WaitEnter();
CloseHandle(hcsb);
}

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
}

Parameters referenced from the same variable point to different locations

I'm trying to store HWND pointers in an int vector along with other data, I'm using the following code to get the data and store it on creation:
void createscalingwindow(HWND &cswpara0,DWORD cswpara1,const CHAR* cswpara2,
const CHAR* cswpara3,DWORD cswpara4,int cswpara5,
int cswpara6,int cswpara7,int cswpara8,HWND cswpara9,
HMENU cswpara10,HINSTANCE cswpara11,LPVOID cswpara12)
{
cswpara0 = CreateWindowEx (cswpara1, cswpara2, cswpara3, cswpara4, cswpara5,
cswpara6,cswpara7,cswpara8,cswpara9,cswpara10,
cswpara11,cswpara12);
sizevalues.push_back((int)&cswpara0);
snprintf (buffer, 20,"%d", sizevalues[zero]);
MessageBox (NULL, buffer, "pointer", NULL);
sizevalues.push_back(cswpara5);
sizevalues.push_back(cswpara6);
sizevalues.push_back(cswpara7);
sizevalues.push_back(cswpara8);
return;
}
This following code is a prototype that currently only shows the values in a messagebox, but I later plan to have it resize child windows to scale with the parent
void scalewindowsize (HWND &ownerwin, HWND &childwin)
{
/*check owner window*/
char buffer[100];
int checknumber = 0;
while (checknumber < sizevalues.size())
{
if (sizevalues[checknumber] == (int)&ownerwin)
{
snprintf (buffer, 100,"%d", sizevalues[checknumber]);
MessageBox (NULL, buffer, "foundit", NULL);
break;
}
snprintf (buffer, 20,"%d", (int)&ownerwin);
checknumber = (checknumber + 5);
MessageBox (NULL, buffer, "fail", NULL);
}
return;
}
The problem is that the first Messagebox in createscalingwindow produces a value of 4235304 while the second one produces an entirely different number (the number varies). Why is this?
UPDATE: Found out part of the cause, in order to reproduce this the HWND used as a parameter to scalewindowsize must be used in a window procedure with the same parameter HWND in that window procedure.
Don't store non-int values in an int vector. That's asking for trouble.
Instead create a class that has fields (with the proper types) for all your values, and create a vector that contains objects of that class.
Your numbers changing is however likely caused by you taking the address of a local variable and using it after the function declaring the variable returns. You should just push the value of the HWND, not the address where it's stored. Handles are plain numbers, so there's no need to pass them by reference, unless you plan to change them in the function (I don't see why you'd need to do that in createscalingwindow either - you could just return the value)

Debugging font linking

I have a problem with a program we're developing. It is written using MFC but does not use unicode. We have made a translation into simplified chinese. So far this is our first and only localization. We have moved all strings to resources to make them translateable. Everything seems to work fine on our computers (both Win7 and XP) but for some customers computers running windows XP we get problems:
On those computers all translated strings work except for those we enter into tree cotrols (CTreeCtrl is used directly). I'm not sure if it is the tree control or the text we enter that causes the problem, but the font seems to not get substituted in those controls. My guess is that maybe it does not get substituted because some of the strings also contain latin characters. Still, that kind of substitution seems to work in other places of the program and not all strings entered into the tree contain those characters either.
So my first question is: Is there a way to get to know what is happening inside the control? We can have remote access to the computers where the problem is happening but running a debugger on them may be a little tricky. What kind of tools can be used to diagnose this problem?
One possible solution that crossed my mind was to subclass the tree controls to get more control over the actual text drawing, maybe using the approach from http://blogs.msdn.com/b/oldnewthing/archive/2004/07/16/185261.aspx to get around the problem. Could this be effective or would it just be an awful lot of work for nothing?
Thanks a lot!
Ok, it seems on their system there was either a bug in the tree control implementation or they had some systemwide addin that hooked into the drawing in some way. What I ended up doing was to do custom drawing through notifications in the tree view and then using font linking to resolve the fonts. I dont think font linking would be necessary, though, because I think most of the time it ended up doing just TextOutW() with the preselected font anyway.
Here is a somewhat simplified code sample of what I ended up with:
void MyDlg::OnCustomDrawTreeItem( NMHDR* pNMHDR, LRESULT* pResult )
{
if (!mpFontLink)
{
*pResult = CDRF_DODEFAULT;
return;
}
LPNMTVCUSTOMDRAW pCustomdraw = (LPNMTVCUSTOMDRAW) pNMHDR;
switch(pCustomdraw->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
{
// Ask to do custom draw
*pResult = CDRF_NOTIFYITEMDRAW;
break;
}
case CDDS_ITEMPREPAINT:
{
// Ask for post paint notification
*pResult = CDRF_NOTIFYPOSTPAINT;
break;
}
case CDDS_ITEMPOSTPAINT:
{
// Get the rect of only the item, not the tree stuff
RECT rcItem;
m_pageTree.GetItemRect((HTREEITEM) pCustomdraw->nmcd.dwItemSpec, &rcItem, TRUE);
// Erase the item background in case the previous string drawn was wider
HDC hDC = pCustomdraw->nmcd.hdc;
FillRect( hDC, &rcItem, (HBRUSH) GetClassLongPtr(m_pageTree.GetSafeHwnd(), GCLP_HBRBACKGROUND));
pageStruct *pS = (pageStruct*) pCustomdraw->nmcd.lItemlParam;
DWORD dwFontCodepages = 0, dwStrCodepages = 0;
HFONT hOriginalFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT);
HRESULT hr = mpFontLink->GetFontCodePages( hDC, hOriginalFont, &dwFontCodepages);
OML_CStringW tData = pS->csCaption.GetBuffer();
// Set up position etc
DWORD dwAlignOrig = GetTextAlign(hDC);
if (!(dwAlignOrig & TA_UPDATECP)) {
SetTextAlign(hDC, dwAlignOrig | TA_UPDATECP);
}
POINT ptOrig;
MoveToEx(hDC, 2 + rcItem.left, 1 + rcItem.top, &ptOrig);
SetTextColor( hDC, pCustomdraw->clrText );
SetBkColor( hDC, pCustomdraw->clrTextBk );
// Loop over the parts of the text
TuInt32 nIndex = 1;
while (nIndex <= tData.GetLength())
{
long nActualChars = 0;
wchar_t *pStr = (wchar_t*)tData.BaseGetItemP( nIndex );
TuInt32 nChars = 1 + tData.GetLength() - nIndex;
hr = mpFontLink->GetStrCodePages(pStr, nChars,
dwFontCodepages, &dwStrCodepages, &nActualChars);
if (dwStrCodepages & dwFontCodepages)
{
// We end up here almost every time, that is why TextOutW would probably be enough.
// This part is supported by the original font (or the GDI can help us switch automatically)
TextOutW(hDC, 0, 0, pStr, nActualChars);
}
else
{
// We need to link
HFONT hLinked;
if (FAILED(hr = mpFontLink->MapFont(hDC, dwStrCodepages, 0, &hLinked)))
{
// Fail: Output the rest without linking
TextOutW( hDC, 0, 0, pStr, nChars );
break;
}
// Output with linked font
SelectObject(hDC, hLinked);
TextOutW( hDC, 0, 0, pStr, nActualChars);
SelectObject(hDC, hOriginalFont);
mpFontLink->ReleaseFont( hOriginalFont );
}
nIndex += nActualChars;
}
OML_LOG_1( "_END:");
// Reset alignment mode
if (!(dwAlignOrig & TA_UPDATECP)) {
SetTextAlign(hDC, dwAlignOrig);
MoveToEx(hDC, ptOrig.x, ptOrig.y, NULL);
}
*pResult = CDRF_SKIPDEFAULT;
}
default:
{
*pResult = CDRF_DODEFAULT;
break;
}
}
} /* OnCustomDrawTreeItem */