Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`PROCESSENTRY32W` in C#?

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);
like image 649
Cubi73 Avatar asked Nov 10 '15 14:11

Cubi73


People also ask

What is Process32Next?

Process32Next function retrieves information about the next process recorded in a system snapshot.

What is processentry32?

Describes an entry from a list of the processes residing in the system address space when a snapshot was taken.

What is dwSize?

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"

What is tlhelp32 H?

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.


1 Answers

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; 
 }; 
like image 151
Scott Chamberlain Avatar answered Sep 18 '22 04:09

Scott Chamberlain