Hello, I am trying to write a program which executes another program (3rd party) to do some processing and I need to capture if this program has errored. The program does not appear to write the errors to the Event Viewer, which is how I was intending to catch these occurences.
If the program errors it displays a message/error box. Is there a way of retrieving the number of Windows a program has attached to it. The thought I have had is to get this window count on startup and then monitor the count until the program is complete.
Any help much obliged.
AlanPosted Nov 7, 2008, 2:50 PM
I was thinking that all you needed to do here was to get the main window handle of the 3rd party application using the Process class and then use FindWindowEx to look for a child window with the standard windows messagebox class name ("#32770") and the caption if you know what it'll be.
However, when I tried to detect the appearance of a MessageBox in a simple .NET application, I found that messagebox was always a top level window even if you specified the IWin32Window parameter. So, in other words, you need to pass IntPtr.Zero as the first argument of FindWindowEx or just use FindWindow instead.
FWIW, here's the very simple and 'rough and ready' code I wrote to test this:
// showbox.cs
using System;
using System.Windows.Forms;
class Program
{
static void Main()
{
Application.Run(new ShowBox());
}
}
class ShowBox : Form
{
private Button btn;
public ShowBox()
{
btn = new Button();
btn.Text = "Press me";
btn.Click += new EventHandler(button_Click);
this.Controls.Add(btn);
}
private void button_Click(object sender, EventArgs e)
{
MessageBox.Show(this, "Hello from Show Box", "Greeting");
}
}
// capturebox.cs
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
class CaptureBox
{
[DllImport("user32.dll")]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
static IntPtr hwndParent;
static void Main()
{
Process[] procs = Process.GetProcessesByName("showbox");
if (procs.Length == 0)
{
Console.WriteLine("Showbox isn't running");
return;
}
hwndParent = procs[0].MainWindowHandle;
bool hasAppeared = false;
do
{
if (!procs[0].HasExited)
{
hasAppeared = CheckMessageBox();
Thread.Sleep(1000); // check every second
}
else
{
Console.WriteLine("Showbox has exited");
break;
}
}
while(!hasAppeared);
}
static bool CheckMessageBox()
{
// IntPtr hwndMB = FindWindowEx(hwndParent, IntPtr.Zero, "#32770", "Greeting");
// Apparently MessageBox is always top level in .NET
IntPtr hwndMB = FindWindowEx(IntPtr.Zero, IntPtr.Zero, "#32770", "Greeting");
if (hwndMB == IntPtr.Zero)
{
Console.WriteLine("MessageBox not showing");
return false;
}
else
{
Console.WriteLine("MessageBox has appeared");
return true;
}
}
}
If the 3rd party application is unmanaged, I think you'll just have to experiment to see whether you need to specify the main window handle or not.
One other thing you'll need to watch out for is that (I think) the "#32770" windows class name is used for any dialog, not just MessageBox, so you really need to specify the caption as well to ensure you don't get a mistaken notification, particularly if other applications could be running.