I have MFC dialog based window application. Main dialog form creation is shown in code below. I have some code that runs on separate thread and sometimes I need to send message to dialog window. For this I need window handler.
Line MyAppDlg.GetSafeHwnd() returns 0. Why ? How to get dialog window handler?
BOOL CMyApp::InitInstance()
{
CWinApp::InitInstance();
// Activate "Windows Native" visual manager for enabling themes in MFC controls
CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
startAll(NULL);
CMyAppDlg MyAppDlg;
m_pMainWnd = &MyAppDlg;
m_pActiveWnd = &MyAppDlg;
AuthMsgHWND = MyAppDlg.GetSafeHwnd();
INT_PTR nResponse = MyAppDlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
else if (nResponse == -1)
{
TRACE(traceAppMsg, 0, "Warning: dialog creation failed, so application is terminating unexpectedly.\n");
TRACE(traceAppMsg, 0, "Warning: if you are using MFC controls on the dialog, you cannot #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS.\n");
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
The dialog object has been created but the dialog window (and its HWND) are not created until after DoModal is called. The first place you can get access to this HWND is in the dialog's OnInitDialog function.
You've tried to get the HWND of the object before the dialog has been created with DoModal - that won't work. And since DoModal won't return until the dialog has been destroyed, you can't do it after. You'll have to find another point where you can capture that handle.
P.S. Don't call SendMessage from another thread. You're asking for trouble. Use PostMessage instead.
Related
I am confused with endDialog() and endConversion() when using bot-framework.
What's the difference between them?
If I don't invoke them, just using send()? What constraint will be?
When inside a dialog, you can invoke some other dialog. For e.g.
bot.dialog("/", [
function(session, data, next()){
session.send("Hi");
if(session.message.text === "hello"){
// starts a new dialog
session.beginDialog("helloDialog");
next();
} else {
next();
}
}, function(sesion, data){
session.send("end of root dialog");
}
]);
bot.dialog("helloDialog",[
function(session){
session.send("inside the hello dialog");
session.endDialog(); // explicitly ends the dialog
}
])
When user input is hello, output is
Hi
inside the hello dialog
end of root dialog
When user input is anything else, output is
Hi
end of root dialog
session.endDialog ends the current dialog, and resumes the parent dialog.
session.endConversation ends the conversation itself.
In Technical terms, when a dialog is called, the dialog moves into a stack called dialogStack. When another dialog is called from current dialog, that new dialog is placed at the top of dialogStack. When this new dialog completes its operation, this dialog is popped from the stack, and the last dialog resumes.
When session.endConversation is invoked, the dialog stack is emptied right away (this is a behavior am not fully sure though)
I have a CEdit field in my dialog where I have implemented EN_KILLFOCUS, so when the user enters invalid data a warning message is displayed when the focus moves away from this field and the focus returns to the CEdit field so that the user can enter proper data. If the user enters invalid data and clicks on the CANCEL button, then also a warning message is displayed which is undesirable because the user is anyway trying to cancel his actions. I have tried implementing PostQuitMessage when the user clicks on CANCEL button, but this closes the entire application. I want only my dialog to close when the user clicks CANCEL button. Is there any way that I can close the dialog instantly after I click on CANCEL button. This is the code that I tried.
void CMARPropWnd::OnParentNotify(UINT message, LPARAM lParam)
{
CCDialog::OnParentNotify(message, lParam);
// TODO: Add your message handler code here
CPoint ptButtonDown(LOWORD(lParam),HIWORD(lParam));
if ((message == WM_LBUTTONDOWN) && (ChildWindowFromPoint(ptButtonDown) == GetDlgItem(eMARPropWndCancelBtnId)))
{
PostQuitMessage(0);
}
}
Try
OnCancel();
instead of PostQuitMessage(0);
Note that OnCancel() is a virtual method of CDialog, so this is the "most correct", and will do any special code that may override the default CDialog behavior.
I am having a child window derived from CFormView. On certain condition in OnCreate() function, I want to close this window.
I tried 2 options:
int CFilterWindow::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFormView::OnCreate(lpCreateStruct) == -1)
return -1;
//Trial-1
if (!IsInitialized())
{
DestroyWindow();
return 0;
}
//Trial-2
if (!IsInitialized())
{
return -1;
}
return 0;
}
In both scenarios, the window is closed but my system returns "Failed to create empty document."
How do I avoid this message?
This is a completely normal behavior.
Document, Frame and View are created in one turn. First the document is created, than the frame and than the inner view. If one of the operations failed all other are also rolled back and fail.
So in the case of the MDI OnFileNew calls OpenDocumentFile from you template.
This function creates the new CDocument, followed by a new frame window. The frame window creates the view. This fails due to your code.
Your error message comes from CMultiDocTemplate::OpenDocumentFile because CreateNewFrame fails.
Let the MFC create your window and destroy the view it in OnInitialUpdate. This should work without this message.
In my XUL application, I open a dialog window, by this code:
var win = myWindow.openDialog("chrome://mywindow/content/mydialog.xul",
"Dialog creation",
"chrome, dialog, modal, resizable=yes",
params).focus();
And I access the information passed by user, by this code:
if (params.out){
dialogVariablesValues = params.out['inputValues'];
sameDialog = params.out['sameDialog'];
(...)
}
When the OK button in the dialog window is clicked, the window is closed, the if (params.out) becomes true and I can get the values. I don't have any problem with this approach. The problem is that I need to change my dialog window to be dependent. So I have changed the code to:
var win = myWindow.openDialog("chrome://mywindow/content/mydialog.xul",
"Dialog creation",
"chrome, dialog, dependent, resizable=yes",
params).focus();
But params.out is always null...
Does anyone know how I can get the values when the dependent dialog is closed?
With a dependent dialog the execution continues after the openDialog() call even though the dialog is still open. So you want your code to be "notified" when that dialog is closed. The easiest solution should be passing a callback in the params and changing the dialog to call your callback when it is closed. So the code opening the dialog would look like this:
params.callback = function(inputValues, sameDialog)
{
// Do something with the dialog result here
};
myWindow.openDialog(..., params).focus();
And the dialog would have code like this:
var inputValues = ...;
var sameDialog = ...;
window.addEventListener("unload", function()
{
// Dialog is being closed, call the callback
window.arguments.callback(inputValues, sameDialog);
}, false)
In short:
I want to show a view or action sheet and only continue code execution after the user has dismissed the view / sheet. So: line one shows the view, line two reads some result variable.
In detail why I would need this:
I'm porting a Windows Forms application over to the iPad. The original implementation has a communication class which uses a web service to communicate with the server. It offers a couple of methods to get data. Conveniently it checks prior to each call if the user still has a valid connection or if he has to re-enter his password for security reasons.
If the password is required, the .NET class shows a modal dialog which blocks any further code executio and if the password was entered, retries the last call it has made before showing the dialog.
Now using CocoaTouch I'm facing a problem. I replaced the code that shows the dialog with a UIActionSheet. Works great but code execution continues immediately, whereas in Windows Forms it is blocked (the next line in Windows Forms after showing the dialogs is to read the entered password from the dialog) until the dialog has been closed.
I tried a Thread.Sleep() until the user dismisses the UIActionSheet but the Thread.Sleep() also blocks the main loop and my view won't even be drawn.
The alternative I currently see is to change all methods in the already working class and give them a return value: if password required, handle it, then retry.
But this means that all over my code I will have to add these checks because at any given moment the password might be needed. That's why it is nested in communication class in Windows Forms.
Any other ideas?
René
Yes, it is possible.
To do this, what you can do is to run the mainloop manually. I have not managed to stop the mainloop directly, so I instead run the mainloop for 0.5 seconds and wait until the user responds.
The following function shows how you could implement a modal query with the above approach:
int WaitForClick ()
{
int clicked = -1;
var x = new UIAlertView ("Title", "Message", null, "Cancel", "OK", "Perhaps");
x.Show ();
bool done = false;
x.Clicked += (sender, buttonArgs) => {
Console.WriteLine ("User clicked on {0}", buttonArgs.ButtonIndex);
clicked = buttonArgs.ButtonIndex;
};
while (clicked == -1){
NSRunLoop.Current.RunUntil (NSDate.FromTimeIntervalSinceNow (0.5));
Console.WriteLine ("Waiting for another 0.5 seconds");
}
Console.WriteLine ("The user clicked {0}", clicked);
return clicked;
}
I think this approach using async/await is much better, and doesn't suffer from freezing the app when rotating the device, or when the autoscrolling interferes and leaves you stuck in the RunUntil loop forever without the ability to click a button (at least these problems are easy to reproduce on iOS7).
Modal UIAlertView
Task<int> ShowModalAletViewAsync (string title, string message, params string[] buttons)
{
var alertView = new UIAlertView (title, message, null, null, buttons);
alertView.Show ();
var tsc = new TaskCompletionSource<int> ();
alertView.Clicked += (sender, buttonArgs) => {
Console.WriteLine ("User clicked on {0}", buttonArgs.ButtonIndex);
tsc.TrySetResult(buttonArgs.ButtonIndex);
};
return tsc.Task;
}