Click here to Skip to main content
15,891,253 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Hi everybody,

After long researches I want to submit you my problem...

I want to read the text of a MessageBox (or pop-up) window from an other program but the thing is, this MessageBox is not a child of his main program so i can't access to it...

this is what I tried without success...

C#
hwndChild = FindWindowEx(hwnd, IntPtr.Zero, null, null);
                while (hwndChild != IntPtr.Zero)
                {
                    GetWindowText(hwndChild, bld, 255);
                    Console.WriteLine(bld.ToString());
                    //SendMessage(hwndChild, WM_SYSCOMMAND, SC_CLOSE, 0);
                    hwndChild = FindWindowEx(hwnd, hwndChild, null, null);
                }



OR

C#
hwndChild = FindWindowEx(hwnd, IntPtr.Zero, null, null);
                while (hwndChild != IntPtr.Zero)
                {
                    IntPtr lgTexte = SendMessage(hwndChild, WM_GETTEXTLENGTH, 0, 0);
                    #if STRING
                    string sbTitre = new string('0',lgTexte);
                    #else
                    StringBuilder sbTitre = new StringBuilder((int)lgTexte);
                    #endif
                    GetControlText((int)hwndChild, WM_GETTEXT, (int)lgTexte + 1, sbTitre);
                    Console.WriteLine("hwnd={0} => {1}", hwndChild, sbTitre);
                    hwndChild = FindWindowEx(hwnd, hwndChild, null, null);
                }
Posted

Let me tell you that you are doing a bad business. Applications are isolated one from another and are not designed to do such tricks. Technically, its quite possible, but why doing it? The results cannot be reliable; a tiny change in the application implementation will ruin your tricky work. And the results will always be ugly.

If you doing it all only for some investigation, I can understand it.

There is no such thing as a window which is a child or a "program". You can find everything starting from the process. Let's assume that you found a process from a list of processes (unreliable, because you can only identify it by known name, but nothing can guarantee you that this name is unique) or got it from the System.Diagnostics.Process.Start:
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx[^] (see GetProcesses),
http://msdn.microsoft.com/en-us/library/e8zac0ca.aspx[^].

First, you can find main window, if it is available. You should understand that this call can throw an exception:
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.mainwindowhandle.aspx[^].

Now, the tricky part: the process shows a modal window. You need to use P/Invoke for such a tricky method as
GetLastActivePopup: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633507%28v=vs.85%29.aspx[^].

I assumed that the dialog's parent is the main window of the application; you should use its handle as a parameter. This covers most cases, but the parent window can be some other one. In this case, you will need to walk through the hierarchy of the application windows starting from main:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633514%28v=vs.85%29.aspx[^],
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633515%28v=vs.85%29.aspx[^] (use GW_CHILD).

—SA
 
Share this answer
 
Hi, thanks for your answer

Well i'm doing this because I want to "supervise" a "program" which doesn't return any error codes, and only display a messageBox (it was desgin to be an API). I want to get this error message cause I want to report it (e.g. by email)
I can automatically click "Ok" on this messageBox, but I will not be aware about the error...

Thank you for your tips I will take a look

AP
 
Share this answer
 
Ok. there exists a way to get what you expected to get. try this method it works for me.

1. First Find your window using class name or title (i used messagebox title in my test)
2. For Finding your window pass set ParentHandle and ChildHandle both to Null(IntPtr.Zero) so it uses desktopwindow as the parent window and search through all the opened windows.
3. on getting the windowHandle from step 2 Enumerate through its child windows
4. Use the combination of GetWindowTextLength and GetWindowText to get your text.

sample code
C#
//include these dll imports as first step in your class and call as explained below
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);

[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern int GetWindowText(IntPtr hWnd, [Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpString, int nMaxCount);

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool IsChild(IntPtr hWndParent, IntPtr hwnd);

private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetWindowTextLength(IntPtr hWnd);

Method definitions
public static List<intptr> GetChildWindows(IntPtr parent)
{
   List<intptr> result = new List<intptr>();
   GCHandle listHandle = GCHandle.Alloc(result);
   try
   {
       EnumWindowsProc childProc = new EnumWindowsProc(EnumWindow);
       EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
   }
   finally
   {
      if (listHandle.IsAllocated)
         listHandle.Free();
     }
      return result;
}

private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
   GCHandle gch = GCHandle.FromIntPtr(pointer);
   List<intptr> list = gch.Target as List<intptr>;
   if (list == null)
   {
       throw new InvalidCastException("GCHandle Target could not be cast as List<intptr>;");
     }
    list.Add(handle);
    // You can modify this to check to see if you want to cancel the operation, then return a null here
    return true;
}

private void button1_Click(object sender, EventArgs e)
{
  IntPtr windowHandle = FindWindowEx(IntPtr.Zero, IntPtr.Zero, null, "Save As");  // My Message box has caption "Save As" you may change this as per your requirement

  List<intptr> childs =  GetChildWindows(windowHandle);

  foreach (IntPtr child in childs)
  {
     bool isChild = IsChild(windowHandle, child);

     int length = GetWindowTextLength(child);
     StringBuilder bb = new StringBuilder(length+1);

     GetWindowText(child, bb, bb.Capacity);
   }

}</intptr></intptr></intptr></intptr></intptr></intptr></intptr>
 
Share this answer
 
Thank you very much SA,

The function GetLastActivePopup is perfect for my application. It is working !!

AP
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900