【问题标题】:C# Get Path/Filename by Handle (hWnd) 32 and 64bitC# 通过句柄 (hWnd) 32 和 64 位获取路径/文件名
【发布时间】:2011-06-13 17:05:22
【问题描述】:

我得到以下代码来通过句柄获取路径/文件名:

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern int GetWindowThreadProcessId(IntPtr handle, out uint processId);

    public static string GetProcessPath(IntPtr hwnd)
    {
        uint pid = 0;
        GetWindowThreadProcessId(hwnd, out pid);
        Process proc = Process.GetProcessById((int)pid);
        return proc.MainModule.FileName.ToString();
    }

它在 32 位中完美运行,但在 64 位中出现错误 >“只有部分 ReadProcessMemory 或 WriteProcessMemory 请求已完成。” 项目编译为 x86(平台目标 x86)。

我该如何解决?

~谢谢罗恩

【问题讨论】:

  • 嗯...错误在哪一行?
  • return proc.MainModule.FileName.ToString();
  • 尝试以管理员身份运行您的程序。
  • @Darin Dimitrov,我已经以管理员身份运行它。这不是问题。 @Cody Gray,我不知道。我没有构建此功能,但即使我将其更改为 IntPtr 它也不起作用。 [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr GetWindowThreadProcessId(IntPtr handle, out IntPtr processId);公共静态字符串 GetProcessPath(IntPtr hwnd) { IntPtr pid = IntPtr.Zero; GetWindowThreadProcessId(hwnd, out pid);进程 proc = Process.GetProcessById(pid.ToInt32());返回 proc.MainModule.FileName.ToString(); }

标签: c# .net path 64-bit filenames


【解决方案1】:

在检查 64 位进程时,这完全可以在 32 位应用程序中实现,尽管不像 64 位编译应用程序那样简单:

    [Flags]
    enum ProcessAccessFlags : uint
    {
        All = 0x001F0FFF,
        Terminate = 0x00000001,
        CreateThread = 0x00000002,
        VMOperation = 0x00000008,
        VMRead = 0x00000010,
        VMWrite = 0x00000020,
        DupHandle = 0x00000040,
        SetInformation = 0x00000200,
        QueryInformation = 0x00000400,
        Synchronize = 0x00100000,
        ReadControl = 0x00020000,
        PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
    }

    [DllImport("kernel32.dll")]
    private static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId);

    [DllImport("kernel32.dll")]
    private static extern bool QueryFullProcessImageName(IntPtr hprocess, int dwFlags, StringBuilder lpExeName, out int size);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool CloseHandle(IntPtr hHandle);

    private static Process GetProcessByHandle(IntPtr hwnd)
    {
        try
        {
            uint processID;
            GetWindowThreadProcessId(hwnd, out processID);
            return Process.GetProcessById((int)processID);
        }
        catch { return null; }
    }

    private static string GetExecutablePathAboveVista(int ProcessId)
    {
        var buffer = new StringBuilder(1024);
        IntPtr hprocess = OpenProcess(ProcessAccessFlags.PROCESS_QUERY_LIMITED_INFORMATION,
                                      false, ProcessId);
        if (hprocess != IntPtr.Zero)
        {
            try
            {
                int size = buffer.Capacity;
                if (QueryFullProcessImageName(hprocess, 0, buffer, out size))
                {
                    return buffer.ToString();
                }
            }
            finally
            {
                CloseHandle(hprocess);
            }
        }
        return null;
    }

    private static string GetWindowPath(IntPtr hwind)
    {
        try
        {
            Process currentProcess = GetProcessByHandle(hwind);

            if (Environment.OSVersion.Version.Major >= 6)
            {
                string newMethReturn = GetExecutablePathAboveVista(currentProcess.Id);
                if (!string.IsNullOrWhiteSpace(newMethReturn))
                    return newMethReturn;
            }


            if (currentProcess != null)

                return currentProcess.MainModule.FileName;
            else
                return null;
        }
        catch
        { return null; }
    }

【讨论】:

  • 晚了 3 年,但想说谢谢,一直很难找到优雅地停止我正在包装的进程的方法,这被证明是拼图的最后一块我需要一种方法来区分具有相同标题但不是可执行路径的两个窗口。
【解决方案2】:

它在 64x 机器上运行良好。对代码的唯一更改是检查值,如下所示:

if (hwnd != IntPtr.Zero)
{
    if (pid != 0) 
    {
        var p = Process.GetProcessById((int) pid)
        if (p != null)
        {
            //...
        }
    }
}

【讨论】:

    【解决方案3】:

    从您的问题看来,您目前已将程序编译为 32 位应用程序。但是,您尝试查询的进程(假设您在 64 位版本的 Windows 上运行)无疑是 64 位的。 That kind of thing isn't allowed。尽管您可以在 64 位版本的 Windows 上运行 32 位应用程序,但它们在专用的 Windows on Windows (WOW64) 子系统下运行。这就是为什么您会收到 Win32Exception 声称“仅完成了 ReadProcessMemory 或 WriteProcessMemory 请求的一部分”的原因。如果您还不知道 Windows 如何管理 32 位和 64 位进程,我同意这不是最具描述性的错误消息,但有了这些知识,它至少更有意义。

    解决方案是将您的应用程序编译为 64 位应用程序 (x64) 或“任何 CPU”。 之后一切都应按预期工作。如果可能,我建议使用“Any CPU”,这将允许应用程序在 32 位操作系统上以 32 位模式运行,在 64 位操作系统上以 64 位模式运行。这确实是理想的情况,假设:

    1. 您已正确编写 P/Invoke 定义(即,在适当的情况下使用 IntPtr,而不是 Integer)。
    2. 您不依赖编译为 32 位的第 3 方 DLL(您没有源代码)。

    【讨论】:

    • 我不认为这是问题所在。我刚刚使用此代码编写了一个示例 WinForms 应用程序,针对 x86 编译,它在我的 Windows 7 x64 上运行良好。
    • @Darin:你在审问哪个进程?这可能是关键问题。从问题中不清楚提问者是否正在为他的应用程序传递一个窗口句柄(这没有多大意义;有更好的方法可以为当前应用程序获取此信息),或者系统上的一些其他进程.
    • @Darin Dimitrov,如果您使用此功能提取您正在使用的 exe 的路径,它将起作用。但是如果你尝试提取另一个 exe 的路径,它会抛出这个错误。
    • @Cody,托管进程。你是对的。我会尝试其他进程。
    • @Ron:第 3 方类是由附属 DLL 提供的,还是您在项目中放置的代码?如果您有源代码,那么将其重新编译为 64 位也很简单。除非它执行大量繁重的 P/Invoke(即使那样,这些问题还是可以修复的),否则它不太可能为“任何 CPU”编译任何兼容性问题。用 .NET 编写的普通托管代码非常可移植。但是不,我不知道任何其他解决方案。
    【解决方案4】:

    我不知道这有一个已知问题,它闻起来很环保。错误级别很低,可能是wow64仿真层。我只能建议您下注并使用不同的方式来获取相同的信息。您可以使用 WMI,Win32_Process class。对 ProcessId 运行选择查询,ExecutablePath 属性为您提供您正在寻找的内容。使用 WMI Code Creator utility 进行实验,它会自动生成您需要的 C# 代码。然而,这将以同样的方式失败的可能性不为零。

    【讨论】:

    • WMI 是一种密集查找,应尽可能避免。
    猜你喜欢
    • 1970-01-01
    • 2011-06-20
    • 2017-04-14
    • 1970-01-01
    • 2014-04-29
    • 1970-01-01
    • 2012-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多