C# C通过句柄(hWnd)32和64位获取路径/文件名

C# C通过句柄(hWnd)32和64位获取路径/文件名,c#,.net,path,64-bit,filenames,C#,.net,Path,64 Bit,Filenames,我获得了以下代码以通过句柄获取路径/文件名: [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern int GetWindowThreadProcessId(IntPtr handle, out uint processId); public static string GetProcessPath(IntPtr hwnd) {

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

    [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

我怎样才能修好它


~Thank Ron

从您的问题中可以看出,您目前已将程序编译为32位应用程序。但是,假设您运行的是64位版本的Windows,那么您试图查询的进程无疑是64位的。虽然您可以在64位版本的Windows上运行32位应用程序,但它们在Windows WOW64子系统上的专用Windows下运行。这就是为什么会出现Win32Exception,声称ReadProcessMemory或WriteProcessMemory请求只完成了一部分。我同意,如果您还不知道Windows如何管理32位和64位进程,那么它并不是最具描述性的错误消息,但有了这些知识,它至少有一点意义

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

您已经正确地编写了P/Invoke定义,即在适当的情况下使用IntPtr,而不是Integer。 您不依赖第三方DLL,因为您没有编译为32位的源代码。
我不知道这有什么问题,闻起来很环保。错误级别非常低,可能是wow64仿真层。我只能建议你用不同的方式来获得相同的信息。您可以使用WMI。在ProcessId上运行select查询,ExecutablePath属性将提供您要查找的内容。使用W进行实验,它会自动生成所需的C代码。然而,这种方法以同样的方式失败的可能性并不是零。

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

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

在检查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; }
    }

陛下返回proc.MainModule.FileName.ToString中的哪一行是错误;尝试以管理员身份运行您的程序。@Darin Dimitrov,我已经以管理员身份运行了。这不是问题所在@科迪·格雷,我不知道。我没有构建这个函数,但即使我将其更改为IntPtr,它也不会工作。[DllImportuser32.dll,CharSet=CharSet.Auto,SetLastError=true]私有静态外部IntPtr GetWindowThreadProcessIdIntPtr句柄,out IntPtr processId;公共静态字符串GetProcessPathIntPtr hwnd{IntPtr pid=IntPtr.Zero;GetWindowThreadProcessIdhwnd,out pid;Process proc=Process.GetProcessByIdpid.ToInt32;return proc.MainModule.FileName.ToString;}我认为这不是问题所在。我刚刚用这段代码编写了一个WinForms应用程序示例,它是针对x86编译的,在我的Windows 7 x64上运行得非常好。@Darin:你在询问哪个进程?这可能是关键问题。这个问题不清楚询问者是否正在为他的应用程序传递一个没有多大意义的窗口句柄;对于当前应用程序或系统上的其他进程,有更好的方法获取这些信息。@Darin Dimitrov,如果您使用此函数提取正在使用的exe的路径,它将起作用。但如果您试图提取另一个exe的路径,它将抛出此错误。@Cody,宿主进程。你说得对。我将尝试其他进程。@Ron:这是卫星DLL提供的第三方类,还是您在项目中放置的代码?如果您有源代码,那么只需将其重新编译为64位即可。它不太可能为任何CPU编译任何兼容性问题,除非它执行大量的P/Invoke,即使这样,这些问题还是可以解决的。用.NET编写的普通托管代码非常便于移植。但是没有,我不知道还有其他解决方案。WMI是一种密集型查找,应该尽可能避免。参加聚会晚了3年,但想说声谢谢,一直很难找到一种方法来优雅地停止我正在包装的进程,这被证明是最后一块拼图,因为我需要一种方法来区分两个标题相同的窗口,但不是可执行路径。