Get text from an edit control - winapi

I tried this:
int editlength;
int buttonid = 3324; // id to button, the numbers dont mean anything
int editid = 5652; // id to edit
LPTSTR edittxt;
HWND button; // created in wWinmain as a button
HWND edit; // created in wWinMain as an edit control
// LRESULT CALLBACK WindowProc
switch(uMsg)
{
case WM_COMMAND:
if(wParam == buttonid)
{
filedit = GetDlgItem(hwnd, editid); // I tried with and without this
editlength = GetWindowTextLength(filedit);
GetWindowText(filedit, edittxt, editlength);
MessageBox(hwnd, edittxt, L"edit text", 0);
}
break;
}
But I get don't see any text in the message box.

The last argument to GetWindowText() is the size of your buffer. Since you set it to the length of the string, you are telling the function that your buffer is too small because there's no room for the null terminator. And nothing gets copied.
In addition, you must already allocate the buffer to hold the copy of the text. What does edittxt point to? I don't even see where you initialize it.
Correct usage would look something like this:
TCHAR buff[1024];
GetWindowText(hWndCtrl, buff, 1024);

edittxt needs to be a pointer to a buffer that gets the text.. so try this...
char txt[1024];
....
GetWindowText(filedit, txt, sizeof(txt));
You may have to adjust for unicode.. sorry its been a while since I did raw win32.

Related

RegisterPointerInputTarget not consuming all input

I'm working in Windows 10 and I am trying to write a C++ program that intercepts all touch screen input, however some input is still getting through.
My code calls RegisterPointerInputTarget with PT_TOUCH to intercept touch input. This mostly seems to work, however the results are inconsistent. As a test I have added code that uses SendInput to move the mouse slowly to the right whenever touch input is detected. With my program running I can, for example, open up MS Paint and touch the screen. So long as I hold my finger still on the cursor moves slowly to the right as expected. The moment I move my finger however, the cursor snaps to the position under my finger, just as it would if my program were not running at all.
To give another example, if I try the same thing in visual studio, again the cursor moves slowly to the right until I move my finger at which point the cursor follows my fingers' movement but slowly, lagging be behind it with a significant delay.
The code to set up my window looks like this;
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
static const char* class_name = "DUMMY_CLASS";
WNDCLASSEX wx = {};
wx.cbSize = sizeof(WNDCLASSEX);
wx.lpfnWndProc = WndProc; // function which will handle messages
wx.hInstance = hInst;
wx.lpszClassName = class_name;
HWND hWnd = 0;
if (RegisterClassEx(&wx)) {
hWnd = CreateWindowEx(0, class_name, "dummy_name", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
}
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
if (RegisterTouchWindow(hWnd, 0) &&
RegisterPointerInputTarget(hWnd, PT_TOUCH))
{
...
and my message handling code looks like this;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_TOUCH:
{
INPUT Inputs[1] = { 0 };
Inputs[0].type = INPUT_MOUSE;
Inputs[0].mi.dx = 1;
Inputs[0].mi.dy = 0;
Inputs[0].mi.dwFlags = MOUSEEVENTF_MOVE;
SendInput(1, Inputs, sizeof(INPUT));
Ideally this test code would simply move the cursor for any touch input. Any help in fixing or just understanding this would be greatly appreciated!
I have made some progress with this but have hit other, related, problems I will ask about in a separate question. I will add a comment here when that question is live. The key to sorting out this initial issue however was to make sure I am returning 0, without calling DefWindowProc from all WM_POINTERENTER, WM_POINTERLEAVE, WM_POINTERUP, WM_POINTERDOWN, WM_POINTERUPDATE and WM_TOUCH messages, and to put my SendInput call into the code processing the WM_UPDATE message.

RestoreCapture FMX - Win32

I took this example of subclassing a Form's HWND as a starting point and then added in jrohde's code from from here that is designed to let you drag a Form by clicking anywhere on it (not on the caption bar). This code fails on the ReleaseCapture()line with this message: E2283 Use . or -> to call '_fastcall TCommonCustomForm::ReleaseCapture()
If i comment that line out the code runs and i can move the form by left mouse don and drag, but i can't let go of it. The mouse gets stuck to the form like flypaper. If i replace the ReleaseCapture() with a ShowMessage i can break out but that is obviously not the way to go...
What do i need to do allow that RestoreCapture() to run? This is Win32 app.
BELOW IS THE CODE i added to the original switch(uMsg) block:
// two int's defined above the switch statement
static int xClick;
static int yClick;
// new case added to the switch
case WM_LBUTTONDOWN:
SetCapture(hWnd);
xClick = LOWORD(lParam);
yClick = HIWORD(lParam);
break;
case WM_LBUTTONUP:
//ReleaseCapture(); // This is the problem spot <------------------------
ShowMessage("Up");
break;
case WM_MOUSEMOVE:
{
if (GetCapture() == hWnd) //Check if this window has mouse input
{
RECT rcWindow;
GetWindowRect(hWnd,&rcWindow);
int xMouse = LOWORD(lParam);
int yMouse = HIWORD(lParam);
int xWindow = rcWindow.left + xMouse - xClick;
int yWindow = rcWindow.top + yMouse - yClick;
SetWindowPos(hWnd,NULL,xWindow,yWindow,0,0,SWP_NOSIZE|SWP_NOZORDER);
}
break;
thanks, russ
From the error message you can derive that the compiler resolves the function ReleaseCapture() to TCommonCustomForm::ReleaseCapture(). But you want to call the Win32 API function ReleaseCapture(). Use ::ReleaseCapture(); instead of ReleaseCapture(); to enforce this.

Is there a way to forward TTN_NEEDTEXT to CFrameWnd?

I have an application that already deals with the generating of tooltips. I am modifying a CWnd derived class that has a parent frame. It doesn't implement tooltips.
From this, I can get tooltips to show up by adding the following code:
BEGIN_MESSAGE_MAP(CMyWindow, CWnd)
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipNotify)
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipNotify)
END_MESSAGE_MAP()
BOOL CMyWindow::OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult)
{
UNREFERENCED_PARAMETER(id);
UNREFERENCED_PARAMETER(pResult);
// need to handle both ANSI and UNICODE versions of the message
TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
CStringA strTipText;
UINT_PTR nID = pNMHDR->idFrom;
if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||
pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))
{
// idFrom is actually the HWND of the tool
nID = ::GetDlgCtrlID((HWND)nID);
}
if (nID != 0) // will be zero on a separator
strTipText.Format("Control ID = %d", nID);
if (pNMHDR->code == TTN_NEEDTEXTA)
{
strncpy_s(pTTTA->szText, sizeof(pTTTA->szText), strTipText,
strTipText.GetLength() + 1);
}
else
{
::MultiByteToWideChar(CP_ACP, 0, strTipText, strTipText.GetLength() + 1,
pTTTW->szText, sizeof(pTTTW->szText) / (sizeof pTTTW->szText[0]));
}
return TRUE; // message was handled
}
I can use GetParentFrame() to get the frame window, so I'd like to leverage the tooltip code that is already in place so that I get a consistent look. Is there some way that I can forward the TTN_NEEDTEXT message so that it gets handled by the frame window?
In your message map, you use ON_NOTIFY_whatever, which should hint that the message that TTN_NEEDTEXT uses is WM_NOTIFY — and indeed this is the case. So you can just produce the WM_NOTIFY yourself and send it to the parent.
The documentation for WM_NOTIFY says wParam is the control's identifier and lParam is the NMHDR pointer. There's an example on the bottom of the page that shows wParam is just the idFrom member of the NMHDR, so you have everything you need to reconstruct the message:
LRESULT lr = this->GetParentFrame()->SendMessage(WM_NOTIFY, pNMHDR->idFrom, (LPARAM) pNMHDR);
When you should issue this call is up to what you need to do. In this case, you would probably want to make it the first call, override your string, and return TRUE. I'm not fully sure, though.
Note: if MFC provides a function to do this, I don't know it; I personally don't use MFC, but the concepts are the same.
So what about the return value from that SendMessage()? Well, you can return it via pResult (for instance, if you're just tweaking the parent's alterations slightly), or you can ignore it and return a custom value. But for TTN_NEEDTEXT, it won't matter; TTN_NEEDTEXT doesn't care what the LRESULT is.

Clipboard data won't get pasted

I'm tryng to load into and paste data from the clipboard like this:
int main() {
Sleep(3000);
char buf[] = "Hello33";
HWND hwnd = GetActiveWindow();
if (OpenClipboard(hwnd)) {
EmptyClipboard();
HGLOBAL hClipboardData;
hClipboardData = GlobalAlloc(GMEM_DDESHARE, BUFLEN);
char * pchData;
pchData = (char*) GlobalLock(hClipboardData);
strcpy(pchData, LPCSTR(buf));
GlobalUnlock(hClipboardData);
SetClipboardData(CF_TEXT, hClipboardData);
CloseClipboard();
SendMessage(hwnd, WM_PASTE, 0, 0);
}
}
Starting the program, then open text editor, text editor is the top window and no text is pasted. If I do the paste command Ctrl-V I got Hello33 into the text area.
GetActiveWindow returns the main window not the child window
you should try GetFocus();
but even this will not work, be cause it is in an other thread that belong to other process.
to resolve that, call AttachThreadInput
finally i suggest to drop all of this, and try FindWindow instead and send message directly to the Edit Box, by using SendDlgItemMessage

Win32 Edit Control Caret Placement Offset

I gave an English explanation of my problem below but it is a visual issue so if you don't want to read it all just look at the picture at the bottom).
I'm working on building a reverse polish notation calculator for my class and I just completed having the button controls on my GUI be able to append their values to the edit control which works fine, but the caret is doing something weird and I can't find any information on it.
I send a custom message to the edit control in which it finds the length of the current text in the control and then places the caret at the end of the text so I can then add what text needs to be added (it is right aligned with ES_RIGHT), which again works just fine, but when the caret is in the right most place it can be, it is placed practically right through the middle of most any number.
This only seems to happen in the right most place the caret can be (i.e. anywhere else the caret sits directly to the right of the preceding char, as it should) and I have tried replacing the caret all the way to the right using code, placing it using my keyboard/mouse, and tried adjusting the dimensions of the window in hopes that it was just an offset of the width I defined for it that caused the last place to be off slightly, but the problem persists and it makes it hard to read the last char in the text field.
Relevant Code:
LRESULT CALLBACK EditBoxClass::WinProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_COMMAND:
break;
case WM_APPEND_EDIT:
/* Get current length of text in the box */
index = new int( GetWindowTextLength (hWnd) );
SetFocus( hWnd );
/* Set the caret to the end of the text in the box */
SendMessage( hWnd, EM_SETSEL, (WPARAM)index, (LPARAM)index );
/* "Replace" the selection (the selection is actually targeting
nothing and just sits at the end of the text in the box)
with the passed in TCHAR* from the button control that
sent the WM_APPEND_EDIT message */
SendMessage( hWnd, EM_REPLACESEL, 0, lParam );
break;
}
return CallWindowProc( EditClassStruct.GetOldProc(), hWnd, msg, wParam, lParam );
}
Picture of problem:
After facing the same problem and presenting my first approach in this answer, I'll now provide two well working solutions. I think there is no other way to fix this glitch properly (unless you're a Microsoft programmer who is responsible for this part of the WinAPI).
I was wondering how to fix this problem on edit controls created with ES_MULTILINE but this glitch seems to be only a problem on single-line edit controls (tested on Windows 7 64-bit). Enabling Visual Styles is also helpful but the problem still remains (the offset is at least not so obvious).
Explanation
Normally, when the caret is at the farthest right position it's x value (provided by GetCaretPos ()) should be equal to the rect.right value provided by EM_GETRECT (when the edit control was created with ES_RIGHT). Due to unknown reasons this is not the case. So you have to check if the caret position is at least in the near of the rect.right value (but not farther away than the last letter is wide). So you have two possibilities to fulfill this task:
You must calculate the width of the outer right character using GetTextExtentPoint32 (), subtract it from the rect.right value provided by calling SendMessage () with EM_GETRECT and check whether the x position of the caret is bigger than the result or not OR
You must calculate the margin between the rect.right value and the outer right caret position (3 in my case) and use this value as a hardcoded offset to do a simple check.
After those steps (regardless which one you have chosen) you have to reposition the caret when necessary.
1. Approach (recommended)
case WM_LBUTTONDOWN: {
TRACKMOUSEEVENT tme = {sizeof (tme), TME_LEAVE, hwnd, HOVER_DEFAULT};
TrackMouseEvent (&tme);
}
break;
case WM_KEYDOWN:
case WM_MOUSELEAVE:
case WM_SETCURSOR: {
DefSubclassProc (hwnd, message, wParam, lParam);
DWORD end;
SendMessage (hwnd, EM_GETSEL, (WPARAM) NULL, (LPARAM) &end);
int len = GetWindowTextLength (hwnd);
if (end < len || len <= 0)
return TRUE;
wchar_t *buffer = new wchar_t[len + 1];
GetWindowText (hwnd, buffer, len + 1);
wchar_t lastChar[] = {buffer[len - 1], '\0'};
delete[] buffer;
SIZE size;
HDC hdc = GetDC (hwnd);
if (hdc == NULL)
return TRUE;
GetTextExtentPoint32 (hdc, lastChar, 1, &size);
ReleaseDC (hwnd, hdc);
POINT pt;
RECT rect;
GetCaretPos (&pt);
SendMessage (hwnd, EM_GETRECT, (WPARAM) 0, (LPARAM) &rect);
if ((rect.right - size.cx) <= pt.x)
SetCaretPos (rect.right, pt.y);
return TRUE;
}
break;
2. Approach (improved original version)
case WM_LBUTTONDOWN: {
TRACKMOUSEEVENT tme = {sizeof (tme), TME_LEAVE, hwnd, HOVER_DEFAULT};
TrackMouseEvent (&tme);
}
break;
case WM_KEYDOWN:
case WM_MOUSELEAVE:
case WM_SETCURSOR: {
DefSubclassProc (hwnd, message, wParam, lParam);
POINT pt;
RECT rect;
GetCaretPos (&pt);
SendMessage (hwnd, EM_GETRECT, (WPARAM) 0, (LPARAM) &rect);
if ((rect.right - pt.x) <= 3)
SetCaretPos (rect.right, pt.y);
return TRUE;
}
break;
You have to subclass the edit controls. Then use this code in their window procedures and enjoy.
In both cases, tracking the mouse event is not absolutely necessary but recommended to completly avoid this glitch. Calling DefSubclassProc () will ensure that the cursor is changed on mouse over.
This may or may not be the cause, but you are misusing EM_SETSEL. You are dynamically allocating (and leaking) an int on the heap and passing a pointer to it as the message parameters, but EM_SETSEL does not expect or use pointers to begin with. So get rid of the dynamic allocation.
Also, the default window proc is not going to know how to handle your WM_APPEND_EDIT message, so there is no point in passing the message to CallWindowProc().
Try this instead:
case WM_APPEND_EDIT:
{
/* Get current length of text in the box */
int index = GetWindowTextLength( hWnd );
SetFocus( hWnd );
/* Set the caret to the end of the text in the box */
SendMessage( hWnd, EM_SETSEL, (WPARAM)index, (LPARAM)index );
/* "Replace" the selection (the selection is actually targeting
nothing and just sits at the end of the text in the box)
with the passed in TCHAR* from the button control that
sent the WM_APPEND_EDIT message */
SendMessage( hWnd, EM_REPLACESEL, 0, lParam );
return 0;
}
That being said, try using EM_GETRECT/EM_SETRECT to expand the right edge of the edit control's formatting rectangle by a few pixels. That should give the caret some extra room to work with.

Resources