【问题标题】:P/Invoking CreateToolhelp32Snapshot failing in Compact FrameworkP/Invoking CreateToolhelp32Snapshot 在 Compact Framework 中失败
【发布时间】:2008-12-26 15:23:06
【问题描述】:

嘿,我正在为我的智能手机做一个小应用程序,使用 Windows Mobile 6。我正在尝试获取所有当前正在运行的 processec,但方法 CreateToolhelp32Snapshot 总是返回 -1。所以现在我卡住了。我尝试调用 GetLastError() 方法时出错,但该方法返回 0 值。 这是我的代码的 sn-p。

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

【问题讨论】:

  • "if ((int)handle > 0)" 不正确;你应该使用“如果(句柄!= -1)”。您是否说 CreateToolhelp32Snapshot 总是返回 -1 字面意思是真的,或者您是根据您发布的代码说的吗?您可能会得到一个未通过测试的有效句柄。

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


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

附带说明一下,Smart Device FrameworkOpenNETCF.ToolHelp namespace 已实现所有这些并正常工作(以防您不想重新发明轮子)。

【讨论】:

  • OpenNETCF.ToolHelp 对我不起作用。它抛出“无法创建快照”。幸运的是,ProcessCE class 为我完成了这项工作。
【解决方案2】:

代替

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 找到这个,它解决了我的问题。

【讨论】:

    【解决方案3】:

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

    ...true 表示被调用者将 调用 SetLastError;否则为假。 默认为假。

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

    至于您看到的 API 故障,我没有发现任何明显的临时情况;您拥有的代码似乎与示例代码 here 非常相似。

    【讨论】:

      【解决方案4】:

      这是基于 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));

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-04
        • 1970-01-01
        • 2011-06-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多