PInvoke NetLocalGroupGetMembers运行到FatalExecutionEngineError

时间:2015-11-26 10:11:23

标签: c# winapi pinvoke

我需要在C#中使用win32 NetLocalGroupGetMembers。我发现并测试了三种解决方案。所有三个都失败了FatalExecutionEngineError。该框架为.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);
    }
}

2 个答案:

答案 0 :(得分:3)

我看到以下错误:

  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. 您不检查错误的返回值。
  5. 修复这些错误,您的程序将正常运行。

答案 1 :(得分:0)

为了完整起见,这里是代码如何pinvoke NetLocalGroupGetMembers

我纠正了大卫建议的代码。 Martin Liversage也有一个我没有实施的建议。但它可能很有用。

如果您喜欢,请不要回复此答案,但 upvote Davids回答,发现错误。

参考api:

public static class NetworkAPI
{
    [DllImport("Netapi32.dll")]
    public extern static uint 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 IntPtr 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 IntPtr lgrmi1_sid;
        public int lgrmi1_sidusage;
        public string lgrmi1_name;
    }

    // documented in MSDN
    public const uint ERROR_ACCESS_DENIED = 0x0000005;
    public const uint ERROR_MORE_DATA = 0x00000EA;
    public const uint ERROR_NO_SUCH_ALIAS = 0x0000560;
    public const uint NERR_InvalidComputer = 0x000092F;

    // found by testing
    public const uint NERR_GroupNotFound = 0x00008AC;
    public const uint SERVER_UNAVAILABLE = 0x0006BA;
}

调用该函数:

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

    string groupName = "Administratoren";
    string computerName = null; // null for the local machine

    uint retVal = NetworkAPI.NetLocalGroupGetMembers(computerName, groupName, 1, out bufPtr, -1, out EntriesRead, out TotalEntries, out Resume);

    if(retVal != 0)
    {
        if (retVal == NetworkAPI.ERROR_ACCESS_DENIED) { Console.WriteLine("Access denied"); return; }
        if (retVal == NetworkAPI.ERROR_MORE_DATA) { Console.WriteLine("ERROR_MORE_DATA"); return; }
        if (retVal == NetworkAPI.ERROR_NO_SUCH_ALIAS) { Console.WriteLine("Group not found"); return; }
        if (retVal == NetworkAPI.NERR_InvalidComputer) { Console.WriteLine("Invalid computer name"); return; }
        if (retVal == NetworkAPI.NERR_GroupNotFound) { Console.WriteLine("Group not found"); return; }
        if (retVal == NetworkAPI.SERVER_UNAVAILABLE) { Console.WriteLine("Server unavailable"); return; }
        Console.WriteLine("Unexpected NET_API_STATUS: " + retVal.ToString()); 
        return;
    }

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

        for (int i = 0; i < EntriesRead; i++)
        {
            Members[i] = (NetworkAPI.LOCALGROUP_MEMBERS_INFO_1)Marshal.PtrToStructure(iter, typeof(NetworkAPI.LOCALGROUP_MEMBERS_INFO_1));

            //x64 safe
            iter += Marshal.SizeOf(typeof(NetworkAPI.LOCALGROUP_MEMBERS_INFO_1));

            Console.WriteLine(Members[i].lgrmi1_name);
        }
        NetworkAPI.NetApiBufferFree(bufPtr);
    }

}