| 发表于:2007-03-22 14:51:275楼 得分:0 |
类成员的传递 同样只要类具有一个固定的类成员布局,你也可以传递一个类成员给一个不受管辖的动态链接库函数,下面的例子主要说明如何传递一个sequential顺序定义的mysystemtime类给user32.dll的getsystemtime函数, 函数用c/c++调用规范如下: void getsystemtime(systemtime* systemtime); 不像传值类型,类总是通过引用传递参数. [c#] [structlayout(layoutkind.sequential)] public class mysystemtime { public ushort wyear; public ushort wmonth; public ushort wdayofweek; public ushort wday; public ushort whour; public ushort wminute; public ushort wsecond; public ushort wmilliseconds; } class win32api { [dllimport( "user32.dll ")] public static extern void getsystemtime(mysystemtime st); } 回调函数的传递: 从受管辖的代码中调用大多数动态链接库函数,你只需创建一个受管辖的函数定义,然后调用它即可,这个过程非常直接。 如果一个动态链接库函数需要一个函数指针作为参数,你还需要做以下几步: 首先,你必须参考有关这个函数的文档,确定这个函数是否需要一个回调;第二,你必须在受管辖代码中创建一个回调函数;最后,你可以把指向这个函数的指针作为一个参数创递给dll函数,. 回调函数及其实现: 回调函数经常用在任务需要重复执行的场合,譬如用于枚举函数,譬如win32 api 中的enumfontfamilies(字体枚举), enumprinters(打印机), enumwindows (窗口枚举)函数. 下面以窗口枚举为例,谈谈如何通过调用enumwindow 函数遍历系统中存在的所有窗口 分下面几个步骤: 1. 在实现调用前先参考函数的声明 bool enumwindows(wndenumproc lpenumfunc, lparmam iparam) 显然这个函数需要一个回调函数地址作为参数. 2. 创建一个受管辖的回调函数,这个例子声明为代表类型(delegate),也就是我们所说的回调,它带有两个参数hwnd和lparam,第一个参数是一个窗口句柄,第二个参数由应用程序定义,两个参数均为整形。 当这个回调函数返回一个非零值时,标示执行成功,零则暗示失败,这个例子总是返回true值,以便持续枚举。 3. 最后创建以代表对象(delegate),并把它作为一个参数传递给enumwindows 函数,平台会自动地 把代表转化成函数能够识别的回调格式。 [c#] using system; using system.runtime.interopservices; public delegate bool callback(int hwnd, int lparam); public class enumreportapp { [dllimport( "user32 ")] public static extern int enumwindows(callback x, int y); public static void main() { callback mycallback = new callback(enumreportapp.report); enumwindows(mycallback, 0); } public static bool report(int hwnd, int lparam) { console.write( "窗口句柄为 "); console.writeline(hwnd); return true; } } 指针类型参数传递: 在windows api函数调用时,大部分函数采用指针传递参数,对一个结构变量指针,我们除了使用上面的类和结构方法传递参数之外,我们有时还可以采用数组传递参数。 下面这个函数通过调用getusername获得用户名 bool getusername( lptstr lpbuffer, // 用户名缓冲区 lpdword nsize // 存放缓冲区大小的地址指针 ); [dllimport( "advapi32.dll ", entrypoint= "getcomputername ", exactspelling=false, setlasterror=true)] static extern bool getcomputername ( [marshalas(unmanagedtype.lparray)] byte[] lpbuffer, [marshalas(unmanagedtype.lparray)] int32[] nsize ); 这个函数接受两个参数,char * 和int *,因为你必须分配一个字符串缓冲区以接受字符串指针,你可以使用string类代替这个参数类型,当然你还可以声明一个字节数组传递ansi字符串,同样你也可以声明一个只有一个元素的长整型数组,使用数组名作为第二个参数。上面的函数可以调用如下: byte[] str=new byte[20]; int32[] len=new int32[1]; len[0]=20; getcomputername (str,len); messagebox.show(system.text.encoding.ascii.getstring(str)); 最后需要提醒的是,每一种方法使用前必须在文件头加上: using system.runtime.interopservices; | | |
|