I declared the function Process32FirstW
and the structure PROCESSENTRY32W
like this:
[DllImport("KERNEL32.DLL", CallingConvention = CallingConvention.StdCall, EntryPoint = "Process32FirstW")]
private static extern bool Process32FirstW (IntPtr hSnapshot, ref ProcessEntry pProcessEntry);
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode, Size = 568)]
internal struct ProcessEntry {
[FieldOffset(0)] public int Size;
[FieldOffset(8)] public int ProcessId;
[FieldOffset(32)] public int ParentProcessID;
[FieldOffset(44), MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string ExeFile;
}
When calling Process32FirstW
(with a 64-bit process), I always get a TypeLoadException
saying
The type
ProcessEntry
couldn't be loaded, because the object field at offset 44 is aligned wrong or is overlapped by another field, which isn't an object field.
I also tried using char[]
instead of string
for ProcessEntry.ExeFile
and using Pack=4
and Pack=8
in the structure's StructLayoutAttribute
. I always set ProcessEntry.Size
to 568 and I copied the offset data from a C++ program (64-bit build):
typedef unsigned long long ulong;
PROCESSENTRY32W entry;
wcout << sizeof(PROCESSENTRY32W) << endl; // 568
wcout << (ulong)&entry.dwSize - (ulong)&entry << endl; // 0
wcout << (ulong)&entry.th32ProcessID - (ulong)&entry << endl; // 8
wcout << (ulong)&entry.th32ParentProcessID - (ulong)&entry << endl; // 32
wcout << (ulong)&entry.szExeFile - (ulong)&entry << endl; // 44
I can't figure out, what is going wrong, so how to declare PROCESSENTRY32W
in C# for a 64-bit application? Do I have to use C++/CLI or am I simply doing something wrong here?
EDIT: Running this code as a 64-bit program works perfectly fine for me
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32W entry;
entry.dwSize = sizeof(PROCESSENTRY32W);
if (Process32FirstW(hSnapshot, &entry)) {
do {
// Do stuff
} while (Process32NextW(hSnapshot, &entry));
}
CloseHandle(hSnapshot);
Process32Next function retrieves information about the next process recorded in a system snapshot.
Describes an entry from a list of the processes residing in the system address space when a snapshot was taken.
dwSize: "The size of the structure, in bytes." sizeof: "sizeof(x) returns the amount of memory (in bytes) that the variable or type x occupies"
The Module32First function (tlhelp32. h) retrieves information about the first module associated with a process. Module32FirstW. The Module32FirstW (Unicode) function (tlhelp32. h) retrieves information about the first module associated with a process.
PROCESSENTRY32 is fully defined as
typedef struct tagPROCESSENTRY32 {
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID;
ULONG_PTR th32DefaultHeapID;
DWORD th32ModuleID;
DWORD cntThreads;
DWORD th32ParentProcessID;
LONG pcPriClassBase;
DWORD dwFlags;
TCHAR szExeFile[MAX_PATH];
} PROCESSENTRY32, *PPROCESSENTRY32;
You ignore ULONG_PTR th32DefaultHeapID;
, that member is 4 bytes on 32 bit systems and 8 bytes on 64 bit systems, that means your FieldOffsetAttribute
for ParentProcessID
and ExeFile
will have a different offset depending on if you are running 32 bits vs 64 bits. Looking at your math it appears you assumed it would always be 8 bytes.
The easiest workaround is don't explicitly define the offsets and use IntPtr
to dynamicly figure the correct offset.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
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;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With