How to access Mainfrm member variable status without using ((CMainFrame*) AfxGetMainWnd ())->...? - c++

I have a MDI appliation in MFC to modify. I want to check the value of a flag which is a member variable of MainFrm from a lower level class. But I don't want to access it using
'((CMainFrame*) AfxGetMainWnd ())->IsFlagOn()' kind of function because for that i have to give the mainfrm.h in a lower level class. I somehow feel this will create some circular reference later, after reading this Why are circular references considered harmful?
what are the other ways to get the flag value from mainfrm class.Please guide !
note: here class hierarchy is mainfrm->CTestExplorerFrame->CTestExplorerView->CTestExplorerTreeCtrl
I want to check from the lowest level about a flag that is only accessed by mainfrm

AfxGetMainWnd() returns a CWnd* that you can use to communicate with the mainframe via the Windows message system. Define a custom message and send this message to the CWnd*
#define UWM_MYREQUEST (WM_APP + 2)
int datatoget;
CWnd* pMainframe = AfxGetMainWnd();
pMainframe->SendMessage(UWM_MYREQUEST, (WPARAM)&datatoget, 0);
The mainframe needs code like this to receive and handle the custom message:
ON_MESSAGE(UWM_MYREQUEST, OnMyRequest)
LRESULT CMainFrame::OnMyRequest(WPARAM wparam, LPARAM lparam)
{
int* ptoget = (int*)wparam;
*ptoget = m_datarequested;
return 0;
}

I would declare an (pure virtual) interface class where you have a pure virtual call to get the value of the flag you are interested in at CTestExplorerTreeCtrl. Then the MainFrame implements this interface class and passes a pointer to CTestExplorerTreeCtrl. This way you can avoid any references to the MainFrame class.

Related

C++ Winapi HWND Get element by Name

Is there a way I can get a HWND by it's property "name"? I know that every IDE has its own properties for HWND elements but those properties are applied to the HWND.
I'm not working in Visual Studio, this is just a case. I want to get HWNDs by Name in C++ without VS Libraries.
For example:
HWND button = GetHwndByName("button1"); //Example
Property "name" is button1
I'm going to assume you're either trying to access your GUI controls in code or some other program's GUI controls.
As some people have mentioned, the (name) property in the properties editor is just the variable name used for that control. Your screenshot shows Visual Studio editing a .net program. In the case of .net, the (name) field is the name of the class member of the window class that represents the control. So if (name) is button1 then Visual Studio might generate code like
// pseudo-C++/C#-like
class Form1 : public System.Windows.Forms.Form {
private:
System.Windows.Forms.Button *button1;
...
};
The idea here is that you would have event handlers as part of your Form1 class:
void Form1::onButton1Clicked(void)
{
this->button1->SetText("You clicked me!");
}
As such, the (name) is not an intrinsic property of the window from Windows's point of view.
I don't know what CA Plex's GUI editor looks like, but I would assume, given you said you were using C++, that it either
a) produces a class like the one I pasted above, in which case you would just use the (name) directly as members, or
b) produces a header file with each of those control names as global HWND variables
Either way, you can just use them directly from within your code. Perhaps have something like
void doToAllButtons(void (*f)(HWND, LPARAM), LPARAM lParam)
{
(*f)(button1, lParam);
(*f)(button2, lParam);
(*f)(button3, lParam);
}
and simply write an appropriate function to call via this one.
If you need to interface with another program and want to use its variable names, then you're out of luck. You'll need to find the windows you want some other way, such as with FindWindow().

Nested Dialog Procedures

I'm not sure how to call Dialog Procedures of certain classes and was looking for some help.
I'm aware for a normal Message Procedure you can do this in the MessageProc:
case WM_CREATE:
{
CREATESTRUCT* cs = (CREATESTRUCT*)_lParam;
pApplication = (CApplication*)cs->lpCreateParams;
return pApplication->MessageProc(_Msg, _wParam, _lParam);
}
which will allow you to create a Message Proc independent to the class.
However due to the fact I don't know exactly how the first two lines work (just the definition that they return the 'this' pointer of the application), I can't work out what to do to get my Dialog Procedures to do a similar thing
case WM_INITDIALOG:
{
//How can I get the pointer to the inspector that
//I want to call the dialog proc on?
return pInspector->DlgProc(_hWndDlg, _Msg, _wParam, _lParam);
}
Any help to both get the pointer to the inspector working and also clarify exactly what the other two lines are doing in WM_CREATE would be appreciated
When a window is created, it receives a WM_CREATE message with a pointer to a CREATESTRUCT structure, and in there is a pointer-sized userdata field (lpCreateParams). This value comes from the lpParam argument passed to the CreateWindowEx() function.
This is the general mechanism which lets you associate your own class or data structure with an instance of a window.
This pointer generally needs to be saved somewhere in order to use it later on. One common way of doing this is to store it in a window property:
case WM_CREATE:
{
CREATESTRUCT* cs = (CREATESTRUCT*)_lParam;
pApplication = (CApplication*)cs->lpCreateParams;
SetProp(hWnd, L"my.property", (HANDLE)pApplication);
}
Then to retrieve the value when handling other messages:
pApplication = (CApplication*)GetProp(hWnd, L"my.property");
Dialogs are not exactly like normal windows, so although a similar mechanism exists, it is implemented differently. When a dialog procedure receives the WM_INITDIALOG message, the lParam value is equivalent to the lpCreateParams value in a WM_CREATE message.
In order to save your pInspector value it would need to have been provided as the dwInitParam value when the dialog was created, but assuming that it was, you can handle this in a similar way:
case WM_INITDIALOG:
{
pInspector = (CInspector*)lParam;
SetProp(hWnd, L"my.property", (HANDLE)pInspector);
}
And to retrieve the value when handling other messages:
pInspector = (CInspector*)GetProp(hWnd, L"my.property");

Retrieve WTL object from handle

I had to rewrite a custom file dialog (derived from MFC's CFileDialog) to WTL's CFileDialog. I have a bit of a problem to retrieve data when I don't have access to the dialog object itself. Imagine the following.
I have a member in the class
static WNDPROC m_wndProc;
I initialize it in the following static member fnct.
void CMyFileDialog::OnInitDone(LPOFNOTIFY lpon)
{
m_wndProc = (WNDPROC)::SetWindowLong(thisHWND, GWL_WNDPROC, reinterpret_cast<long>
(&CMyFileDialog::WndProcSelect));
}
The handle comes into the callback method with no problem and I can "connect" to it with CWindow
LRESULT CALLBACK CMyFileDialog::WndProcSelect(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// ...
CWindow callerWnd(hwnd);
}
And here, I don't know the real methodology to convert the CWindow to my CMyFileDialog. As I think, this CWindow class is just connected somehow to the handle itself, but does not the same object as it was created before. So for example, if I have a CString or other members in my CMyFileDialog, it won't access its state, because it was created in another object.
I think you are doing something wrong here. You have access to the message map without having to modify the WndProc (that is something that the CFileDialogImpl will have already done).
See for example http://www.codeproject.com/Articles/12999/WTL-for-MFC-Programmers-Part-IX-GDI-Classes-Common#usingcfiledialog, where they simply
BEGIN_MSG_MAP(CMyFileDialog)
CHAIN_MSG_MAP(CFileDialogImpl<CMyFileDialog>)
END_MSG_MAP()
You could always use SetWindowLongPtr with your "this" pointer, then it would be fairly easy to extract the pointer to your CMyFileDialog.

MFC :: passing data using structure

So I have this MFC dialog program I am working with. The dialogs are written but now I am having difficulty passing data around from dialog to dialog. I have the following structure _dlgDataHandler set up in a class derived from CWinApp and have have created a "new" statement for a pointer to this type.
//.......SRK.h file
class CSRK_App : public CWinApp
{
public:
CFSB_App();
// added the following data structure for data passing withing the program
typedef struct _dlgDataHandler {
char RepetitionRadio[24];
// another member
// yet another member and so on as necessary
} *dlgDataHandlerPtr;
// extern dlgDataHandlerPtr dlgDataHandler;
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSRK_App)
public:
virtual BOOL InitInstance();
//}}AFX_VIRTUAL
// Implementation
//{{AFX_MSG(CSRK_App)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//....... SRK.cpp A pointer to a new dataHandler created in this block about 2/3 the way down
// CSRK_App initialization
BOOL CSRK_App::InitInstance()
{
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
//SetRegistryKey(_T("Local AppWizard-Generated Aplications"));
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
//CSRK_Dlg dlg;
CDialogMain dlg("SRK - Beta"); // added 12/27 **
m_pMainWnd = &dlg;
//const char* m_pszHelpFilePath = NULL;
//free((void*)m_pszHelpFilePath);
//m_pszHelpFilePath=_tcsdup(_T("c:\SRKHelp.rtf"));
// the following line added to allocate memory for the structure
dlgDataHandlerPtr dlgDataHandler = new _dlgDataHandler;
dlg.SetWizardMode(); // added 12/27 **
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
In the dialog .cpp files, there are five, I need to be able to get data from the AFX variables "m_" and load them into this dataHandler Structure (or another one like it) so that they can be used in other dialogs and parts of the program, specifically my actual code when all the dialog data collection is done. Someone said to use AfxGetApp() so that I could have a handle on the current instance but I do not understand what they are talking about. And yes I have read about it in many forums, I just don't get it. I further realize this is probably not the best way to do it. I am trying to learn MFC/OOP with what time I have available, but for now, I am just trying to get a handle on the basic process as I can tune it later once I understand how to collect and pass simple data around.
I further don't understand how calling AfxGetApp() will help me get a handle on the members of CSRK_App. It inherited CWinApps public members but AfxGetapp() can't see what CSRK_App has... can it?
First, to explain the AfxGetApp advice you have received. There is some extra hand-waving using 'new' and a pointer, but this is basically using a global variable for the structure that holds your data. This is not the best way to do what you are trying to do. There are many pitfalls.
AfxGetApp() is an MFC call that returns a pointer to your main App class derived from CWinApp.
If you want to use that returned pointer, you need to cast it as a CSRK_App* pointer with:
CSRK_App* pApp = static_cast <CSRK_App*> ( AfxGetApp());
Then you can use pApp->dlgDataHandlerPtr->... to access the variables you need.
Now, for the pitfalls. Someone else may chime in with a reason why the 'new' and the pointer are helpful, but I do not see any advantage to this approach as compared to just having a local variable dlgDataHandler inside your CSRK_App class. That would simplify the code.
The next issue is that all your data is public in a struct. Any dialog class that can call AfxGetApp can read or write any data in that struct. You have no way to control access.
Also, all of your dialog classes must now include SRK_App.h so they know the structure, and have access to all other variables in that App class.
A cleaner, object-oriented approach would be to declare the struct (class) for the data in a separate .h file that could be included in the dialog classes. Then, you would pass a pointer/reference to this data into the constructor of the dialog classes. The dialog class would have no need to know anything about the App class.
For an even higher level of segregation, the dialog classes can be written so they only get a copy of the dlgDataHandler class passed in before calling .DoModal(), and then after the DoModal call returns with IDOK, the App class can have control over which data from the dialog gets updated into the dlgDataHandler class. The advantage of this approach is that it insures that no matter how the dialog class is programed, the user can always "Cancel" the dialog without modifying any data.

Wrapping a PropertySheet; how to handle callbacks?

I'm writing an (unmanaged) C++ class to wrap the Windows PropertySheet. Essentially, something like this:
class PropSheet {
PROPSHEETHEADER d_header;
public:
PropSheet(/* parameters */);
INT_PTR show();
private:
static int CALLBACK *propSheetProc(HWND hwnd, UINT msg, LPARAM lParam);
};
The constructor just initializes the d_header member:
PropSheet::PropSheet(/* parameters */) {
d_header.dwSize = sizeof(PROPSHEETHEADER);
d_header.dwFlags = PSH_USECALLBACK;
// ...
d_header.pfnCallback = &propSheetProc;
// ...
}
After which I can show it, modally, with:
INT_PTR PropSheet::show() {
return PropertySheet(&d_header);
}
Now the problem is, because the callback is static, that it cannot access the wrapper class. If this were a normal window, with a WindowProc instead of a PropSheetProc, I could attach some extra data to the window using cbWndExtra in WNDCLASS, in which I could store a pointer back to the wrapper, like in this article. But property sheets do not offer this functionality.
Furthermore, because the property sheet is shown modally, I can execute no code between the creation and destruction of the actual window, except when that code is executed through the callback or one of the sheets's window procedures.
The best solution I've come up with so far is to, right before showing the property sheet, store a pointer to the wrapper class inside a global variable. But this assumes that I'll only be showing one property sheet at a time, and is quite ugly anyway.
Does anyone have a better idea how to work around this?
As you are showing the property sheet modally, you should be able to use the parent window (i.e. its handle) of the property sheet to map to an instance, using ::GetParent() on the hwndDlg parameter of PropSheetProc().
Awesome, yet another Win32 API that uses callbacks without a user-defined context parameter. It is not the only one, alas. e.g. CreateWindow is bad (it gives you user-defined context, but that context isn't available for the first few window messages), SetWindowsHookEx is even worse (no context at all).
The only "solution" that is general-purpose and effective is to emit a small piece of executable code with a 'this' pointer hardcoded. Something like this: http://episteme.arstechnica.com/eve/forums/a/tpc/f/6330927813/m/848000817831?r=848000817831#848000817831
It's horrible.
The PROPSHEETPAGE structure has an lParam field available for callbacks. In your PROPSHEETHEADER, you can include the PSH_PROPSHEETPAGE flag to pass an array of PROPSHEETPAGE items describing your pages, or omit the flag to pass an array of preallocated HPROPSHEETPAGE handles instead (which means using CreatePropertySheetPage(), and thus using PROPSHEETPAGE anyway).
You've already admitted "I can execute no code between the creation and destruction of the actual window". It seems that a global variable wouldn't be a terrible hack.
I've found another option: using SetProp to add a property that stores the pointer to the wrapper. Only requires the global variable once, to be able call SetProp from the property sheet callback.