windows - Sådan undgår du en Win32-undtagelse, når du åbner Process.MainModule.FileName i C #?

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg startede et nyt projekt med de fulde stier til alle løbende processer. Når man får adgang til nogle af processerne, kolliderer programmet og kaster en Win32Exception . Beskrivelsen siger, at der opstod en fejl under notering af procesmodulerne. Jeg troede først, at dette problem kunne opstå, fordi jeg kører det på en 64-bit platform, så jeg genkompilerede den til CPU-typerne x86 og AnyCPU . Jeg får den samme fejl.


Process p = Process.GetProcessById(2011);
string s = proc\_by\_id.MainModule.FileName;


Fejlen opstår i linje # 2. De tomme felter viser processer, hvor fejlen opstod:
Screenshot


Er der nogen måde at omgå denne fejlmeddelelse?

Bedste reference


Undtagelsen kastes, når du forsøger at få adgang til ejendommen MainModule. Dokumentationen for denne ejendom opregner ikke Win32Exception som en mulig undtagelse, men når man ser på IL for ejendommen er det tydeligt, at adgang til det kan kaste denne undtagelse. Generelt vil det smide denne undtagelse, hvis du forsøger at gøre noget, der er umuligt eller ikke tilladt i OS.


Win32Exception har egenskaben NativeErrorCode og også en Message, der vil forklare, hvad problemet er. Du bør bruge disse oplysninger til fejlfinding af dit problem. NativeErrorCode er Win32 fejlkode. Vi kan gætte hele dagen lang, hvad problemet er, men den eneste måde at rent faktisk finde ud af dette er at inspicere fejlkoden.


Men for at fortsætte med at gætte, har en kilde til disse undtagelser adgang til 64 bit-processer fra en 32-bitsproces. Gør det vil kaste en Win32Exception med følgende besked:



  En 32 bit processer kan ikke få adgang til moduler af en 64 bit proces.



Du kan få antallet af bits af din proces ved at evaluere Environment.Is64BitProcess.


Selv kører som en 64 bit proces, vil du aldrig få adgang til MainModule af proces 4 (System) eller proces 0 (System Idle Process). Dette vil kaste en Win32Exception med meddelelsen:



  Kan ikke opregne procesmodulerne.



Hvis du har problemer med at lave en procesliste, der ligner den i Task Manager, skal du håndtere proces 0 og 4 på en særlig måde og give dem bestemte navne (ligesom Task Manager gør). Bemærk at i ældre versioner af Windows har systemprocessen ID 8.

Andre referencer 1


Se venligst Jeff Mercado s svar her.


Jeg tilpassede sin kode lidt for blot at få filepathen til en bestemt proces:


string s = GetMainModuleFilepath(2011);


.


private string GetMainModuleFilepath(int processId)
{
    string wmiQueryString = "SELECT ProcessId, ExecutablePath FROM Win32\_Process WHERE ProcessId = " + processId;
    using (var searcher = new ManagementObjectSearcher(wmiQueryString))
    {
        using (var results = searcher.Get())
        {
            ManagementObject mo = results.Cast<ManagementObject>().FirstOrDefault();
            if (mo != null)
            {
                return (string)mo["ExecutablePath"];
            }
        }
    }
    return null;
}

Andre referencer 2


Hvis du vil slippe af Win32Exception og få den bedste ydeevne, lad os gøre det her:



  1. Vi bruger Win32 API til at få procesfilnavn

  2. Vi gennemfører en cache (kun forklaring)



Først skal du importere Win32 API


[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int processId);

[DllImport("psapi.dll")]
static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, [In] [MarshalAs(UnmanagedType.U4)] int nSize);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);


For det andet, lad os skrive den funktion, der returnerer procesfilnavn.


[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string GetProcessName(int pid)
{
      var processHandle = OpenProcess(0x0400 | 0x0010, false, pid);

      if (processHandle == IntPtr.Zero)
      {
          return null;
      }

      const int lengthSb = 4000;

      var sb = new StringBuilder(lengthSb);

      string result = null;

      if (GetModuleFileNameEx(processHandle, IntPtr.Zero, sb, lengthSb) > 0)
      {
          result = Path.GetFileName(sb.ToString());
      }

      CloseHandle(processHandle);

      return result;
}


Endelig lad os implementere en cache, så vi ikke behøver at kalde denne funktion for ofte. Opret en klasse ProcessCacheItem med egenskaber (1) procesnavn (2) oprettelsestid. Tilføj en const ItemLifetime og sæt til 60 sekunder. Opret en ordbog hvor nøgleproces PID og værdi er objekt forekomst af ProcessCacheItem. Når du vil få procesnavn, skal du først tjekke cache. Hvis emne i cache udløbet, skal du fjerne det og tilføje opdateret en.

Andre referencer 3


Måske fordi du forsøger at få adgang til MainModule-ejendommen til nogle processer (sandsynligvis dem, der kører under SYSTEM legitimationsoplysninger), som du ikke har tilladelse til ...

Andre referencer 4


Kan også deaktivere den næste mulighed ...


[[Projektegenskaber]] 1 [17]