多语言展示
当前在线:1139今日阅读:84今日分享:32

VB与API学习 经验分享

VB与API学习关于API初学者的教程第一篇啥是API?API(Advanced Programmers Interface,高档程序员接口)(注:API实习是指Application Programming Interface,应用程序编程接口;此处疑为原文过失,不过在VB中也能够这么说吧!)是一套用来操控Windows的各个部件(从桌面的外观到位一个新进程分配的内存)的外观和行为的一套预先界说的Windows函数.用户的每个动作都会引发一个或几个函数的作业以Windows通知发作了啥.这在某种程度上很象Windows的天然代码.其他的言语仅仅供给一种能主动而且更简略的拜访API的办法.VB在这方面作了许多作业.它彻底躲藏了API而且供给了在Windows环境下编程的一种彻底不相同的办法.这也就是说,你用VB写出的每行代码都会被VB转换为API函数传递给Windows.例如,Form1.Print...VB 将会以必定的参数(你的代码中供给的,或是默许参数)调用TextOut 这个API函数.相同,当你点击窗体上的一个按钮时,Windows会发送一个音讯给窗体(这关于你来说是躲藏的),VB获取这个调用并经过剖析后生成一个特定作业(Button_Click).API函数包括在Windows体系目录下的动态联接库文件中(如User32.dll,GDI32.dll,Shell32.dll...).API 声明正如在'啥是API'中所说,API函数包括在坐落体系目录下的DLL文件中.你能够自个输入API函数的声明,但VB供给了一种更简略的办法,即运用API Text Viewer.要想在你的工程中声明API函数,只需作业API Text Viewer,翻开Win32api.txt(或.MDB若是你现已把它转换成了数据库的话,这样能够加疾速度.注:微软的这个文件有许多的短少,你能够试一下本站供给下载的api32.txt),挑选'声明',找到所需函数,点击'增加(Add)'并'复制(Copy)',然后张贴(Paste)到你的工程里.运用预界说的常量和类型也是相同的办法.你将会遇到一些问题:假定你想在你的窗体模块中声明一个函数.张贴然后作业,VB会通知你:编译过失...Declare 句子不允许作为类或政策模块中的 Public 成员...看起来很蹩脚,其实你需求做的仅仅在声明前面增加一个Private(如 Private Declare Function...).--不要忘了,可是这将使该函数只在该窗体模块可用.在有些状况下,你会得到'不明确的称谓'这样的提示,这是由于函数.常量或其他的啥东西共用了一个称谓.由于绝大多数的函数(也能够是全部,我没有验证过)都进行了别号化,亦即意味着你能够经过Alias子句运用其它的而不是他们原有的称谓,你只需简略地改动一下函数称谓而它仍然能够正常作业.你能够经过查看VB的Declare句子帮助主题来获取有关Alias的具体阐明.音讯(Messages)好了,如今你现已晓得啥是API函数了,但你也必定听说过音讯(若是你还没有,你很快就会)而且想晓得它是啥.音讯是Windows通知你的程序发作了哪些作业或需求实施特定操作的根柢办法.例如,当用户点击一个按钮,移动鼠标,或是向文本框中键入文字时,一条音讯就会被发送给你的窗体.全部发送的音讯都有四个参数--一个窗口句柄(hwnd),一个音讯编号(msg)还有两个32位长度(Long)的参数.hwnd即要承受音讯的一个窗口的句柄,msg即音讯的标识符(编号).该标识符是指引发音讯的动作类型(如移动鼠标),别的两个参数是该音讯的附加参数(例如当鼠标移动韶光标的当时方位)可是,当音讯发送给你时你为啥看不到呢--就象有人在偷你的信相同?请先别动火,让我通知你.小偷其实是Visual Basic.但它并没有偷走你的信,而是在阅读了之后挑出重要的以一种好的办法通知你.这种办法就是你代码中的作业(Event).这样,当用户在你的窗体上移动鼠标时,Windows会发送一条WM_MOUSEMOVE音讯给你的窗口,VB得到这条音讯以及它的参数并作业你在作业MouseMove中的代码,一起VB会把这条音讯的第二个32位数(它包括了x,y坐标,单位为像素(Pixel),每个位16位)转换为两个单精度数,单位为缇(Twip).如今,若是你需求光标坐标的像素标明,可是VB现已把它转换成了缇,因而你需求从头把它转换为以像素为单位.在这里,Windows给了你所需求的,但VB'好心肠'进行了转换而使你不得不从头转换.你能够会问--我莫非不能自个接纳音讯吗?答案是必定的,你能够运用一种叫做子类处置(Subclass)的办法.但你除非有必要不然最佳不要运用,由于这与VB的安全程序设计有一点点的违反.(注:子类处置的确有很大的危险,但若是运用稳妥,是很有用途的.不过有一点必定要注意,即千万不要运用VB的断点调试功用,这能够会致使VB溃散!)需求抵偿阐明的是:你能够发送音讯给你自个的窗口或其他的窗口,只需调用SendMessage或PostMessage(SendMessage会使接遭到音讯的窗口立刻处置音讯,而PostMessage是把音讯发送到一个称为音讯部队的部队中去,等待处置(它将会在该音讯处置完后回来,例如有些推迟)).你有必要拟定承受音讯的窗口的句柄,欲发送音讯的编号(全部的音讯的编号均为常量,你能够经过API Text Viewer查得)以及两个32位的参数.(二)关于API初学者的教程第二篇Windows的一些格外之处这个主题是要通知你Windows 的一些与在VB中的不相同的细节Windows经过句柄(Handle)辨认每个窗体,控件,菜单,菜单项或其他任何你能想得到的东西.当你的程序作业时,它所包括的每个部件都有一个仅有断定的句柄用来同其他的部件相差异.例如,某个按钮得句柄就与其他部件不相同,当你想要经过API来实施有关该按钮的某种操作时就有必要运用这个句柄.从哪儿得到它呢?VB 为每个具有Windows句柄的控件都供给了Hwnd特征来标明其句柄.Windows 运用像素(Pixel)而不是缇(Twip).因而,把触及API函数调用的控件的ScaleMode特征设为3--(Pixel)是个不错的主见,这样你能够经过ScaleXXX特征得到它们的国际单位值.虽然这样,你能够有时仍需求进行从Twip到Pixel的转换(反之亦然),你能够经过Screen政策的TwipsPerPixelX和TwipsPerPixelY来完毕.举例如下:PixelXValue=TwipXValue\Screen.TwipsPerPixelXPixelYValue=TwipYValue\Screen.TwipsPerPixelYTwipXValue=PixelXValue*Screen.TwipsPerPixelXTwipYValue=PixelYValue*Screen.TwipsPerPixelY我并没有在实习中见到过TwipsPerPixelX 和 TwipsPerPixelY 的值有啥不相同,但你最佳是把它们差异开来而不是混用,这至少是一种好的程序设计特性.别的需求注意的是,这里用的是' \ '(整除) 而不是 ' / ' ,这是由于像素值有必要是整数.别的需求说到的是,Windows函数顶用到了不相同的坐标体系,因而需求注意.完毕要注意的是,一旦你运用了API 函数,VB就能够不再可靠了---API调用中一个简略的语法过失就会致使VB 溃散!(请常常保管您的工程).VB 并不能辨认API调用中的过失,因而一旦你的程序呈现失常,要先查看API调用---是不是短少 ByVal,或许是过失的类型,参数等等.从哪里得到有关函数的阐明?这个主题不会通知你如何经过API函数改动按钮文字或如何疾速查找一个文件.这不是一个API函数文档.为了得到有关函数的阐明,你需求SDK帮助或微软的SDK文档(至少有40M---我如何能够放在这里?).这些SDK帮助一般都包括在Borland Dephli 3.0 开发包或许MS Visual C++中.到网上去或找您的兄弟要一个,版别越新越好注意Win3.x 的SDK 帮助对你并没有用,由于许多函数现已过于陈腐乃至丢掉不必,虽然他们中的大多数由于与 Windows95兼容而仍然存在.API参数类型若是你现已有了一个SDK帮助,你必定主见到了函数的回来之或参数有许多新鲜的类型如VOID,LPCSTR, 和DWORD.若是你对C言语对比晓得的话,那你必定晓得它们的意思.关于其他不晓得C言语的人,这里有一张摘自 VB Books Online(标题是:C言语声明到Visual Basic的转换)C 言语数据类型 在VB中的声明 Call withATOM ByVal variable As Integer An expression that evaluates to an IntegerBOOL ByVal variable As Long An expression that evaluates to a LongBYTE ByVal variable As Byte An expression that evaluates to a ByteCHAR ByVal variable As Byte An expression that evaluates to a ByteCOLORREF ByVal variable As Long An expression that evaluates to a LongDWORD ByVal variable As Long An expression that evaluates to a LongHWND, HDC,HMENU,etc.(Windows handles) ByVal variable As Long An expression that evaluates to a LongINT, UINT ByVal variable As Long An expression that evaluates to a LongLONG ByVal variable As Long An expression that evaluates to a LongLPARAM ByVal variable As Long An expression that evaluates to a LongLPDWORD variable As Long An expression that evaluates to a LongLPINT, LPUINT variable As Long An expression that evaluates to a LongLPRECT variable As type Any variable of that user-defined typeLPSTR, LPCSTR ByVal variable As String An expression that evaluates to a StringLPVOID variable As Any Any variable (use ByVal when passing a string)LPWORD variable As Integer An expression that evaluates to an IntegerLRESULT ByVal variable As Long An expression that evaluates to a LongNULL As Any orByVal variable As Long ByVal Nothing or ByVal 0& or vbNullString  SHORT ByVal variable As Integer An expression that evaluates to an IntegerVOID Sub procedure Not applicableWORD ByVal variable As Integer An expression that evaluates to an IntegerWPARAM ByVal variable As Long An expression that evaluates to a Long注释:你大概注意到了BOOL类型(Boolean)求出的值为Long而不是Boolean.因而0标明'假'(False),其他任何值标明'真'(True).HWND,HDC,HMENU,etc.---etc.指其他全部与于前面所述类似的类型.它们都以'H'开端来标明不相同政策的句柄.举例来说,HBITMAP标明一副位图的句柄,HBRUSH标是一个刷子的句柄等等.它们均为Long而且要按值传递(ByVal).相同要注意LPVOID被声明为Any型变量,这篇文章将会有独立的一个主题用来论说Any类型.有些类型以'LP'开端.LP 是Long Pointer的缩写.因而LPWORD实习标明数据所存的内存地址.不过,你并没有必要调用某个函数来获取这个地址.当你按引证(ByRef)传递参数时,你实习上传递的就是它的地址.在这里你只需记住:若是某个参数的类型以'LP'开端,大概按引证(ByRef)传递.趁便说一句,LPARAM 与 Lparam 很类似但不是Lparam,Lparam不是一个指针,在这里你有必要传递它的实在值,因而要按值(ByVal)传递.NULL也是一种新鲜的类型.你能够从 VB 中晓得到有关它的描绘,这里我不去议论它.按你需求的办法传递它吧,在大多数状况下,能够用 ByVal 0& 或 vbNullString.完毕,VOID是用来指那些没有回来值的函数的.API中没有SUBs,这就是它们的象征.只需记住:若是一个函数被声明为VOID ,你有必要在 VB 中把它声明为 SUB.(三) 关于API初学者的教程第三篇Any有些音讯的参数声明为Any.这标明该参数是一种可变的类型(你能够以整型,字符串,用户自界说或其他的类型来传递).这有一个这样的比如:Public Declare Function SendMessage Lib 'User32' Alias 'SendMessageA' ByVal Hwnd as Long, ByVal wMsg as Long, ByVal wParam as Long, lParam as Any) as LonglParam 声明为Any并按引证(ByRef)传递.这里是在这个函数中若是lParam是不相同类型的值时应遵循的规矩:若是该值是 传递办法numeric ByVal(as Long,or as Any)Null ByVal(as Long,or as Any)String ByRef(as String,or as Any)Type ByRef(as Any)array of Type ByRef(as Any)若是你的函数声明同上面的一个而且你想传递一个Long型数,你大概这样写:Call SendMessage(Me.Hwnd,WM_XXXX,0&,ByVal LongValue)注意虽然头三个参数也是数值,但它们前边并没有ByVal.这是由于在函数声明中它们现已被声明为按值传递(ByVal).第四个参数,由所以按引证传递(ByRef)(VB并不晓得你要传递参数的类型),因而你有必要加上ByVal 你能够运用别号技能来传递不相同类型的参数:Public Declare Function SendMessageLng Lib 'User32' Alias 'SendMessageA'(ByVal Hwnd as Long, ByVal wMsg as Long, ByVal wParam as Long, ByVal lParam as Long) as Long或:Public Declare Function SendMessageStr Lib 'User32' Alias 'SendMessageA'(ByVal Hwnd as Long, ByVal wMsg as Long, ByVal wParam as Long, lParam as String) as Long注意API参数类型自身是不会改动的.比如中的第四个参数总是一个4字节的长型数.当你按值(ByVal)传递一个Long或 Null时,该4字节长的数值就直接传递给函数.若是你传递一个String或其他的啥,你是按引证(ByRef)传递,VB传递的实习上是变量的地址,也是4个字节.参数传递你现已晓得如何传递参数了,只需把他放到调用的函数中立刻.可是,当你运用API函数时,在传递参数是有一些你大概注意的 细节. ByVal仍是ByRef. 一般状况下,你不必为此忧虑,VB的API阅读器现已为你做好了全部,只需你输入数值它就会照所声明的办法传递.总的来说,ByVal是把实习的数值传递给函数,而ByRef是把地址传给函数.仅有的费事就是 Any 类型. 把字符串传递给API函数也并不难.API函数需求的是字符串首字符的地址,然后读取该地址直到遇到一个Null字符.听起来很蹩脚,但仅仅VB处置字符串的实习办法.你仅有要记住的是必定要按引证传递(ByRef)字符串 当你想得到所需的函数回来值信息时,状况有略微的一点不相同.这里是GetComputerName函数的声明:Declare Function GetComputerName Lib 'kernel32' Alias 'GetComputerNameA'(ByVal lpBuffer As String, nSize As Long) As Long第一个参数是一个指向字符串的长途指针,第二个参数是字符串的长度.若是你仅仅简略的声明一个字符串类型的变量并把它传递给函数,就会呈现过失.因而,你首要需求初始化字符串.这里是如何得到核算机姓名的比如: Dim Buffer As StringBuffer = Space(255)Ret& = GetComputerName(Buffer, Len(Buffer))if Ret& > 0 then CompName$ = Left(Buffer, Ret&)在这里,待传递的字符串被初始化为有255个空格的字符串.咱们把它传递给函数一起还有它的长度.若是犯错则回来值为0.CompName中将保管核算机名. 有些函数也需求传递数组,这里是一个比如:Declare Function SetSysColors Lib 'user32' Alias 'SetSysColors' (ByVal nChanges As Long, lpSysColor As Long, lpColorValues As Long) As Long完毕两个参数是Long型数组.为了传递数组,你只需传递它的第一个元素.下面是示例代码:Const COLOR_ACTIVECAPTION = 2Const COLOR_INACTIVECAPTION = 3Const COLOR_CAPTIONTEXT = 9Const COLOR_INACTIVECAPTIONTEXT = 19Dim SysColor(3) As LongDim ColorValues(3) As LongDim Ret& SysColor(0) = COLOR_ACTIVECAPTIONSysColor(1) = COLOR_INACTIVECAPTIONSysColor(2) = COLOR_CAPTIONTEXTSysColor(3) = COLOR_INACTIVECAPTIONTEXTColorValues(0) = RGB(58, 158, 58) '深绿ColorValues(1) = RGB(93, 193, 93) '浅绿ColorValues(2) = 0 '黑色ColorValues(3) = RGB(126, 126, 126) '灰色Ret& = SetSysColors(4&, SysColor(0), ColorValues(0))该程序将改动全部活动和非活动窗口的标题栏布景和文本的色彩.(四) 关于API编程初学者的教程第四篇回调(CallBacks)所谓回调,就是你自个界说一个函数,并通知Windows何时为何调用.你能够写一个有特定数量和类型参数的函数,然后通知Windows何时调用,并传递给它所需的参数.Windows就会调用你界说的函数,处置参数,并给你回来值.回调的一个典型应用是从Windows获得接连的数据流.这里是一个需求回调的函数的声明:Declare Function EnumWindows Lib 'User32'ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long第一个参数是你的回调函数的地址,第二个参数是你想传递的的纵情数值.该值将被传递到你的函数,所以你就晓得了它要调用啥.VB 5.0现已供给了一个很有用的操作符 AddressOf ,能够得到一个函数的地址.当你调用一个函数时它只能用在参数的前面,下面这种用法是过失的而且会致使犯错:FuncP = AddressOf MyFunction因而你有必要这样调用EnumWindows函数:Success& = EnumWindows(AddressOf cbFunc, 58&)你有必要也要自个写回调函数.问题是有许多不相同种类的回调而且有各式各样的参数,有关这些参数的描绘能够在SDK帮助或MS SDK文档中找到.这里是一个回调的声明:Function cbFunc (ByVal Hwnd, ByVal lParam) as Long这里是一个回调的比如:Private Declare Function GetWindowText Lib 'user32' Alias 'GetWindowTextA'(ByVal hwnd As Long,ByVal lpString As String,ByVal cch As Long) As LongSuccess& = EnumWindows(AddressOf cbFunc, 58&)Function cbFunc (ByVal Hwnd, ByVal lParam) as LongIf lParam = 58 then 'enum windows Str$ = Space(255) Ret& = GetWindowText(Str$, Len(Str$)) Debug.Print Left(Str$, Ret&)End IfEnd Function这个比如将列出窗口的标题,(不包括子窗体)窗口程序Windows并不晓得作业. 这些是VB特有的躲藏Windows获取你的窗口发作作业的实在办法的一种办法.VB很像是一个将Windows言语翻译成VB言语的阐冥具.可是实践并非如此,你很快就会遇到.梦想你想晓得用户何时加亮了菜单选项(不是点击,仅仅加亮即挑选了)VB并不供给这种作业,但你能够见到其他的程序,但你阅读它的菜单时状态栏会呈现相应的文字.若是他们能,你为何不能?OK,这里是大致的实在状况.每个窗口都有一个格外的程序叫做窗口程序.它实习上是一个回调函数.该函数将在你的窗口发作作业的任何时刻发送音讯.这样当用户加亮一个菜单项时就会发送一条音讯(WM_COMMAND).那为啥我看不到这条音讯呢?这是由所以VB创立窗口程序而不是你.当Windows发送音讯时,该程序将为之分配特定的作业,并将其参数转换为对比简略用的作业的参数.可是在有些状况下,它会疏忽有些音讯而不能收到实在的输入.若是你真的想得到这些音讯,你有必要对你的窗体进行子类处置,咱们将在别的一个主题中谈到.这里是一个回调窗口程序的声明:Function WindowProc(ByVal Hwnd As Long, ByVal wMsg As Long,ByVal wParam As Long, ByVal lParam As Long) As Long第一个参数指定窗口的句柄,第二个参数是音讯的标识符(如WM_COMMAND或WM_MOUSEMOVE),wParam和lParam时两个32位的数值,它们的含义依赖于音讯的类型.(五) 关于API编程初学者的教程第五篇子类处置当你一最大极限利用了VB所给你的而且还想晓得更多的东西,或仅仅想更多地晓得你自个的窗口,你将会发现子类处置的优势.子类处置是指用一个新的窗口函数来替代当时活动窗口函数.这个用户自界说函数能处置任何需求的音讯,并能调用正本的窗口函数,它将在正本的窗口函数之前收到各种音讯.但正本的那个窗口处置函数仍然存在,并没有不见.若是你不想处置某条音讯,你大概让正本的窗口函数去处置它.子类处置是经过调用SetWindowLong函数完毕的,该函数将改动指定窗口的格外特征.下面是它的声明:Declare Function SetWindowLong Lib 'user32' Alias 'SetWindowLongA'(ByVal hwnd As Long, ByVal nIndex As Long,ByVal dwNewLong As Long) As Long第一个参数代表要进行子类处置的窗口,第二个参数大概是GWL_WNDPROC(-4),第三个参数是新的窗口函数的地址.拜见回调和窗口函数一节.此函数将在窗口获得焦点,发作作业,或其他状况下(如其他进程改动了体系的某些参数)被随时调用.若是发作过失SetWindowLong函数将回来0,不然将回来正本的窗口函数的地址.这个地址格外重要,你大概把它保管在一个变量中或其他地方.当你不处置某些音讯时(实习上,你能够只处置不到1%的音讯,其他的都将由原窗口函数处置),调用正本的窗口函数就需求该地址.调用原窗口函数将由CallWindowProc来完毕.这里是它的声明:Declare Function CallWindowProc Lib 'user32' Alias'CallWindowProcA'(ByVal lpPrevWndFunc As Long,ByVal hWnd As Long,ByVal Msg As Long,ByVal wParam As Long, ByVal lParam As Long) As Long第一个参数是原窗口函数的地址,其他的同你接纳到的四个参数相同.你能够改动其间的值来操控对音讯的处置.例如,当你收到了一条WM_MOUSEMOVE音讯时,你从lParam中得到鼠标地址方位的坐标并将其改成了其他的坐标.那么原窗口函数就会以为鼠标坐落其他的方位然后做出一些诙谐的事如闪现其他控件的Tooltip.你指定的回来值也是有含义的,它依赖于发送的音讯.在完毕你的程序时将操控权交回给原窗口函数是很重要的,一般在Form_Unload中完毕如下:Ret& = SetWindowLong(Me.Hwnd, GWL_WNDPROC, oldWndProcAddress)若是你在VB中发起程序时忘掉了这一行,作用将是VB溃散并会丢掉没有保管的数据.千万要留心.这里是子类处置的一个简略示例:Dim oldWndProc As LongPrivate Sub Form_Load()oldWndProc = SetWindowLong(Me.Hwnd, GWL_WNDPROC, AddressOf MyWndProc)End SubPrivate Sub Form_Unload()Ret& = SetWindowLong(Me.Hwnd, GWL_WNDPROC, oldWndProc)End SubFunction MyWndProc(ByVal Hwnd As Long,ByVal wMsg as Long,ByVal wParam As Long,ByVal lParam As Long)Debug.Print wMsg & ' ' & wParam & ' ' & lParamRet& = CallWindowProc(oldWndProc, Hwnd, wMsg, wParam, lParam)End Function处置参数有时函数并不以你所需的办法回来信息.一个典型的比如是将两个代表鼠标方位的整形(2 byte)数合并为一个4 Byte的数.还有一个比如是区别一个数的某位是不是为1.你还能够得到一个代表一个计划地址的Long型数.合并和别离一个数并不需求过多的描绘.你能在下面的网站上找到APIMacro.bas,它包括了你需求的多种函数.能够用一下办法查看一个数的第N位是不是为1:If Value and (2^N) then ...置1Value = Value Or 2^N置0Value = Value And Not 2^N若是你想设定或获得预先晓得的某位的信息,用1024替代2^10要快的多.由于这样VB无需自个进行核算(VB憎恶 '^' ?).若是你接纳到一个类型的指针,你要做的作业将稍多一点.你能够运用CopyMem函数来获得信息.下面是它的声明:Declare Sub CopyMem Lib 'kernel32' Alias 'RtlMoveMemory' (pDest As Any, pSource As Any, ByVal ByteLen As Long)若是你接纳到了一个指向RECT 类型的指针并存在Long型变量Addr 中,能够这样处置:Dim Info As RectCall CopyMem(Info, ByVal Addr, len(Info))注意ByVal关键词.如今,若是你想把信息写回,运用:Call CopyMem(ByVal Addr, Info, Len(Info))完毕语我期望这份教程能帮助你晓得如何操控API函数的威力和如何正确运用它们.可是要留心!就像火,若是你让它失掉操控,你就会玩蛋.当然,不要忘了VB是进行简略.安全程序设计的言语,而API函数则正巧相反.若是你想得到更多的操控功用,最佳转移到VC++ 或许Delphi.(这一点,洞主不敢苟同).祝你在API探险中好运!I
推荐信息