P /在Compact Framework中调用CreateToolhelp32Snapshot失败

时间:2008-12-26 15:23:06

标签: c# .net compact-framework windows-ce

嘿,我正在使用Windows Mobile 6为我的智能手机做一个小应用程序。我正在尝试获取当前正在运行的所有进程,但方法CreateToolhelp32Snapshot始终返回-1。所以现在我卡住了。我试图通过调用GetLastError()方法获得错误,但该方法返回0值。 这是我的代码片段。

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);

4 个答案:

答案 0 :(得分:3)

  • 首先,你的手柄检查是错误的。高位在一个句柄中是常见的,导致它在转换为有符号的int时看起来像一个负数。你应该检查是不是NULL(0)还是INVALID_HANDLE_VALUE(-1 / 0xffffffff)。
  • 您不应该“调用GetLastError”,而是调用Marshal.GetLastWin32Error()
  • 您没有在P / Invoke声明中设置SetLastError属性。在C#中,默认为false,在VB中默认为true。
  • 您的PROCESS32实施在哪里?在调用之前必须设置dwLength成员的docs clearly state,如果发生这种情况,这里不清楚。

作为旁注,Smart Device FrameworkOpenNETCF.ToolHelp namespace已经实现并且有效(如果您不想重新发明轮子)。

答案 1 :(得分:1)

而不是

CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

使用

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

默认情况下,CreateToolhelp32Snapshot将尝试对堆进行快照,这可能会导致内存不足错误。

https://social.msdn.microsoft.com/Forums/en-US/e91d845d-d51e-45ad-8acf-737e832c20d0/createtoolhelp32snapshot-windows-mobile-5?forum=vssmartdevicesnative找到了它,它解决了我的问题。

答案 2 :(得分:0)

如果您没有看到有效的“上次错误”信息,可能您可能需要在API的DllImport属性(MSDN reference with code examples)上添加“SetLastError”属性。根据此属性的文档,您应将SetLastError设置为...

  

... true表示被调用者会   调用SetLastError;否则,错误。   默认值为false。

     

运行时封送程序调用   GetLastError并缓存该值   返回,以防止它   被其他API调用覆盖。您   可以通过调用检索错误代码   GetLastWin32Error

至于你看到的API失败,我没有发现任何明显的副作用;您拥有的代码似乎与示例代码here非常相似。

答案 3 :(得分:0)

这是基于MSDN文档的正确实现方式

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);

最重要的是这一行,因为您必须设置procEntry的大小:

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