19

I can't solve this problem. I get an error:

The name 'hWnd' does not exist in the current context

It sounds very easy and probably is... sorry for asking so obvious questions.

Here's my code:

public static IntPtr WinGetHandle(string wName)
{
    foreach (Process pList in Process.GetProcesses())
    {
        if (pList.MainWindowTitle.Contains(wName))
        {
            IntPtr hWnd = pList.MainWindowHandle;
        }
    }
    return hWnd;
}

I tried with many different ways and each fails. Thanks in advance.

Patrick
  • 674
  • 1
  • 8
  • 22
VixinG
  • 1,387
  • 1
  • 17
  • 31

7 Answers7

20

Update: See Richard's Answer for a more elegant approach.

Don't forget you're declaring you hWnd inside the loop - which means it's only visible inside the loop. What happens if the window title doesn't exist? If you want to do it with a for you should declare it outside your loop, set it inside the loop then return it...

IntPtr hWnd = IntPtr.Zero;
foreach (Process pList in Process.GetProcesses())
{
    if (pList.MainWindowTitle.Contains(wName))
    {
        hWnd = pList.MainWindowHandle;
    }
}
return hWnd; //Should contain the handle but may be zero if the title doesn't match

Or in a more LINQ-y way....

IntPtr? handle = Process
    .GetProcesses()
    .SingleOrDefault(x => x.MainWindowTitle.Contains(wName))
    ?.Handle;
return handle.HasValue ? handle.Value : IntPtr.Zero
Basic
  • 26,321
  • 24
  • 115
  • 201
  • I tried declaring it before **foreach** and I got `Use of unassigned local variable 'hWnd'` in `return hWnd` line, that's why I asked here. – VixinG Nov 25 '12 at 02:13
  • Then you should initialise it to `IntPtr.Zero` (see my edit). This is because the window title isn't being matched - so you're never setting the variable which points to an area of memory with undefined contents. – Basic Nov 25 '12 at 02:14
  • I see, it should be `IntPtr hwnd = IntPtr.Zero;` :) – VixinG Nov 25 '12 at 02:14
  • That's just a warning in the event that you never assign the variable. You can suppress it in the compiler options, ignore it, or assign it a default value IntPtr.Zero – pinkfloydx33 Nov 25 '12 at 02:15
  • 2
    It can't be null, because of `Cannot convert null to 'System.IntPtr' because it is a non-nullable value type` – VixinG Nov 25 '12 at 02:15
  • 1
    @VixinG Thanks, nice catch - clearly it's too late and I've had too much coffee to type code without an IDE :) Fixed – Basic Nov 25 '12 at 02:15
  • http://msdn.microsoft.com/en-us/library/system.intptr.zero.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1 IntPtr.Zero != null – pinkfloydx33 Nov 25 '12 at 02:17
  • 1
    You should add a break inside the if or you will waste a lot of processor time. – AndresRohrAtlasInformatik Mar 25 '18 at 10:20
  • So, we are potentially about to iterate over all the active processes. Not sure if it's good – Ivan P. Dec 20 '20 at 12:58
9

As an option to solve this problem:

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

public IntPtr GetHandleWindow(string title)
{
    return FindWindow(null, title);
} 
Wizard
  • 153
  • 1
  • 6
  • 1
    A much better solution that what is suggested by others answers with `GetProcesses()` and `MainWindowTitle` (which sometimes fails). – tigrou Dec 03 '21 at 12:10
7

Coming several years late to this but, as others have mentioned, the scope of hWnd is only in the foreach loop.

However it's worth noting that, assuming you're doing nothing else with the function, there are two issues with the answers others have provided:

  1. The variable hWnd is actually unnecessary since it's only being used for one thing (as the variable for the return)
  2. The foreach loop is inefficient as, even after you've found a match, you continue to search the rest of the processes. In actual fact, it'll return the last process it finds that matches.

Assuming that you don't want to match the last process (point #2), then this is a cleaner and more efficient function:

public static IntPtr WinGetHandle(string wName)
{
    foreach (Process pList in Process.GetProcesses())
        if (pList.MainWindowTitle.Contains(wName))
            return pList.MainWindowHandle;

    return IntPtr.Zero;
}
Richard
  • 1,471
  • 7
  • 23
  • 47
4

Because you are declaring hWnd inside the if block, it is inaccessible to the return statement which is outside it. See http://www.blackwasp.co.uk/CSharpVariableScopes.aspx for clarification.

The code you've provided can be fixed by moving the declaration of the hWnd variable:

public static IntPtr GetWindowHandleByTitle(string wName)
{
    IntPtr hWnd = IntPtr.Zero;
    foreach (Process pList in Process.GetProcesses())
    {
        if (pList.MainWindowTitle.Contains(wName))
        {
            hWnd = pList.MainWindowHandle;
        }
    }
    return hWnd;
}
Mukesh Methaniya
  • 752
  • 1
  • 5
  • 13
Mitch
  • 21,223
  • 6
  • 63
  • 86
1

hWnd is declared in the foreach loop. Its context is inside foeach loop. To get its value declare it outside foreach loop.

Use it like this,

public static IntPtr WinGetHandle(string wName){
    IntPtr hWnd = NULL;

    foreach (Process pList in Process.GetProcesses())
        if (pList.MainWindowTitle.Contains(wName))
            hWnd = pList.MainWindowHandle;

    return hWnd;
}
Shiplu Mokaddim
  • 56,364
  • 17
  • 141
  • 187
1

For a method that allows you to search, case insensitive, by part of the window title (that will search all windows, not just the first window for each process)

using System.Runtime.InteropServices;
using System.Text;

var hwnd = GetHandleByTitle("Chrome");
Console.WriteLine(hwnd);

[DllImport("USER32.DLL")]
static extern IntPtr GetShellWindow();

[DllImport("USER32.DLL")]
static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam);

[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);

static IntPtr GetHandleByTitle(string windowTitle)
{
    const int nChars = 256;

    IntPtr shellWindow = GetShellWindow();
    IntPtr found = IntPtr.Zero;

    EnumWindows(
        delegate (IntPtr hWnd, int lParam)
        {
                    //ignore shell window
                    if (hWnd == shellWindow) return true;

                    //get Window Title
                    StringBuilder Buff = new StringBuilder(nChars);

            if (GetWindowText(hWnd, Buff, nChars) > 0)
            {
                        //Case insensitive match
                        if (Buff.ToString().Contains(windowTitle, StringComparison.InvariantCultureIgnoreCase))
                {
                    found = hWnd;
                    return true;
                }
            }
            return true;

        }, 0
    );

    return found;
}

delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);
Daniel Barnes
  • 163
  • 2
  • 9
0
#include <windows.h>
#using <System.dll>

using namespace System;
using namespace System::Diagnostics;
using namespace System::ComponentModel;

// get window handle from part of window title
public static IntPtr WinGetHandle(string wName)
{
    IntPtr hwnd = IntPtr.Zero;
    foreach (Process pList in Process.GetProcesses())
    {
        if (pList.MainWindowTitle.Contains(wName))
        {
            hWnd = pList.MainWindowHandle;
            return hWnd;
        }
    }
    return hWnd;
}

// get window handle from exact window title
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

public IntPtr GetHandleWindow(string title)
{
    return FindWindow(null, title);
}