|
Hello, the codegurus around the world.;)
Basically, we don't need to create CMyDialog in MyDoc class.
(Or, maybe we call some member function of CMyDoc with createing MyDialog and
call this function in the menu associated in CMyView).
Anyway, there are at least two ways to access the member value of CMyDoc.
1) Pass the parent's CWnd through the dialog class constructor.
(Or use GetParent() function of CWnd).
So, what is the parent? CMyDoc(?), CMyview or CMyFrame. No problems.
(Oops, CMyDoc will not be derived from CWnd.)
2) Use the global functions like AfxGetApp() or AfxGetMainWnd()
to get CMyFrame's CWnd and use GetDocument() functions.
So, we can enjoy MFC since we have many ways to do anything.
Please, don't send me your email about your questions directly.
Have a nice day!
Sonork - 100.10571:vcdeveloper
-Masaaki Onishi-
|
|
|
|
|
I store all my data in the CDocument derived class ( including the data for the dialog) and pass a pointer to it into the dialog itself.
This is a very neat way of doing things. All you have to do then is DoModal() and there is no more passing data between the classes.
Using this method helped me finally understand pointers.
e.g. in my View I handle the Options menu item. The handler will show the COptionsDlg dialog.
// in the View class I handle the Options menu handler
void CMyView::OnOptions()
{
COptionsDlg dlg;
dlg.SetupDocument(GetDocument());
if (dlg.DoModal()==IDOK)
GetDocument()->SetModifiedFlag();
}
//Add a SetupDocument member fn to COptionsDlg
//This function stores the CMyDoc pointer argument in a member variable
//
void COptionsDlg::SetupDocument(CMyDoc* pDoc)
{
m_pDoc=pDoc; //m_pDoc is declared in OptionsDlg.h as CMyDoc* m_pDoc
//remember to #include "MyDoc.h" there too
}
// in the COptionsDlg, link Edit boxes with the data members of the
// CDocument dervied class using DDX
void COptionsDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(COptionsDlg)
DDX_Text(pDX, IDC_EDIT1,m_pDoc->m_iOption1);
DDX_Text(pDX, IDC_EDIT2,m_pDoc->m_iOption2);
//}}AFX_DATA_MAP
}
When you click on OK, the framework's OnOK()function calls UpdateData(true) so the edit box values are stored in the CMyDoc members.
if you want the full source for this example email me on john@wmgallery.co.uk
|
|
|
|
|
I've noticed similar questions in other threads where people have recommended not DDXing to the CDocument inherited class directly as the Dialog shouldn't care about the Document. I don't agree with this.
One of the main reasons for the Document/View pattern is to maintain a single copy of the Document data throughout the application. This is exactly what my method(above) does - it passes a pointer to the single Document object between classes. The Dialog is as valid a 'view' as the View.
Coping data into members belonging to other objects and them reading from the members again opens the way for bugs and makes things more rigid.
That's what I reckon anyways
|
|
|
|
|
I have this timer that sets some buttons but it doesn't take place in the dialog window until I click the button or if I have a break in the code when I come out.
void CStatus::OnTimer(UINT nIDEvent)
{
if(nIDEvent == 3153)
{
UpdateData(true);
m_153_tti_enab.m_MouseOnButton = true;
m_153_tti_inhbt.m_MouseOnButton = true;
m_153_min_inhbt.m_MouseOnButton = true;
m_153_test.m_MouseOnButton = true;
m_153_malf.m_MouseOnButton = true;
m_153_rt.m_MouseOnButton = true;
UpdateData(false);
}
Any ideas as to why this won't update the window?
Thanks for all the help!!!
|
|
|
|
|
Try forcing the window to repaint itself with Invalidate(FALSE); after the UpdateData call.
Christian
We're just observing the seasonal migration from VB to VC. Most of these birds will be killed by predators or will die of hunger. Only the best will survive - Tomasz Sowinski 29-07-2002 ( on the number of newbie posters in the VC forum )
Cats, and most other animals apart from mad cows can write fully functional vb code. - Simon Walton - 6-Aug-2002
|
|
|
|
|
The Invalidate() does cause the window to update...GOOD. but it blinks really bad. Any easy way to smooth this out?
|
|
|
|
|
Invalidate(FALSE) should cause the window to redraw itself WITHOUT erasing first, and should therefore not flicker. Beyond that, my MFC is a little rusty, I'm sorry. Is your WM_PAINT message doing anything strange ?
Christian
We're just observing the seasonal migration from VB to VC. Most of these birds will be killed by predators or will die of hunger. Only the best will survive - Tomasz Sowinski 29-07-2002 ( on the number of newbie posters in the VC forum )
Cats, and most other animals apart from mad cows can write fully functional vb code. - Simon Walton - 6-Aug-2002
|
|
|
|
|
Is the application busy?
And what is ...m_MouseOnButton?
What is it expected to do?
Give a little more insight to your app.
int x=1, y=5;
x^=y^=x^=y;
<a href="http://www.codeproject.com/tips/StupidXORTrick.asp" target="_blank">ClickHereForHelp();</a>
|
|
|
|
|
The app isn't busy...m_MouseOnButton is a way of setting the button to the active state. So what I'm doing is reading in some values and if they are true then I set the button on and hope it updates on the page by changing color.
Thanks for the help.
|
|
|
|
|
jimNLX wrote:
if they are true then I set the button on and hope it updates
Hope is the last to die, people say.
How exactly are you setting the button on? Where does it happen? When?
int x=1, y=5;
x^=y^=x^=y;
<a href="http://www.codeproject.com/tips/StupidXORTrick.asp" target="_blank">ClickHereForHelp();</a>
|
|
|
|
|
enab.m_MouseOnButton = true; this is how I set the button state to on and I do this in OnTimer()
|
|
|
|
|
Sorry, where does the button actually react on the flag? is it a check button? and the variable is DDX'd to it?
int x=1, y=5;
x^=y^=x^=y;
<a href="http://www.codeproject.com/tips/StupidXORTrick.asp" target="_blank">ClickHereForHelp();</a>
|
|
|
|
|
I'm using CButtonST (from this board) and subclass this in OnInit then OnTimer reads a flag and sets
OnInit code:
m_jam.SubclassDlgItem(IDC_JAM,this);
m_jam.SetTooltipText(IDS_TRNFREEZE);
m_jam.SetActiveBgColor(COLOR_ORANGE);
OnTimer code:
m_jam.m_MouseOnButton = true;
|
|
|
|
|
Did you try using a standard button instead? If it works with the standard button I would say its a bug in the CButtonST class.
btw: your call to UpdateData(true) isnt needed at all as far as I see from your code.
int x=1, y=5;
x^=y^=x^=y;
<a href="http://www.codeproject.com/tips/StupidXORTrick.asp" target="_blank">ClickHereForHelp();</a>
|
|
|
|
|
If I run it w/o breakpoints, it puts up three CFIleDialogs like it should, but then crashes - memory could not be read.
If I try to debug it with a breakpoint, it says its an NTDLL first chance exception - invalid handle. and never even puts up the three dialogs! I can put the breakpoint anywhere even quite early and I stil ge this. In the call stack I havent gone very far when it happens. I'm troubled that a direct run, and a breakpoint debug run arent following the same route? Although The three CFILEDLgs are postmessage triggered, so maybe thats significant?
Helppp!
ns
Weirder yet, after the three fldialogs get their inputs they save then to the registry. and then crashes. But if you run the program again after these keys have been created, it runs just fine!!
SO its a crash about an invalid handle but doesnt allow the filedlgs to popup like they do when the program is run without debug mode.
|
|
|
|
|
And the code ?
Is the program single threaded ? What are you storing in the registry ? How does your programs execution path differ once those keys exist ?
Christian
We're just observing the seasonal migration from VB to VC. Most of these birds will be killed by predators or will die of hunger. Only the best will survive - Tomasz Sowinski 29-07-2002 ( on the number of newbie posters in the VC forum )
Cats, and most other animals apart from mad cows can write fully functional vb code. - Simon Walton - 6-Aug-2002
|
|
|
|
|
Its single threaded. I'm storing names of databases etc (strings). Once the registry keys are in, I dont postmessage to trigger the open CFiledlgs, but get the registry info. at this point its fine. I do this(no error trapping):
void CTrain1View::QueryRegistry()
{
CString dbName;
HKEY keyHandle1, keyHandle2, keyHandle3;
CString str;
;
DWORD valSize = sizeof(DWORD);
RegOpenKeyEx(HKEY_CURRENT_USER, "Software",
0, KEY_ALL_ACCESS, &keyHandle1);
LONG res = RegOpenKeyEx(keyHandle1, "MyCompany4",
0, KEY_ALL_ACCESS, &keyHandle2);
RegOpenKeyEx(keyHandle2, "MyApplication4",
0, KEY_ALL_ACCESS, &keyHandle3);
DWORD size=128;
DWORD type = REG_SZ;
LPSTR psz = dbName.GetBuffer(size);
LONG result = RegQueryValueEx( keyHandle3,"Database Name",0,&type,(LPBYTE)psz,&size );
dbName.ReleaseBuffer();
size=128;
LPSTR psz1 = m_PhotoDBPath.GetBuffer(size);
result = RegQueryValueEx( keyHandle3,"Photo Database Name",0,&type,(LPBYTE)psz1,&size );
m_PhotoDBPath.ReleaseBuffer();
size=128;
LPSTR psz2 = m_ImageFolderLoc.GetBuffer(size);
result = RegQueryValueEx( keyHandle3,"Image Folder Location",0,&type,(LPBYTE)psz2,&size );
m_ImageFolderLoc.ReleaseBuffer();
gImageFolderLoc = m_ImageFolderLoc;
RegCloseKey(keyHandle1);
RegCloseKey(keyHandle2);
RegCloseKey(keyHandle3);
if (result == ERROR_SUCCESS)
{
gDatabaseName=dbName;
CString filename = DatabaseName(dbName);
GetStuff(dbName );
InitDisplay();
}
if ( dbName =="")
{
PostMessage(WM_COMMAND, ID_SELECTDATABASE);
}
}
and the postmessage is handled as:
CFileDialog fileDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY|OFN_FILEMUSTEXIST, "Database Files(*.mdb)|*.mdb||",NULL);
fileDlg.m_ofn.lpstrTitle = "Open Database";
if ( fileDlg.DoModal() == IDOK)
{
m_szlstfile = fileDlg.GetPathName();
CString fileExt = fileDlg.GetFileExt();
if(fileExt != "MDB" && fileExt != "mdb" )
{
m_badfilename=TRUE;
AfxMessageBox ("The file selected is not a database file");
imageMap.clear();
InitDisplay();
return;
}
m_listdisplay.DeleteAllItems();
CFileDialog fileDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY|OFN_FILEMUSTEXIST, "Database Files(*.mdb)|*.mdb||",NULL);
fileDlg.m_ofn.lpstrTitle = "Select Database For Photographs";
int nRetPhoto = fileDlg.DoModal();
if ( nRetPhoto == IDOK)
{
m_PhotoDBPath = fileDlg.GetPathName();
CString fileExt = fileDlg.GetFileExt();
if(fileExt != "MDB" && fileExt != "mdb" )
{
AfxMessageBox ("The file selected is not a database file. No record added");
return;
}
}
CFileDialogST dlg;
int nRetValue;
CString sFolder;
nRetValue = dlg.SelectFolder(_T("Please select the Image folder"), _T("c:\\"), 0x40|BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS, this);
if (nRetValue == IDOK)
{
m_ImageFolderLoc = dlg.GetSelectedFolder();
gImageFolderLoc = m_ImageFolderLoc;
MessageBox(m_ImageFolderLoc, _T("GetSelectedFolder"), MB_ICONINFORMATION);
}
HKEY keyHandle1, keyHandle2, keyHandle3;
CString str;
DWORD disp;
RegOpenKeyEx(HKEY_CURRENT_USER, "Software",
0, KEY_ALL_ACCESS, &keyHandle1);
RegCreateKeyEx(keyHandle1, "MyCompany4", 0, "",
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
&keyHandle2, &disp);
RegCreateKeyEx(keyHandle2, "MyApplication4", 0, "",
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
&keyHandle3, &disp);
DWORD type = REG_SZ;
DWORD size = m_szlstfile.GetLength();
LONG result = RegSetValueEx( keyHandle3,"Database Name",0,type,(LPBYTE)LPCSTR(m_szlstfile),size );
size = m_PhotoDBPath.GetLength();
result = RegSetValueEx( keyHandle3,"Photo Database Name",0,type,(LPBYTE)LPCSTR(m_PhotoDBPath),size );
size = m_ImageFolderLoc.GetLength();
result = RegSetValueEx( keyHandle3,"Image Folder Location",0,type,(LPBYTE)LPCSTR(m_ImageFolderLoc),size );
if (result != ERROR_SUCCESS)
AfxMessageBox("Registry error");
RegCloseKey(keyHandle1);
RegCloseKey(keyHandle2);
RegCloseKey(keyHandle3);
gDatabaseName = m_szlstfile;
if (pDoc->m_db.IsOpen()) pDoc->m_db.Close();
GetStuff(m_szlstfile );
InitDisplay();
I have two CFiledlgs with the same name, but even making them distinct doesnt help.
Thanks for helping!
ns
|
|
|
|
|
Seems that its really what I suggested: you dont check the return values from the first RegOpenKey(...) calls. They will definitly fail and thus you have a invalid handle in keyHandle1 , so the next call to RegOpenKey() to open the MyCompany key will fail and throw your exception.
Always check for return values - even if you are sure it will succeed (which it doesnt in your case).
int x=1, y=5;
x^=y^=x^=y;
<a href="http://www.codeproject.com/tips/StupidXORTrick.asp" target="_blank">ClickHereForHelp();</a>
|
|
|
|
|
ns wrote:
Weirder yet, after the three fldialogs get their inputs they save then to the registry. and then crashes. But if you run the program again after these keys have been created, it runs just fine!!
Could it be that you read this registry keys too? If so, I suppose that you do a RegOpenKey(..) which fails, thus you have a invalid handle that you dont check for, thus the next use of this handle will fail again.
Take a look in this areas.
int x=1, y=5;
x^=y^=x^=y;
<a href="http://www.codeproject.com/tips/StupidXORTrick.asp" target="_blank">ClickHereForHelp();</a>
|
|
|
|
|
When i do read it (after the initial crash) its successful. I dont know if the source I posted above gives any clues...
Thanks,
ns
|
|
|
|
|
Well, I changed PostMessage to sendMessage and things worked! Apparently there was a timing issue and the code that needed to be run didnt, while the code that triggered the postmessage went on as though it had the data from the postmessage function already. This only recently became a problem, since it worked fine before. It was impossible to debug, and the only way was a lucky trial and error. I had no hope.
ANyways, now I'm not so thrilled (but can live with it) with the fact that CFileDialogs pop up out of the blue when the app starts with no background blank UI suggesting which program is spawning them. SO its not very informative, and not traditional really. ANy ideas on how I can make things so that the blank UI comes up behind the CFileDialog (like it used to when I postMessaged the CFileDialog).
This was a nightmare crash and I cant yet believe its resolved. Nothing in the debugging suggested that that was the problem. In fact the postmessage never got triggered when a breakpoint was put at it(it got there and went past). But when I ran it directly, I did get the postmessaged CFileDialog. So there was no similarity between debug mode and run mode events. However the postmessage in a simpler version of my program would trigger just fine at the right time and get things done in time for the main program to use the data and not crash.
Thanks everyone for helping, and sorry again for the ultra long post,but I wanted to put forth as much information as possible to get your input.
APpreciate the help,
ns
|
|
|
|
|
Be asured that the problem is not solved. Just hidden. I wouldnt give up now and continue the search for the problem. There is nothing like a timing problem, just things like uninitialized variables, unsynchronized resource access and most important false expectations on program behavior. Not to forget of course unchecked error conditions.
int x=1, y=5;
x^=y^=x^=y;
<a href="http://www.codeproject.com/tips/StupidXORTrick.asp" target="_blank">ClickHereForHelp();</a>
|
|
|
|
|
Thanks for the warning. In my registry code, the source I got my code from said that if I tested the 'result' of querying the key at the end of a series of queries, it would fail if any one of them failed, so I ony need to test it the final time. I dont know if thats sound programming, but thats what I read. I feel like I'm walking on eggshells now, since there are zillions of user choices that could trigger errors that I havent accounted for. Also, every time I do a 'new' I havent checked for NULL which I should do in case theres not enough memory and the pointer comes back NULL right?
I'll have to spend one day going through the code and putting in error tests whereever I can forsee they are required. Thanks for the caution. This stuff is nervewracking! Not being transparently predictable.
|
|
|
|
|
Is there any way to use GetFileSecurity API in an application that will also be used on a 9x machine? Because when you compile and run on 9x you get errors because the OS does not have that API. If so could someone show me how. Thank you.
<><><><><><><><><><><><><><>
Matthew R. Miller
mattrmiller@computersmarts.net
www.computersmarts.net
|
|
|
|
|
You should use LoadLibrary and GetProcAddress.
I'm not sure if it's possible to use delay load in your case - this technique works on per-library basis, and the function in question is located in advapi32.dll.
Tomasz Sowinski -- http://www.shooltz.com
Free your mind and your ass will follow.
|
|
|
|
|