1

I'm working on an application that scans my active processes, and after selection, passes key commands to that process. The problem I'm having is that not all my processes seem to have a MainWindowTitle. Below is the code snippit where I immediately recognized this problem:

Dictionary<int, string> procInfo = new Dictionary<int, string>();
Process[] processes = Process.GetProcesses();
foreach (Process procData in processes)
{
    if (procData.MainWindowTitle.Length > 0)// || procData.ProcessName == "notepad++")
    {
        procInfo.Add(procData.Id, procData.ProcessName);
    }
}

foreach (KeyValuePair<int, string> proc in procInfo)
{
    lstProcesses.Items.Add(proc.Value + " (" + proc.Key.ToString() + ")");
}

If you look at line 5, you'll see where I was forcing Notepad++ into the list to test against my results from WinSpy++ (alternative to Spy++) and without the force it refuses to display as it's MainWindowTitle property is blank.

Without the MainWindowTitle I can't get the class name for the application:

//procID set earlier and shown to be working
Process proc = Process.GetProcessById(procID);
string winTitle = proc.MainWindowTitle;

IntPtr hWnd = proc.MainWindowHandle;
StringBuilder buffer = new StringBuilder(1024);
GetClassName(hWnd, buffer, buffer.Capacity);
string winCaption = buffer.ToString();

And thus I can't target the application to pass in key commands:

//winCaption currently blank, winTitle tested and working
IntPtr appHandler = FindWindow(winCaption, winTitle);
SetForegroundWindow(appHandler);
SendKeys.SendWait("things and junk");

I have the proper DllImports setup for my project so the problem isn't there and I haven't found an answer here or anything reliable cruising the rest of the interwebs. Am I missing something in my code, or is this just bad and should I feel bad?

the_pete
  • 822
  • 7
  • 19
  • possible duplicate of [Why is Process.MainWindowTitle always empty for all but one window?](http://stackoverflow.com/questions/10063847/why-is-process-mainwindowtitle-always-empty-for-all-but-one-window) – MethodMan Nov 24 '14 at 20:40
  • I found that answer and while this is similar, my issue is spread throughout all of my processes, not just IE. – the_pete Nov 24 '14 at 21:10

1 Answers1

1

I had to completely scrap the options above in favor of a P/Invoke solution: http://pinvoke.net/default.aspx/user32.EnumDesktopWindows

Taking advantage of GetWindowText, GetWindowThreadProcessID and GetClassName in a new function:

//the following was jacked from: http://pinvoke.net/default.aspx/user32.EnumDesktopWindows
var procCollection = new List<string>();
//Dictionary<string, int> procCollection = new Dictionary<string, int>();
EnumDelegate filter = delegate(IntPtr hWnd, int lParam)
{
    //return window titles
    StringBuilder strbTitle = new StringBuilder(255);
    int nLength = GetWindowText(hWnd, strbTitle, strbTitle.Capacity + 1);
    string winTitle = strbTitle.ToString();

    //return thread process id
    uint getID = 0;
    GetWindowThreadProcessId(hWnd, ref getID);
    int winID = Convert.ToInt32(getID);

    //return class names
    StringBuilder strbClass = new StringBuilder(255);
    GetClassName(hWnd, strbClass, strbClass.Capacity+1);
    string winClass = strbClass.ToString();

    if (IsWindowVisible(hWnd) && string.IsNullOrEmpty(winTitle) == false)
    {
        procCollection.Add(winTitle+" -- "+winID+" -- "+winClass);
    }
    return true;
};

if (EnumDesktopWindows(IntPtr.Zero, filter, IntPtr.Zero))
{
    //foreach (KeyValuePair<string, int> procInfo in procCollection)
    foreach(string procData in procCollection)
    {
        //if (procInfo.Key != "Start" && procInfo.Key != "Program Manager")
        if (procData.Contains("Start") == false && procData.Contains("Program Manager") == false)
        {
            lstProcesses.Items.Add(procData);
        }
    }
}

Allows me to get everything I need to build my list of open Windows. This doesn't give me the list of processes like WinSpy++ (Spy++), but it's exactly what I need.

the_pete
  • 822
  • 7
  • 19