C#中使用网络函数 (第一部分 用户函数)[翻译]


作者: Michael Bright
原文:http://www.csharphelp.com/archives2/archive439.html

本文将着重介绍Win32 API库中涉及网络管理的函数。首先我要讲一讲在.Net框架中管理用户的两个方法,第一种是Active Directory方法,这种方法要求你安装Active Directory。如果你打算管理一个小网络上的用户,或者一个未安装Active Directory的独立工作站,为了管理用户而安装Active Directory显得有些不值得。另外一种方法则是这篇文章所要讲到的——使用Win32 API库函数。在这篇文章中,我将介绍如何使用C# 添加、删除和修改用户和组,以及如何查询一个主机或网络的用户和网络信息。我们将用到以下函数
  • NetUserAdd
  • NetUserDel
  • NetUserGetInfo
  • NetUserSetInfo
  • NetUserChangePassword
  • NetUserEnum
  • NetUserGetLocalGroups

初始化

首先,正如许多C#开发者都知道的,我们要引入InteropServices名字空间到我们的工程中,以便能够访问dll中的函数。这可以通过如下的代码片断实现:

/ 代码片断 1.0

using System.Runtime.InteropServices;

代码结束

 

一旦我们拥有了访问权限,我们就可以将dll中的函数声明引入,我们将使用方法和结构体来关联它们。函数调用将在下面讨论:

使用C#添加一个用户

在网络函数中最重要的操作之一就是向一个网络或计算机添加一个用户。要通过C#添加一个用户,我们需要使用NetAddUser函数,该函数允许 我们添加用户到特定的计算机,如果我们将servername置空,用户将被添加到本地计算机。在下面的代码片断中,我们将看到如何声明和使用 NetUserAdd函数。我们在使用该函数前,需要定义一个结构体USER_INFO_1,来作为NetUserAdd的参数。

/ 代码片断 1.1 声明 

None.gif [DllImport( " Netapi32.dll " )]
None.gif
extern   static   int  NetUserAdd([MarshalAs(UnmanagedType.LPWStr)]  string  servername,  int  level,  ref  USER_INFO_1 buf,  int  parm_err);
代码结束

在使用代码时,你要注意到一点——尽管使用了最后一个int参数,你不需要知道返回的错误值。如果你一定要了解错误,需要修改代码。既然我们已经声明了我们要使用的外部API,我们应该声明结构体了。
ExpandedBlockStart.gifContractedBlock.gif/**////// 代码片断 1.2 结构体声明
None.gif

None.gif[StructLayout(LayoutKind.Sequential, CharSet
= CharSet.Unicode)]
None.gif
public struct
 USER_INFO_1
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif
public string
 usri1_name; 
InBlock.gif
public string
 usri1_password; 
InBlock.gif
public int
 usri1_password_age; 
InBlock.gif
public int
 usri1_priv; 
InBlock.gif
public string
 usri1_home_dir; 
InBlock.gif
public string
 comment; 
InBlock.gif
public int
 usri1_flags; 
InBlock.gif
public string
 usri1_script_path;
ExpandedBlockEnd.gif}
 
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**/
//// 代码结束
InBlock.gif

 

 

 

 

 


在声明之后,我们就可以在我们的程序中调用该函数。下面是NetUserAdd的如何使用的代码:
ExpandedBlockStart.gif ContractedBlock.gif /**/ ///// 代码片断 1.3 NetUserAdd
None.gif
None.gifUSER_INFO_1 NewUser 
=   new  USER_INFO_1();  //  Create an new instance of the USER_INFO_1 struct
None.gif

None.gifNewUser.usri1_name 
=   " UserTestOne " //  Allocates the username
None.gif
NewUser.usri1_password  =   " password " //  allocates the password
None.gif
NewUser.usri1_priv  =   1 //  Sets the account type to USER_PRIV_USER
None.gif
NewUser.usri1_home_dir  =   null //  We didn't supply a Home Directory
None.gif
NewUser.comment  =   " My First User Made through C# " //  Comment on the User
None.gif
NewUser.usri1_script_path  =   null //  We didn't supply a Logon Script Path
None.gif

None.gif
if (NetUserAdd( null  , 1  , ref  NewUser,  0 ) != 0 //  If the call fails we get a non-zero value
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gifMessageBox.Show(
"Error Adding User","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
ExpandedBlockEnd.gif}

ExpandedBlockStart.gifContractedBlock.gif
/**/ //// 代码结束
 

上面的代码将向当前的本地计算机添加用户,但是正如我说的,如果你想向网络上的另一台计算机添加用户,你可以将第一个参数中的null替换为那台计算机的名称。

使用C#删除一个用户


与前面的函数相比,删除用户的函数要简单得多。在上面的代码中,如果添加用户失败,返回非零值。与上面的代码相同,删除用户函数也是如此。要从本地计算机删除用户,你可以使用下面的代码片断。
ExpandedBlockStart.gif ContractedBlock.gif /**/ ///// 代码片断 1.4 声明
None.gif
None.gif[DllImport(
" Netapi32.dll " )]
None.gif
extern   static   int  NetUserDel([MarshalAs(UnmanagedType.LPWStr)]  string  servername, [MarshalAs(UnmanagedType.LPWStr)]  string  username);
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**/ //// 代码结束

NetUserDel的调用代码如下:
ExpandedBlockStart.gif ContractedBlock.gif /**/ ///// 代码片断 1.5 NetUserDel
None.gif
None.gif
if (NetUserDel( null  , " UserTestOne " ) != 0 //  If the call fails we get a non-zero value
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gifMessageBox.Show(
"Error Removing User","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
ExpandedBlockEnd.gif}
 
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**/ //// 代码结束
InBlock.gif

与NetUserAdd的调用一样,如果想删除远程计算机上的用户,需要将第一个参数替换为远程计算机名。

使用C#获得并修改用户信息

要在C#中获得用户信息,我们需要调用NetUserGetInfo,这个调用需要使用一个结构体来管理数据,并且用户信息会返回到结构体中。与 NetUserGetInfo相关的函数是NetUserSetInfo,你可以使用该函数修改你获得的用户信息。要注意的是,这两个函数相互依赖,例如 使用NetUserSetInfo函数,你必须知道用户的权限级别(privilege level),权限级别是通过NetUserGetInfo函数获得的。在下面的代码片断中,我们将看到这两个函数的声明,另外我们将再次使用 USER_INFO_1结构体。

ExpandedBlockStart.gif ContractedBlock.gif /**/ ///// 代码片断 1.6 声明
None.gif
None.gif[DllImport(
" Netapi32.dll " )]
None.gif
extern   static   int  NetUserGetInfo([MarshalAs(UnmanagedType.LPWStr)]  string  servername,[MarshalAs(UnmanagedType.LPWStr)]  string  username, int  level, out  IntPtr bufptr);
None.gif
None.gif[DllImport(
" Netapi32.dll " )]
None.gif
extern   static   int  NetUserSetInfo([MarshalAs(UnmanagedType.LPWStr)]  string  servername,[MarshalAs(UnmanagedType.LPWStr)]  string  username, int  level, ref  USER_INFO_1 buf,  int  error);
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**/ //// 代码结束

使用这些声明,我们可以十分轻松地获得和修改用户设置。在下面的代码中,我们将获得我们先前添加的用户UserTestOne的用户信息,并且我们将修改一些用户信息。

ExpandedBlockStart.gif ContractedBlock.gif /**/ ///// 代码片断 1.7 NetUserGetInfo
None.gif
None.gifIntPtr bufPtr;
None.gifUSER_INFO_1 User 
=   new  USER_INFO_1();
None.gif
if (NetUserGetInfo( null " Administrator " , 1 , out  bufPtr) != 0 )
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gifMessageBox.Show(
"Error Getting User Info","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
ExpandedBlockEnd.gif}

None.gifUser 
=  (USER_INFO_1)Marshal.PtrToStructure(bufPtr,  typeof (USER_INFO_1)); 
None.gifMessageBox.Show(
" Users Name:  "   +  User.usri1_name  +   "  Users Comments:  "   +  User.comment  +   "  Users Privilege Level:  "   +  User.usri1_priv);
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**/ //// 代码结束

在这个例子中,我们使用了Marshaling来获得数据,这是我唯一找到的有效方法。

ExpandedBlockStart.gif ContractedBlock.gif /**/ ///// 代码片断 1.8 NetUsetSetInfo
None.gif
None.gifUSER_INFO_1 Update 
=   new  USER_INFO_1();
None.gifUpdate.comment 
=   " This is Our C# Updated Comment " ;
None.gifUpdate.usri1_priv 
=   2 //  Note that this can only be obtained programmatically using NetUserGetInfo
None.gif
if (NetUserSetInfo( null " UserTestOne " , 1 , ref  Update, 0 ) != 0 )
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gifMessageBox.Show(
"Error Setting User Info","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**/ //// 代码结束

我们来总结一下,NetUserSetInfo依靠NetUserGetInfo正常工作。与其他的网络函数一样,如果你修改第一个参数为计算机名称,你将可以远程使用该函数。

使用c#修改用户密码

另外一个网络管理的重要函数是用来修改密码的。函数NetUserChangePassword是在我们能够提供当前用户的原密码的基础上进行工作的。声明NetUserChangePassword可以使用如下代码片断:
ExpandedBlockStart.gif ContractedBlock.gif /**/ ///// 代码片断 1.9 声明
None.gif
None.gif[DllImport(
" Netapi32.dll " )]
None.gif
extern   static   int  NetUserChangePassword([MarshalAs(UnmanagedType.LPWStr)]  string  domainname,[MarshalAs(UnmanagedType.LPWStr)]  string  username,[MarshalAs(UnmanagedType.LPWStr)]  string  oldpassword,[MarshalAs(UnmanagedType.LPWStr)]  string  newpassword);
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**/ //// 代码结束 
 

使用以上声明,如果我们知道用户原密码的话,我们就可以修改用户的密码。同样,我们可以远程使用该函数,只需要将null参数改为特定计算机的名称即可。

ExpandedBlockStart.gif ContractedBlock.gif /**/ ///// 代码片断 2.0 NetUserChangePassword
None.gif
None.gif
if (NetUserChangePassword( null " UserTestOne " " password " " ournewpassword " ) != 0 )
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gifMessageBox.Show(
"Error Changing User Password","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**/ //// 代码结束 

获得用户列表 

在管理一个网络时,有一份准确的网络用户列表或计算机列表是很重要的。如果要获得这样一份列表,我们必须使用NetUserEnum函数,该函数 返回用户的名称和相关数据到一个结构体。在这个例子中,我们打算使用USER_INFO_0结构体来传递值。由于我们只需要获得用户名,于是我就将 username元素添加到结构体的声明中。要注意的是,这个函数使用网络缓冲(network buffer),该缓冲必须被释放,以节省资源,我们可以使用NetAPIBufferFree函数。一旦我们进行了声明,我们就可以使用如下代码片断获 得用户列表。

ExpandedBlockStart.gif ContractedBlock.gif /**/ ///// 代码片断 2.1 声明
None.gif
None.gif[StructLayout(LayoutKind.Sequential, CharSet
= CharSet.Unicode)]
None.gif
public   struct  USER_INFO_0
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
public String Username;
ExpandedBlockEnd.gif}

None.gif
None.gif[DllImport(
" Netapi32.dll " )]
None.gif
extern   static   int  NetUserEnum([MarshalAs(UnmanagedType.LPWStr)]  string  servername,  int  level,  int  filter,  out  IntPtr bufptr,  int  prefmaxlen,  out   int  entriesread,  out   int  totalentries,  out   int  resume_handle);
None.gif
None.gif[DllImport(
" Netapi32.dll " )]
None.gif
extern   static   int  NetApiBufferFree(IntPtr Buffer);
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**/ //// 代码结束
None.gif

一旦我们进行了声明,我们就可以使用如下代码片断获得用户列表。

ExpandedBlockStart.gif ContractedBlock.gif /**/ ///// 代码片断 2.2 NetUserEnum
None.gif
None.gif
int  EntriesRead;
None.gif
int  TotalEntries;
None.gif
int  Resume;
None.gifIntPtr bufPtr;
None.gif
None.gifNetUserEnum(
null 0 2 out  bufPtr,  - 1 out  EntriesRead,  out  TotalEntries,  out  Resume);
None.gif
None.gif
if (EntriesRead >   0 )
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gifUSER_INFO_0[] Users 
= new USER_INFO_0[EntriesRead];
InBlock.gifIntPtr iter 
= bufPtr;
InBlock.gif
for(int i=0; i < EntriesRead; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifUsers[i] 
= (USER_INFO_0)Marshal.PtrToStructure(iter, typeof(USER_INFO_0)); 
InBlock.gifiter 
= (IntPtr)((int)iter + Marshal.SizeOf(typeof(USER_INFO_0)));
InBlock.gifMessageBox.Show(Users[i].Username);
ExpandedSubBlockEnd.gif}

InBlock.gifNetworkAPI.NetApiBufferFree(bufPtr);
ExpandedBlockEnd.gif}

ExpandedBlockStart.gifContractedBlock.gif
/**/ //// 代码结束

上面的代码通过MessageBox来枚举显示本地计算机上的用户。我们也可以替换null字符串参数指定一台远程计算机。 

识别用户组的关系

在这篇文章中我们要了解的最后一个函数是NetUserGetLocalGroups。这个函数允许我们判断一个用户属于哪些组,并且显示这些 组。与前面的函数相同,在使用该函数后,我们要清除网络缓冲。NetUserGetLocalGroups的声明同样需要一个结构体 LOCALGROUP_USERS_INFO_0,用于返回组名称。 

ExpandedBlockStart.gif ContractedBlock.gif /**/ ///// 代码片断 2.3 声明
None.gif [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
None.gif
public   struct  LOCALGROUP_USERS_INFO_0
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
public string groupname;
ExpandedBlockEnd.gif}

None.gif
None.gif[DllImport(
" Netapi32.dll " )]
None.gif
public   extern   static   int  NetUserGetLocalGroups([MarshalAs(UnmanagedType.LPWStr)]  string  servername,[MarshalAs(UnmanagedType.LPWStr)]  string  username,  int  level,  int  flags,  out  IntPtr bufptr,  int  prefmaxlen,  out   int  entriesread,  out   int  totalentries);
ExpandedBlockStart.gifContractedBlock.gif
/**/ //// 代码结束

通过上面的声明,我们可以使用与前面的函数类似的代码调用该函数。

ExpandedBlockStart.gif ContractedBlock.gif /**/ ///// 代码片断 2.4 NetUserGetLocalGroups
None.gif int  EntriesRead;
None.gif
int  TotalEntries;
None.gifIntPtr bufPtr;
None.gif
None.gifNetUserGetLocalGroups(
null " Administrator " , 0 , 0 , out  bufPtr, 1024 , out  EntriesRead,  out  TotalEntries);
None.gif
None.gif
if (EntriesRead >   0 )
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gifLOCALGROUP_USERS_INFO_0[] RetGroups 
= new LOCALGROUP_USERS_INFO_0[EntriesRead];
InBlock.gifIntPtr iter 
= bufPtr;
InBlock.gif
for(int i=0; i < EntriesRead; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifRetGroups[i] 
= (LOCALGROUP_USERS_INFO_0)Marshal.PtrToStructure(iter, typeof(LOCALGROUP_USERS_INFO_0)); 
InBlock.gifiter 
= (IntPtr)((int)iter + Marshal.SizeOf(typeof(LOCALGROUP_USERS_INFO_0)));
InBlock.gifMessageBox.Show(RetGroups[i].groupname);
ExpandedSubBlockEnd.gif}

InBlock.gifNetApiBufferFree(bufPtr);
ExpandedBlockEnd.gif}

ExpandedBlockStart.gifContractedBlock.gif
/**/ //// 代码结束

上面的例子返回用户Administrator所在的组。通过本文,我们了解了如何通过.Net平台调用方法使用与管理用户相关的网络函数。关于原作者[见原文]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值