Why cant code in a modeless dialog function use my external access function?
-
Thursday, May 03, 2012 10:05 PM
I have four C++ files, kb.cpp, kb.h, enumerate_launcher.cpp, enumerate_launcher.h.
As follows:
-------------------------------------
// kb.cpp
#include "kb.h"
#include "enumerate_launcher.h"
#define KB_G
void enumerate_things() {
// Uses object candidates, defined in kb.h
return;
}
void make_bundles() {
enumerate_launcher *guard= NULL;
prep_candidates(); // Makes candidates and num_candidates.
if ((candidates != NULL) && (num_candidates > 0)) {
// At this point (breakpoint), candidates and num_candidates are what I expected.
guard= new enumerate_launcher(AfxGetMainWnd()); // Bring up the modeless dialog.
guard->Create(IDD_ENUMERATE_LAUNCHER, NULL);
guard->ShowWindow(SW_SHOWNORMAL);
}
return;
} // make_bundles
// ACCESS FUNCTIONS
thing **get_candidates() {
return(candidates);
} // get_candidates
int get_num_candidates() {
return(num_candidates);
} // get_num_candidates
-------------------------------------------------
// kb.h
#ifdef KB_G
static thing **candidates= NULL;
static int num_candidates= 0;
#endif
void enumerate_bundles();
// ACCESS FUNCTIONS
thing **get_candidates();
int get_num_candidates();
---------------------------------------------
// enumerate_launcher.cpp
// enumerate_launcher is a modeless dialog. When it becomes visible, I click the BEGIN button
// IDC_BEGIN, which causes the strange behavior I'm asking about.
enumerate_launcher::enumerate_launcher(CWnd* pParent /*=NULL*/)
: CDialog(enumerate_launcher::IDD, pParent) {
} // enumerate_launcher constructor
enumerate_launcher::~enumerate_launcher() {
} // enumerate_launcher destructor
void enumerate_launcher::DoDataExchange(CDataExchange* pDX) {
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_BEGIN, start_enum);
} // enumerate_launcher::DoDataExchange
BEGIN_MESSAGE_MAP(enumerate_launcher, CDialog)
ON_BN_CLICKED(IDC_BEGIN, &enumerate_launcher::OnClickedBegin)
END_MESSAGE_MAP()
// enumerate_launcher message handlers
BOOL enumerate_launcher::OnInitDialog() {
CDialog::OnInitDialog();
return(TRUE);
} // enumerate_launcher::OnInitDialog
void enumerate_launcher::OnClickedBegin() {
BOOL counted_them= TRUE;
// DEBUGGERY
thing **checkit= get_candidates();
// END DEBUGGERY
// When I get here (breakpoint), checkit comes out NULL!
if ((get_candidates() != NULL) && (get_num_candidates() > 0)) {
counted_them= enumerate_bundles();
}
} // enumerate_launcher::OnClickedBegin
---------------------------------------------
// enumerate_launcher.h
class enumerate_launcher : public CDialog {
DECLARE_DYNAMIC(enumerate_launcher)
public:
enumerate_launcher(CWnd* pParent = NULL); // standard constructor
virtual ~enumerate_launcher();
// Dialog Data
enum { IDD = IDD_ENUMERATE_LAUNCHER };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
public:
virtual BOOL OnInitDialog();
CButton start_enum;
afx_msg void OnClickedBegin();
}; // class enumerate_launcher
-----------------------------------
I have kicked out some other variables which are irrelevant.
My problem is that the dialog knows about the function enumerate_bundles
defined in kb, so it should know about get_candidates, also defined in kb.
But the access function get_candidates returns NULL to the dialog, whereas
if I call it after prep_candidates, it will return what I expect.
In many of my other applications in the past, I have been able to successfully
pass static variables to other modules this way. What am I missing?
Is there something magic about modeless dialogs?
All Replies
-
Friday, May 04, 2012 1:51 AM
In many of my other applications in the past, I have been able to successfully
If you define variables in a header file, then each .cpp file that inclides this header gets a separate copy.
pass static variables to other modules this way. What am I missing?
Is there something magic about modeless dialogs?
If you must use global variables, then use this pattern:
// kb.h
extern thing **candidates; // declaration
extern int num_candidates; // declaration
// kb.cpp
thing **candidates = NULL; // definition
int num_candidates = 0; // definition
David Wilkinson | Visual C++ MVP- Marked As Answer by CADMeister Wednesday, May 09, 2012 5:09 PM
-
Friday, May 04, 2012 4:32 AM
I made one mistake when I presented this- in kb.cpp, I really had the #define KB_G before #include "kb.h".
Please correct me if I am wrong, but I believe that the effect of this strategy is to exclude the statics from being
seen by the module enumerate_launcher, since there is no such define in it. However, it does know about the
function enumerate_bundles(). Note that get_candidates() is also communicated to enumerate_launcher. Both functions are outside the ifdef in kb.h.
get_candidates() should transmit the candidates pointer to the module enumerate_launcher, to the variable named checkit.
In the enumerate_bundles module, I don't mention candidates- I would get an error if I did.
The problem manifests itself with a NULL checkit in the function OnClickedBegin, and non-NULL and properly formed candidates in the module kb.
Please take another look, with the modification of putting #define KB_G before the include, and tell me where I'm wrong.
- Marked As Answer by CADMeister Wednesday, May 09, 2012 5:09 PM
-
Friday, May 04, 2012 10:24 AM
I made one mistake when I presented this- in kb.cpp, I really had the #define KB_G before #include "kb.h".
Well, yes, this was confusing. But really, if you only want to use candidates and num_candidates in kb.cpp, why not put them in kb.cpp? Once again, defining variables in header files is a bad idea.
I really do not understand what your problem is. You do not show the function prep_candidates(), but you say it "makes" candidates and num_candidates. So clearly candidates is NULL unless you call prep_candidates(). If you are expecting candidates to be non-NULL, where do you think you are defining it to be non-NULL?
David Wilkinson | Visual C++ MVP- Marked As Answer by CADMeister Wednesday, May 09, 2012 5:09 PM
-
Friday, May 04, 2012 5:37 PM
Since I last posted, I resolved one mystery, which might explain the problem. You interpreted my cryptic remarks correctly- prep_candidates does make it non-NULL. What I discovered is that after I raised the dialog, my own code deleted and NULLed candidates. I did not count on the asynchronous nature of the dialog- I am using the dialog's button to start a computation using candidates.
My intent is that the dialog has a begin button, a progress bar, and a terminate-at-any-time button. I have fixed my code so that the begin button triggers what I want it to, I don't prematurely kill candidates, and the progress bar reports the progress of my computation. Unfortunately, while the progress bar is operating, my terminate button is locked out.
A previous adviso suggested that I don't know anything about the message pump, and that I should use a thread for my computation. What I am trying to do is simple, and I think that all the other Windows apps which I have used, having a single dialog monitoring the action, maybe don't use threads. I think that developers of these GUIs must use some kind of timing tricks to prevent clogging the message pump. But, I haven't figured it out yet.
What I would like to find is:
An algorithm, or code, for operation of a dialog which has a simple progress bar, a begin button, and an interruptor button. For my application, I will use the interruptor button to terminate the operation being monitored. My interruptor button doesn't respond until progress is all done, at which time it is useless.
- Edited by CADMeister Friday, May 04, 2012 5:38 PM mistake
-
Friday, May 04, 2012 5:46 PM
Doing the lengthy operation in a worker thread is the preferred answer, because it leaves the primary thread available to respond to a click on the interruptor button. (And also to paint the changed progress bar.)
You could hack together a solution that uses a timer instead of a thread. The idea is that each time you receive the WM_TIMER message you do a brief portion of the lengthy operation, then return. Continue on the next WM_TIMER, again for a brief interval only.
- Marked As Answer by CADMeister Wednesday, May 09, 2012 5:09 PM
-
Friday, May 04, 2012 5:48 PM
What I would like to find is:
You need to use a worker thread. In an MFC application you should use AfxBeginThread() to start the thread.
An algorithm, or code, for operation of a dialog which has a simple progress bar, a begin button, and an interruptor button. For my application, I will use the interruptor button to terminate the operation being monitored. My interruptor button doesn't respond until progress is all done, at which time it is useless.
David Wilkinson | Visual C++ MVP -
Saturday, May 05, 2012 12:06 AM
Thanx for the teach.
I had to try my idea but it didn't work.
With the use of one simple worker thread, triggered by the BEGIN button of my dialog, the whole thing works like a trained pig.
Seems to me that this world could use a new kind of resource- a multi-control "true" modeless dialog, where the controls simulated parallelism for single cpu machines.
I wonder if there is such an operating system as a multi-pump system.
- Marked As Answer by CADMeister Wednesday, May 09, 2012 5:09 PM
-
Saturday, May 05, 2012 12:07 AM
Thanx for the teach.
I had to try my idea but it didn't work.
With the use of one simple worker thread, triggered by the BEGIN button of my dialog, the whole thing works like a trained pig.
Seems to me that this world could use a new kind of resource- a multi-control "true" modeless dialog, where the controls simulated parallelism for single cpu machines.
I wonder if there is such an operating system as a multi-pump system.
- Marked As Answer by CADMeister Wednesday, May 09, 2012 5:09 PM
-
Saturday, May 05, 2012 1:16 AM
Seems to me that this world could use a new kind of resource- a multi-control "true" modeless dialog, where the controls simulated parallelism for single cpu machines.
Worker thread works even with a single CPU, because each thread gets time from the OS. Windows is a preemptive multitasking OS:
http://en.wikipedia.org/wiki/Preemptive_multitasking
David Wilkinson | Visual C++ MVP- Marked As Answer by CADMeister Wednesday, May 09, 2012 5:09 PM

