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 + 260
,Process32FirstW
将 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;
};
但是根据document,Marshal.StructureToPtr
和Marshal.PtrToStructure
已经过时了,我们应该避免使用它。而这种通过指针传递值的方式在C#中通常被引用所取代。
首先,声明 Process32First
和 Process32Next
的字符集和引用参数
[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();
}
}
}
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 + 260
,Process32FirstW
将 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;
};
但是根据document,Marshal.StructureToPtr
和Marshal.PtrToStructure
已经过时了,我们应该避免使用它。而这种通过指针传递值的方式在C#中通常被引用所取代。
首先,声明 Process32First
和 Process32Next
[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();
}
}
}