Using DllImport to Call a Function in .NET
嚴競雄
JingxiongYan@hotmail.com
在.NET開發環境中 如果我們需要調用其他非託管庫中的函數 則需要使用DllImportAttribute這個屬性 在MSDN中 這個屬性是被這樣定義的
You can apply this attribute to methods.
The DllImportAttribute attribute provides the information needed to call a function exported from an unmanaged DLL. As a minimum requirement, you must supply the name of the DLL containing the entry point.
You apply this attribute directly to C# and C++ method definitions; however, the Visual Basic compiler emits this attribute when you use the Declare statement. For complex method definitions that include BestFitMapping, CallingConvention, ExactSpelling, PreserveSig, SetLastError, or ThrowOnUnmappableChar fields, you apply this attribute directly to Visual Basic method definitions.
可將該屬性應用於方法,DllImportAttribute 屬性提供對從非託管 DLL 匯出的函數進行調用所必需的資訊,作為最低要求,必須提供包含進入點的 DLL 的名稱。並且,MSDN給了我們一個具體的執行個體,在CSharp中利用DllImport調用User32.dll庫中的MessageBox方法
首先,我們先看一下在Windows XP Pro SP3的SDK中MessageBox方法是如何被定義的
/*
* MessageBox() Flags
*/
#define MB_OK 0x00000000L
#define MB_OKCANCEL 0x00000001L
#define MB_ABORTRETRYIGNORE 0x00000002L
#define MB_YESNOCANCEL 0x00000003L
#define MB_YESNO 0x00000004L
#define MB_RETRYCANCEL 0x00000005L
#if(WINVER >= 0x0500)
#define MB_CANCELTRYCONTINUE 0x00000006L
#endif /* WINVER >= 0x0500 */
#define MB_ICONHAND 0x00000010L
#define MB_ICONQUESTION 0x00000020L
#define MB_ICONEXCLAMATION 0x00000030L
#define MB_ICONASTERISK 0x00000040L
#if(WINVER >= 0x0400)
#define MB_USERICON 0x00000080L
#define MB_ICONWARNING MB_ICONEXCLAMATION
#define MB_ICONERROR MB_ICONHAND
#endif /* WINVER >= 0x0400 */
#define MB_ICONINFORMATION MB_ICONASTERISK
#define MB_ICONSTOP MB_ICONHAND
#define MB_DEFBUTTON1 0x00000000L
#define MB_DEFBUTTON2 0x00000100L
#define MB_DEFBUTTON3 0x00000200L
#if(WINVER >= 0x0400)
#define MB_DEFBUTTON4 0x00000300L
#endif /* WINVER >= 0x0400 */
#define MB_APPLMODAL 0x00000000L
#define MB_SYSTEMMODAL 0x00001000L
#define MB_TASKMODAL 0x00002000L
#if(WINVER >= 0x0400)
#define MB_HELP 0x00004000L // Help Button
#endif /* WINVER >= 0x0400 */
#define MB_NOFOCUS 0x00008000L
#define MB_SETFOREGROUND 0x00010000L
#define MB_DEFAULT_DESKTOP_ONLY 0x00020000L
#if(WINVER >= 0x0400)
#define MB_TOPMOST 0x00040000L
#define MB_RIGHT 0x00080000L
#define MB_RTLREADING 0x00100000L
#endif /* WINVER >= 0x0400 */
#ifdef _WIN32_WINNT
#if (_WIN32_WINNT >= 0x0400)
#define MB_SERVICE_NOTIFICATION 0x00200000L
#else
#define MB_SERVICE_NOTIFICATION 0x00040000L
#endif
#define MB_SERVICE_NOTIFICATION_NT3X 0x00040000L
#endif
#define MB_TYPEMASK 0x0000000FL
#define MB_ICONMASK 0x000000F0L
#define MB_DEFMASK 0x00000F00L
#define MB_MODEMASK 0x00003000L
#define MB_MISCMASK 0x0000C000L
WINUSERAPI
int
WINAPI
MessageBoxA(
__in_opt HWND hWnd,
__in_opt LPCSTR lpText,
__in_opt LPCSTR lpCaption,
__in UINT uType);
WINUSERAPI
int
WINAPI
MessageBoxW(
__in_opt HWND hWnd,
__in_opt LPCWSTR lpText,
__in_opt LPCWSTR lpCaption,
__in UINT uType);
#ifdef UNICODE
#define MessageBox MessageBoxW
#else
#define MessageBox MessageBoxA
#endif // !UNICODE
#if defined(_M_CEE)
#undef MessageBox
__inline
int
MessageBox(
HWND hWnd,
LPCTSTR lpText,
LPCTSTR lpCaption,
UINT uType
)
{
#ifdef UNICODE
return MessageBoxW(
#else
return MessageBoxA(
#endif
hWnd,
lpText,
lpCaption,
uType
);
}
#endif /* _M_CEE */
由此可知,MessageBox共有四個參數 我們只需要按照它所定義的類型跟著套用就行了
using System;
using System.Runtime.InteropServices;
class Example
{
// Use DllImport to import the Win32 MessageBox function.
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);
static void Main()
{
// Call the MessageBox function using platform invoke.
MessageBox(new IntPtr(0), "Hello World!", "Hello Dialog", 0);
}
}
怎麼樣,是不是很簡單呢,清楚了原理,現在我們就自己動手寫一個DllImportAttribute的應用吧 這個程式所需要完成的功能是向系統中添加一個使用者帳號,通常情況下,我們可以使用Netapi32.dll中的NetUserAdd和NetLocalGroupAdd這兩個函數來完成具體的操作,首先我們看下這兩個函數的原型
NET_API_STATUS NET_API_FUNCTION
NetUserAdd (
IN LPCWSTR servername OPTIONAL,
IN DWORD level,
IN LPBYTE buf,
OUT LPDWORD parm_err OPTIONAL
);
/*
................................
省略掉不相關的內容
*/
typedef struct _USER_INFO_1 {
LPWSTR usri1_name;
LPWSTR usri1_password;
DWORD usri1_password_age;
DWORD usri1_priv;
LPWSTR usri1_home_dir;
LPWSTR usri1_comment;
DWORD usri1_flags;
LPWSTR usri1_script_path;
}USER_INFO_1, *PUSER_INFO_1, *LPUSER_INFO_1;
NET_API_STATUS NET_API_FUNCTION
NetLocalGroupAdd (
IN LPCWSTR servername OPTIONAL,
IN DWORD level,
IN LPBYTE buf,
OUT LPDWORD parm_err OPTIONAL
);
typedef struct _LOCALGROUP_INFO_1 {
LPWSTR lgrpi1_name;
LPWSTR lgrpi1_comment;
}LOCALGROUP_INFO_1, *PLOCALGROUP_INFO_1, *LPLOCALGROUP_INFO_1;
好了 搞清楚了它的具體結構 現在就可以自己動手開發一個應用了 CSharp中的具體代碼如下
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System;
//Author:嚴競雄
namespace Task
{
class AddUserApplication
{
[DllImport("Netapi32.dll")]
extern static int NetUserAdd([MarshalAs(UnmanagedType.LPTStr)] string servername, int level, ref USER_INFO_1 buf, int parm_err);
[DllImport("Netapi32.dll")]
extern static int NetLocalGroupAdd([MarshalAs(UnmanagedType.LPTStr)] string servername, int level, ref LOCALGROUP_INFO_1 buf, int parm_err);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct USER_INFO_1
{
public string user_information_1_name;
public string user_information_1_password;
public string user_information_1_password_age;
public int user_information_1_priv;
public string user_information_1_home_dir;
public string comment;
public int user_information_1_flags;
public string user_information_1_script_path;
}
public struct LOCALGROUP_INFO_1
{
[MarshalAs(UnmanagedType.LPWStr)]public string Add_localgroup_1_name;
[MarshalAs(UnmanagedType.LPWStr)]public string Add_localgroup_1_comment;
}
public static void Main()
{
if ((Add_a_User_Account())==false )
{
Console.Write("Error: Adding User Failed Sorry");
}
else
Add_a_UserAccount_to_LocalGroup();
}
//public static void Usage()
//{
//Console.Write("------------------------------------");
//Console.Write("Code BY Delphiscn");
//Console.Write("Email:Delphiscn@gmail.com");
//Console.Write("Blog: http://blog.csdn.net/delphiscn");
//Console.Write("------------------------------------");
//}
public static Boolean Add_a_User_Account()
{
USER_INFO_1 AddUser = new USER_INFO_1();
AddUser.user_information_1_name = "Delphiscn";
AddUser.user_information_1_password = "EvilOctal";
AddUser.user_information_1_priv = 1;
AddUser.user_information_1_home_dir = null;
AddUser.comment = "Add a User Named Delphiscn";
AddUser.user_information_1_script_path = null;
if (NetUserAdd(null, 1, ref AddUser, 0) != 0)
{
Console.Write("Error: Adding User Failed");
return false;
}
return true;
}
public static void Add_a_UserAccount_to_LocalGroup()
{
LOCALGROUP_INFO_1 AddToGroup= new LOCALGROUP_INFO_1();
AddToGroup.Add_localgroup_1_name = "Administrators";
AddToGroup.Add_localgroup_1_comment = "Add a User to the Administrators Group";
if (NetLocalGroupAdd(null, 1, ref AddToGroup , 0) != 0)
{
Console.Write("Adding To the Administrators Group Failed");
}
}
}
}
在Windows XP Pro SP3 VS 2008 SP1 .NET3.5環境下測試通過