{"id":1623,"date":"2014-03-03T07:00:00","date_gmt":"2014-03-03T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2014\/03\/03\/adventures-in-automation-dismissing-all-message-boxes-from-a-particular-application-but-only-if-they-say-that-the-operation-succeeded\/"},"modified":"2014-03-03T07:00:00","modified_gmt":"2014-03-03T07:00:00","slug":"adventures-in-automation-dismissing-all-message-boxes-from-a-particular-application-but-only-if-they-say-that-the-operation-succeeded","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20140303-00\/?p=1623","title":{"rendered":"Adventures in automation: Dismissing all message boxes from a particular application but only if they say that the operation succeeded"},"content":{"rendered":"<p>\nSuppose you have a program that is part of your workflow,\nand it has the annoying habit of showing a message box\nwhen it is finished.\nYou want to automate this workflow,\nand part of that automation is dismissing the message box.\n<\/p>\n<p>\nLet&#8217;s start by writing the annoying program:\n<\/p>\n<pre>\n#include &lt;windows.h&gt;\nint WINAPI WinMain(\n    HINSTANCE hinst, HINSTANCE hinstPrev,\n    LPSTR lpCmdLine, int nCmdShow)\n{\n  Sleep(5000);\n  MessageBox(nullptr, GetTickCount() % 1000 &lt; 800 ?\n             \"Succeeded!\" : \"Failed!\", \"Annoying\", MB_OK);\n  return 0;\n}\n<\/pre>\n<p>\nThis annoying program pretends to do work for a little while,\nand then displays a message box saying whether or not it succeeded.\n(Let&#8217;s say it succeeds 80% of the time.)\n<\/p>\n<p>\nOur Little Program will automate this task and respond based on\nwhether the operation succeeded.\nThis is just a small extension of our previous program which\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2014\/02\/24\/10502479.aspx\">\nlogs the contents of every message box<\/a>,\nexcept we are paying attention only to one specific message box.\n<\/p>\n<p>\nTo the rescue: UI Automation.\n<\/p>\n<pre>\nusing System.Windows.Automation;\nusing System.Diagnostics;\nusing System.Threading;\nclass Program\n{\n [System.STAThread]\n public static void Main(string[] args)\n {\n  int processId = 0;\n  bool succeeded = false;\n  var resultReady = new ManualResetEvent(false);\n  Automation.AddAutomationEventHandler(\n   WindowPattern.WindowOpenedEvent,\n   AutomationElement.RootElement,\n   TreeScope.Children,\n   (sender, e) =&gt;\n   {\n    var element = sender as AutomationElement;\n    if ((int)element.GetCurrentPropertyValue(\n             AutomationElement.ProcessIdProperty) != processId)\n    {\n     return;\n    }\n    var text = element.FindFirst(TreeScope.Children,\n      new PropertyCondition(AutomationElement.AutomationIdProperty,\n                            \"65535\"));\n    if (text != null &amp;&amp; text.Current.Name == \"Succeeded!\")\n    {\n     succeeded = true;\n     var okButton = element.FindFirst(TreeScope.Children,\n       new PropertyCondition(AutomationElement.AutomationIdProperty,\n                             \"2\"));\n     var invokePattern = okButton.GetCurrentPattern(\n       InvokePattern.Pattern) as InvokePattern;\n     invokePattern.Invoke();\n    }\n    resultReady.Set();\n   });\n  \/\/ Start the annoying process\n  Process p = Process.Start(\"annoying.exe\");\n  processId = p.Id;\n  \/\/ Wait for the result\n  resultReady.WaitOne();\n  if (succeeded)\n  {\n   Process.Start(\"calc.exe\");\n  }\n  Automation.RemoveAllEventHandlers();\n }\n}\n<\/pre>\n<p>\nMost of this program you&#8217;ve seen before.\n<\/p>\n<p>\nWe register an automation event handler for new window\ncreation that ignores windows that belong to processes\nwe don&#8217;t care about.\nThat keeps us from being faked out by windows that happen\nto be created while our annoying task is running.\n<\/p>\n<p>\nFor simplicity&#8217;s sake, I&#8217;ve removed other sanity checks\nwhich verify that the window which appeared is the one\nwe actually care about.\nIn real life, we might check the window class or the window title.\nI left that out because it&#8217;s not really relevant to the story.\n<\/p>\n<p>\nOnce we think we have the window we want,\nwe suck out the text so we can see whether the message was\na success or failure message.\nIf it was a success,\nwe dismiss the dialog box by pushing the OK button;\notherwise we leave the error message on the screen so the\nuser can see what happened.\nEither way,\nwe signal the main thread that we have a result.\n<\/p>\n<p>\nAfter registering the event handler, we run the annoying process,\ntell the event handler the process ID,\nand wait for the signal.\nOnce the signal arrives,\nwe see whether it declared the operation a success,\nand if so, we\nproceed to the next step of, um, say,\nlaunching the calculator.\n(I just picked something arbitrary.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Suppose you have a program that is part of your workflow, and it has the annoying habit of showing a message box when it is finished. You want to automate this workflow, and part of that automation is dismissing the message box. Let&#8217;s start by writing the annoying program: #include &lt;windows.h&gt; int WINAPI WinMain( HINSTANCE [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-1623","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Suppose you have a program that is part of your workflow, and it has the annoying habit of showing a message box when it is finished. You want to automate this workflow, and part of that automation is dismissing the message box. Let&#8217;s start by writing the annoying program: #include &lt;windows.h&gt; int WINAPI WinMain( HINSTANCE [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/1623","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=1623"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/1623\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=1623"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=1623"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=1623"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}