|
I suppose I should have mentioned that this happens when the application is first launched.
QSWDoc::SetModifiedFlag() is being called from QSWDoc::OnNewDocument(), which calls CDocument::OnNewDocument().
If I step into or over the code pFrameWnd->OnUpdateFrameTitle(TRUE); I am absolutely hung and have to use Task Manager to close Visual Studio. At this point my call stack is referencing 00000000().
Sydney Liles
Software Engineer
|
|
|
|
|
Sydney Liles wrote:
QSWDoc::SetModifiedFlag() is being called from QSWDoc::OnNewDocument(), which calls CDocument::OnNewDocument().
Interesting... At this point (application launching) in a SDI app (maybe a MDI app too; not sure off-hand), the main window doesn't yet exist. So AfxGetMainWnd() *should* be returning NULL... Not sure why it isn't; you might want to trace through *that* call & see what's up. But in any case, you'll need to find a different place for your code; even in MFC6 you shouldn't be able to get away with this.
---
Shog9
If I could sleep forever, I could forget about everything...
|
|
|
|
|
Thanks for your help. It is not fixed yet, but by tracking through the AfxGetMainWnd() call I realized that I do have a window, sort of -- it is a splash screen and that appears to be the true source of the problem -- I am getting a pointer to something that is not truly a window or even a frame. Anyway, I am off on another bug hunt. Thanks again.
Sydney Liles
Software Engineer
|
|
|
|
|
Ok, I am playing around with VC++ again and have only done a little work on a form and am already getting compiler errors . My guess is the error will be apparent to someone who uses VC++ often. This is what I have added:
void CTestDlg::OnShowFileDlg()
{
CFileDialog cd(true);
if(IDOK == cd.DoModal())
{
FunWithFile(cd);
}
}
void CTestDlg::FunWithFile(CFileDialog cd)
{
MessageBox(_T("Hello"), _T("Test Message"), MB_OK);
}
and I get the following error messages
<br />
--------------------Configuration: Test - Win32 Debug--------------------<br />
Compiling...<br />
TestDlg.cpp<br />
C:\Documents and Settings\np0383\My Documents\C++\Test\TestDlg.cpp(181) : error C2664: 'FunWithFile' : cannot convert parameter 1 from 'class CFileDialog' to 'class CFileDialog'<br />
No copy constructor available for class 'CFileDialog'<br />
C:\Documents and Settings\np0383\My Documents\C++\Test\TestDlg.cpp(191) : error C2352: 'CWnd::MessageBoxA' : illegal call of non-static member function<br />
c:\program files\microsoft visual studio\vc98\mfc\include\afxwin.h(2197) : see declaration of 'MessageBoxA'<br />
Error executing cl.exe.<br />
<br />
Test.exe - 2 error(s), 0 warning(s)<br />
Any clues? Thanks in advance.
Nick Parker
|
|
|
|
|
You are passing the entire dialog as an object and the compiler is trying to make a copy of the dialog. When you pass a parameter as an object and not a reference or pointer then the compiler will try to make a copy of your object. Bad practice.
Instead pass a pointer to your dialog. Why are you passing a dialog? Anyway. Pass a pointer rather than the object.
FunWithFile(&cd)
and
void FunWithFile( CFileDialog* cd )
or even better
void FunWithFile( const CFileDialog* cd ) This way you pass a pointer but cannot change anything.
|
|
|
|
|
|
The clue has already been posted: you'd better pass a pointer rather than the whole object. You try to pass the whole object and consequently a copy of your object. To make a copy you need a constructor CFileDialog(const CFileDialog &) Even if you had it, it would be a poor way of implementing what you want because it would be too time- and resource- consuming. Thus pass a pointer and enjoy.
Hope this helps.
|
|
|
|
|
|
Pass the dialog by reference.
void CTestDlg::FunWithFile
(CFileDialog& cd)
{
MessageBox(_T("Hello"), _T("Test Message"), MB_OK);
}
/ravi
Let's put "civil" back in "civilization"
http://www.ravib.com
ravib@ravib.com
|
|
|
|
|
|
Ravi,
The pointer thingy (like my naming convention) worked out great however I still get an error just with the MessageBox.
void CTestDlg::FunWithFile(CFileDialog& cd)
{
MessageBox(_T("Hello"), _T("Test Message"), MB_OK);
}
Does this one make sense?
<br />
--------------------Configuration: Test - Win32 Debug--------------------<br />
Compiling...<br />
TestDlg.cpp<br />
C:\Documents and Settings\np0383\My Documents\C++\Test\TestDlg.cpp(192) : error C2352: 'CWnd::MessageBoxA' : illegal call of non-static member function<br />
c:\program files\microsoft visual studio\vc98\mfc\include\afxwin.h(2197) : see declaration of 'MessageBoxA'<br />
Error executing cl.exe.<br />
<br />
Test.exe - 1 error(s), 0 warning(s)<br />
Also, how do you access the methods of the pointer to the object once it has been passed. I understand if you just want to say RTFM.
Thanks again.
Nick Parker
|
|
|
|
|
Hi Nick,
You've probably got FunWithFile declared as a static member function, ie:
in your header file, it probably looks like this:
class CTestDlg : public CDialog
{
...
static void FunWithFile(CFileDialog & cd);
...
};
If that's the case, the reason you see this is because FunWithFile is a static member function, w/ explains the message "illegal call of non-static member function" (CWnd::MessageBox is not declared as static in it's header file).
Here's a rule of thumb to follow w/ static class members (be they static data members or static member functions).
The static keywoard (when used w/ classes) effectively makes the function or member data global, but limits it's scope to a class level.
You can call CTestDlg::FunWithFile without an instance of a CTestDlg object because that function is effectively a global function, but you have to use the scope resolution operator to access the function from outside the class because the scope is limited to the class level.
void AnyFunctionYouWant()
{
CFileDialog fd(TRUE);
if( fd.DoModal() == IDOK )
{
CTestDlg::FunWithFile( fd );
}
}
If you want to, you could change your test function to use
::MessageBox(NULL, _T("blah blah"), _T("blah"), MB_OK);
AfxMessageBox(_T("blah blah blah");
HTH,
Wes
Sonork ID 100.14017 wtheronjones
|
|
|
|
|
Thanks Wes, I'll try that as soon as I get back from the gym (just got home from work). Thanks again.
Nick Parker
|
|
|
|
|
That did it, thanks for the pointer (no pun intended). I'm sure I'll be back soon asking some other *dumb* question.
Nick Parker
|
|
|
|
|
Nick, you need to use ::MessageBox() to indicate global scope. Otherwise, the compiler looks for a method named MessageBox() that belongs to CTestDlg .
The reason why the error message refers to "MessageBoxA' instead of just "MessageBox" is because Windows #defines it so, since you're doing a non-Unicode build.
/ravi
Let's put "civil" back in "civilization"
http://www.ravib.com
ravib@ravib.com
|
|
|
|
|
Nick Parker wrote:
Also, how do you access the methods of the pointer to the object once it has been passed. I understand if you just want to say RTFM.
Thanks again.
There are two ways to access methods through a pointer. For example, you have a class CFooClass with member function bar(). Normally, of course, we say:
CFooClass foo;<br />
foo.bar();
Now declare a pointer to CFooClass:
CFooClass* pfoo = &foo; // pfoo is address of foo
Two methods of accessing member functions:
(*pfoo).bar();
pfoo->bar();
I generally prefer method #2 is it's somewhat prettier to look at, but it really doesn't matter.
Jeff Sand
jsand at interaccess dot com
|
|
|
|
|
Thanks Jeff, after looking at it I think that pfoo->bar(); looks a lot better. Are there reasons for the two different methods where one only works in certain situations or are there just many ways of doing one thing? Thanks again.
Nick Parker
|
|
|
|
|
I have a class where I have member variables.
I have declared a static member function to handle one single call to AfxBeginThread(...).
AfxBeginThread calls this static member function that calls a non-static member function in return that does all the background processing.
If I use global vars (declared outside the class scope) the application is fine. But as soon as I declare those globals as protected members of this class which calls AfxBeginThread, I get an access violation. My class looks like this:
class CReadIntoSybaseDlg : public CDialog
{
// Construction
public:
CReadIntoSybaseDlg(CWnd* pParent = NULL); // standard constructor
static UINT TestThread(LPVOID pParam);
UINT RunThread();
// Dialog Data
//{{AFX_DATA(CReadIntoSybaseDlg)
enum { IDD = IDD_READINTOSYBASE_DIALOG };
CButton m_OK;
CButton m_Cancel;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CReadIntoSybaseDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
CWinThread *m_pThWorker;
CMutex *cs;
CDatabase db;
CDaoDatabase db2;
CSybNames rs;
CDaoRecordset ds;
COleVariant oleVar;
CDaoTableDefInfo tb;
volatile BOOL running;
// Generated message map functions
//{{AFX_MSG(CReadIntoSybaseDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
virtual void OnOK();
virtual void OnCancel();
afx_msg void OnStop();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
I call AfxBeginThread(TestThread,0)
Then this TestThread is declared like this:
UINT TestThread(LPVOID pParam)
{
return ((CReadIntoSybaseDlg *)AfxGetApp())->RunThread();
}
In RunThread(), I am using the various CDatabase and CDaoDatabase variables as members of this class i.e. db, db2, rs,ds. If I declare them globally, its fine. But the moment I put my declaration in the class, it starts complaining. I know it has to do with threading but I have no clue. Could someone please help.
Thanks a lot in advance.
ashish
|
|
|
|
|
achandra007 wrote:
UINT TestThread(LPVOID pParam)
{
return ((CReadIntoSybaseDlg *)AfxGetApp())->RunThread();
}
AfxGetApp() returns the main application object, which is a CWinApp - derived object. You should not cast that to your dialog class. You need to some other way to get the dialog object pointer ( if you app is a dialog based app then AfxGetMainWnd() might do it)
--------------------------------------------------
|
|
|
|
|
Thanks for the suggestion but my problem is with the threading. I can't seem to avoid the Access Violation when I use the CDatabase etc variables in my class and not as globals.
ashish
|
|
|
|
|
achandra007 wrote:
UINT TestThread(LPVOID pParam)
{
return ((CReadIntoSybaseDlg *)AfxGetApp())->RunThread();
}
You are doing complete nonsense here! AfxGetApp() retuns a pointer to the one-and-only CWinApp object. This has nothing to do with your dialog and the result of your cast is just "undefined".
--
Daniel Lohmann
http://www.losoft.de
(Hey, this page is worth looking! You can find some free and handy NT tools there )
|
|
|
|
|
Thank you for politely replying to my question. Suprisingly, the "nonsense" works when I use global variables of type CDataset etc. But I won't waste your time in getting you to explain that. If you can answer my question (see the original post), then I thank you in advance. Otherwise, don't waste my time with these useless suggestions.
thanks
ashish
|
|
|
|
|
Ashish,
Why do you try to blame the experienced people that just want to help you?
Surprisingly it works is really the right term here! This is definitively a huge bug in your code which, as I wrote, results in undefined behaviour. Undefined beheaviour means that anything could happen: Even that it surprisingly seems to work, but just stops working if you change something at a complete different position in your code.
To make it short: This bug has a good chance to be the reason for your access violations!
Fix it, check what happens and if you have still problems post the code again. It would be very kind if you enclose it with <pre> and </pre> tags next time, so it will appear well formatted in the forum. This would make it much better readable and therfore increases your chances to get a no-"nonsense" answer.
--
Daniel Lohmann
http://www.losoft.de
(Hey, this page is worth looking! You can find some free and handy NT tools there )
|
|
|
|
|
Daniel
I am not trying to blame anyone. I asked a question and I think you just got off about the code. I admit it may have bugs - that is why I am asking the questions. But read my original post and then read my reply to Wes Jones. If you can still help, then thanks in advance. Otherwise, there is no need to pontificate. I will learn without it as well.
thanks
ashish
|
|
|
|
|
Hi Ashish,
Not to be rude, but there are plenty of problems w/ the code.
The access violoation you are seeing is due to the fact that CYourApp does not have a RunThread() function.
When you call AfxGetApp() is is returning a pointer to a CWinApp derived class, which is really a pointer to your CYourApp class which the class wizard creates for you. The ptr returned by AfxGetApp() is totally unrelated to any instances of CReadIntoSybaseDlg. The reason it didn't blow up on you when you used global data is because there wasn't any code implicitly trying to access the 'this' pointer in the implementation of RunThread. Since you're casting the ptr to CReadIntoSybaseDlg, your tricking it into calling your CReadIntoSybaseDlg::RunThread function. Your new function is trying to access member data via the 'this' ptr, but since you've casted the pointer to an invalid type, the 'this' ptr is really invalid.
Here's the proper way to call it:
CReadIntoSybaseDlg::StartThreadFunc()
{
m_pThWorker = AfxBeginThread(TestThread, this);
}
UINT CReadIntoSybaseDlg::TestThread(LPVOID lpvParam)
{
CReadIntoSybaseDlg * pThis = reinterpret_cast<CReadIntoSybaseDlg*>(lpvParam);
ASSERT( pThis );
pThis->RunThread();
return 0;
}
Other things that would make your code a little nicer would be to rename the member variables w/ the m_ prefix.
I'd recommend that you, or anyone else reading this, read the book "Programming Windows Applications" by Jeffrey Richter, or even the earlier version of the book titled "Advanced Window Applications" or something like that.
Also, get a copy of the big red MFC book from Wrox press by Mike Blazncack (sp?).
Without knowing the rest of your code, you're probably going to be better of, performance wise, if you use a CCriticalSection instead of a CMutex.
I also want to warn you to be careful not to access the database objects from different threads at the same time, which is probably what your doing w/ the CMutex anyway. Bad things can happen if one thread's doing an insert and another's doing a rollback.
HTH,
-Wes
Sonork ID 100.14017 wtheronjones
|
|
|
|