.net QueryFullProcessImageName返回错误31

aydmsdu9  于 2022-11-19  发布在  .NET
关注(0)|答案(2)|浏览(213)

我正在开发一个应用程序,它应该能够显示和检索系统中所有进程的信息。
我尝试使用函数QueryFullProcessImageName获取进程的完整路径,但失败并显示错误31(连接到系统的设备不工作),这种情况仅发生在程序首次枚举运行进程后创建的新进程中。
下面是我用来获取完整路径的方法:

public static string GetProcessFullPath(SafeProcessHandle Handle)
    {
        uint MaxPathLength = 1024;
        StringBuilder ExePath = new StringBuilder(1024);
        if (NativeMethods.Win32ProcessFunctions.QueryFullProcessImageName(Handle.DangerousGetHandle(), 0, ExePath, ref MaxPathLength))
        {
            return ExePath.ToString();
        }
        else
        {
            Win32Exception ex = new Win32Exception(Marshal.GetLastWin32Error());
            Logger.WriteEntry(new LogEntry("Non è stato possibile recuperare il percorso completo dell'eseguibile di un processo, codice di errore: " + ex.NativeErrorCode + " (" + ex.Message + ")", EventSource.WindowsAPI, EventSeverity.Error));
            return "Non disponibile";
        }
    }

下面是函数的声明:

[DllImport("Kernel32.dll", EntryPoint = "QueryFullProcessImageNameW", SetLastError = true, CharSet = CharSet.Unicode)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool QueryFullProcessImageName(IntPtr ProcessHandle, uint PathType, StringBuilder ExePath, ref uint Characters);

我不知道导致此错误的原因,我从WMI(Win32_ProcessStartTrace)收到新进程的通知。
这就是我获取GetProcessFullPath方法中使用的进程句柄的方式(PID来自WMI通知):

public static SafeProcessHandle GetProcessHandle(uint ProcessID)
    {
        IntPtr UnsafeProcessHandle = NativeMethods.Win32ProcessFunctions.OpenProcess(NativeMethods.Win32Enumerations.ProcessAccessRights.PROCESS_ALL_ACCESS, false, ProcessID);
        if (UnsafeProcessHandle == IntPtr.Zero)
        {
            UnsafeProcessHandle = NativeMethods.Win32ProcessFunctions.OpenProcess(NativeMethods.Win32Enumerations.ProcessAccessRights.PROCESS_QUERY_LIMITED_INFORMATION, false, ProcessID);
            if (UnsafeProcessHandle == IntPtr.Zero)
            {
                Win32Exception ex = new Win32Exception(Marshal.GetLastWin32Error());
                Logger.WriteEntry(new LogEntry("Non è stato possibile aprire un processo, codice di errore: " + ex.NativeErrorCode + " (" + ex.Message + ")", EventSource.WindowsAPI, EventSeverity.Error));
                return new SafeProcessHandle(UnsafeProcessHandle, true);
            }
            else
            {
                return new SafeProcessHandle(UnsafeProcessHandle, true);
            }
        }
        else
        {
            return new SafeProcessHandle(UnsafeProcessHandle, true);
        }
    }

编辑:进一步的测试表明,即使我试图获取其完整路径的进程在调用函数时已经启动,也会发生问题。

lh80um4z

lh80um4z1#

GetProcessImageFileName可以工作,但它以设备形式返回路径,而我需要Win32路径。
您可以使用GetLogicalDriveStringsQueryDosDevice将dos文件路径转换为windows文件路径。
一些代码:

// dos file path => windows file path
BOOL DosPathToNtPath(LPTSTR pszDosPath, LPTSTR pszNtPath)
{
    TCHAR           szDriveStr[500];
    TCHAR           szDrive[3];
    TCHAR           szDevName[100];
    INT             cchDevName;
    INT             i;

    //Check the parameters
    if (!pszDosPath || !pszNtPath)
        return FALSE;

    //Get local disk string
    if (GetLogicalDriveStrings(sizeof(szDriveStr), szDriveStr))
    {
        for (i = 0; szDriveStr[i]; i += 4)
        {
            if (!lstrcmpi(&(szDriveStr[i]), _T("A:\\")) || !lstrcmpi(&(szDriveStr[i]), _T("B:\\"))) { continue; }

            szDrive[0] = szDriveStr[i];
            szDrive[1] = szDriveStr[i + 1];
            szDrive[2] = '\0';
            // Query Dos device name
            if (!QueryDosDevice(szDrive, szDevName, 100)) { return FALSE; }

            // Hit
            cchDevName = lstrlen(szDevName);
            if (_tcsnicmp(pszDosPath, szDevName, cchDevName) == 0) {
                // Copy drive
                lstrcpy(pszNtPath, szDrive);

                // Copy path
                lstrcat(pszNtPath, pszDosPath + cchDevName);

                return TRUE;
            }
        }
    }

    lstrcpy(pszNtPath, pszDosPath);
    return FALSE;
}

然后简单地呼叫,

GetProcessImageFileName(hProcess, szImagePath, MAX_PATH);
DosPathToNtPath(szImagePath,pszFullPath);

您可以将其转换为C#代码。

huus2vyu

huus2vyu2#

QueryFullProcessImageName函数因ERROR_GEN_FAILURE而失败(310x1f,“A device attached to the system is not functioning”)如果进程是“僵尸”进程,即进程已终止但并非所有句柄都已关闭。在这种情况下,您仍然可以使用带有PROCESS_NAME_NATIVE标志的QueryFullProcessImageNameW来获取本机路径,但您可能只想跳过它,因为它不再运行了。

相关问题