以下是我在调用时用的转换,你可以参考一下:
DWORD 用int
WORD 用Int16
指针用 out(要先声明) 或ref(要先初始化)
string 用string
数构或类时,用StructLayout声明结构处理
句柄用 IntPtr
DWORD 用int
WORD 用Int16
指针用 out(要先声明) 或ref(要先初始化)
string 用string
数构或类时,用StructLayout声明结构处理
句柄用 IntPtr
调试欢乐多
WM_MOUSEMOVE = $0200;
WM_LBUTTONDOWN = $0201;
WM_LBUTTONUP = $0202;
WM_LBUTTONDBLCLK = $0203;
WM_RBUTTONDOWN = $0204;
WM_RBUTTONUP = $0205;
WM_RBUTTONDBLCLK = $0206;
WM_MBUTTONDOWN = $0207;
WM_MBUTTONUP = $0208;
WM_MBUTTONDBLCLK = $0209;
WM_MOUSEWHEEL = $020A;
WM_VKEYTOITEM = $002E;
dword Uint32
float single
double double
int int32
char* string
BYTE byte
SHORT int
WORD uint
INT int
UINT uint
LONG int
BOOL int
DWORD uint
ULONG uint
CHAR char
LPSTR string或 System.StringBuilder 用 ANSI 修饰。
LPCSTR string或 System.StringBuilder 用 ANSI 修饰。
LPWSTR string或 System.StringBuilder 用 Unicode 修饰。
LPCWSTR string或 System.StringBuilder 用 Unicode 修饰。
FLOAT single
DOUBLE double
一楼就讲得差不多!
我试着给你写一点:
HANDLE System.IntPtr
DWORD int // 好像API调用里就这一种传值的简单类型,反正值传的全是32位,int 搞定
enum int // 也可以自定义枚举类型
LPDWORD ref int
LPCTSTR [MarshalAs(UnmanagedType.LPTStr)] string //字符串常量
LPTSTR [MarshalAs(UnmanagedType.LPTStr)] StringBuiler // 字符串缓冲区
LPstruct ref struct // struct 的 Layout 一定要设好,尤其是中间有字符串的情况
BYTE * [MarshalAs(UnmanagedType.LPArray)] byte[] // 其它数组也一样差不多了吧。
注意:
1、有字符串的时候 [DllImport("xxx.dll", CharSet = CharSet.Auto)]
2、字符串常量和字符串缓冲区一定要区别对待,要不然会破坏托管堆。字符串常量没什么说的了,字符串缓冲区的我举个例子:
StringBuilder sb = new StringBuilder(80); // 缓冲区大小
xxx(sb,...);
sb.ToString(); // 再这样得到返回值。
3、结构体要定义成[StructLayout(LayoutKind.Squential)] struct {...}
结构体中有字符串的还要这样:
[StructLayout(LayoutKind.Squential, CharSet = CharSet.Auto)]
struct
{
...
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] // 长度查MSDN自己定
string str;
...
}
结构体中字段的长度一定要对应好,比如BYTE要用byte,SHORT、WORD要用Int16,LONG、DWORD要用int,CHAR要用byte(都是8位,所以楼上xxdneu(xxd)的好像有点儿不对)
有些时候LayoutKind.Squential并不能解决问题,那样就得用LayoutKind.Explicit,然后每个结构成员添加FieldOffset属性。union 就可以这样处理。
4、最后,就是最麻烦的void *问题。
因为C#的类型检查实在是太强了,所有我也没一个很好的解决方案。
我的经验是在用到void*时,看我要传什么类型的值,那我就把它声明为那个类型的引用,比如ref int。不知上面说的有没有不妥的,在API或者其它非托管库调用有问题的,还可以和我联系
QQ:25738191 我们一起讨论一下。
[DllImport("kernel32.dll", SetLastError=true)]
static extern int GetShortPathName (
string lpszLongPath,
string lpszShortPath,
int cchBuffer)
我觉得就有问题,应该这样声明:
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetShortPathName (
[MarshalAs(UnmanagedType.LPTStr)]
string path,
[MarshalAs(UnmanagedType.LPTStr)]
StringBuilder shortPath,
int shortPathLength);.NET 中字符串类型是不可改变类型,这意味着它的值将永远保持不变。将字符串类型作为缓冲区使用至少会破坏由封送器在转换字符串时创建的临时缓冲区;严重时会破坏托管堆。StringBuilder就是被设计为用作缓冲区的。我的资料摘自MSDN
我还有一个难题:ScanSendCommand(HANDLE hScanner,
IN OUT LPTSTR pCmd_CmdResponse, IN OUT int* piLength);上述函数中的IN OUT 在C#中该用什么代替?有资料说用 [IN,OUT]代替? 但好象不对啊。