Problem bei 32bit und 64bit Prozesse!

  • VB.NET
  • .NET (FX) 1.0–2.0

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von Cheffboss.

    Problem bei 32bit und 64bit Prozesse!

    Moin! :)
    Ich habe folgendes Problem, ich habe ein Programm das auf Ziel-CPU: x86 sein muss.
    Wenn ich nun alle Prozesse auflisten will, gibt es anscheinend auch 64bit Prozesse, die dann nicht aufgelistet werden und das dann dieser Fehler erscheint.
    „Nur ein Teil der ReadProcessMemory- oder WriteProcessMemory-Anforderung wurde abgeschlossen“

    Ich habe stundenlang gegoogelt, leider ohne Erfolg.
    Ich habe mitbekommen das einige Leute das gleiche Problem haben, aber es schwer ist eine Lösung zu finden.
    Ich habe ein Englischen Text gefunden, dies das Problem erläutert.
    So wie ich es verstanden habe gibt es die Funktion „EnumProcessModulesEx“.
    Diese aber leider erst ab Windows Vista existiert.
    Leider habe ich nicht herausgefunden, wie man diese Funktion anwendet.
    Freue mich falls mir jemand, von euch, weiter helfen kann!
    Es muss doch eine Lösung geben! ?(
    BIG THX

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. For Each prozlist As Process In Process.GetProcesses
    3. If prozlist.MainWindowTitle <> "" Then
    4. Try
    5. Me.ListBox1.Items.Add(prozlist.MainModule.FileName.ToLower)
    6. Catch ex As Exception
    7. MsgBox(ex.Message)
    8. End Try
    9. End If
    10. Next
    11. End Sub






    As detailed in the comments of the MSDN page for Process.Modules and this thread there is a known issue in Process.Modules when enumerating 32 bit processes from a 64 bit process and visa-versa:
    Internally .NET's Process.Modules is using function EnumProcessModules from PSAPI.dll. This function has a known issue that it cannot work across 32/64 bit process boundary. Therefore enumerating another 64-bit process from 32-bit process or vice versa doesn't work correctly.
    The solution seems to be to use the EnumProcessModulesEx function, (which must be called via P/Invoke), however this function is only available on later versions of Windows.
    We fixed this issue by adding a new function called EnumProcessModulesEx to PSAPI.dll (msdn2.microsoft.com/en-us/library/ms682633.aspx), but we currently cannot use it in this case:
    • it only works on Windows Vista or Windows Server 2008
    • currently .NET 2.0 Framework don't have a service pack or hotfix to make Process.Modules use this new API
    Visual Basic.NET 8o
    MS-SQL
    8o
    Was mich mal wieder überrascht, sind Deine Projekteinstellungen (Screenshot#1). Option Strict Off, nicht alle Warnungskonfigurationen auf Fehler, VB6-Namespace drinne …

    Zum Problem: einfach bei einer Suchmaschine den Funktionsnamen + Pinvoke eingeben (also EnumProcessModulesEx pinvoke) und Du landest z.B. auf einer Seite, die sogar mit Beispiel ist.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Cheffboss schrieb:

    Diese aber leider erst ab Windows Vista existiert.
    Welches Zielsystem hast Du?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @VaporiZed
    Das mit der „EnumProcessModulesEx Funktion“ ist gar nicht so einfach.
    Ich versuche mich darüber schlau zu machen.
    Leider habe ich bis jetzt kein Plan wie ich diese verwenden kann.

    @RodFromGermany
    Es sollte mindestens ab WinXP laufen.
    Falls auch Win2000 unterstützt wird, wäre es noch besser…
    Visual Basic.NET 8o
    MS-SQL
    8o

    VaporiZed schrieb:


    .. und Du landest z.B. auf einer Seite, die sogar mit Beispiel ist.


    Wenn Du das Beispiel zum LAufen bringst, dann zeige es bitte, egal ob VB.Net oder C#. Also ich bin nach dem Einbinden der GetModuleFileNameEx Funktion kläglich gescheitert. Die modifizierte Signatur hat auch nicht geholfen.
    Da ich hier ohnehin nicht weiß was ich da mache, habe ich es dann auch schnell wieder gelassen.
    @Dksksm
    Ok, ich hoffe ich finde eine Lösung.
    Die auch anderen helfen kann..

    @an alle
    Ich habe nun diesen Code gefunden, und hoffe das ich dann auch von einer 32bit Anwendung die Daten(Prozepfad, Fenstertitel) auslesen kann.
    Weiß jemand, wie man alle ProzessIds auslesen kann, und meine Funktion zu verwenden?
    THX

    VB.NET-Quellcode

    1. Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    2. ' Alle Ids auflisten...
    3. Dim wert As String = ProzesseInformartionenAuslesen(Process.GetCurrentProcess().Id)
    4. ListView1.Items.Add(wert)
    5. End Sub
    6. Public Shared Function ProzesseInformartionenAuslesen(ByVal prozessID As Integer) As String
    7. Dim Pfad As String = "" : Dim Title As String = ""
    8. Try
    9. Dim Query As String = "SELECT Name, ExecutablePath FROM Win32_Process WHERE ProcessId = " & prozessID
    10. Using mos As ManagementObjectSearcher = New ManagementObjectSearcher(Query)
    11. Using moc As ManagementObjectCollection = mos.[Get]()
    12. Pfad = (From mo In moc.Cast(Of ManagementObject)() Select mo("ExecutablePath")).First().ToString()
    13. Title = (From mo In moc.Cast(Of ManagementObject)() Select mo("Name")).First().ToString()
    14. End Using
    15. End Using
    16. Catch
    17. End Try
    18. Return Title & "#" & Pfad
    19. End Function




    edit2:
    Habe nun doch allle ProzesIds ausgelesen. ^^

    VB.NET-Quellcode

    1. For Each test As Process In Process.GetProcesses
    2. ' Alle Ids auflisten...
    3. Dim wert As String = ProzesseInformartionenAuslesen(test.Id)
    4. ListView1.Items.Add(wert)
    5. Next

    Visual Basic.NET 8o
    MS-SQL
    8o

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Cheffboss“ ()

    @an alle
    Ich weiß nicht ob ich jetzt einen neuen Beitrag eröffnen darf.
    Da ich folgendes Problem habe:

    VB.NET-Quellcode

    1. Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    2. For Each values As Process In Process.GetProcesses
    3. Dim wert As String = ProzesseInformartionenAuslesen(values.Id)
    4. If Not wert = "" Then
    5. Me.ListBox1.Items.Add(wert)
    6. End If
    7. Next
    8. Übertrag()
    9. End Sub
    10. Public Shared Function ProzesseInformartionenAuslesen(ByVal prozessID As Integer) As String
    11. Dim Pfad As String = ""
    12. Dim ergebnis As String = ""
    13. Try
    14. Dim Query As String = "SELECT ExecutablePath FROM Win32_Process WHERE ProcessId = " & prozessID
    15. Using mos As ManagementObjectSearcher = New ManagementObjectSearcher(Query)
    16. Using moc As ManagementObjectCollection = mos.[Get]()
    17. Pfad = (From mo In moc.Cast(Of ManagementObject)() Select mo("ExecutablePath")).First().ToString().ToLower
    18. Dim windowText As String = Process.GetProcessById(prozessID).MainWindowTitle
    19. If Not windowText = "" Then
    20. ergebnis = windowText & "#" & Pfad
    21. End If
    22. End Using
    23. End Using
    24. Catch
    25. End Try
    26. Return ergebnis
    27. End Function


    Der Code geht soweit, aber es ist verdammt langsam!
    Wie kann ich den Code schneller bekommen? ?(
    Visual Basic.NET 8o
    MS-SQL
    8o
    @Dksksm
    @an alle
    Leider, schaff ich es auch nicht die „GetModuleFileNameEx“ Funktion Zu verwenden. ;(
    Man findet auch so gut wie keine Informationen darüber.
    Hmmm, ich hoffe das ich doch irgendeine Lösung finde.
    Ich möchte wie gesagt, nur den Fenstername und den Prozessname auflisten in einer Listbox.
    Visual Basic.NET 8o
    MS-SQL
    8o
    @Dksksm

    VB.NET-Quellcode

    1. Imports System.Diagnostics
    2. Imports System.Runtime.InteropServices
    3. Public Class Form1
    4. Private Const LIST_MODULES_ALL = 3 'https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodulesex
    5. <DllImport("psapi.dll", SetLastError:=True)> Private Shared Function EnumProcessModulesEx(ProcessHandle As IntPtr, ByRef ModuleArrayAddress As IntPtr, MaximumSizeOfModuleArray As UInteger, ByRef ActualNeededSizeOfModuleArray As UInteger, Flag As UInteger) As Boolean
    6. End Function
    7. <DllImport("psapi.dll")> Private Shared Function GetModuleFileNameEx(ProcessHandle As IntPtr, hModule As IntPtr, lpBaseName As Text.StringBuilder, nSize As Integer) As UInteger
    8. End Function
    9. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    10. Dim Processes = Process.GetProcessesByName("notepad") 'z.B.; dann muss aber (bei mir) ZielCPU auf x64 gestellt werden, da notepad auch ein 64-Bit-Prozess ist
    11. For Each Process In Processes
    12. Dim ModuleHandles = CType(Array.CreateInstance(GetType(IntPtr), 1024), IntPtr())
    13. Dim GcHandle = Runtime.InteropServices.GCHandle.Alloc(ModuleHandles, GCHandleType.Pinned)
    14. Dim ModuleArrayAdress = GcHandle.AddrOfPinnedObject()
    15. Dim MaximumSizeOfModuleArray = CUInt(Marshal.SizeOf(GetType(IntPtr)) * ModuleHandles.Length)
    16. Dim ActualNeededSizeOfModuleArray = 0UI
    17. Dim HandleOfCurrentProcess = Process.Handle
    18. If EnumProcessModulesEx(Process.Handle, ModuleArrayAdress, MaximumSizeOfModuleArray, ActualNeededSizeOfModuleArray, LIST_MODULES_ALL) Then
    19. Dim CountOfModules = CInt(ActualNeededSizeOfModuleArray / Marshal.SizeOf(GetType(IntPtr)))
    20. For i = 0 To CountOfModules - 1
    21. Dim StringBuilder = New Text.StringBuilder(1024)
    22. Dim ModuleHandle As IntPtr
    23. GetModuleFileNameEx(HandleOfCurrentProcess, ModuleHandle, StringBuilder, StringBuilder.Capacity)
    24. Console.WriteLine("File Path: " + StringBuilder.ToString())
    25. Next
    26. Console.WriteLine("Number of Modules: " & CountOfModules)
    27. Console.WriteLine()
    28. End If
    29. GcHandle.Free() 'crasht leider dank EnumProcessModulesEx
    30. Next
    31. End Sub
    32. End Class

    erster Entwurf; bringt aber nix, weil man dann mit GetModuleFileNameEx den Namen der Exe bekommt, die man aber schon kennt
    Daher weiß ich leider auch gar nicht, warum EnumProcessModulesEx das Ziel sein soll
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @an alle
    Danke, an euch. :)
    Ich habe das Problem nun mit Anonymous pipe gelöst.
    Der Lösungsweg, da Prozess1 mit 32bit laufen muss, wegen einer teuren DDL.
    Habe ich gesagt, Prozess2 als AnyCPU, soll mir die Prozesse auslesen und an Prozess1 schicken.
    Somit könnte ich ganz simpel das Problem lösen, und kann meine DLL weiterverwenden.
    Als Beispiel hab ich euch eine kleine Grafikerstellt.

    Quellcode findet man unter:
    Anonyme Pipes unter VB.NET richtig anwenden!

    Visual Basic.NET 8o
    MS-SQL
    8o