通过名称/标题返回窗口句柄

19

我无法解决这个问题。 我收到了一个错误:

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

听起来很容易,实际上也确实如此...很抱歉问这么明显的问题。

这是我的代码:

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

我尝试了许多不同的方法,但每一种都失败了。 提前致谢。

7个回答

21

更新:查看Richard的答案,其中提供了一种更简洁的方法。

别忘了你在循环内部声明了hWnd,这意味着它只在循环内部可见。如果窗口标题不存在会发生什么?如果你想用for循环实现它,应该在循环外面声明它,在循环中设置它,然后返回它...

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

或者更符合LINQ的方式...
IntPtr? handle = Process
    .GetProcesses()
    .SingleOrDefault(x => x.MainWindowTitle.Contains(wName))
    ?.Handle;
return handle.HasValue ? handle.Value : IntPtr.Zero

我尝试在 foreach 之前声明它,但是在 return hWnd 行中出现了 Use of unassigned local variable 'hWnd',这就是我在这里询问的原因。 - VixinG
2
它不能为 null,因为它是一个非空值类型,所以无法将 null 转换为 'System.IntPtr'。 - VixinG
1
@VixinG 谢谢,发现得好 - 很明显我太晚了,喝了太多咖啡,没有 IDE 就无法编写代码 :) 已修复。 - Basic
1
你应该在 if 语句里添加一个 break,否则会浪费大量的处理器时间。 - AndresRohrAtlasInformatik
所以,我们可能要迭代所有活动进程。不确定这是否好。 - Ivan P.
显示剩余4条评论

9
作为解决此问题的一个选择:
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

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

1
一个比其他答案中使用 GetProcesses()MainWindowTitle(有时会失败)更好的解决方案。 - tigrou

7
几年后才来到这里,正如其他人所提到的,hWnd 的范围仅限于 foreach 循环中。
然而值得注意的是,假设您在函数中没有做任何其他事情,那么其他人提供的答案有两个问题:
1. 变量 hWnd 实际上是不必要的,因为它只用于一个目的(作为 return 的变量)。 2. foreach 循环效率低下,即使在找到匹配项之后,您仍然继续搜索其余进程。实际上,它将返回最后一个与之匹配的进程。
假设您不想匹配最后一个进程(点#2),那么这是一种更清洁和高效的函数:
public static IntPtr WinGetHandle(string wName)
{
    foreach (Process pList in Process.GetProcesses())
        if (pList.MainWindowTitle.Contains(wName))
            return pList.MainWindowHandle;

    return IntPtr.Zero;
}

4
因为你在 if 块内声明了 hWnd,所以它对于在外部的 return 语句是不可访问的。请参阅 http://www.blackwasp.co.uk/CSharpVariableScopes.aspx 进行澄清。
可以通过移动 hWnd 变量的声明来修复您提供的代码:
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;
}

1

一种允许您通过窗口标题的部分进行不区分大小写的搜索的方法(将搜索所有窗口,而不仅仅是每个进程的第一个窗口)。

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);

1

hWndforeach 循环中声明。 它的上下文是在 foreach 循环内部。要获取其值,请在 foreach 循环外部声明。

使用方法如下:

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;
}

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);
} 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接