In OnInitDialog I call this method to create 9 CComboBox drop lists:
void CChristianLifeMinistryStudentsDlg::CreateSampleConversationVideoCombos()
{
CChristianLifeMinistryStudentEdit* pArrayStudents[9] =
{
&m_editMainStudent1,
&m_editMainStudent2,
&m_editMainStudent3,
&m_editClass1Student1,
&m_editClass1Student2,
&m_editClass1Student3,
&m_editClass2Student1,
&m_editClass2Student2,
&m_editClass2Student3
};
CChristianLifeMinistryStudentEdit* pArrayAssistants[9] =
{
&m_editMainStudent1Assist,
&m_editMainStudent2Assist,
&m_editMainStudent3Assist,
&m_editClass1Student1Assist,
&m_editClass1Student2Assist,
&m_editClass1Student3Assist,
&m_editClass2Student1Assist,
&m_editClass2Student2Assist,
&m_editClass2Student3Assist
};
CString strChairman, strAuxClassCounsellor;
strChairman.LoadString(IDS_STR_MWB_CHAIRMAN);
strAuxClassCounsellor.LoadString(IDS_STR_AUX_CLASS_COUNSELLOR);
for (int i = 0; i < 9; i++)
{
CRect rctStudent, rctAssistant;
pArrayStudents[i]->GetWindowRect(rctStudent);
pArrayAssistants[i]->GetWindowRect(rctAssistant);
ScreenToClient(&rctStudent);
ScreenToClient(&rctAssistant);
CRect rctSampleConversationVideo;
rctSampleConversationVideo.SetRect(rctStudent.TopLeft(), rctAssistant.BottomRight());
m_cbSampleConversationVideo[i].Create(CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP | WS_VISIBLE,
rctSampleConversationVideo, this, IDC_COMBO_OCLM_AYFM_ASSIGN1_MH + i);
m_cbSampleConversationVideo[i].SetFont(GetFont());
m_cbSampleConversationVideo[i].AddString(strChairman);
m_cbSampleConversationVideo[i].AddString(strAuxClassCounsellor);
}
}
What I can't work out is if I need to call DestroyWindow on each of these when the dialog is closed? I don't seem to get any memory leaks.
When you have a window handled by the MFC you have two parts. The first is the window itself (represented by the HWND), the second is the object in the MFC that wraps the functionality implements a message map and offers easy member function access by wrapping the windows messages.
The lifetime of a window ends when DestroyWindow is called. A parent window like a dialog will destroy all it child windows automatically. It doesn't matter if the child was created by calling CreateDialog/DoModal, or created later using any other Create method.
Finally all windows are destroyed when the process ends. In fact all windows created inside a thread are destroyed when the thread ends. But windows should be destroyed by the user before the thread ends.
The MFC memory block is another thing. Some MFC windows are designed to be allocated on the stack or inside a window class as a member.
Dialogs and all windows that are usually created as a child windows (static, list view, buttons, etc.) are created on the stack or as a member inside another window class.
Also all this window that are designed to live on the stack or as a member call DestroyWindow when the destructor of the class is called and if the window still exists. This also causes a message on the debug output and usually this should be avoided.
Frame windows and views are created on the heap. All MFC windows that are created on the heap have have a PostNcDestroy function that finally deletes the MFC memory block, when WM_DESTROY was handled. PostNcDestroy is always called from the WM_NCDESTROY handler.
You find details about this also in TN017 in the MSDN
Related
I made a thread to set some text on EditBox on Lobby Dialog. Below is my code.
And MainLobby is the Dialog Class. This project is "Dialog Based MFC Project".
MainLobby Lobby;
_beginthreadex(NULL, 0, ReceiveMessage, (void *)Lobby.GetSafeHwnd(), 0, NULL);
Lobby.DoModal();
But it doesn't work. Where is wrong? I thought hard but I couldn't find the answer.
I tried not Lobby.GetSafeHwnd() but Lobby.m_hwnd
unsigned WINAPI ReceiveMessage(void *arg)
{
HWND hDlg = (HWND)arg;
char msg[BUF_SIZE];
int msgLen;
while( (msgLen = recv(CClientApp::hSocket, msg, BUF_SIZE, 0)) != 0 )
{
SetDlgItemText(hDlg, IDC_LOBBY_CBOX, msg);
}
}
I am using MFC now. I will be glad a good idea.
The device context has to be updated.
Try:
UpdateData(true);
SetDlgItemText(hDlg, IDC_LOBBY_CBOX, msg);
UpdateData(false);
Or try it with a CString member variable for IDC LOBBY CBOX.
It is clear from your code that you are not using MFC properly. A Windows dialog based application does not require the programmer to explicitly create message handlers or receivers, that is what the MFC framework itself is doing for you. There is no reason to call beginthreadex before starting the dialog message loop as part of the DoModal method. When you invoke DoModal on any class descended From Dialog or DialogEX, the window is constructed, the member objects are constructed, and the message loop is started before the WM_INITDIALOG message is sent to the dialog for any other initialization before the dialog window is displayed. Once the window is displayed, the message loop is running, and text will display automatically in an edit control when you send it correctly. Normally one would declare a CEdit object with some name using the Class Wizard in visual studio then map the MFC object to the dialog object. Rather than type out all the details I will refer to this article: http://msdn.microsoft.com/en-us/library/6d1asasd.aspx
The dialog's HWND has not been initialized before DoModal is called. So your thread does not receive the proper HWND. The first place that you can access the correct HWND value is inside the dialog's OnInitDialog member function.
I see two problems in your code.
First you are calling Lobby.GetSafeHwnd before DoModal, so before the window is constructed. You should move the thread creation to the WM_INITDIALOG handler of MainLobby to create the thread there. Or you could create a modeless dialog.
Second you are using _beginthreadex in your MFC code. If you are starting a thread that uses MFC, then you need to start that thread with AfxBeginThread. If you only use CRT, then you use _beginthreadex. If you use neither, then use Windows CreateThread. The reason for this is that each layer (CRT, MFC) needs to do some housekeeping of thread specific information. This can only be done if you call the proper thread creation functions.
Third, you might consider using the MFC socket objects like CAsyncSocket. This object can send windows messages to your dialog if some data is available on the socket. This perfectly fits into your scenario with an MFC dialog that should handle socket data.
Another thing, but you already got that right: to access an MFC GUI object you need to be in the thread of that GUI object. So calling the Windows SetDlgItemText with the raw handle hDlg needs to be done, you cannot call an MFC function here.
BTW, are you sure your overall strategy is right? I don't see how you handle dialog life time, socket life time and how you put both together.
I'm working on a C++ FLTK application. This is a multi-thread application that creates & shows a modal window in a thread using below code:
Fl_Double_Window* dlg = new Fl_Double_Window(0, 0, 200, 100);
...
dlg->set_modal();
Fl::visual(FL_DOUBLE|FL_INDEX);
dlg->show();
then in same thread I create a new thread & pass pointer to Fl_Double_Window object to it as thread parameter:
CreateThread(
NULL, // default security attributes
0, // use default stack size
&beginProgress, // thread function name
(LPVOID) dlg, // argument to thread function
0, // use default creation flags
NULL);
& in my thread function I do some operations & then I need to hide the showing modal window:
DWORD WINAPI beginProgress(LPVOID args)
{
//do some operations
((Fl_Double_Window*)args)->hide();
return 0;
}
the problem is here that my code executes successfully with no error, but after executing hide method of dlg object pointer, window does NOT hides & seem calling hide or even deleting window object using delete dlg has no effect.
I guess this problem is related to multi-threading behavior, but I can't guess what cause the problem & how should I solve it.
Please read the FLTK guide on multithreading:
FLTK supports multiple platforms, some of them which do not allow any
other but the main thread to handle system events and open or close
windows. The safe thing to do is to adhere to the following rules for
threads on all operating systems:
Don't show() or hide() anything that contains widgets derived from Fl_Window, including dialogs, file choosers, subwindows or Fl_GL_Windows
Here is the FLTK-recommended way to handle GUI updates from a background thread:
The only
workaround is to store what you want to do in static variables, call
fltk::awake(), and make the main thread call fltk::wait() repeatedly,
checking and acting on the static values after each call.
I've used MFC dialogs before where you do:
EnterNameDlg dlg;
dlg.DoModal();
string str = dlg.GetName();
However a dialog I have now actually looks at a list-box control in such a method and it's not working. Although the class instance clearly exists after DoModal(), does the actual dialog get destroyed? I noticed calling DoModal() a 2nd time leads to OnInitDialog() also being called again which seems to support this theory, the dialog is recreated from the template rather than simply made visible the 2nd time.
Yes, DoModal creates a dialog on each call and destroys the window before returning.
Only the data members will still be valid. Of course, you can add more data members in your EnterNameDlg class if you want to collect data during dialog's lifetime.
As soon as the dlg gets out of scope, everything will be deallocated.
After DoModal class instance still exists, but window and all its controls are destroyed. You can call only functions that don't work with dialog controls after DoModal. Inside of the dialog class, keep required values in class members like CString, when OK button is pressed. These members can be read after dialog is closed.
The entirety of MFC is built around an awkward pairing - the Windows window with its associated handle, and the MFC class object. The MFC classes are designed to outlast the window in most cases.
I have an OnMove handler in my dialog class, which does some stuff with control objects (i.e a CButton). I'm finding this handler gets called before the dialog OnInitDialog method is called, and hence when I try to call methods on the child controls, I get ASSERTS in debug as the controls don't yet exist... they are created in OnInitDialog.
There's two things I'd like to be able to check:
How do I tell the dialog has been initialized?
How do I check an individual CWnd control object's window has been created?
In both cases I'm looking for class members or method call results that can be used.
Set a flag in OnInitDialog
Use your dialog's m_hWnd:
if ( ::IsWindow(m_Ctrl.m_hWnd) ) {
...
}
I have a Win32 C++ Application. There is the _tWinMain(...) Method with GetMessage(...) in a while loop at the end. Before GetMessage(...) I create the main window with
HWND m_MainHwnd = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_LAYERED, CAxWindow::GetWndClassName(), _TEXT("http://www.-website-.com"), WS_POPUP, 0, 0, 1024, 768, NULL, NULL, m_Instance, NULL);
ShowWindow(m_MainHwnd)
If I do not create the main window, my application needs about 150K in memory.
But with creating the main window with the WebBrowser Control inside, the memory usage increases to 8500K.
But, I want to dynamically unload the main window. My _tWinMain(...) keeps running! Im unloading with
DestroyWindow(m_MainHwnd)
But the WebBrowser control won't unload and free up it's memory used!
Application memory used is still 8500K!
I can also get the WebBrowser Instance or with some additional code the WebBrowser HWND
IWebBrowser2* m_pWebBrowser2;
CAxWindow wnd = (CAxWindow)m_MainHwnd;
HRESULT hRet = wnd.QueryControl(IID_IWebBrowser2, (void**)&m_pWebBrowser2);
So I tried to free up the memory used by main window and WebBrowser control with (let's say it's experimental):
if(m_pWebBrowser2)
m_pWebBrowser2->Release();
DestroyWindow(m_hwndWebBrowser); //<-- just analogous
OleUninitialize();
No success at all.
I also created a wrapper class which creates the main window. I created a pointer and freed it up with delete:
Wrapper* wrapper = new Wrapper();
//wrapper creates main window inside and shows it
//...do some stuff
delete(wrapper);
No success. Still 8500K.
So please, how can I get rid of the main window and it's WebBrowser control and free up the memory, returning to about 150K.
Later I will recreate the window. It's a dynamically load and unload of the main window, depending on other commands.
Thanks!
Regards
Martin
You have what is known as a reference leak. Before you call ::Release() on your IWebBrowser2*, see how many references are open. If it's not 1, then something else somewhere has a reference to your object.
Also, don't forget to IWebBrowser2::Quit() your control...
The memory isn't always released exactly when you want it to be. There may be some things that the class is doing in the background that it must wait for before the memory can be entirely deleted. Its also possible that the memory has been freed but the kernel holds it as assigned to your process under the assumption that your process will probably want to use it in a bit anyway.
If you create another web browser window after you've destroyed the previous does the memory jump up a further 8350K or does it stay more-or-less the same?