I have a program that sends information in the background using Outlook. I want to avoid having the user deal with the "Outbox is not empty" message that appears when a user tries to close Outlook when an email is in the outbox. because in most cases the email in the outbox will not be an email they sent themselves. I am able to get a handle to the dialog, but I don't know which command to send to make it close. The only close command I know about will not work for a dialog box.
I must use Outlook to send the email due to security constraints.
I got the code from here which shows you how to trap the window events and sort through the window you want. I have found the window, and it helped me to stop the threads that might be sending email, but the dialog is still hanging there when I'm done.
The following code executes whenever an Explorer window is deactivated (i.e. loses focus)
void ExplorerWrapper_Deactivate()
{
IntPtr hBuiltInDialog = WinApiProvider.FindWindow("#32770", "Microsoft Office Outlook");
if (hBuiltInDialog != IntPtr.Zero)
{
// ok, found one
// let's see what childwindows are there
List<IntPtr> childWindows = WinApiProvider.EnumChildWindows(hBuiltInDialog);
// Let's get a list of captions for the child windows
List<string> childWindowNames = WinApiProvider.GetWindowNames(childWindows);
// now check some criteria to identify the build in dialog..
// here are the three child window names as cut and pasted from the code when debugging
// [0] = "There are unsent messages in your Outbox. To send messages, Outlook must remain running and connected to your e-mail server. Do you want to exit anyway?\r\n\r\nExiting in <0d> seconds"
// [1] = "Exit Without Sending"
// [2] = "Don't Exit"
if ((childWindowNames.Contains("There are unsent messages in your Outbox. To send messages, Outlook must remain running and connected to your e-mail server. Do you want to exit anyway?\r\n\r\nExiting in <0d> seconds")) &&
(childWindowNames.Contains("Exit Without Sending")) &&
(childWindowNames.Contains("Don't Exit")))
{
// at this point, we need to empty the outbox of any IkeNet email, and if the outbox is then empty, close the dialog
// and let outlook close as well
NotifyAdmin.SetShutdownRequested();
/// this close command does not seem to work for this window. supposedly it acts just like pressing
/// the <esc> key, which does nothing to the window when the program is running.
WinApiProvider.SendMessage(hBuiltInDialog,
WinApiProvider.WM_SYSCOMMAND, WinApiProvider.SC_CLOSE, 0);
}
}
}
The WinApiProvider.SC_CLOSE command will not work for this kind of window.
Any suggestions will be appreciated.
You could try using SendKeys to [tab][tab][enter] (or whatever the keystrokes are). I know it's not an elegant solution, but is this solution really elegant to begin with?
I would try sending a mouse click event to the Cancel button (or Close button -- I'm not familiar with the dialog box in question).
Related
I writing an application in C# in Visual Studio 2017. I'm using Windows Forms App (.NET Framework). I have a MessageBox pop up with its default settings (only the OK button and the X in the top right corner). When the user selects "OK" the remaining code resumes. I want to write separate code to run when the user selects the X to close the message box. How can I tell if the user has clicked the X to close the message box?
I have tried using
DialogResult result = MessageBox.Show("Message here");
if(result != DialogResult.OK){
//Do stuff here
}
but even when the X is pressed, result still comes back as Dialog.OK.
What should I do?
Update
This code works fine
DialogResult result = MessageBox.Show("Message here", "MessageBoxTitle", MessageBoxButtons.OKCancel);
if(result != DialogResult.OK){
//Do stuff here
}
However, my message box now has an unnecessary Cancel button. Is there a way to achieve this with just the MessageBoxButtons.OK setting so that I avoid having the Cancel button?
This is a limitation of the underlying Win32 MessageBox API.
The API does not provide a way to specify how the Close box works separately. Clicking the Close box (or pressing Escape) always returns the ID of the Cancel button if there is one, or the default button if there isn't.
And unfortunately, no, you can't try to cheat by setting the default button to a nonexistent button -- if you do that, the default will be reset to one of the existing buttons.
So if you want to handle the Close box in a more sophisticated way than that, you'll have to create your own dialog box rather than letting ::MessageBox do it for you.
In addition to the answer about Windows API.
System.Windows.Forms.MessageBox.Show("Message") internally calls private method System.Windows.Forms.ShowCore(...).
Method .Show(text) is defined in that way:
/// <summary>
/// Displays a message box with specified text.
/// </summary>
public static DialogResult Show(string text)
{
return ShowCore(null, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1, 0, false);
}
It means that .Show(text) is just a shorthand version of full method call. Therefore, you can achieve only those results that could be achieved by calling the actual .ShowCore(...) method.
I have an issue with a MMC snapin developed using C#. Using the code from Microsoft's MMC sample for an snapin using a property page I have noticed a DisconnectedContext error popping up after displaying a modal messagebox from a property page.
I can reproduce this every time, and I can "fix" it with a bit of a hack.
using the sample code for CanApplyChanges() in the property page's user control, I display a messagebox if there is a validation error:
public bool CanApplyChanges()
{
if (this.password.Text != this.passwordConfirm.Text)
{
MessageBoxParameters mbp = new MessageBoxParameters();
mbp.Text = "Passwords do not match";
userPropertyPage.ParentSheet.ShowDialog(mbp);
}
}
Commenting out this messagebox stops the error. I can change this to display the messagebox parented to the MMC console instead, so (I assume) it doesn't block the property page message pump, but obviously this allows the user to continue interacting with the page which is not the best UI.
Has anyone else seen this problem - I open the property page, cancel it, open it again, make it pop the modal messagebox (using the recommended way of displaying them) when you click the Apply button, then click cancel and re-open the page - I always get the DisconnectedContext error.
I don't do anything fancy in the constructor or RefreshData() methods of my control - I fetch simple data from an EntityFramework object and place it in a few textbox and checkbox controls.
Obviously there is a problem with the thread that show the property sheet interacting badly with the rest of the snapin, but I have no threads of my own, and there is no interaction between my control and the only place I interact with the parent property sheet is to call that ShowDialog method.
Any ideas will be welcomed at this point, as would any information leading to a successful apprehension of the bug!
I have created a task managment application and I wanted to implement the ability for 2-users to chat about specific task.
In Form1 I have a timer that check on the database for any new message sent. When a new message found, the chat form appear showing the message.
Till now, everything is working as expected but I have only one problem.
The problem :
Once a new message found for the first time, the chat window appear, but when another new message is found, another window appear, and for each new message I have a new instance of the chat window created.
The code I'm using :
List<string> tasksToDiscuss = checkForTasksToDiscuss(fullname);
if (tasksToDiscuss.Count > 0) {
// open the chat window directly minimized
Form14 frm14 = new Form14();
frm14.get_from = fullname;
frm14.get_to = tasksToDiscuss[1];
frm14.get_task_id = int.Parse(tasksToDiscuss[3]);
// set message as read
if (setMessageAsRead(tasksToDiscuss[1], fullname, int.Parse(tasksToDiscuss[3])))
{
// now show the chat window minimized
frm14.Show();
}
}
I tried to replace the line: frm14.Show(); with frm14.ShowDialog();
I noticed that when the new message is received, the chat window (form14) is shown, and when another message is received from the same user, no new chat window appear, but the problem is that after i close the chat window, it doesn't appear anymore even when i receive new messages.
What I think to do is to change the chat window (Form14.Text) to the user fullname, and the next time a message is received, I check whether the specific window is already open, then don't open it otherwise i show the form using the .Show() method.
Is this the proper way to make the window doesn't appear if a new message is received and it is aloready opened ? and How to check wether a window is opened according to it's Text (title bar text) ?
Thank's for taking time reading my question. Any help would be highly appreciated
Firstly you are creating a new instance of Form14 every time you have a new message.
Secondly Show and ShowDialog do two very different things:
Show just displays the form, whereas ShowDialog displays the form as a modal dialog. This means the user can't do anything else until they dismiss the form.
You need to have a single instance of the form and you can use the Visible property to determine whether it's shown or not. So you would have:
private Form14 frm14;
Then in the constructor:
frm14 = new Form14();
Then in your code:
if (!frm14.Visible)
{
// Add the message
frm14.Show();
} else{
// Top
frm14.BringToFront();
}
Try making form14 a member of form1.
When you get a new message check the Visible property of forom14
to know if it is already showing.
I'm trying to write a program with C# that sends text into other windows.
How do I write a command in C# that sends a text into the window that is currently under the users focus?
For example:
If the user clicks an open notepad window, or an open outlook letter, or an open excel sheet, and then clicks the button on my program, a text will be "pasted" directly into the last notepad window/outlook letter/excel cell that the user clicked on last.
I hope my question is clear enough. I'm not so experienced and am missing a lot of terminology.
Take your application out of focus by minimizing or hiding the main window, and then send your text with
SendKeys.SendWait("Hello World!");
Finally, restore your main window.
If the code is executed in the main form, you could do this
this.Visible = false;
SendKeys.SendWait("Hello World!");
this.Visible = true;
Olivier's response actually seems more accurate (and taught me something :)) than my original "does not seem achievable". If you need an example, then take a look at this:
http://www.codeproject.com/Articles/18366/Sending-Keystrokes-to-another-Application-in-C
However, on a more complex level, without an API to call into, there is not much more that you can do beyond this solution.
How do I read a message of standard Win message box (Info)?
Using
SendMessage(this.HandleControl, WM_GETTEXT, builder.Capacity, builder);
I can only read the header of the message box or the text of the button, but not the message itself.
thanks.
Notes (from Q&A):
this.HandleControl is a handler to the message box window
Spy++ shows no child controls bar the button. That's what it made me thinking that Message Boxes have their own way of keeping text w/out using labels
It's a legacy app written with delphi, the button's class is TButton as per Spy++, but still there's no controls except of button inside the dialog window.
After checking a notepad window, both Image & Text are 'selectable', I guess my app doesn't use a std MessageBox. still, how do I go about extracting the text out of the thing? I can see that no labels in my delphi app can be selected by Spy++ Finder tool.
The message text is in a label control on the modal MessageBox dialog window. You have to get the window handle to the MessageBox dialog (win32 API FindWindow) then retrieve the window handle to the control (win32 API GetDlgItem) and then retrieve the text from that window win32 API GetWindowText).
EDIT --
TCHAR text[51] = {0};
HWND msgBox = ::FindWindow(NULL, TEXT("MessageBoxCaption"));
HWND label = ::GetDlgItem(msgBox, 0xFFFF);
::GetWindowText(label, text, sizeof(text)-1);
Try simulating a copy operation (Ctrl-C), then fetch the text from the clipboard: messageboxes allow copying the whole content that way (if they're properly done).
The OP commented that: that worked, thanks. I might end up with doing it that way. Ideally we wanted to keep our implementation focus independant, but choosing between a dedicated PC and OCR I'd probably go the first route.
Personally I've tested this in Delphi 6 and it comes out looking like this:
---------------------------
Confirm
---------------------------
You are about to close the program
WARNING: Are you sure?
---------------------------
Yes No
---------------------------
Note: This is based on an answer that was proposed by "Stefan" in the comments to the original Question