PInvoke NetLocalGroupGetMembers遇到FatalExecutionEngineError

PInvoke NetLocalGroupGetMembers遇到FatalExecutionEngineError

问题描述:

我需要在C#中使用win32 NetLocalGroupGetMembers.我找到并测试了三种解决方案.所有这三个都失败,并带有FatalExecutionEngineError.该框架是.net 4.0

I need to use win32 NetLocalGroupGetMembers in C#. I found and tested three solutions. All three fail with an FatalExecutionEngineError. The framework is .net 4.0

这是一个完整的例子:

对api的引用:

static class NetworkAPI
{
    [DllImport("Netapi32.dll")]
    public extern static int NetLocalGroupGetMembers([MarshalAs(UnmanagedType.LPWStr)] string servername, [MarshalAs(UnmanagedType.LPWStr)] string localgroupname, int level, out IntPtr bufptr, int prefmaxlen, out int entriesread, out int totalentries, out int resumehandle);

    [DllImport("Netapi32.dll")]
    public extern static int NetApiBufferFree(IntPtr Buffer);

    // LOCALGROUP_MEMBERS_INFO_1 - Structure for holding members details
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct LOCALGROUP_MEMBERS_INFO_1
    {
        public int lgrmi1_sid;
        public int lgrmi1_sidusage;
        public string lgrmi1_name;
    }
}

调用函数:

static void Main(string[] args)
{
    int EntriesRead;
    int TotalEntries;
    int Resume;
    IntPtr bufPtr;

    string groupName = "Administrators";

    NetworkAPI.NetLocalGroupGetMembers(null, groupName, 1, out bufPtr, -1, out EntriesRead, out TotalEntries, out Resume);

    if (EntriesRead > 0)
    {
        NetworkAPI.LOCALGROUP_MEMBERS_INFO_1[] Members = new NetworkAPI.LOCALGROUP_MEMBERS_INFO_1[EntriesRead];
        IntPtr iter = bufPtr;

        // EntriesRead has the correct quantity of members of the group, so the group is found
        for (int i = 0; i < EntriesRead; i++)
        {
            // --------------------------------------------------
            // ==> here the FatalExecutionEngineError happens:
            Members[i] = (NetworkAPI.LOCALGROUP_MEMBERS_INFO_1)Marshal.PtrToStructure(iter, typeof(NetworkAPI.LOCALGROUP_MEMBERS_INFO_1));
            //
            // --------------------------------------------------

            iter = (IntPtr)((int)iter + Marshal.SizeOf(typeof(NetworkAPI.LOCALGROUP_MEMBERS_INFO_1)));
            Console.WriteLine(Members[i].lgrmi1_name);
        }
        NetworkAPI.NetApiBufferFree(bufPtr);
    }
}

我看到以下错误:

  1. 简历句柄是一个指针.使用ref IntPtr resumehandle作为该参数,并在第一次调用时传递IntPtr.Zero.或者,如果您不需要使用简历句柄,则将参数声明为IntPtr resumehandle并传递IntPtr.Zero.有关完整的详细信息,请查阅MSDN上的功能文档.
  2. 该结构的lgrmi1_sid成员是一个指针.这样声明:public IntPtr lgrmi1_sid.
  3. IntPtr投射到int将导致指针在64位上被截断.可以直接在IntPtr上使用算术,或者对转换为long的旧C#版本使用算术.前者更好,例如:iter += Marshal.SizeOf(typeof(NetworkAPI.LOCALGROUP_MEMBERS_INFO_1));.
  4. 您不检查返回值是否有错误.
  1. The resume handle is a pointer. Use ref IntPtr resumehandle for that parameter, and pass IntPtr.Zero on the first call. Or if you don't need to use a resume handle declare the parameter as IntPtr resumehandle and pass IntPtr.Zero. Consult the function documentation on MSDN for the full details.
  2. The lgrmi1_sid member of the struct is a pointer. Declare it as such: public IntPtr lgrmi1_sid.
  3. Casting an IntPtr to an int will lead to pointer truncation on 64 bit. Either use arithmetic directly on the IntPtr, or for older C# versions cast to long. The former is better, like so: iter += Marshal.SizeOf(typeof(NetworkAPI.LOCALGROUP_MEMBERS_INFO_1));.
  4. You do not check the return value for errors.

修复这些错误,您的程序将正确运行.

Fix those errors and your program will run correctly.