0

I have a problem I'm trying to get a window's title by it's process name and I can't do it here s what I tried :

Process[] p = Process.GetProcessesByName("Acrobat");
Console.WriteLine(p[0].MainWindowTitle);
Console.ReadLine();

But the problem is that I can only get it only if the associated process does have a main window. How can I make it working ?

The main goal is that I've a method named BringToFront() But this method ask for a caption name which is "thenameofthePDF.pdf - Adobe Acrobat Pro (Yes, acrobat is running with an opened pdf) I would like to bring to front my Acrobat window.. but for this I need the name of the windows as my method is asking for the caption. Here is the entire code at the moment:

class Program
{
    [DllImport("User32.dll")]
    public static extern Int32 SetForegroundWindow(int hWnd);

    [DllImport("user32.dll")]
    public static extern int FindWindow(string lpClassName, string lpWindowName);

    private static void BringToFront(string className, string CaptionName)
    {
        SetForegroundWindow(FindWindow(className, CaptionName));
    }

    static void Main(string[] args)
    {
        // BringToFront("Acrobat", "mypdf.pdf - Adobe Acrobate Pro");
        Process[] p = Process.GetProcesses();
        foreach (var process in p)
        {
           Console.WriteLine(process.MainWindowTitle);
        }
        Console.ReadLine();
    }
}
Mehdy Amazigh
  • 31
  • 1
  • 6
  • You want to find the title of a window that doesn't exist? Have you thought, carefully, about what that even means? – Damien_The_Unbeliever May 15 '13 at 10:26
  • I don't really understand why it is not working, can a program have "subwindows" without having a "main" window ? Why it is not working I'm sure that acrobat is running, has a windows title and has a graphical interface. – Mehdy Amazigh May 15 '13 at 10:32
  • 1
    We may do better if we know your overall goal - I presume the ultimate goal isn't just to be able to dump Acrobat's Window title to the console - it sounds like this is part of a "solution" to a problem you haven't told us about - and you may not be solving it the right way. – Damien_The_Unbeliever May 15 '13 at 10:36
  • @Damien_The_Unbeliever You're right, I edited my question, sorry, hope this is clear now. – Mehdy Amazigh May 15 '13 at 10:48

3 Answers3

2

Did you read the manual, does the following apply?

A process has a main window associated with it only if the process has a graphical interface. If the associated process does not have a main window (so that MainWindowHandle is zero), MainWindowTitle is an empty string (""). If you have just started a process and want to use its main window title, consider using the WaitForInputIdle method to allow the process to finish starting, ensuring that the main window handle has been created. Otherwise, the system throws an exception.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
1

One possible solution is to enumerate all top-level windows and pick the one you are interested in. In your case this would be all windows with a class of AcrobatSDIWindow and a window title starting with your document name.

class Program
{
    public class SearchData
    {
        public string ClassName { get; set; }
        public string Title { get; set; }

        private readonly List<IntPtr> _result = new List<IntPtr>();
        public List<IntPtr> Result
        {
            get { return _result; }
        }
    }

    [DllImport("User32.dll")]
    public static extern Int32 SetForegroundWindow(IntPtr hWnd);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, ref SearchData data);

    private delegate bool EnumWindowsProc(IntPtr hWnd, ref SearchData data);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

    public static bool EnumProc(IntPtr hWnd, ref SearchData searchData)
    {
        var sbClassName = new StringBuilder(1024);
        GetClassName(hWnd, sbClassName, sbClassName.Capacity);
        if (searchData.ClassName == null || Regex.IsMatch(sbClassName.ToString(), searchData.ClassName))
        {
            var sbWindowText = new StringBuilder(1024);
            GetWindowText(hWnd, sbWindowText, sbWindowText.Capacity);
            if (searchData.Title == null || Regex.IsMatch(sbWindowText.ToString(), searchData.Title))
            {
                searchData.Result.Add(hWnd);
            }
        }
        return true;
    }

    static void Main(string[] args)
    {
        var searchData = new SearchData 
            { 
                ClassName = "AcrobatSDIWindow", 
                Title = "^My Document\\.pdf.*"
            };

        EnumWindows(EnumProc, ref searchData);

        var firstResult = searchData.Result.FirstOrDefault();
        if (firstResult != IntPtr.Zero)
        {
            SetForegroundWindow(firstResult);
        }
    }
}
Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
0

If you dump them all out using GetProcesses() it appears that the window title will have 'Adobe Reader', prefixed by the name of the PDF if one is open. So you might need to do that and walk the array instead.

For example if I have UserManual.pdf open and I run the code below it displays UserManual.pdf - Adobe Reader on the console:

        Process[] p = Process.GetProcesses();
        String Title = String.Empty;
        for (var i = 0; i < p.Length; i++)
        {
            Title = p[i].MainWindowTitle;

            if (Title.Contains(@"Adobe"))
                Console.WriteLine(Title);
        }
Alan B
  • 4,086
  • 24
  • 33
  • Yes the pdf is opened but this doesn't work I can only see "Acrobat". And within a foreach loop using MainWindowTitle property, I can't see the pdf name. – Mehdy Amazigh May 15 '13 at 10:49