.net 互操作之p/invoke- 数据封送(字符串版本-ANSI和UniCode,返回错误码,回调函数,常量)(6)
2010-08-26 23:52 Clingingboy 阅读(932) 评论(0) 编辑 收藏 举报处理字符串的函数(ANSI和UniCode版本)
非托管函数后缀名A表示ANSI,W表示宽字符(Unicode),如GetUserName有GetUserNameA和GetUserNameW
p/inlvoke设置方式
1.设置CharSet
DllImport默认为Ansi
[DllImport("advapi32.dll", CharSet = CharSet.Ansi)]
2.设置EntryPoint
[DllImport("advapi32.dll", EntryPoint = "GetUserNameA")]
3.自动行为
当设置CharSet 会自动去寻找后缀名为W和A的函数,设置ExactSpelling为true时,需要保证生命函数与非托管函数名是一致的
[DllImport("advapi32.dll", EntryPoint = "GetUserNameA", CharSet = CharSet.Auto,ExactSpelling=true)]
4.自动系统平台设置
当CharSet 设置为Auto时,会根据系统来寻找函数封送
[DllImport("advapi32.dll", EntryPoint = "GetUserNameW", CharSet = CharSet.Auto)]
错误码
首先要设置SetLastError=true
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
两种处理方式
1.使用Win32 API FormatMessage
public class FormatErrorCode { const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100; const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; //Win32 API //DWORD WINAPI FormatMessage( // __in DWORD dwFlags, // __in_opt LPCVOID lpSource, // __in DWORD dwMessageId, // __in DWORD dwLanguageId, // __out LPTSTR lpBuffer, // __in DWORD nSize, // __in_opt va_list* Arguments //); [DllImport("kernel32.dll")] public static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, ref IntPtr lpMsgBuf, uint nSize, IntPtr Arguments); //Win32 API //HLOCAL WINAPI LocalFree( // __in HLOCAL hMem //); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr LocalFree(IntPtr hMem); public static string GetLastErrorMsg() { int lastError = Marshal.GetLastWin32Error(); IntPtr lpMsgBuf = IntPtr.Zero; uint dwChars = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, IntPtr.Zero, (uint)lastError, 0, ref lpMsgBuf, 0, IntPtr.Zero); if (dwChars == 0) { return ""; } string errorMsg = Marshal.PtrToStringAnsi(lpMsgBuf); // 释放内存 LocalFree(lpMsgBuf); return errorMsg; } }
测试
public static void TestErrorMsgByWin32Exception() { GetFileAttributes("FileNotFoundDemo.txt"); // error code获得最后一次获得的错误
int lastErrorCode = Marshal.GetLastWin32Error(); // 将Win32的错误码转化成一个用户友好的托管异常 Win32Exception win32Exception = new Win32Exception(lastErrorCode); Console.WriteLine("GetFileAttributes last win32 error message: {0}", win32Exception.Message); }
2.使用托管的Win32Exception
public static void TestErrorMsgByWin32ExceptionDefault() { // 试图获得一个不存在的文件的属性 GetFileAttributes("FileNotFoundDemo.txt"); // 使用Win32的缺省构造函数,使其自动调用Marshal.GetLastWin32Error()来 // 将Win32的错误码转化成一个用户友好的托管异常 Win32Exception win32Exception = new Win32Exception(); Console.WriteLine("GetFileAttributes last win32 error message: {0}", win32Exception.Message); }
明显的第2种简单很多,会自动去调用Marshal.GetLastWin32Error()方法
处理回调函数
定义常量
这个比较麻烦,烦是Win32 API 定义的常量,想使用的话,必须重新定义一遍,所以找到常量的值是关键.可以讲一组功能相近的常量定义成枚举
[Flags] public enum FileAttributeFlags : uint { //文件属性标志 FILE_ATTRIBUTE_READONLY = 0x00000001, FILE_ATTRIBUTE_HIDDEN = 0x00000002, FILE_ATTRIBUTE_SYSTEM = 0x00000004, FILE_ATTRIBUTE_DIRECTORY = 0x00000010, FILE_ATTRIBUTE_ARCHIVE = 0x00000020, FILE_ATTRIBUTE_DEVICE = 0x00000040, FILE_ATTRIBUTE_NORMAL = 0x00000080, FILE_ATTRIBUTE_TEMPORARY = 0x00000100, FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200, FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400, FILE_ATTRIBUTE_COMPRESSED = 0x00000800, FILE_ATTRIBUTE_OFFLINE = 0x00001000, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000, FILE_ATTRIBUTE_ENCRYPTED = 0x00004000, FILE_ATTRIBUTE_VALID_FLAGS = 0x00007fb7, FILE_ATTRIBUTE_VALID_SET_FLAGS = 0x000031a7, }