作者:Michael Bright
原文:http://www.csharphelp.com/archives2/archive439.html
翻譯作者: Tony Qu
翻譯原文:http://www.cnblogs.com/tonyqus/archive/2004/12/26/82120.aspx
本文將着重介紹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 聲明
extern static int NetUserAdd([MarshalAs(UnmanagedType.LPWStr)] string servername, int level, ref USER_INFO_1 buf, int parm_err);
//// 代碼結束
在使用代碼時,你要注意到一點——儘管使用了最後一個int參數,你不需要知道返回的錯誤值。如果你一定要了解錯誤,需要修改代碼。既然我們已經聲明瞭我們要使用的外部API,我們應該聲明結構體了。
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct USER_INFO_1
{
public string usri1_name;
public string usri1_password;
public int usri1_password_age;
public int usri1_priv;
public string usri1_home_dir;
public string comment;
public int usri1_flags;
public string usri1_script_path;
}
//// 代碼結束
在聲明之後,我們就可以在我們的程序中調用該函數。下面是NetUserAdd的如何使用的代碼:
USER_INFO_1 NewUser = new USER_INFO_1(); // Create an new instance of the USER_INFO_1 struct
NewUser.usri1_name = "UserTestOne"; // Allocates the username
NewUser.usri1_password = "password"; // allocates the password
NewUser.usri1_priv = 1; // Sets the account type to USER_PRIV_USER
NewUser.usri1_home_dir = null; // We didn't supply a Home Directory
NewUser.comment = "My First User Made through C#"; // Comment on the User
NewUser.usri1_script_path = null; // We didn't supply a Logon Script Path
if(NetUserAdd(null ,1 ,ref NewUser, 0)!=0) // If the call fails we get a non-zero value
{
MessageBox.Show("Error Adding User","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
//// 代碼結束
上面的代碼將向當前的本地計算機添加用戶,但是正如我說的,如果你想向網絡上的另一臺計算機添加用戶,你可以將第一個參數中的null替換爲那臺計算機的名稱。
使用C#刪除一個用戶
與前面的函數相比,刪除用戶的函數要簡單得多。在上面的代碼中,如果添加用戶失敗,返回非零值。與上面的代碼相同,刪除用戶函數也是如此。要從本地計算機刪除用戶,你可以使用下面的代碼片斷。
[DllImport("Netapi32.dll")]
extern static int NetUserDel([MarshalAs(UnmanagedType.LPWStr)] string servername, [MarshalAs(UnmanagedType.LPWStr)] string username);
//// 代碼結束
NetUserDel的調用代碼如下:
if(NetUserDel(null ,"UserTestOne")!=0) // If the call fails we get a non-zero value
{
MessageBox.Show("Error Removing User","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
//// 代碼結束
與NetUserAdd的調用一樣,如果想刪除遠程計算機上的用戶,需要將第一個參數替換爲遠程計算機名。
使用C#獲得並修改用戶信息
要在C#中獲得用戶信息,我們需要調用NetUserGetInfo,這個調用需要使用一個結構體來管理數據,並且用戶信息會返回到結構體中。與 NetUserGetInfo相關的函數是NetUserSetInfo,你可以使用該函數修改你獲得的用戶信息。要注意的是,這兩個函數相互依賴,例如使用NetUserSetInfo函數,你必須知道用戶的權限級別(privilege level),權限級別是通過NetUserGetInfo函數獲得的。在下面的代碼片斷中,我們將看到這兩個函數的聲明,另外我們將再次使用 USER_INFO_1結構體。
[DllImport("Netapi32.dll")]
extern static int NetUserGetInfo([MarshalAs(UnmanagedType.LPWStr)] string servername,[MarshalAs(UnmanagedType.LPWStr)] string username,int level,out IntPtr bufptr);
[DllImport("Netapi32.dll")]
extern static int NetUserSetInfo([MarshalAs(UnmanagedType.LPWStr)] string servername,[MarshalAs(UnmanagedType.LPWStr)] string username,int level,ref USER_INFO_1 buf, int error);
//// 代碼結束
使用這些聲明,我們可以十分輕鬆地獲得和修改用戶設置。在下面的代碼中,我們將獲得我們先前添加的用戶UserTestOne的用戶信息,並且我們將修改一些用戶信息。
IntPtr bufPtr;
USER_INFO_1 User = new USER_INFO_1();
if(NetUserGetInfo(null, "Administrator",1,out bufPtr)!=0)
{
MessageBox.Show("Error Getting User Info","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
User = (USER_INFO_1)Marshal.PtrToStructure(bufPtr, typeof(USER_INFO_1));
MessageBox.Show("Users Name: " + User.usri1_name + " Users Comments: " + User.comment + " Users Privilege Level: " + User.usri1_priv);
//// 代碼結束
在這個例子中,我們使用了Marshaling來獲得數據,這是我唯一找到的有效方法。
USER_INFO_1 Update = new USER_INFO_1();
Update.comment = "This is Our C# Updated Comment";
Update.usri1_priv = 2; // Note that this can only be obtained programmatically using NetUserGetInfo
if(NetUserSetInfo(null, "UserTestOne",1,ref Update,0)!=0)
{
MessageBox.Show("Error Setting User Info","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
//// 代碼結束
我們來總結一下,NetUserSetInfo依靠NetUserGetInfo正常工作。與其他的網絡函數一樣,如果你修改第一個參數爲計算機名稱,你將可以遠程使用該函數。
使用c#修改用戶密碼
另外一個網絡管理的重要函數是用來修改密碼的。函數NetUserChangePassword是在我們能夠提供當前用戶的原密碼的基礎上進行工作的。聲明NetUserChangePassword可以使用如下代碼片斷:
[DllImport("Netapi32.dll")]
extern static int NetUserChangePassword([MarshalAs(UnmanagedType.LPWStr)] string domainname,[MarshalAs(UnmanagedType.LPWStr)] string username,[MarshalAs(UnmanagedType.LPWStr)] string oldpassword,[MarshalAs(UnmanagedType.LPWStr)] string newpassword);
//// 代碼結束
使用以上聲明,如果我們知道用戶原密碼的話,我們就可以修改用戶的密碼。同樣,我們可以遠程使用該函數,只需要將null參數改爲特定計算機的名稱即可。
if(NetUserChangePassword(null, "UserTestOne", "password", "ournewpassword")!=0)
{
MessageBox.Show("Error Changing User Password","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
//// 代碼結束
獲得用戶列表
在管理一個網絡時,有一份準確的網絡用戶列表或計算機列表是很重要的。如果要獲得這樣一份列表,我們必須使用NetUserEnum函數,該函數返回用戶的名稱和相關數據到一個結構體。在這個例子中,我們打算使用USER_INFO_0結構體來傳遞值。由於我們只需要獲得用戶名,於是我就將 username元素添加到結構體的聲明中。要注意的是,這個函數使用網絡緩衝(network buffer),該緩衝必須被釋放,以節省資源,我們可以使用NetAPIBufferFree函數。一旦我們進行了聲明,我們就可以使用如下代碼片斷獲得用戶列表。
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct USER_INFO_0
{
public String Username;
}
[DllImport("Netapi32.dll")]
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);
[DllImport("Netapi32.dll")]
extern static int NetApiBufferFree(IntPtr Buffer);
//// 代碼結束
一旦我們進行了聲明,我們就可以使用如下代碼片斷獲得用戶列表。
int EntriesRead;
int TotalEntries;
int Resume;
IntPtr bufPtr;
NetUserEnum(null, 0, 2, out bufPtr, -1, out EntriesRead, out TotalEntries, out Resume);
if(EntriesRead> 0)
{
USER_INFO_0[] Users = new USER_INFO_0[EntriesRead];
IntPtr iter = bufPtr;
for(int i=0; i < EntriesRead; i++)
{
Users[i] = (USER_INFO_0)Marshal.PtrToStructure(iter, typeof(USER_INFO_0));
iter = (IntPtr)((int)iter + Marshal.SizeOf(typeof(USER_INFO_0)));
MessageBox.Show(Users[i].Username);
}
NetworkAPI.NetApiBufferFree(bufPtr);
}
//// 代碼結束
上面的代碼通過MessageBox來枚舉顯示本地計算機上的用戶。我們也可以替換null字符串參數指定一臺遠程計算機。
識別用戶組的關係
在這篇文章中我們要了解的最後一個函數是NetUserGetLocalGroups。這個函數允許我們判斷一個用戶屬於哪些組,並且顯示這些組。與前面的函數相同,在使用該函數後,我們要清除網絡緩衝。NetUserGetLocalGroups的聲明同樣需要一個結構體 LOCALGROUP_USERS_INFO_0,用於返回組名稱。
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct LOCALGROUP_USERS_INFO_0
{
public string groupname;
}
[DllImport("Netapi32.dll")]
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);
//// 代碼結束
通過上面的聲明,我們可以使用與前面的函數類似的代碼調用該函數。
int EntriesRead;
int TotalEntries;
IntPtr bufPtr;
NetUserGetLocalGroups(null, "Administrator",0,0,out bufPtr,1024,out EntriesRead, out TotalEntries);
if(EntriesRead> 0)
{
LOCALGROUP_USERS_INFO_0[] RetGroups = new LOCALGROUP_USERS_INFO_0[EntriesRead];
IntPtr iter = bufPtr;
for(int i=0; i < EntriesRead; i++)
{
RetGroups[i] = (LOCALGROUP_USERS_INFO_0)Marshal.PtrToStructure(iter, typeof(LOCALGROUP_USERS_INFO_0));
iter = (IntPtr)((int)iter + Marshal.SizeOf(typeof(LOCALGROUP_USERS_INFO_0)));
MessageBox.Show(RetGroups[i].groupname);
}
NetApiBufferFree(bufPtr);
}
//// 代碼結束
上面的例子返回用戶Administrator所在的組。通過本文,我們瞭解瞭如何通過.Net平臺調用方法使用與管理用戶相關的網絡函數。