Process32FirstW 始终 returns 错误

Process32FirstW always returns false

Process32FirstW 在找到进程和 return PROCESSENTRY32W 结构中的第一个进程时假设 return 为真,但它没有,所以我无法在 Process32Next 中枚举它。它作为 bool 函数不 return 的原因是什么? [([([(我改变了结构减速)])])])]

        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESSENTRY32W
        {
            public uint dwSize;
            public uint cntUsage;
            public uint th32ProcessID;
            public IntPtr th32DefaultHeapID;
            public uint th32ModuleID;
            public uint cntThreads;
            public uint th32ParentProcessID;
            public int pcPriClassBase;
            public uint dwFlags;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szExeFile;
        }; 
        [DllImport("kernel32.dll", EntryPoint = "CreateToolhelp32Snapshot")]
        public static extern IntPtr CreateToolhelp32SnapshotRtlMoveMemory(UInt32 dwFlagsdes, UInt32 th32ProcessID);

        [DllImport("kernel32", EntryPoint = "Process32FirstW", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool Process32FirstW(IntPtr hSnapshot, IntPtr lppe);

        [DllImport("kernel32", EntryPoint = "Process32Next")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool Process32Next(IntPtr hSnapshot, IntPtr lppe);

        [DllImport("kernel32", EntryPoint = "CloseHandle")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseHandle(IntPtr handle);

        public static Dictionary<int, Process> get_process_list()
        {
            //Dictionary<string, Process> returnable_processes_ = new Dictionary<string, Process>();
            Dictionary<int, Process> returnable_processes_ = new Dictionary<int, Process>();
            IntPtr HANLDE_Processes = CreateToolhelp32SnapshotRtlMoveMemory(2,0);

            PROCESSENTRY32W p32Iw = new PROCESSENTRY32W();
            p32Iw.dwSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(PROCESSENTRY32W));
            IntPtr p32IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(p32Iw));
            Marshal.StructureToPtr(p32Iw, p32IntPtr, false);
            bool blFirstProcess = Process32FirstW(HANLDE_Processes, p32IntPtr); // returns false no matter what?
            int x = Marshal.GetLastWin32Error();

            if(blFirstProcess)
            { 

                do
                {
                    Marshal.PtrToStructure(p32IntPtr, p32Iw);
                    int PID = (int) p32Iw.th32ProcessID;
                    returnable_processes_.Add(PID, new Process());

                } 
                while(Process32Next(HANLDE_Processes, p32IntPtr));
            }





            Marshal.FreeHGlobal(p32IntPtr);
            return returnable_processes_;
        }

确实是字符集问题。您使用 api 的 ***W 版本。 PROCESSENTRY32W.szExeFile 的实际类型是 wchar_t,也就是 2 个字节,所以你传递的结构大小少了 260 个字节(你可以简单地尝试 p32Iw.dwSize + 260Process32FirstW 将 return true,如果我们不考虑后续执行)。 修复结构声明和 运行 "C/C++ Programming" C# 代码。

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct PROCESSENTRY32 
   { 
      public uint dwSize; 
      public uint cntUsage; 
      public uint th32ProcessID; 
      public IntPtr th32DefaultHeapID; 
      public uint th32ModuleID; 
      public uint cntThreads; 
      public uint th32ParentProcessID; 
      public int pcPriClassBase; 
      public uint dwFlags; 
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst=260)] public string szExeFile; 
    };

但是根据documentMarshal.StructureToPtrMarshal.PtrToStructure已经过时了,我们应该避免使用它。而这种通过指针传递值的方式在C#中通常被引用所取代。

首先,声明 Process32FirstProcess32Next

的字符集和引用参数
[DllImport("kernel32", EntryPoint = "Process32First", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool Process32First(IntPtr hSnapshot, ref PROCESSENTRY32W lppe);

[DllImport("kernel32", EntryPoint = "Process32Next", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool Process32Next(IntPtr hSnapshot, ref PROCESSENTRY32W lppe);

然后,传递PROCESSENTRY32W的ref类型:

bool blFirstProcess = Process32First(HANLDE_Processes, ref p32Iw); // returns false no matter what?
if (blFirstProcess)
{
   do
   {
      //Marshal.PtrToStructure(p32IntPtr, p32Iw);
      int PID = (int)p32Iw.th32ProcessID;
      returnable_processes_.Add(PID, new Process());
      Console.WriteLine(p32Iw.szExeFile);
   }
   while (Process32Next(HANLDE_Processes, ref p32Iw));
 }

总结一下,一个最小的、可编译的例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace ConsoleApp
{
    class Program
    {
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
         public struct PROCESSENTRY32W
        {
            public uint dwSize;
            public uint cntUsage;
            public uint th32ProcessID;
            public IntPtr th32DefaultHeapID;
            public uint th32ModuleID;
            public uint cntThreads;
            public uint th32ParentProcessID;
            public int pcPriClassBase;
            public uint dwFlags;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szExeFile;
        };
        [DllImport("kernel32.dll", EntryPoint = "CreateToolhelp32Snapshot")]
        public static extern IntPtr CreateToolhelp32SnapshotRtlMoveMemory(UInt32 dwFlagsdes, UInt32 th32ProcessID);

        [DllImport("kernel32", EntryPoint = "Process32First", SetLastError = true, CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool Process32First(IntPtr hSnapshot, ref PROCESSENTRY32W lppe);

        [DllImport("kernel32", EntryPoint = "Process32Next", CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool Process32Next(IntPtr hSnapshot, ref PROCESSENTRY32W lppe);

        [DllImport("kernel32", EntryPoint = "CloseHandle")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseHandle(IntPtr handle);
        public static Dictionary<int, Process> get_process_list()
        {
            //Dictionary<string, Process> returnable_processes_ = new Dictionary<string, Process>();
            Dictionary<int, Process> returnable_processes_ = new Dictionary<int, Process>();
            IntPtr HANLDE_Processes = CreateToolhelp32SnapshotRtlMoveMemory(2, 0);

            PROCESSENTRY32W p32Iw = new PROCESSENTRY32W();
            int size = System.Runtime.InteropServices.Marshal.SizeOf(typeof(PROCESSENTRY32W));
            p32Iw.dwSize = Convert.ToUInt32(size);
            //IntPtr p32IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(p32Iw));
            //Marshal.StructureToPtr(p32Iw, p32IntPtr, false);
            bool blFirstProcess = Process32First(HANLDE_Processes, ref p32Iw); // returns false no matter what?
            int x = Marshal.GetLastWin32Error();

            if (blFirstProcess)
            {

                do
                {
                    int PID = (int)p32Iw.th32ProcessID;
                    returnable_processes_.Add(PID, new Process());
                    Console.WriteLine(p32Iw.szExeFile);

                }
                while (Process32Next(HANLDE_Processes, ref p32Iw));
            }
            return returnable_processes_;
        }
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            get_process_list();
            Console.ReadKey();
        }
    }
}