English 中文(简体)
NetUserModalsGet() returns strings incorrectly for C#.NET
原标题:

EDIT: Yet another followup at https://stackoverflow.com/questions/1799742/shouldnt-netusermodalsget-tell-me-what-domain-a-machine-is-part-of-and-where

Thanks to Gonzalo s help, I m able to use the NetUserModalsGet() from C#. But there s still some kinks: the string members (usrmod1_primary and usrmod2_domain_name) come out messed up. Here s the code:

[DllImport("netapi32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern uint NetUserModalsGet(
    string server,
    int level,
    out IntPtr BufPtr
);

[DllImport("netapi32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern uint NetApiBufferFree(
    IntPtr bufptr
);

public struct USER_MODALS_INFO_0
{
    public uint usrmod0_min_passwd_len;
    public uint usrmod0_max_passwd_age;
    public uint usrmod0_min_passwd_age;
    public uint usrmod0_force_logoff;
    public uint usrmod0_password_hist_len;
};

public struct USER_MODALS_INFO_1
{
    public uint usrmod1_role;
    public string usrmod1_primary;
};

public struct USER_MODALS_INFO_2
{
    public string usrmod2_domain_name;
    public uint usrmod2_domain_id;
};

public struct USER_MODALS_INFO_3
{
    public uint usrmod3_lockout_duration;
    public uint usrmod3_lockout_observation_window;
    public uint usrmod3_lockout_threshold;
};

...

uint retVal;
IntPtr myBuf;
USER_MODALS_INFO_0 myInfo0 = new USER_MODALS_INFO_0();
USER_MODALS_INFO_1 myInfo1 = new USER_MODALS_INFO_1();
USER_MODALS_INFO_2 myInfo2 = new USER_MODALS_INFO_2();
USER_MODALS_INFO_3 myInfo3 = new USER_MODALS_INFO_3();

retVal = NetUserModalsGet("\\" + tbHost.Text, 0, out myBuf);
if (retVal == 0)
{
    myInfo0 = (USER_MODALS_INFO_0)Marshal.PtrToStructure(myBuf, typeof(USER_MODALS_INFO_0));
    myResults += String.Format("usrmod0_force_logoff={0}
usrmod0_max_passwd_age={1}
usrmod0_min_passwd_age={2}
usrmod0_min_passwd_len={3}
usrmod0_password_hist_len={4}
",
        myInfo0.usrmod0_force_logoff.ToString("X8"),
        myInfo0.usrmod0_max_passwd_age.ToString("X8"),
        myInfo0.usrmod0_min_passwd_age.ToString("X8"),
        myInfo0.usrmod0_min_passwd_len.ToString("X8"),
        myInfo0.usrmod0_password_hist_len.ToString("X8")
        );
}
myResults += String.Format("retVal={0}

", retVal);
retVal = NetApiBufferFree(myBuf);

retVal = NetUserModalsGet("\\" + tbHost.Text, 1, out myBuf);
if (retVal == 0)
{
    myInfo1 = (USER_MODALS_INFO_1)Marshal.PtrToStructure(myBuf, typeof(USER_MODALS_INFO_1));
    myResults += String.Format("usrmod1_primary={0}
usrmod1_role={1}
",
        myInfo1.usrmod1_primary,
        myInfo1.usrmod1_role.ToString("X8")
        );
}
myResults += String.Format("retVal={0}

", retVal);
retVal = NetApiBufferFree(myBuf);

retVal = NetUserModalsGet("\\" + tbHost.Text, 2, out myBuf);
if (retVal == 0)
{
    myInfo2 = (USER_MODALS_INFO_2)Marshal.PtrToStructure(myBuf, typeof(USER_MODALS_INFO_2));
    myResults += String.Format("usrmod2_domain_id={0}
usrmod2_domain_name={1}
",
        myInfo2.usrmod2_domain_id.ToString("X8"),
        myInfo2.usrmod2_domain_name
        );
}
myResults += String.Format("retVal={0}

", retVal);
retVal = NetApiBufferFree(myBuf);

retVal = NetUserModalsGet("\\" + tbHost.Text, 3, out myBuf);
if (retVal == 0)
{
    myInfo3 = (USER_MODALS_INFO_3)Marshal.PtrToStructure(myBuf, typeof(USER_MODALS_INFO_3));
    myResults += String.Format("usrmod3_lockout_duration={0}
usrmod3_lockout_observation_window={1}
usrmod3_lockout_threshold={2}
",
        myInfo3.usrmod3_lockout_duration.ToString("X8"),
        myInfo3.usrmod3_lockout_observation_window.ToString("X8"),
        myInfo3.usrmod3_lockout_threshold.ToString("X8")
        );
}
myResults += String.Format("retVal={0}

", retVal);
retVal = NetApiBufferFree(myBuf);

What I get as a result is:

usrmod0_force_logoff=FFFFFFFF
usrmod0_max_passwd_age=00375F00
usrmod0_min_passwd_age=00000000
usrmod0_min_passwd_len=00000000
usrmod0_password_hist_len=00000000
retVal=0

usrmod1_primary=
usrmod1_role=00000003
retVal=0

usrmod2_domain_id=08C409B0
usrmod2_domain_name=M
retVal=0

usrmod3_lockout_duration=0000012C
usrmod3_lockout_observation_window=0000012C
usrmod3_lockout_threshold=00000000
retVal=0

All of that except usrmod1_primary and usrmod2_domain_name makes sense. The tested machine is a member of a domain, whose name does start with an M. I smell some Unicode hijinx, but I can t see what s wrong.

最佳回答

The strings in your structs are marshaled as ANSI by default, but the Net* APIs work almost exclusively with Unicode strings. So apply the attribute

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]

to USER_MODALS_INFO_1 and _2 and your should be good.

A couple of other things:

  • There s no point in specifying SetLastError=true in yor DllImport attributes in this case, because NetUserModalsGet doesn t return error info via SetLastError (you get it in the return value).

  • USER_MODALS_INFO_2.usrmod2_domain_id is a pointer and therefore better modeled as an IntPtr (for x64 compatibility).

问题回答

暂无回答




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签