Visual Basic變態(tài)用法之函數(shù)指針_第1頁
Visual Basic變態(tài)用法之函數(shù)指針_第2頁
Visual Basic變態(tài)用法之函數(shù)指針_第3頁
免費(fèi)預(yù)覽已結(jié)束,剩余1頁可下載查看

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

一、函數(shù)指針AddressOf得到一個VB內(nèi)部的函數(shù)指針,我們可以將這個函數(shù)指針傳遞給需要回調(diào)這個函數(shù)的API,它的作用就是讓外部的程序可以調(diào)用VB內(nèi)部的函數(shù)。VBCVB指針傳遞給API以實(shí)現(xiàn)回調(diào),并沒指出函數(shù)指針諸多神奇的功能,因?yàn)閂B是不鼓勵使用指針的,函數(shù)指針也不例外。首先讓我們對函數(shù)指針的使用方式來分個類。1VB就是兩個API:SetWindowLongCallWindowProc。我們可以使SetWindowLong這個API來將原來的窗口函數(shù)指針換成自己的函數(shù)指針可以用CallWindowProc我們可以在不破壞原有窗口功能的前提下處理鉤入的消息。具體的處理,我們應(yīng)該很熟悉了,VB文檔也講得很清楚了。這里需要注意的就是CallWindowProc這個API,在后面我們將看到它的妙用。在這里我們稱回調(diào)為讓"外部調(diào)用內(nèi)部的函數(shù)指針"。2、程序內(nèi)部使用。比如在C里我們可以將C函數(shù)指針作為參數(shù)傳遞給一個需要函數(shù)指針的C函數(shù),如后面還要講到的C庫函數(shù)qsort,它的聲明如下:COMPAREpfnCompare);#defineint(cdecl*COMPARE)(constvoid*elem1,constvoid*elem2)voidqsort(void*base,size_tnum,size_twidth,COMPAREpfnCompare);它需要一個COMPARE類型函數(shù)指針,用來比較兩個變量大小的,這樣排序函數(shù)可以調(diào)用這個函數(shù)指針來比較不同類型的變量,所以qsort可以對不同類型的變量數(shù)組進(jìn)行排序。3、調(diào)用外部的函數(shù)API函數(shù)的指針。比如通過LoadLibrary動態(tài)加載DLL,然后再通過GetProcAddressDLL的技術(shù)可以讓我們更靈活的調(diào)用外部函數(shù)。我們稱這種方式為"從內(nèi)部調(diào)用外部的函數(shù)指針"4載多個DLL,將其中一個DLLDLL上面所分的"內(nèi)"和"外"都是相對而言(DLL實(shí)際上還是在進(jìn)程內(nèi)),這樣分類有助于以后我們談問題,請記住我上面的分類,因?yàn)橐院蟮奈恼乱矔玫竭@個分類來分析問題。函數(shù)指針的使用不外乎上面四種方式。但在實(shí)際使用中卻是靈活多變的。比如在C++里繼承和多態(tài),在COM里的接口,都是一種叫vTable的函數(shù)指針表的巧妙應(yīng)用。使用函數(shù)指針,可以使程序的處理方式更加高效、靈活。VB文檔里除了介紹過第一方式外,對其它方式都沒有介紹,并且還明確指出不支持到Basic”的函數(shù)指針(也就是上面說的第二種方式),實(shí)際上,通過一定的HACK,上面VBVBvTableCOMVB“Basic到Basic”"Basic到"API到"Basic到BasicVB說得有點(diǎn)繞口,但是仔細(xì)想想窗口子類派生技術(shù)里CallWindowProc,我們可以用CallWindowProc來強(qiáng)制外部的操作系統(tǒng)調(diào)用我們原來的保存的窗口函數(shù)指針,同樣我們也完全可以用它來強(qiáng)制調(diào)用我們內(nèi)部的函數(shù)指針。呵呵,前面說過要少講原理多講招式,現(xiàn)在我們就來開始學(xué)習(xí)招式吧!考慮我們在VB里來實(shí)現(xiàn)和C里一樣支持多關(guān)鍵字比較的qsort。完整的源代碼見本文配套代碼,此處僅給出函數(shù)指針應(yīng)用相關(guān)的代碼。'當(dāng)然少不了的CopyMemory,不用ANY的版本。DeclareSubDeclareSubCopyMemoryLib"kernel32"Alias_"RtlMoveMemory"(ByValdestAsLong,ByValsourceAsLong,_ByValnumBytesAsLong)'嘿嘿,看下面是如何將CallWindowProc的聲明做成Compare聲明的。DeclareDeclareFunctionCompareLib"user32"Alias_"CallWindowProcA"(ByValpfnCompareAsLong,ByValpElem1AsLong,_ByValByValpElem2AsLong,ByValunused1AsLong,_ByValByValunused2AsLong)AsInteger''注:ByValxxxxxAsLong,還記得吧!這是標(biāo)準(zhǔn)的指針聲明方法。'聲明需要比較的數(shù)組元素的結(jié)構(gòu)PublicTypeTEmployee'聲明需要比較的數(shù)組元素的結(jié)構(gòu)PublicTypeTEmployeeNameAsStringSalaryAsCurrencyEndType''再來看看我們的比較函數(shù)'先按薪水比較,再按姓名比較FunctionCompareSalaryName(Elem1AsTEmployee,_Elem2AsTEmployee,_unused1AsLong,_unused2'先按薪水比較,再按姓名比較FunctionCompareSalaryName(Elem1AsTEmployee,_Elem2AsTEmployee,_unused1AsLong,_unused2AsLong)AsIntegerDimRetAsIntegerRet=Sgn(Elem1.Salary-Elem2.Salary)IfRet=0ThenRet=StrComp(Elem1.Name,Elem2.Name,vbTextCompare)EndIfCompareSalaryName=RetEndFunction''先按姓名比較,再按薪水比較FunctionCompareNameSalary(Elem1AsTEmployee,_Elem2AsTEmployee,_unused1AsLong,_unused2FunctionCompareNameSalary(Elem1AsTEmployee,_Elem2AsTEmployee,_unused1AsLong,_unused2AsLong)AsIntegerDimRetAsIntegerRet=StrComp(Elem1.Name,Elem2.Name,vbTextCompare)IfRet=0ThenRet=Sgn(Elem1.Salary-Elem2.Salary)EndIfCompareNameSalary=RetEndFunction最后再看看我們來看看我們最終的最后再看看我們來看看我們最終的qsort的聲明。SubSubqsort(ByValArrayPtrAsLong,ByValnCountAsLong,_ByValnElemSizeAsInteger,ByValpfnCompareAsLong)上面的ArrayPtrCqsortCBasic的函數(shù)指針傳遞給Basicqsort使用方式如下:DimEmployees(1To10000)AsTEmployee'假設(shè)下面的調(diào)用對Employees數(shù)組進(jìn)行了賦值初始化。CallInitArray()'現(xiàn)在就可以調(diào)用我們的qsort來進(jìn)行排序了。Callqsort(VarPtr(Employees(1)),UBound(Employees),_LenB(Employees(1)),AddressOfCompareSalaryName)'或者先按姓名排,再按薪水排Callqsort(VarPtr(Employees(1)),UBound(Employees),_LenB(Employees(1)),AddressOfCompareNameSalary)聰明的朋友們,你們是不是已經(jīng)看出這里的奧妙了呢?作為一個測驗(yàn),你能現(xiàn)在就給出在qsort里使用函數(shù)指針的方法嗎?比如現(xiàn)在我們要通過調(diào)用函數(shù)指針來比較數(shù)組的第i個元素和第j個元素的大小。API調(diào)。具體的實(shí)現(xiàn)如下:Subqsort(ByValArrayPtrAsLong,ByValnCountAsLong,ByValnElemSizeAsInteger,ByValpfnCompareAsLong)DimiAsLong,jAsLongIfCompare(pfnCompare,ArrayPtr+(i-1)*nElemSize,_ArrayPtr+(j-1)*nElemSize,0,0)>0Then'如果第i個元素比第j個元素大則用CopyMemory來交換這兩個元素。EndIFEndSubCompareCallWindowProc這個API。這個API針,這個API能夠強(qiáng)馬上回調(diào)這個函數(shù)指針,并將這個API的后四個Long這個API要求傳遞給的函數(shù)指針必須符合WndProcWndProc的原形如下:LRESULT(CALLBACK*WNDPROC)(HWND,UINT,WPARAM,LPARAM);上面的LRESULT、HWND、UINT、WPARAM、LPARAM都可以對應(yīng)于VB里的Long型,這真是太好了,因?yàn)長ong型可以用來作指針嘛!再來看看工作流程,當(dāng)我們用AddressOfCompareSalaryNameqsortqsort的形參pfnCompare被賦值成了實(shí)參CompareSalaryName調(diào)用ComparepfnCompare,就相當(dāng)于調(diào)用了如下的VBCallCompareSalaryName(ArrayPtr+(i-1)*nElemSize,ArrayPtr+(j-1)*nElemSize,0,0)這不會引起參數(shù)類型不符錯誤嗎?CompareSalaryName的前兩個參數(shù)不是TEmployee類型嗎VBVB上這個調(diào)用是API進(jìn)行的回調(diào),而VB不可能去檢查API的LongVB我們可以將這個LongCompareSalaryName+(i-1)*TEmployee"ArrayPtr+i*iCVC或Delphi里寫一個DLL,API來實(shí)現(xiàn)和CallWindowProcCallWindowProccall正是因?yàn)镃allWindowProcCurlandHACK方式,我們要在VB里憑空構(gòu)造一個IUnknown接口,在IUnknown接口的vTable原有的三個入口后再加入一個新入口,在新入口里插入機(jī)器代碼,這個機(jī)器代碼要處理掉this指針,最后才能調(diào)用到我們給的函數(shù)指針,這個函數(shù)指針無論是內(nèi)部的還是外部的都一樣沒問題。在我們深入討論COM是就是這個已經(jīng)經(jīng)過了我不少優(yōu)化的快速排序算法ShellSorShellSort實(shí)現(xiàn)上簡單。從算法的理論上來講qsort應(yīng)該比ShellSort平均性能好,但是在VBVBPJ一篇專欄的配套代碼ShellSort,非常得棒,本文的思想就取自這個ShellSort)。但是應(yīng)當(dāng)指出無論是這里的快速排序還是ShellSort,都還可

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論