CMFCTabCtrl catch tab change event - visual-c++

I want to catch the tab change event of a CMFCTabCtrl. Below is the code I'm trying to do that. But it does not catch the change event.
BOOL SurvChatDlg::OnNotify( WPARAM wParam, LPARAM lParam, LRESULT*
pResult )
{
if(((LPNMHDR)lParam)->code==TCN_SELCHANGE)
{
int i = m_TabControl.GetActiveTab();
AfxMessageBox("Changed");
}
return CDialog::OnNotify( wParam, lParam, pResult );
}

According to this forum thread, you need to handle the AFX_WM_CHANGING_ACTIVE_TAB message sent to the parent window.
This forum thread has more code samples.

If you want to catch the post tab change, the tab that will be active, need AFX_WM_CHANGE_ACTIVE_TAB ie;
ON_REGISTERED_MESSAGE(AFX_WM_CHANGE_ACTIVE_TAB,OnTabSetActive)
LRESULT CYourClass::OnTabSetActive(WPARAM wParam, LPARAM lParam)
{
const int iActiveTab = (int)wParam;
int iCheckActiveTab = m_wndTabs.GetActiveTab(); //CMFCTabCtrl m_wndTabs;
m_wndTabs.SetActiveTab(iActiveTab); //good idea to also add this depending on usage.
return 0;
}
And if you require manually changing the tab call using;
SendMessage(AFX_WM_CHANGE_ACTIVE_TAB, iTabNum2ChangeTo, 0);
Posted the above after trying to find a solution to my problem where using
CMFCTabCtrl::SetActiveTab()
would crash but in debug mode only. And this OP was googles top answer.
AFX_WM_CHANGING_ACTIVE_TAB appears to catch the event prior to the actual tab change, hence why hasn't worked for the OP, and can be checked by;
int iCheckActiveTab = m_wndTabs.GetActiveTab();

Related

Hooking local WndCallback using SetWindowLong: ACCESS DENIED

I'd like to locally hook my WindowProc function. First I was thinking of SetWindowsHookEx, but I wouldn't like to have an external DLL only for this hook. I'd like to make it internally and locally (I don't want a global hook).
That's why I came across with SetWindowsLong. I'm trying to change the WindowProc with the GWL_WNDPROC option, however I always get error: Access Denied and I've got no idea why. Here's my very simple example which is sadly not working:
#include <windows.h>
#include <stdio.h>
WNDPROC pOrigProc;
LRESULT CALLBACK HookWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
printf("Message arrived!\n");
return CallWindowProc(pOrigProc, hwnd, uMsg, wParam, lParam);
}
int main()
{
HWND handle = FindWindow("ConsoleWindowClass", 0);
if(!handle)
{
printf("HWND get error!\n");
}
else
{
DWORD dwProcId;
GetWindowThreadProcessId(handle, &dwProcId);
if( dwProcId != GetCurrentProcessId())
{
printf("Corrupted Handle!\n");
}
else
{
printf("Window handle belongs to my process!\n");
}
}
pOrigProc = (WNDPROC)SetWindowLong(handle, GWL_WNDPROC, (LONG)HookWndProc);
if(!pOrigProc)
{
printf("SWL Error: %d\n", GetLastError());
}
else
{
printf("Successfully hooked the Window Callback!\n");
}
MSG message; // Let's start imitating the prescence of a Win32GUI
while (GetMessage(&message, NULL, 0, 0))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
}
Of course FindWindow is not going to be the best solution in my main project, but I think it's good enough in this small example. As you can see I'm making sure that the found HWND is my own, so it shouldn't be the problem.
In my case it's returning "Window handle belongs to my process!" and SWL Error: 5
Error 5 is (according to msdn) ACCESS DENIED.
I hope someone can see that possible small stupid mistake which I can't find. Thank you!
MSDN says "You cannot change this attribute if the window does not belong to the same process as the calling thread". From your example is visible that your app is console, not GUI. And probably the ConsoleWindowClass is not defined by your app but globally by Windows. Try similar but with GUI project.

MFC - Posting data via PostMessage to the GUI

I Read a few threads on how passing data from Workerthread to Main window(Dialog), but I still don't understand and still need help.
My workerthread should process some calculations and display the result during each loop to an edit on the GUI. I know, I should use PostMessage but since the calculation I'm doing implies a control element, I don't know how to solve this problem ...
//CWorkerThreadMgr.h manages the second thread
HRESULT Start (HWND hWnd);// from where the workerthread will be started
HWND m_hWnd ; //Window handle to the UI ;
HANDLE m_hTread; //handle of the worker thread
static UINT WINAPI ThreadProc( LPVOID lptest );
static UINT WINAPI ThreadProc( LPVOID lptest )
{
CWorkerThreadMgr* pCalculateMgr = reinterpret_cast< CWorkerThreadMgr*(lptest);
//The following operation:rand() *m_Slider.GetPos() should
//should be calculated and the result displayed each time in the edit box in the gui
for( UINT uCount = 0; uCount < 40; uCount++ ){
pCalculateMgr->rand() *m_Slider.GetPos();//?don't allowed to touch the gui!!
PostMessage(pCalculateMgr-> m_hWnd, WM_SENDCALCULATED_VALUE,wparam(rand() *m_Slider.GetPos(),0);
}
}
LRESULT CStartCalculationDlg::OnSendCalculatedValue( WPARAM Result, LPARAM )
{
// The resut should be displayed in the edit box
m_Calculation.Format(_T("%d"),???);
SetDlgItemText(IDC_CALCULATION, m_Calculation);
return 1;
}
void CStartCalculationDlg::OnHScroll(UINT nSBCode, UINT nPos,CScrollBar* pScrollBar)
{
m_SliderValue.Format(_T("%d"),m_Slider.GetPos());
SetDlgItemText(IDC_SLIDER_VALUE,m_SliderValue);
}
// Implementation in the CStartCalculationDlg.h
CWorkerThreadMgr m_WorkerThreadMgr //instance of the WorkerThreadMgr
CSliderCtrl m_Slider //member variable of the slider control
CString m_SliderValue // member variable of the edit box, where the current value of the
//slider will be displayed
CString m_Calculation // member variable of the edit box where the calculated
//result from the workerthread will be displayed via PostMessage
afx_msg LRESULT OnSendCalculatedValue( WPARAM, LPARAM );
afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
The next probem is that, when my slider control is moved and gets a new value, the thread procedure should know it and update the value of the slider. How can I manage to do it?
Instead of reading the slider position from the worker thread, read it in the UI thread and make it available to the worker thread.
I'm really no expert in this field, but I've done some worker threads as explained here.
What I would do in your case is create a static variable, like the "running" flag used in the article linked above, to hold the current position of the slider. Then, in the OnHScroll handler set it to the appropriate value.
As long as you only write to that variable from one thread, you should not have synchronization issues.
From worker thread:
m_data = foo();
PostMessage(hWndMain, UWM_SOME_CUSTOM_MESSAGE, 0, 0);
From UI thread:
LRESULT CMainFrame::OnSomeCustomMessage(WPARAM wParam, LPARAM lParam)
{
CMyData data = m_pWorker->GetData();
// Do stuff...
return 0;
}
GetData must be guarded by a critical section:
CMyData CMyWorker::GetData()
{
// This critical section is used in the worker thread too, whenever m_data is accessed.
m_lock.Lock();
CMyData data = m_data;
m_lock.Unlock();
return data;
}
See CCriticalSection on MSDN.

Get ID of Button for Switch Statement: MFC

Language: Visual C++, MFC
Environment: Visual Studio 2005
I have a dialog that requires the user to set file paths for six different settings. Each text box has a browse button which launches a file browser.
How can I set it up so that all of the browse buttons all call the same function to launch the chooser, then use a switch to determine which button invoked the file chooser so that I can set the text of the appropriate CEdit box with the path? // run-on sentence, hah
I'm sure I'll have to use GetDlgCtrlID, I'm just not sure how.
Thank you for your help in advance!
~ Jon
EDIT: Here's the code I have now...very simple because I'm just getting it to work for now.
BEGIN_MESSAGE_MAP(FSC_3DPersp, CSAPrefsSubDlg)
//{{AFX_MSG_MAP(FSC_3DPersp)
// NOTE: the ClassWizard will add message map macros here
//}}AFX_MSG_MAP
ON_COMMAND(BN_CLICKED, &FSC_3DPersp::Browse)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// FSC_3DPersp message handlers
void FSC_3DPersp::Browse(UINT uiID)
{
// TODO: Add your control notification handler code here
switch(uiID)
{
case IDC_BUTTON1:
MessageBox("1");
break;
case IDC_BUTTON2:
MessageBox("2");
break;
case IDC_BUTTON3:
MessageBox("3");
break;
case IDC_BUTTON4:
MessageBox("4");
break;
case IDC_BUTTON5:
MessageBox("5");
break;
case IDC_BUTTON6:
MessageBox("6");
break;
case IDC_BUTTON7:
MessageBox("7");
break;
}
}
BOOL FSC_3DPersp::OnCommand(WPARAM wParam, LPARAM lParam)
{
if (HIWORD(wParam) == BN_CLICKED)
{
Browse(LOWORD(wParam));
return TRUE;
}
return CWnd::OnCommand(wParam, lParam);
}
If you're responding to the BN_CLICKED message, the button ID will be contained in the LOWORD of the wparam of the message.
Edit: MFC normally discards the wparam of the message. To access it you must override the OnCommand handler in your dialog.
BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam)
{
if (HIWORD(wParam) == BN_CLICKED)
{
Browse(LOWORD(wParam));
return TRUE;
}
return CWnd::OnCommand(wParam, lParam);
}
ON_COMMAND expects a function that has no arguments. For your Browse method you should use ON_CONTROL_RANGE macro:
ON_CONTROL_RANGE(BN_CLICKED, IDC_BUTTON1, IDC_BUTTON7, Browse)
You should make sure IDC_BUTTON1 to IDC_BUTTON7 have consecutive numerical values.
You can read this article for more info http://msdn.microsoft.com/en-us/library/84xtde24.aspx.

Win32 MessageBox doesn't appear

I'm stuck with a strange problem. I'm making a Win32 application in VC++ 2008, making a class to encapsulate most of the work for easy repetition when calling a MessageBox. The message box` is created (I think) but doesn't show up unless I press the Alt key!
What happen exactly is :
I run the program
press Enter
the main window lose focus
give beep sound when i click on the main window as if a modal MessageBox is present
either press Escape... focus is gained OR press Alt then the MessageBox appear with alt key pressed (i.e. menu will drop )!!!!!!
P.S. It was working fine but suddenly this happened. I didn't find any difference - I even made a new project!
This is supposed the Main program:
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
MSG msg;
CWnd cMainWindow(TEXT("DentoMan"), TEXT("Bejkoman")); // pass The class name and window name to the constructor
cMainWindow.CreateDef(); //Create the Window
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
While This is the Class file
CWnd::CWnd() {
};
CWnd::CWnd(LPTSTR lpszClassName, LPTSTR lpszWindowName) {
CWnd::lpszClassName = lpszClassName;
CWnd::lpszWindowName = lpszWindowName;
};
CWnd::~CWnd() {
};
// Create the window with default parameters
HWND CWnd::CreateDef(void) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = StaticWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = (HINSTANCE)GetModuleHandle(NULL);
wcex.hIcon = 0;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 4);
wcex.lpszMenuName = 0;
wcex.lpszClassName = lpszClassName;
wcex.hIconSm = 0;
RegisterClassEx(&wcex);
g_hWnd = CreateWindowEx(0,lpszClassName, lpszWindowName, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, wcex.hInstance, this);
hInst = wcex.hInstance; //Store hInstance in the class hInst variable
if (!g_hWnd) return false;
ShowWindow(g_hWnd, SW_SHOW);
UpdateWindow(g_hWnd);
return g_hWnd;
}
LRESULT CALLBACK CWnd::StaticWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) {
/* The Only Message we take here so we store the 'this' pointer within the window to identify messages
comming from it by the 'this' pointer*/
if ( Message == WM_CREATE ) {
SetWindowLong( hWnd, GWL_USERDATA, (LONG)((CREATESTRUCT FAR *)lParam)->lpCreateParams);
}
/* Store the window pointer in the class pointer we just created in order to run the right public WndPRoc */
CWnd *Destination = (CWnd*)GetWindowLong( hWnd, GWL_USERDATA );
// If the hWnd has a related class, pass it through
if (Destination) {
return Destination->WndProc( hWnd, Message, wParam, lParam );
}
// No destination found, defer to system...
return DefWindowProc( hWnd, Message, wParam, lParam );
};
LRESULT CWnd::WndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) {
// Determine message type
switch (Message) {
case WM_LBUTTONDOWN:
{
/* this is a common trick for easy dragging of the window.this message fools windows telling that the user is
actually dragging the application caption bar.*/
SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION,NULL);
break;
}
/*case WM_CREATE:
break;
*/
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_DESTROY:
UnregisterClass(lpszClassName, hInst);
PostQuitMessage(0);
break;
case WM_KEYDOWN: //KeyBoard keys
// Which key was pressed?
switch (wParam) {
case VK_ESCAPE: //close through escape key
PostQuitMessage(0);
return 0;
case VK_RETURN:
MessageBox(hWnd, TEXT("DFGDGD"), TEXT("DFGDFG"), NULL);
return 0;
} // End Switch
break;
case WM_COMMAND:
/*switch(LOWORD(wParam))
{
}*/
break;
case WM_PAINT:
break;
default:
return DefWindowProc(hWnd, Message, wParam, lParam);
} // End Message Switch
return 0;
};
The Class Header:
class CWnd {
public:
CWnd();
CWnd(LPTSTR lpszClassName, LPTSTR lpszWindowName);
virtual ~CWnd();
virtual HWND CreateDef(void); // Create the window with default parameters
virtual LRESULT WndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam );
private:
static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam);
HWND g_hWnd; //Global window handle for this window
HINSTANCE hInst; //Global instance for this window
LPTSTR lpszClassName;
LPTSTR lpszWindowName;
};
P.S. I included all needed header files, everything goes fine except MessageBox
This is also a link to the code on here
Ohhhhhhh finally i found the solution of this problem ... and for everyone to benefit the problem was in WndProc(.......) at the WM_PAINT Message i wrote some code in it and removed all the code along with BeginPaint and EndPaint functions so the program enter a freeze period once anything is being painted over it including that MessageBox but it only show when i press Alt i think coz the control is transfered to the system in that step to show the system Menu (i think)
the solution either remove the WM_PAINT message handler or add the normal BeginPaint and EndPaint functions
Thanks for everyone who passed on my question
If anyone is still interested, this method works:
MessageBox(NULL,L"error",L"Error",MB_ICONERROR|MB_DEFAULT_DESKTOP_ONLY);
I had a similar problem that was cause by WM_PAINT as somebody above mentioned. Solved it by adding return DefWindowProc(hWnd, Message, wParam, lParam); there.
When you create your MessageBox you should pass WS_CHILD in CreateWindowEx.
EDIT 2:
Ok try this.
MessageBox(hWnd, TEXT("DFGDGD"), TEXT("DFGDFG"), MB_OK);
Try using MB_TOPMOST:
MessageBox(hWnd, TEXT("DFGDGD"), TEXT("DFGDFG"), MB_TOPMOST);

Changing color of a edit control in WInCE (win32)

I have created a edit control with ES_PASSWORD . I want to change the color of my static box to grey.
case WM_CTLCOLOREDIT:
{
HDC hdc = (HDC) wParam ;
SetBkMode( hdc, RGB(65, 65, 65));
return (LRESULT)GetStockObject(NULL_BRUSH);
}
But still by edit control is white color :(
Please help me.
If there are more then one edit control , is there to h
Your message handler should look like this:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CTLCOLOREDIT:
{
HBRUSH hBrush = CreateSolidBrush(RGB(255,0,0));
::SelectObject((HDC)wParam, (HGDIOBJ)hBrush);
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Make sure you don't cal DefWindowProc, that will defeat the override.

Resources