MFC dialog form freezes - visual-c++

I have simple MFC dialog type window that calls external dll function and one of parameters is callback function. Callback function creates another dialog window if it is not created and updates label with information from function parameter:
int userNotify ( int iNotificationType, char* pcNotificationText )
{
if(statusDlg)
{
if ( !(statusDlg->IsWindowVisible()) )
{
statusDlg->ShowWindow(SW_SHOW);
}
statusDlg->showNotification(iNotificationType,pcNotificationText);
} else
{
statusDlg = new StatusDlg(NULL);
statusDlg->Create(StatusDlg::IDD,CWnd::GetDesktopWindow());
statusDlg->ShowWindow(SW_SHOW);
statusDlg->showNotification(iNotificationType,pcNotificationText);
}
return 0;
}
statusDlg is global variable and is very simple MFC dialog form with one static label. And it has one feature - it is placed on topmost.
BOOL StatusDlg::OnInitDialog()
{
staticStatus = (CStatic*)GetDlgItem(IDC_STATIC_TRN_STATUS_DIALOG);
...
SetWindowPos(&this->wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
return TRUE; // return TRUE unless you set the focus to a control
}
Dialog form is shown during callback and label shows required information. But if I try to move form with mouse it becomes like frozen like in picture below and information on label is not updated anymore. Why this happens? How to solve this problem?

When you create StatusDlg you give it a parent of the Desktop. That is very likely wrong and leads to your later issues. The parent of your second dialog should be the main dialog that invokes it.
int userNotify ( CWnd *pParentWnd, int iNotificationType, char* pcNotificationText )
{
...
statusDlg->Create(StatusDlg::IDD, pParentWnd);
...
}
The parent window pointer will simply be the this pointer when you call userNotify.

Related

How to lock a resource using multithreading?

I am having a property sheet where I had four pages .In the second page I am having a list control and a button.And in the second page I created two threads .When I click next in the first page,I am trying enumerating the list control with some values which are being retrieved from the network .So,here the a search dialog and enumerating the list are being handled in two different threads which runs in parallel.On front of the page the search dialog got popped up and background the values from network are retrieved and list is getting enumerated with those values.During that time if I click on the client area then this search dialog is getting minimized.But this should not happen until unless the search dialog is dismissed I must not be given access to the parent window(same scenario as ModalDiaolg box,as we know until unless the child window is closed we will not be able to access the parent right,similarly scenario is required for me.)this is the code I had done for getting those threads to be run at a time.
BOOL CModelSelectionView::CreateModelThread()
{
unsigned threadID;
if( NULL == ( m_hModelThread = (HANDLE)_beginthreadex(
NULL,
0,
&CModelSelectionView::ModelThreadProc,
reinterpret_cast<void*>(this),
0,
&threadID)) )
{
return FALSE;
}
return TRUE;
}
//this thread is for search dialog
UINT CModelSelectionView::ModelThreadProc( void* lpContext )
{
CModelSelectionView *pSelectModelFromList =
reinterpret_cast<CModelSelectionView*> (lpContext);`
AfxSetResourceHandle(theApp.m_hDialogResource);
CSearchingView SearchView(IDD_DIALOG_SEARCH);
INT nRes = SearchView.DoModal();
::CloseHandle( pSelectModelFromList->m_hModelThread );
pSelectModelFromList->m_hModelThread = NULL;
_endthreadex( 0 );
return TRUE;
}
BOOL CModelSelectionView::CreateInstallerThread()
{
unsigned threadID;
if( NULL == ( m_hInstallerThread = (HANDLE)_beginthreadex(
NULL,
0,
&CModelSelectionView::InstallerThreadProc,
reinterpret_cast<void*>(this),
0,
&threadID)) )
{
return FALSE;
}
return TRUE;
}
//Second thread for Initializing the list with some values
UINT CModelSelectionView::InstallerThreadProc( void* lpContext )
{
CModelSelectionView *pSelectModelFromList =
reinterpret_cast<CModelSelectionView*> (lpContext);
pSelectModelFromList->m_listCtrl.DeleteAllItems();
LVITEM lvitem;
lvitem.mask = LVIF_TEXT;
lvitem.iItem = 0;
lvitem.iSubItem = 0;
lvitem.pszText = L"";
lvitem.cchTextMax = sizeof(lvitem.pszText);
int nItem = pSelectModelFromList->m_listCtrl.InsertItem(&lvitem);
::Sleep(200);
pSelectModelFromList->m_listCtrl.SetItemText(0,1,L"XXX");
pSelectModelFromList->m_listCtrl.SetItemText(0,2,L"YYY");
pSelectModelFromList->m_listCtrl.SetItemText(0,3,L"ZZZ");
pSelectModelFromList->m_listCtrl.SetItemText(0,4,L"AAAA");
::Sleep(200);
::TerminateThread(pSelectModelFromList->m_hModelThread, 0);
::CloseHandle(pSelectModelFromList->m_hModelThread );
pSelectModelFromList->m_hModelThread = NULL;
::CloseHandle( pSelectModelFromList->m_hInstallerThread );
pSelectModelFromList->m_hInstallerThread = NULL;
_endthreadex( 0 );
return TRUE;
}
Until unless the search dialog is closed it should not be allowed to access the parent window.For instance when click a button and for that button handler I was calling domodal then a child dialog pop-up appears until unless we dismiss that dialog we will not be allowed to access the parent right ,similarly I have to get in this scenario.
Can anyone suggest me how can I achieve that.
Can anyone please suggest me how
Simply EnableWindow(FALSE) for the window that should not receive any input. It will still be displayed and its contents is updated, but mouse and keyboard events will not reach this window.

Is there a way to override the handler called when a user clicks a checkbox in a CListCtrl? (MFC)

I am trying to disable the user's ability to alter the state of a checkbox in a List Control. I am currently changing the state pragmatically. I already handle the LVN_ITEMCHANGED message, and trying to alter the state there isn't an option due to the layout of the rest of the program. I have also tried doing a HitTest when the user clicks in the List Control and simply resetting the checkbox there but that isn't giving me the exact results I am looking for.
Is there a specific message sent or a function I can override when the user clicks the checkbox itself? I would just like to override the handler or catch the message so that it doesn't go anywhere.
Solution:
I ended up removing the LVS_EX_CHECKBOXES flag and created my own implementation. That way the there is only one way to change the icons. Reading the link from the previous question gave me an idea to set a "busy" flag, otherwise I would get stack overflow errors.
// In my dialog class
m_CListCtrl.SetImageList(&m_ImgList, LVSIL_SMALL); // Custom checkboxes (only two images)
// ...
void CMyDialog::OnLvnItemchangedList(NMHDR *pNMHDR, LRESULT *pResult)
{
if(busy) { return; }
// ....
}
// When calling the SetCheck function:
busy = TRUE; // Avoid stack overflow errors
m_CListCtrl.SetCheck(index, fCheck);
busy = FALSE;
// I derived a class from CListCtrl and did an override on the get/set check:
class CCustomListCtrl : public CListCtrl
{
BOOL CCustomListCtrl::SetCheck(int nItem, BOOL fCheck)
{
TCHAR szBuf[1024];
DWORD ccBuf(1024);
LVITEM lvi;
lvi.iItem = nItem;
lvi.iSubItem = 0;
lvi.mask = LVIF_TEXT | LVIF_IMAGE;
lvi.pszText = szBuf;
lvi.cchTextMax = ccBuf;
GetItem(&lvi);
lvi.iImage = (int)fCheck;
SetItem(&lvi);
return TRUE;
}
// Just need to determine which image is set in the list control for the item
BOOL CCustomListCtrl::GetCheck(int nItem)
{
LVITEM lvi;
lvi.iItem = nItem;
lvi.iSubItem = 0;
lvi.mask = LVIF_IMAGE;
GetItem(&lvi);
return (BOOL)(lvi.iImage);
}
}
This is not as elegant as I had hoped, but it works flawlessly.

Best way to display progress of background thread in ATL?

When using ATL, what is the best way to display the progress of a background thread (e.g. when it's searching for a file) without blocking the UI?
I still want to be able to process messages, to allow for a Cancel button and to possibly allow the user to continue working with the program while the search happens.
There is no ATL specific here. One of the ways to do is to update progress details into member variable and post a message to GUI window, then handle the message by pulling the data from member variable and updating GUI, such as updating static and/or progress bar.
Worker thread pseudo-code:
m_DataCriticalSection.Lock();
m_nProgress = (INT) (nCurrent * 100 / nTotal);
m_DataCriticalSection.Unlock();
PostMessage(WM_MYUPDATEPROGRESS);
Window:
OnMyUpdateProgress()
{
m_DataCriticalSection.Lock();
INT nProgress = m_nProgress;
m_DataCriticalSection.Unlock();
m_ProgressBar.SetPos(nProgress);
}
UPD. A real code snippet, AddText is called on background thread, :
VOID AddText(const CString& sText)
{
_A(sText.Find(_T('\n')) < 0);
BOOL bIsTextEmpty;
{
CRoCriticalSectionLock TextLock(m_TextCriticalSection);
bIsTextEmpty = m_sText.IsEmpty();
m_sText.Append(sText);
m_sText.Append(_T("\r\n"));
}
if(bIsTextEmpty)
PostPrivateMessage(WM_UPDATETEXT);
}
And the code handler:
BEGIN_MSG_MAP_EX(CMainDialog)
// ...
MESSAGE_HANDLER_EX(WM_UPDATETEXT, OnUpdateText)
LRESULT OnUpdateText(UINT, WPARAM, LPARAM)
{
CString sText;
{
CRoCriticalSectionLock TextLock(m_TextCriticalSection);
sText = m_sText;
m_sText.Empty();
}
if(!sText.IsEmpty())
{
m_TextEdit.SetValue(m_TextEdit.GetValue() + sText);
const INT nTextLength = m_TextEdit.GetWindowTextLength();
m_TextEdit.SetSel(nTextLength, nTextLength);
}
return 0;
}
This uses custom classes (not 'pure' ATL), but I hope you get the idea.

Getting edit box text from a modal MFC dialog after it is closed

From a modal MFC dialog, I want to extract text from an edit box after the dialog is closed. I attempted this:
CPreparationDlg Dlg;
CString m_str;
m_pMainWnd = &Dlg;
Dlg.DoModal();
CWnd *pMyDialog=AfxGetMainWnd();
CWnd *pWnd=pMyDialog->GetDlgItem(IDC_EDIT1);
pWnd->SetWindowText("huha max");
return TRUE;
It does not work.
The dialog and its controls is not created until you call DoModal() and as already pointed, is destroyed already by the time DoModal() returns. Because of that you cannot call GetDlgItem() neither before, nor after DoModal(). The solution to pass or retrieve data to a control, is to use a variable in the class. You can set it when you create the class instance, before the call to DoModal(). In OnInitDialog() you put in the control the value of the variable. Then, when the window is destroyed, you get the value from the control and put it into the variable. Then you read the variable from the calling context.
Something like this (notice I typed it directly in the browser, so there might be errors):
class CMyDialog : CDialog
{
CString m_value;
public:
CString GetValue() const {return m_value;}
void SetValue(const CString& value) {m_value = value;}
virtual BOOL OnInitDialog();
virtual BOOL DestroyWindow( );
}
BOOL CMyDialog::OnInitDialog()
{
CDialog::OnInitDialog();
SetDlgItemText(IDC_EDIT1, m_value);
return TRUE;
}
BOOL CMyDialog::DestroyWindow()
{
GetDlgItemText(IDC_EDIT1, m_value);
return CDialog::DestroyWindow();
}
Then you can use it like this:
CMyDialog dlg;
dlg.SetValue("stackoverflow");
dlg.DoModal();
CString response = dlg.GetValue();
Open your dialog resource, right-click on the textbox and choose "Add variable", pick value-type and CString
In the dialog-class: before closing, call UpdateData(TRUE)
Outside the dialog:
CPreparationDlg dlg(AfxGetMainWnd());
dlg.m_myVariableName = "my Value";
dlg.DoModal();
// the new value is still in dlg.m_myVariableName
DoModal() destroys the dialog box before it returns and so the value is no longer available.
It's hard to tell why you are setting m_pMainWnd to your dialog. To be honest, I'm not really sure what you are trying to do there. That's bound to cause problems as now AfxGetMainWnd() is broken.
Either way, you can't get the dialog box's control values after the dialog has been destroyed.
I often use
D_SOHINH dsohinh = new D_SOHINH();
dsohinh.vd_kichthuoc=v_kichthuocDOC;
dsohinh.vd_sohinh=v_soluongDOC;
if(dsohinh.DoModal()==IDOK)
{
v_soluongDOC=dsohinh.vd_sohinh;
v_kichthuocDOC=dsohinh.vd_kichthuoc;
}
SetModifiedFlag(true);
UpdateAllViews(NULL);
With dsohinh is Dialog form that you want to get data to mainform .
After get data then call SetModifiedFlag(true) to set view data updated.
call UpdateAllViews(NULL) to Set data to mainform
This solution may seem long, meaning that so much code has been written for this seemingly small task.
But when we have a list or tree inside the child window where all the items are created in the child window
and the items have to be moved to the parent window,
then it makes sense.
This source code can easily create a window and transfer information from the window before closing to the parents.
//copy the two functions in your code
//1- bool peek_and_pump(void)
// template<class T,class THISCLASS>
//2- void TshowWindow(int id,T *&pVar,THISCLASS *ths)
//and make two member variable
// bool do_exit;
// bool do_cancel;
//in child dialog class.
//set true value in do_exit in child dialog for exit
CchildDialog *dlg;
template<class T,class THISCLASS>
void TshowWindow(int id,T *&pVar,THISCLASS *ths)
{
T *p=pVar;
if(!p)
p= new T;
if(p->m_hWnd)
{
p->SetForegroundWindow();
}
else
{
delete p;
p= new T;
if(!(p->m_hWnd && IsWindow(p->m_hWnd)))
{
p->Create(id,ths);
if(IsWindow(p->m_hWnd))
p->ShowWindow(TRUE);
}
}
pVar=p;
}
bool peek_and_pump(void)
{
MSG msg;
#if defined(_AFX) || defined(_AFXDLL)
while(::PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))
{
if(!AfxGetApp()->PumpMessage())
{
::PostQuitMessage(0);
return false;
}
}
long lIdle = 0;
while(AfxGetApp()->OnIdle(lIdle++))
;
#else
if(::PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
#endif
return true;
}
void CparentPage::OnBnClick1()
{
if(dlg)
{
dlg->DestroyWindow();
}
TshowWindow<CchildDialog,CparentPage>(IDD_DIALOG_child,dlg,this);
dlg->GetDlgItem(IDC_EDIT_1)->SetWindowText("");
dlg->m_temp_window.EnableWindow(FALSE);//enable or disable controls.
dlg->UpdateData(false);//for to be done enable of disable or else.
dlg->do_exit=false;
dlg->do_cancel=false;
while(dlg->do_exit==false)
{
peek_and_pump();//wait for dlg->do_exit set true
}
if( dlg->do_cancel==false )
{
CString str1;
dlg->GetDlgItem(IDC_EDIT_1)->GetWindowText(str1);
//or other member variale of CchildDialog
//after finish all work with dlg then destroy its.
}
dlg->DestroyWindow();
}
void CchildDialog::OnBnClickedOk()
{
UpdateData();
OnOK();
do_exit=true;
do_cancel=false;
}
void CchildDialog::OnBnClickedCancel()
{
OnCancel();
do_exit=true;
do_cancel=true;
}

Is there a Form.Showdialog equivalent for Gtk# Windows?

Using Windows Forms or WPF I can open a dialog window by calling ShowDialog. How can I do that using Gtk#?
I tried just making the Window modal, but although it prevents the user from interacting with the calling window it does not wait for the user to close the dialog before running the code after ShowAll().
Instead of using a Gtk.Window, use Gtk.Dialog, then call dialog.Run (). This returns an integer value corresponding to the ID of the button the user used to close the dialog.
e.g.
Dialog dialog = null;
ResponseType response = ResponseType.None;
try {
dialog = new Dialog (
"Dialog Title",
parentWindow,
DialogFlags.DestroyWithParent | DialogFlags.Modal,
"Overwrite file", ResponseType.Yes,
"Cancel", ResponseType.No
);
dialog.VBox.Add (new Label ("Dialog contents"));
dialog.ShowAll ();
response = (ResponseType) dialog.Run ();
} finally {
if (dialog != null)
dialog.Destroy ();
}
if (response == ResponseType.Yes)
OverwriteFile ();
Note that Dispose()ing a widget in GTK# doesn't Destroy() it in GTK# -- a historical design accident, preserved for backwards-compatibility. However, if you use a custom dialog subclass you can override Dispose to also Destroy the dialog. If you also add the child widgets and the ShowAll() call in the constructor, you can write nicer code like this:
ResponseType response = ResponseType.None;
using (var dlg = new YesNoDialog ("Title", "Question", "Yes Button", "No Button"))
response = (ResponseType) dialog.Run ();
if (response == ResponseType.Yes)
OverwriteFile ();
Of course, you could take it a step further and write an equivalent of ShowDialog.
I'm trying to create a more complex dialog, one that doesn't have windows - it's a search dialog with a completion treeview nested in a scrollview, and is closed with Enter or Escape.
Here's how I've figured you put together the mechanics of a modal dialog manually:
Define a property on your dialog that indicates whether it is completed or not. I'm calling mine ModalResult, an enum with values None, OK and Cancel.
Ensure you have the parent window of the dialog handy (dialogParent below)
Sample code:
// assuming Dispose properly written per #mhutch
using (window = new MyDialogWindow())
{
window.TransientFor = dialogParent;
window.Modal = true;
window.Show();
while (window.ModalResult == ModalResult.None)
Application.RunIteration(true);
// now switch on value of modal result
}
Note however this Ubuntu bug with overlay scrollbars. I don't use them and my app is for personal use, but YMMV.
I implemented the following method on my Gtk.Dialog:
public ResponseType ShowDialog()
{
List<ResponseType> responseTypes = new List<ResponseType>
{
// list all the ResponseTypes that you have buttons for
// or that you call this.Respond(...) with
ResponseType.Ok,
ResponseType.Cancel
};
this.Modal = true;
// start with any ResponseType that isn't contained in responseTypes
ResponseType response = ResponseType.None;
while (!responseTypes.Contains(response))
{
response = (ResponseType)this.Run();
}
this.Destroy();
return response;
}

Resources