Getting value from edit field (C++ WINAPI) - c++

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.

Related

How to detect current active page in Property sheet (C++/VS)

I am using Visual Studio C++ 2010, and I need to detect current active page of Property Sheet. I expect there should be send some message to tell when user activated the Page. But I did not found that message and where to place it in dialog process.
In the program which I work with, there is this main dialog process:
INT_PTR CALLBACK MainDlgProc(HWND hSheet, UINT msg, WPARAM wParam, LPARAM lParam)
{
INT_PTR ret = FALSE;
switch (msg)
{
// bla bla
case WM_COMMAND:
ret = 0; //processing message
if (!Sheet_HandleCommand(hSheet, HIWORD(wParam), LOWORD(wParam), (HWND)lParam))
CALLPROC();
break;
case WM_DESTROY:
// bla bla
return CALLPROC();
default:
return CALLPROC();
}
return ret;
}
I know how to get the handle but I don't know where to "install" it in the code. What's the name of the message to include it into the MainDlgProc?
Use PSM_GETTABCONTROL (or the PropSheet_GetTabControl macro) to get a handle to the tab control, and then use the TCM_GETCURSEL message (or the TabCtrl_GetCurSel macro) to query the currently selected tab index.
Note this is documented not to work if using the Aero wizard style (PSH_AEROWIZARD), presumably because there is no tab control in that case.

Replicating user input from edit control of one MFC dialog to an edit control of another dialog

In one of my dialog based MFC application, I've used two dialogs of similar look. The requirement is when user populates an edit box of one dialog with some data the same to be replicated to similar edit box of another dialog instantly. I'm trying to implement it with EN_CHANGE event of the edit control; where when any change is detected application post a message with updated data to other dialog to update the content of its own edit box. The problem is when the second dialog is setting its edit box content with the received data from first dialog, EN_CHANGE event is getting triggered from the second dialog, which is obvious, resulting in an endless back and forth message exchange. Could anybody please suggest me some solution for instant replicating user inputs between edit boxes of two MFC dialogs while keeping MFC application type as dialog based?
In my implementation both the Dialogs are CDialog derived and have the following CEdit event handler and Message handler methods:
For CScreen1 class:
void CScreen1::OnEnChangeEditUser()
{
static CString msg;
m_username.GetWindowText(msg);
::PostMessage(m_mScreen2,WM_INTER_LOGIN,10,(LPARAM)&msg); //m_mScreen2 is the HWND of 2nd dlg
}
LRESULT CScreen1::OnInterLoginMsg(WPARAM wParam, LPARAM lParam)
{
CString *msg=(CString*)lParam;
switch((int)wParam)
{
case 10:
m_username.SetWindowText(msg->GetString()); //m_username is CEdit Ctrl
delete msg;
break;
}
return 0;
}
For CScreen2 class:
void CScreen2::OnEnChangeEditUser()
{
static CString msg;
m_username.GetWindowText(msg);
::PostMessage(m_mScreen1,WM_INTER_LOGIN,10,(LPARAM)&msg); //m_mScreen1 is the HWND of 1st dlg
}
LRESULT CScreen2::OnInterLoginMsg(WPARAM wParam, LPARAM lParam)
{
CString *msg=(CString*)lParam;
switch((int)wParam)
{
case 10:
m_username.SetWindowText(msg->GetString()); //m_username is CEdit Ctrl
delete msg;
break;
}
return 0;
}
Simply use a boolean variable to play around. I have updated your code here.
For CScreen1 class:
BOOL postchanges = TRUE; //always TRUE
void CScreen1::OnEnChangeEditUser()
{
if (!postchanges)
return;
static CString msg;
m_username.GetWindowText(msg);
::PostMessage(m_mScreen2,WM_INTER_LOGIN,10,(LPARAM)&msg); //m_mScreen2 is the HWND of 2nd dlg
}
LRESULT CScreen1::OnInterLoginMsg(WPARAM wParam, LPARAM lParam)
{
CString *msg=(CString*)lParam;
switch((int)wParam)
{
case 10:
postchanges = FALSE; // do not post msg
m_username.SetWindowText(msg->GetString()); //m_username is CEdit Ctrl
postchanges = TRUE; // revert back
delete msg;
break;
}
return 0;
}
For CScreen2 class: do the same
As the requirement is replicating user input between two Edit controls of different Dialogs; it can be handled through processing keystroke messages.

Windows Journal playback hook (WH_JOURNALPLAYBACK) ignores EVENTMSG HWND parameter

I am working a program to simulate keyboard and mouse clicks programmatically. It need to send the clicks to a target window handle (ex: notepad edit control). I am getting the handle of notepad window and generating generating WM_KEYDOWN, WM_SYSKEYDOWN, WM_KEYUP, WM_SYSKEYUP messages for that window. The events are stored in queue, and later on played using a WH_JOURNALPLAYBACK hook.
For the code snippet below, the target hwnd in the playback proc though set correctly, messages never reach to the target handle. If I bring the notepad to foreground, it does receive the messages.
I am not sure why WH_JOURNALPLAYBACK ignores the handle parameter. I would have liked to generate a series of automation messages for various handles and played it back so that even without bringing the window into focus we can send keyboard and mouse events.
Please let me know
if messages to various target handles can be sent using a journal
playback hook
why in code below hwnd is ignored
..
#include <queue>
#include <iostream>
#include <windows.h>
using std::cout;
using std::endl;
using std::error;
struct Event
{
UINT msg;
UINT wparam;
UINT lparam;
HWND hwnd;
Event(UINT m, UINT wp, UINT lp, HWND h)
:msg(m),
wparam(wp),
lparam(lp),
hwnd(h)
{}
};
HHOOK jhook= NULL;
std::queue<Event> events;
bool gotoNextMsg = false;
LRESULT CALLBACK JournalPlaybackProc(int code, WPARAM wParam, LPARAM lParam)
{
switch( code )
{
case HC_SKIP:
cout<<"skip: "<<endl;
if(!events.empty())
{
events.pop();
}
break;
case HC_GETNEXT:
{
cout<<"next: "<<events.size()<<endl;
gotoNextMsg = true;
EVENTMSG * evm = (EVENTMSG*) lParam;
Event e = events.front();
switch(e.msg)
{
case WM_KEYDOWN:
cout<<"WM_KEYDOWN"<<endl;
break;
case WM_KEYUP:
cout<<"WM_KEYUP"<<endl;
break;
case WM_SYSKEYDOWN:
cout<<"WM_SYSKEYDOWN"<<endl;
break;
case WM_SYSKEYUP:
cout<<"WM_SYSKEYUP"<<endl;
break;
}
cout<<"handle: "<<e.hwnd<<endl;
cout<<"handle1:"<<evm->hwnd<<endl;
evm->message = e.msg;
evm->paramL = e.wparam;
evm->paramH = e.lparam;
evm->hwnd = e.hwnd;
evm->time = ::GetTickCount();
}
break;
default:
if( code < 0 )
::CallNextHookEx(jhook, code, wParam, lParam);
break;
}
if(events.empty())
{
cout<<"uinstalled"<<endl;
::UnhookWindowsHookEx(jhook);
::PostMessage(NULL, WM_USER+100, 0, 0);
}
return 0;
}
A journal hook injects events into the system message queue. For keyboard and mouse messages, the system dispatches them to the current focused window, same as if the user had input them manually. The HWND you specify in the event is not used, it gets replaced during dispatching.
And if you consider that a recorded journal can be played multiple times, and its data can persist across application instances and even reboots, and that HWNDs can be reused for different things over time, it should make sense why a journal playback cannot make use of an event's HWND even if the system message queue were not involved.
So, you cannot use WH_JOURNALPLAYBACK to target a specific window that is not in the foreground. You would have to send the recorded messages yourself. But be aware of some caveats that Raymond Chen has blogged about:
You can't simulate keyboard input with PostMessage
Simulating input via WM_CHAR messages may fake out the recipient but it won't fake out the input system

win32 C++ Custom Color for Trackbar thumb

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

C++: Trying to hook a message box and change its position

I recently started coding in C++ and I am very new to it. (I code in Javascript, PHP, Java and Obj-C more often)
I'm practicing how to hook a message box and change its position. This is what I have in my .cpp file (after reading this SO post).
#include <iostream>
#pragma comment(lib,"User32.lib")
#include <windows.h>
HHOOK hhookCBTProc = 0;
LRESULT CALLBACK pfnCBTMsgBoxHook(int nCode, WPARAM wParam, LPARAM lParam){
if (nCode == HCBT_CREATEWND)
{
CREATESTRUCT *pcs = ((CBT_CREATEWND *)lParam)->lpcs;
if ((pcs->style & WS_DLGFRAME) || (pcs->style & WS_POPUP))
{
HWND hwnd = (HWND)wParam;
SetWindowPos(hwnd, HWND_TOP,130,122, 0, 0,SWP_NOSIZE);
}
}
return (CallNextHookEx(hhookCBTProc, nCode, wParam, lParam));
}
int main(void)
{
hhookCBTProc = SetWindowsHookEx(WH_CBT,pfnCBTMsgBoxHook,
0, GetCurrentThreadId());
int sResult = MessageBox ( NULL, "Hooked!", "oh my", MB_OK );
UnhookWindowsHookEx(hhookCBTProc);
return 0;
}
For some reason the position of the message box isn't changing. Where did it go wrong?
(I know I can create a customized window or dialog. But I am doing it this way because I want to learn how to hook a message box and where I did wrong.)
Firstly you should check in the debugger that your hook is actually being called, if you haven't already.
Secondly, at the time the HCBT_CREATEWND hook event is triggered, the window has only just been created - the system has yet to size and position it. It will do this with the values in the CREATESTRUCT after the hook returns - overriding your SetWindowPos call.
See the docs from MSDN on the lParam value for this particular hook event:
Specifies a long pointer to a CBT_CREATEWND structure containing
initialization parameters for the window. The parameters include the
coordinates and dimensions of the window. By changing these
parameters, a CBTProc hook procedure can set the initial size and
position of the window.
Therefore, the correct way to use this hook to change a window's position is to modify the values in the CREATESTRUCT directly.
Also note that it's quite possible that the dialog manager sizes and positions the window after creation, so if you find that this still isn't working for you, you may need to try watching for the HCBT_MOVESIZE event instead.
From the docs
At the time of the HCBT_CREATEWND notification, the window has been
created, but its final size and position may not have been determined
and its parent window may not have been established.
Maybe try hooking into CBT_ACTIVATE instead.