[原]調用Win32 API netapi32.dll 實現UNC(網絡共享)連接的管理(一)
本章將使用Win32 API netapi32.dll 實現UNC的 連接授權, 斷開連接, 獲取UNC連接狀態三項功能.
一. 首先導入DLL文件:
#region Register Win32 DLL File netapi32.dll
//導入連接授權函數NetUseAdd
[DllImport("netapi32", CharSet = CharSet.Auto, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
static extern int NetUseAdd(
string UncServerName, // not used
int Level, // use info struct level 1 or 2
IntPtr Buf, // Buffer
ref int ParmError
);
//導入斷開連接函數NetUseDel
[DllImport("netapi32", CharSet = CharSet.Auto, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
static extern int NetUseDel(
string UncServerName, //not used
string UseName, //Network Resource what do you want to disconnect;
uint ForceCond //disconnect mode;
);
//導入Get連接狀態函數NetUseGetInfo
[DllImport("netapi32", CharSet = CharSet.Auto, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
static extern int NetUseGetInfo(
string UncServerName,
string UseName,
int Level,
ref IntPtr BufPtr);<PRE></PRE>
上面是已對參數類型做過轉換的針對C#寫的代碼, 有關函數原型的資料請參閱 MSDN,
接下對上面的各項參數做個簡單的介紹,足夠應付本章所講內容(更詳細的請參閱MSDN):
(按由上到下的順序介紹)
string UncServerName:
這個參數不用, Call的時候置空.
int Level:
代表采用那種struct將參數傳入函數, 1代表USE_INFO_1或2代表USE_INFO_2 , 智能在兩者之間選擇一種.
IntPtr Buf,
一個指向上面對應結構的指針(C#沒有指針,但這的作用很像指針,有知道更專業教法的朋友通知一聲),
ref int ParmError:
這個好像沒怎么用到,所以沒仔細研究, 請直接看SourceCode中的用法
uint ForceCond:
斷開連接時的模式, 共有三種:
private const uint USE_NOFORCE = 0; //Do not fail the disconnection if open files exist son the connection.
private const uint USE_FORCE = 1; //Fail the disconnection if open files exists on the connection.
private const uint USE_LOTS_OF_FORCE = 2; //Close any open files and delete the connection.
ref IntPtr BufPtr:
傳入GetNetUseInfo的Struct IntPrt對象, 負責將獲取的信息帶出來.
一下為實現三項功能的完整Source Code:
class WinNet
{
#region Define netapi32.dll need data structure
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct _USE_INFO_2
{
internal string ui2_local;
internal string ui2_remote;
//internal IntPtr ui2_password; // don't pass a string or StringBuilder here!!
internal string ui2_password;
internal uint ui2_status;
internal uint ui2_asg_type;
internal uint ui2_refcount;
internal uint ui2_usecount;
internal string ui2_username;
internal string ui2_domainname;
}
const uint USE_WILDCARD = 0xFFFFFFFF;
private const uint USE_NOFORCE = 0; //Do not fail the disconnection if open files exist son the connection.
private const uint USE_FORCE = 1; //Fail the disconnection if open files exists on the connection.
private const uint USE_LOTS_OF_FORCE = 2; //Close any open files and delete the connection.
private const uint USE_OK = 0; //The connection is valid.
private const uint USE_PAUSED = 1; // Paused by local workstation.
private const uint USE_SESSLOST = 2;// Disconnected.
private const uint USE_DISCONN = 3;// An error occurred.
private const uint USE_NETERR = 4;// A network error occurred.
private const uint USE_CONN = 5;// The connection is being made.
private const uint USE_RECONN = 6;// Reconnecting.
private static WinNet _instance = new WinNet();
public static WinNet Instance
{
get { return _instance; }
}
#endregion
#region Register Win32 DLL File netapi32.dll
[DllImport("netapi32", CharSet = CharSet.Auto, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
static extern int NetUseAdd(
string UncServerName, // not used
int Level, // use info struct level 1 or 2
IntPtr Buf, // Buffer
ref int ParmError
);
[DllImport("netapi32", CharSet = CharSet.Auto, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
static extern int NetUseDel(
string UncServerName, //not used
string UseName, //Network Resource what do you want to disconnect;
uint ForceCond //disconnect mode;
);
[DllImport("netapi32", CharSet = CharSet.Auto, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
static extern int NetUseGetInfo(
string UncServerName,
string UseName,
int Level,
ref IntPtr BufPtr);
#endregion
///
/// Establish a use record
///
///
///
///
///
public static bool UseRecord(string resource, string user, string password, string domain)
{
bool RtnValue = false;
int ret = 1;
int paramError = 0;
_USE_INFO_2 use2 = new _USE_INFO_2();
IntPtr pBuf = IntPtr.Zero;
//use2.ui2_password = IntPtr.Zero;
try
{
pBuf = Marshal.AllocHGlobal(Marshal.SizeOf(use2));
use2.ui2_local = null;
use2.ui2_asg_type = USE_WILDCARD;
use2.ui2_remote = resource;
//use2.ui2_password = Marshal.StringToHGlobalAuto(password);
use2.ui2_password = password;
use2.ui2_username = user;
use2.ui2_domainname = domain;
Marshal.StructureToPtr(use2, pBuf, true);
ret = NetUseAdd(null, 2, pBuf, ref paramError);
if (ret != 0)
{
throw new Exception(ErrorCodeHandler(ret));
}
RtnValue = true;
}
catch (Exception e)
{
throw e;
}
finally
{
Marshal.FreeHGlobal(pBuf);
}
return RtnValue;
}
///
/// Destroy a use record
///
///
public static void DeleteRecord(string resource)
{
int ret = 1;
try
{
ret = NetUseDel(null, resource, USE_LOTS_OF_FORCE);
if (ret != 0)
{
throw new Exception(ErrorCodeHandler(ret));
}
}
catch (Exception e)
{
throw e;
}
}
public static _USE_INFO_2 GetUseInfo(string resource)
{
int ret = 1;
_USE_INFO_2 ui2 = new _USE_INFO_2();
IntPtr pBuf = IntPtr.Zero;
try
{
pBuf = Marshal.AllocHGlobal(Marshal.SizeOf(new _USE_INFO_2()));
ret = NetUseGetInfo(null, resource, 2, ref pBuf);
if (ret != 0)
{
throw new Exception(ErrorCodeHandler(ret));
}
ui2 = (_USE_INFO_2)Marshal.PtrToStructure(pBuf, typeof(_USE_INFO_2));
}
catch
{
//throw e;
}
finally
{
Marshal.FreeHGlobal(pBuf);
}
return ui2;
}
#region Win32 ErrorCode Handler Code
public static string ErrorCodeHandler(int Win32ErrorCode)
{
string RtnMessage = string.Empty;
switch (Win32ErrorCode)
{
case 67:
RtnMessage = "找不到網絡名.";
break;
case 1219:
RtnMessage = "不允許一個用戶使用一個以上用戶名與一個服務器或共享資源的多重連接。中斷與此服務器或共享資源的所有連接,然后再試一次... ";
break;
case 2250:
RtnMessage = "此網絡連接不存在.";
break;
default:
RtnMessage = "Unkown Error Code.";
break;
}
return RtnMessage + "\r\nWin32 Error Code:" + Win32ErrorCode;
}
#endregion
}
關于API調用出項異常的處理, 這也是我在調試代碼的時候碰到的一個Bug, 順便在這個跟大家分享一下:
通常情況下Api調用出現異常的時候, 會通過GetLastError()方法來取得最后一個錯誤, 而在我實際執行的時候出現N(N>10)次錯誤,用GetLastError()得到的錯誤信息都是"重疊 I/O 操作在進行中", 四處求救沒得到答案, 后來我發現在每個API結束之后都會Return一個int類型的返回值: 0代表執行成功, 在本章常用到的已在ErrorCodeHandler()方法中進行了說明.
接下來有空的話計劃寫一個Windows UNC 共享管理的小程序, 其中將涉及到列出當前所有共享的各種狀態,及對所有共享的操作.
Remark:
上面的獲取共享狀態目前僅能判斷connection or disconnection, 應為我的項目對這個只要求這兩種狀態,所以在沒有進行詳細的分類.
浙公網安備 33010602011771號