P/Invoking CreateToolhelp32Snapshot failing in Compact Framework

1

Hey, im doing a little app for my smart phone, using Windows Mobile 6. I'm trying to get all currently running processec, but method CreateToolhelp32Snapshot always returns -1. So now im stuck. I tried to get error with invoking GetLastError() method, but that method returns 0 value. Here is a snippet of my code.

private const int TH32CS_SNAPPROCESS = 0x00000002;
[DllImport("toolhelp.dll")]
public static extern IntPtr CreateToolhelp32Snapshot(uint flags, 
                                                     uint processid);

public static Process[] GetProcesses()
    {
        ArrayList procList = new ArrayList();
        IntPtr handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

        if ((int)handle > 0)
        {
            try
            {
                PROCESSENTRY32 peCurr;
                PROCESSENTRY32 pe32 = new PROCESSENTRY32();

                // get byte array to pass to API call
                byte[] peBytes = pe32.ToByteArray();
                // get the first process
                int retval = Process32First(handle, peBytes);
c#
.net
compact-framework
windows-ce
asked on Stack Overflow Dec 26, 2008 by user19600 • edited Dec 26, 2008 by ctacke

4 Answers

5
  • First, your handle check is wrong. It's common for the high bit to be on in a handle, causing it to look like a negative number when cast to a signed int. You should be checking that is isn't NULL (0) or INVALID_HANDLE_VALUE (-1 / 0xffffffff).
  • You shouldn't be "invoking GetLastError" but calling Marshal.GetLastWin32Error()
  • You've not set the SetLastError attribute in the P/Invoke declaration. In C# it defaults to false, in VB it defaults to true.
  • Where's your PROCESS32 implementation? The docs clearly state that the dwLength member must be set before the call and it's not clear here if that's happening.

As a side note, the Smart Device Framework's OpenNETCF.ToolHelp namespace has all of this implemented and working (in case you'd rather not reinvent the wheel).

answered on Stack Overflow Dec 26, 2008 by ctacke • edited Dec 26, 2008 by ctacke
1

Instead of

CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

use

private const int TH32CS_SNAPNOHEAPS = 0x40000000;
CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0);

By default CreateToolhelp32Snapshot will try to snapshot the heaps and that can cause an out of memory error.

Found this at https://social.msdn.microsoft.com/Forums/en-US/e91d845d-d51e-45ad-8acf-737e832c20d0/createtoolhelp32snapshot-windows-mobile-5?forum=vssmartdevicesnative and it solved my problem.

answered on Stack Overflow Sep 22, 2015 by dquadros
0

If you're not seeing valid "last error" information, perhaps you might need to add the "SetLastError" attribute on the API's DllImport attribute (MSDN reference with code examples). According to the documentation of this attribute, you should set SetLastError to...

...true to indicate that the callee will call SetLastError; otherwise, false. The default is false.

The runtime marshaler calls GetLastError and caches the value returned to prevent it from being overwritten by other API calls. You can retrieve the error code by calling GetLastWin32Error

As for the API failure you're seeing, I don't spot anything obvious offhand; the code you have seems very similar to the sample code here.

answered on Stack Overflow Dec 26, 2008 by reuben
0

This is the proper implementation based on the MSDN documentation

private const int INVALID_HANDLE_VALUE = -1;

[Flags]
private enum SnapshotFlags : uint
{
    HeapList = 0x00000001,
    Process = 0x00000002,
    Thread = 0x00000004,
    Module = 0x00000008,
    Module32 = 0x00000010,
    Inherit = 0x80000000,
    All = 0x0000001F,
    NoHeaps = 0x40000000
}

[DllImport("toolhelp.dll"]
private static extern IntPtr CreateToolhelp32Snapshot(SnapshotFlags dwFlags, int th32ProcessID);

[StructLayout(LayoutKind.Sequential)]
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;
};


IntPtr hSnap = CreateToolhelp32Snapshot(SnapshotFlags.Process, 0);

if (hSnap.ToInt64() != INVALID_HANDLE_VALUE)
{
    PROCESSENTRY32 procEntry = new PROCESSENTRY32();
    procEntry.dwSize = (uint)Marshal.SizeOf(typeof(PROCESSENTRY32));

    if (Process32First(hSnap, ref procEntry))
    {
        do
        {

            //do whatever you want here

        } while (Process32Next(hSnap, ref procEntry));
    }
}

CloseHandle(hSnap);

Most importantly is this line, because you must set the size of the procEntry:

procEntry.dwSize = (uint)Marshal.SizeOf(typeof(PROCESSENTRY32));

answered on Stack Overflow Apr 17, 2020 by GuidedHacking

User contributions licensed under CC BY-SA 3.0