国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項超值服

開通VIP
在VBA中使用WINDOWS API
在VBA中使用Windows API
2009年07月15日, 8:34 上午 分享到微博:
2、Microsoft Platform SDK,包含復(fù)雜的Windows API文檔??梢栽谙旅娴牡刂分胁榭矗?a target="_blank" >http://msdn.microsoft.com/en-us/library/aa383750(VS.85).aspx。
此外,很多程序員還開發(fā)了一些聲明并與大家共享,下面就是一個關(guān)于API聲明的資源網(wǎng)站:http://www.xcelfiles.com/。
使用Declare語句
在從VBA中調(diào)用DLL里的函數(shù)之前,必須為VBA提供在哪里找到函數(shù)以及如何調(diào)用該函數(shù)的信息,有兩種方法:
1、設(shè)置對DLL類型庫的引用。
2、在模塊中使用Declare語句。
設(shè)置對DLL類型庫的引用是使用DLL中的函數(shù)的最容易的方法。一旦設(shè)置引用,就可以將其當(dāng)作工程里的一部分一樣調(diào)用DLL函數(shù)。然而,也要注意一些事項。首先,設(shè)置對多個類型庫的引用會影響應(yīng)用程序的性能;其次,不是所有的DLLs都提供類型庫,雖然可以對沒有提供類型庫的DLL設(shè)置引用,但不能調(diào)用該DLL中的函數(shù)。
注意,組成Windows API的DLLs沒有提供類型庫,因此不能設(shè)置對它們的引用并調(diào)用其中的函數(shù)。要調(diào)用Windows API中的函數(shù),必須在工程里模塊的聲明部分包括Declare語句。
Declare語句是一個定義,告訴VBA在哪里找到特定的DLL函數(shù)以及如何調(diào)用該函數(shù)。在代碼中添加Declare語句最簡單的辦法是使用API Viewer加載宏,其中包含Windows API中大多數(shù)函數(shù)的Declare語句,也包含一些函數(shù)所需要的常量和類型定義。
Declare語句聲明的形式如下:
[Public|Private]Declare Sub name Lib "libname" [Alias "aliasname"][([arglist])][Public|Private]Declare Function name Lib "libname" [Alias "aliasname"] [([arglist])] [As type]
下面是GetTempPath函數(shù)的Declare語句的示例,該函數(shù)返回Windows臨時文件夾的路徑(默認(rèn)為C:\Windows\Temp):
Private Declare Function GetTempPath Lib "kernel32" _Alias "GetTempPathA" (ByVal nBufferLength As Long, _ByVal lpBuffer As String) As Long
關(guān)鍵字Declare告訴VBA在工程中要包含的DLL函數(shù)的定義。在標(biāo)準(zhǔn)模塊中的Declare語句可以是公共的或私有的,取決于你希望API函數(shù)僅用于單個模塊還是整個工程。在類模塊中,Declare語句必須是私有的。
在關(guān)鍵字Function之后是函數(shù)的名字,具體地說,是從VBA中調(diào)用該函數(shù)時使用的名字。這個名字可以與API函數(shù)本身的名字相同,也可以在Declare語句中使用關(guān)鍵字Alias指定打算在VBA中通過不同的名字(別名)調(diào)用該函數(shù)。
在上面的示例中,在DLL中API函數(shù)的名字是GetTempPathA,從VBA中調(diào)用該函數(shù)時使用的名字是GetTempPath。注意,DLL函數(shù)的實際名字出現(xiàn)在關(guān)鍵字Alias之后,同時也注意到GetTempPath是Win32API.txt文件用于該函數(shù)的別名,但你可以將其改變?yōu)槿魏文阆胍拿帧?div style="height:15px;">
下面是為什么要在Declare語句中使用別名的一些理由:
一些API函數(shù)的名字以下劃線(_)開始,在VBA中是不合乎語法的。為了從VBA中調(diào)用該函數(shù),需要使用別名。
因為別名允許將DLL函數(shù)命名為你所希望的名字,所以可以使函數(shù)名字遵循你自已在VBA中的命名標(biāo)準(zhǔn)。
因為API函數(shù)是區(qū)分大小寫的,而VBA函數(shù)則不,所以可以使用別名來改變函數(shù)名的大小寫。
一些DLL函數(shù)帶有接受不同數(shù)據(jù)類型的參數(shù),這些函數(shù)的VBA聲明語句定義這些參數(shù)為類型Any,調(diào)用帶有聲明為Any的參數(shù)的DLL函數(shù)是危險的,因為VBA不會執(zhí)行任何數(shù)據(jù)類型檢查。如果想避免傳遞類型為Any的參數(shù)的危險,可以聲明相同的DLL函數(shù)的多個版本,每一個都具有不同的名字和不同的數(shù)據(jù)類型。
Windows API為所有接受字符串參數(shù)的函數(shù)都包含兩個版本:ANSI版和Unicode版。ANSI版帶有“A”后綴,正如上例所示,而Unicode版帶有“W”后綴。雖然VBA使用Unicode,但在調(diào)用DLL中的函數(shù)之前,它將所有的字符串轉(zhuǎn)換為ANSI字符串,因此在從VBA中調(diào)用Windows API函數(shù)時通常使用ANSI版。API Viewer加載宏自動為所有接受字符串參數(shù)的函數(shù)命名別名,因此可以不必包含“A”后綴而調(diào)用該函數(shù)。
關(guān)鍵字Lib指定包含函數(shù)的DLL。注意,在聲明語句里以字符串形式包含DLL的名字。如果在系統(tǒng)中沒有找到關(guān)鍵字Lib之后指定的DLL,對該函數(shù)的調(diào)用將失敗,導(dǎo)致運(yùn)行時錯誤:48,裝載DLL錯誤。因為可以在VBA代碼中處理這種錯誤,所以可以編寫健壯的代碼得體地處理錯誤。
下面列出了Windows API中最常使用的DLLs:
Kernel32.dll:低級別的操作系統(tǒng)函數(shù),例如內(nèi)存管理和資源處理。
User32.dll:Windows管理函數(shù),例如消息處理、計時器、菜單和通訊。
GDI32.dll:圖像設(shè)備接口(GDI)庫,包含設(shè)置輸出的函數(shù),例如繪圖、顯示上下文和字體管理。
大多數(shù)DLLs,包括Windows API中的DLLs,都采用C/C++編寫,因此,傳遞參數(shù)到DLL函數(shù)需要參數(shù)的理解以及C/C++接受的數(shù)據(jù)類型,而這些不同于VBA函數(shù)。
同時,DLL函數(shù)的許多參數(shù)按值傳遞。默認(rèn)情況下,VBA中的參數(shù)按引用傳遞。因此,當(dāng)DLL函數(shù)需要按值傳遞的參數(shù)時,在函數(shù)定義中包括關(guān)鍵字ByVal是必要的。在函數(shù)定義中忽略ByVal關(guān)鍵字可能會在應(yīng)用程序中導(dǎo)致無效的頁錯誤。有時,可能會發(fā)生VBA運(yùn)行時錯誤:49,壞的DLL調(diào)用協(xié)議。
按引用傳遞參數(shù)傳遞該參數(shù)的內(nèi)存位置到被調(diào)用的過程,如果該過程修改了參數(shù)的值,那么會修改該參數(shù)的唯一的副本,因此,當(dāng)返回到調(diào)用過程時,參數(shù)包含的是修改后的值。
按值傳遞參數(shù)到DLL函數(shù),將傳遞該參數(shù)的副本,函數(shù)操作該參數(shù)的副本,避免了修改實際參數(shù)的內(nèi)容。當(dāng)返回到調(diào)用過程時,該參數(shù)包含與調(diào)用其它過程前相同的值。
因為按引用傳遞允許在內(nèi)存中修改參數(shù)值,如果不恰當(dāng)?shù)匕匆脗鬟f參數(shù),DLL函數(shù)可能會覆蓋它不應(yīng)該覆蓋的內(nèi)存,導(dǎo)致錯誤或者不可預(yù)料的結(jié)果。Windows維護(hù)許多值不應(yīng)該被覆蓋,例如,Windows為每個窗口賦惟一的32位標(biāo)識符,稱作句柄(handle)。句柄總是按值傳遞給API函數(shù),因為如果Windows修改了某窗口的句柄,那么不再能夠追蹤到該窗口。(雖然關(guān)鍵字ByVal出現(xiàn)在String類型的一些參數(shù)前面,但是字符串總是按引用被傳遞到Windows API函數(shù))
上述聲明語句接受兩個參數(shù),一個為Long型,另一個為String型,并返回一個Long型值。
使用常量
除了DLL函數(shù)的聲明語句外,一些函數(shù)還需要定義常量以及在函數(shù)中使用的類型。在模塊的聲明部分包括常量和用戶定義類型。
如何知道函數(shù)需要的常量和用戶定義類型呢?需要查看該函數(shù)的文檔。Win32API.txt文件包含函數(shù)的常量和用戶定義類型的定義??梢允褂肁PI Viewer加載宏找出這些常量和用戶定義類型,并將它們復(fù)制到代碼中。不巧的是,常量和用戶定義類型不會以任何方式與需要它們的聲明語句相聯(lián)系,因此,仍然需要檢查DLL函數(shù)的文檔,決定哪個常量和類型與哪個聲明語句匹配。
函數(shù)可能需要傳遞常量來指明想要函數(shù)返回的信息。例如,GetSystemMetrics函數(shù)接受75個常量,每一個都指定操作系統(tǒng)的不同方面,該函數(shù)返回的信息取決于傳遞給它的常量。要調(diào)用GetSystemMetrics,不需要包括所有的75個常量,只需包括要使用的就可以了。
建議定義常量而不是簡單地傳遞它們代表的值。Microsoft確保在將來的版本中仍然會保留相同的常量,但不保證常量的值相同。
DLL函數(shù)需要的常量通常是隱含的,因此需要查閱函數(shù)的文檔來確定傳遞的常量,以返回特定的值。
在《Professional Excel Development》中介紹了如何查找常量的值的方法。即在Microsoft的站點(diǎn)下載并安裝核心SDK軟件包,其中有一個名為“include”的子目錄,所有用于創(chuàng)建動態(tài)鏈接庫(DLL)的C++頭文件都存放在這個目錄中。通過搜索就能找到常量所在的文件,例如查找SM_CXSCREEN,會返回文件“winuser.h”,打開該文件查詢就可找到相關(guān)的常量。
下面的示例是包括GetSystemMetrics函數(shù)的聲明語句,接受兩個常量,然后展示如何從屬性過程中調(diào)用GetSystemMetrics,以像素為單位返回屏幕的高度。
Declare Function GetSystemMetrics Lib "User32" (ByVal nIndex As Long) As LongConst SM_CXSCREEN As Long = 0 '屏幕寬度Const SM_CYSCREEN As Long = 1 '屏幕高度Public Property Get ScreenHeight() As Long '以像素為單位返回屏幕的高度 ScreenHeight = GetSystemMetrics(SM_CYSCREEN)End Property Public Property Get ScreenWidth() As Long '以像素為單位返回屏幕的寬度 ScreenWidth = GetSystemMetrics(SM_CXSCREEN)End Property
使用用戶定義類型
用戶定義類型是一種數(shù)據(jù)結(jié)構(gòu),可以存儲多個相關(guān)的不同類型的變量,與C/C++中的結(jié)構(gòu)一致。有時,傳遞空的用戶定義類型到DLL函數(shù),函數(shù)填充值;有時,從VBA填充用戶定義類型,并將其傳遞給DLL函數(shù)。
可以將用戶定義類型作為一箱抽屜,每個抽屜可以包含不同類型的項目,但將它們組合在一起可以當(dāng)作相關(guān)項目的單個箱子??梢詮娜魏纬閷汐@得項目而不必?fù)?dān)心存儲在任何其它抽屜中的項目。
要創(chuàng)建用戶定義類型,使用Type … End Type語句。在Type…End Type語句里,列出了每個項目,包含值和數(shù)據(jù)類型。用戶定義類型的元素可以是數(shù)組。
下面的代碼段展示如何定義RECT用戶定義類型,和管理屏幕矩形塊的幾個Windows API函數(shù)一起使用。例如,GetWindowRect函數(shù)接受RECT類型的數(shù)據(jù)結(jié)構(gòu),使用關(guān)于窗口的左側(cè)、頂部、右側(cè)和底部位置的信息填充。
Type RECT Left As Long Top As Long Right As Long Bottom As LongEnd Type
要傳遞用戶定義類型到DLL函數(shù),必須創(chuàng)建該類型的變量。例如,如果打算傳遞RECT類型的用戶定義類型到DLL函數(shù),那么就要包括變量聲明,如下所示:
Private rectWindow As RECT
可以引用用戶定義類型里的單個元素,如下所示:
Debug.Print rectWindow.Left
使用句柄
調(diào)用DLLs中的函數(shù)之前需要理解的另一個重要的概念是句柄(handle)。簡單地說,句柄是32位正整數(shù),Windows用于識別窗口或另一個對象,例如字體或位圖。
在Windows中,窗口有許多不同的表現(xiàn)形式。事實上,在屏幕中看到的幾乎所有事情都在窗口里,并且不能看到的大多數(shù)事情也在窗口里。窗口能夠是一個綁定的屏幕矩形區(qū)域,就像您習(xí)慣看到的應(yīng)用程序窗口一樣。窗體中的控件,例如列表框或滾動條,也都是窗口,雖然不是所有類型的控件都是窗口。在桌面上顯示的圖標(biāo)以及桌面本身,都是窗口。
因為所有這些類型的對象都是窗口,所以Windows能夠相同地對待它們。Windows提供給每個窗口一個唯一的句柄,并使用該句柄去處理窗口。許多API函數(shù)返回句柄或者接受句柄作為其參數(shù)。
當(dāng)窗口創(chuàng)建時Windows賦句柄給該窗口,當(dāng)窗口銷毀時Windows釋放該句柄。雖然句柄保留的時間與窗口存在的時間相同,但不保證一個窗口在銷毀并重新創(chuàng)建后有相同的句柄。因此,如果在變量中存儲句柄,那么記住該窗口銷毀后,該句柄不再有效。
GetActiveWindow函數(shù)是返回窗口句柄的函數(shù)示例,此時,應(yīng)用程序窗口是當(dāng)前活動的窗口。GetWindowText函數(shù)接受某窗口的句柄,并且如果窗口有標(biāo)題的話返回該窗口的標(biāo)題。下面的程序使用GetActiveWindow返回活動窗口的句柄,GetWindowText返回其標(biāo)題:
Declare Function GetActiveWindow Lib "user32" () As LongDeclare Function GetWindowText Lib "user32" _ Alias "GetWindowTextA" (ByVal Hwnd As Long, _ ByVal lpString As String, ByVal cch As Long) As Long Function ActiveWindowCaption() As String Dim strCaption As String Dim lngLen As Long '創(chuàng)建使用空字符填充的字符串 strCaption = String$(255, vbNullChar) '返回字符串的長度 lngLen = Len(strCaption) '調(diào)用GetActiveWindow來返回活動窗口的句柄 '與字符串和其長度一起,傳遞句柄到GetWindowText If (GetWindowText(GetActiveWindow, strCaption, lngLen) > 0) Then '返回Windows已寫入的值給字符串 ActiveWindowCaption = strCaption End IfEnd Function
GetWindowText函數(shù)接受三個參數(shù):窗口的句柄、將返回窗口標(biāo)題里的空結(jié)尾的字符串、以及字符串的長度。
下面列出了Excel中常用的窗口類名稱:
Excel主窗口:XLMAIN
Excel桌面:XLDESK
Excel工作表:EXCEL7
Excel用戶窗體:ThunderDFrame(Excel 2000以后版本)、ThunderRT6DFrame(Excel 2000以后版本,用于作為COM加載項時)、ThunderXFrame(Excel 97)
Excel狀態(tài)欄:EXCEL4
Excel圖表窗口:EXCELE(Excel2007以前版本)
FindWindow函數(shù)使用類名和窗口標(biāo)題查找窗口。下面的代碼以像素為單位查找Excel主窗口的位置和大?。?div style="height:15px;">
'包含窗口大小的用戶定義類型Type RECT Left As Long Top As Long Right As Long Bottom As LongEnd Type '查找窗口的API函數(shù)Declare Function FindWindow Lib "user32" _ Alias "FindWindowA" ( _ ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long '獲取窗口大小的API函數(shù)Declare Function GetWindowRect Lib "user32" ( _ ByVal hWnd As Long, _ lpRect As RECT) As Long Sub ShowExcelWindowSize() Dim hWnd As Long, uRect As RECT '獲取Excel主窗口的句柄 'Excel 2002及以后版本也可使用hWnd=Application.Hwnd hWnd = FindWindow("XLMAIN", Application.Caption) '將窗口大小信息存入到RECT結(jié)構(gòu)中 GetWindowRect hWnd, uRect '顯示結(jié)果 MsgBox "這個Excel窗口的尺寸為:" & _ vbCrLf & "左側(cè):" & uRect.Left & _ vbCrLf & "右側(cè):" & uRect.Right & _ vbCrLf & "頂部:" & uRect.Top & _ vbCrLf & "底部:" & uRect.Bottom & _ vbCrLf & "寬度:" & (uRect.Right - uRect.Left) & _ vbCrLf & "高度:" & (uRect.Bottom - uRect.Top)End Sub
調(diào)用函數(shù)
雖然調(diào)用DLL函數(shù)的許多方式與調(diào)用VBA函數(shù)相似,但是開始時有一些不同可能會使DLL函數(shù)混淆。下面將介紹如何輸入DLL函數(shù)中的參數(shù)并加前綴、如何返回字符串、如何傳遞數(shù)據(jù)結(jié)構(gòu)、能夠接受什么返回值、以及如何獲取錯誤信息。
參數(shù)數(shù)據(jù)類型
在C/C++中使用的數(shù)據(jù)類型、用于描述它們的標(biāo)記都不同于在VBA中的用法,下面描述了DLL函數(shù)中常用的數(shù)據(jù)類型以及它們在VBA中的等效表示。
C/C++數(shù)據(jù)類型匈牙利前綴描述等效的VBA表示
BOOLb8位布爾值。0表示False;非0表示TrueBoolean或Long
BYTEch8位無符號整數(shù)Byte
HANDLEh32位無符號整數(shù),代表Windows對象的句柄Long
intn16位符號整數(shù)Integer
longl32位符號整數(shù)Long
LPlp32位對內(nèi)存中C/C++結(jié)構(gòu)、字符串、函數(shù)或其它數(shù)據(jù)的長指針Long
LPZSTRlpsz32位對C類型空結(jié)尾字符串的長指針Long
雖然您應(yīng)該熟悉這些數(shù)據(jù)類型和前綴,但前面提到的Win32API.txt文件包含了準(zhǔn)備在VBA中使用的聲明語句。如果在代碼中使用這些聲明語句,那么函數(shù)參數(shù)已經(jīng)定義了正確的VBA數(shù)據(jù)類型。
在《Excel 2007 VBA參考大全》的第27章,詳細(xì)介紹了如何將C-樣式聲明轉(zhuǎn)換為VBA聲明語句。
只要已經(jīng)定義并傳遞了正確的數(shù)據(jù)類型,調(diào)用DLL函數(shù)與調(diào)用VBA函數(shù)采取相同的方法。當(dāng)然也有例外,這將在下面的內(nèi)容中介紹。
從DLL函數(shù)中返回字符串
DLL函數(shù)不會以VBA函數(shù)相同的方法返回字符串。因為字符串總是按引用傳遞到DLL函數(shù),DLL函數(shù)能夠修改字符串參數(shù)的值。寧可返回字符串作為函數(shù)的返回值,就像可能在VBA中做的那樣,DLL函數(shù)返回字符串到傳遞給該函數(shù)的String類型的參數(shù)。函數(shù)的實際返回值經(jīng)常是一個長整型值,指定寫入到字符串參數(shù)的字節(jié)數(shù)量。
接受字符串參數(shù)的DLL函數(shù)獲得指針,指向內(nèi)存中該字符串的位置。指針只是內(nèi)存地址,表明在哪里存儲字符串。因此,當(dāng)從VBA中傳遞字符串到DLL函數(shù)時,傳遞給DLL函數(shù)一個指針,指向內(nèi)存中的字符串。接著,這個DLL函數(shù)修改存儲在那個地址的字符串。
要調(diào)用寫到String變量的DLL函數(shù),需要采取額外的步驟合適地格式字符串。首先,String變量必須是空結(jié)尾字符串。一個空結(jié)尾字符串以特定的空字符結(jié)束,空字符通過VBA常量vbNullChar來指定。
其次,DLL函數(shù)不能修改已經(jīng)創(chuàng)建的字符串的大小。因此,需要確保傳遞給函數(shù)的字符串足夠大以容納整個返回值。當(dāng)傳遞字符串到DLL函數(shù)中時,通常需要指定在另一個傳遞的參數(shù)中字符串的大小。Windows追蹤字符串的長度,以確保不會覆蓋掉字符串已使用過的內(nèi)存。
傳遞字符串到DLL函數(shù)中的一個好方法是創(chuàng)建String變量,并使用String$函數(shù)在其中填充空字符,使其足夠大以容納函數(shù)返回的字符串。例如,下面的代碼創(chuàng)建一個144字節(jié)長的字符串,并使用空字符串填充:
Dim strTempPath As StringstrTempPath = String$(144, vbNullChar)
當(dāng)傳遞字符串到DLL函數(shù)中時,如果不知道字符串的長度,那么可以使用Len函數(shù)確定其長度。
獲取Windows臨時文件夾的GetTempPath函數(shù),就是返回String值的DLL函數(shù)的例子。該函數(shù)接受兩個參數(shù),一個空結(jié)尾的字符串變量和一個包含字符串長度的數(shù)值變量。修改該字符串以便包含路徑,例如C:\Temp\。(Windows需要一個臨時文件夾存在,于是該函數(shù)應(yīng)該總是返回該文件夾的路徑。如果由于某種原因不存在臨時文件夾,GetTempPath返回0)。
下面的程序調(diào)用GetTempPath函數(shù)獲取Windows臨時文件夾的路徑:
Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" _ (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long Property Get GetTempFolder() As String '返回用戶臨時文件夾的路徑. '對于根目錄,Windows需要一個臨時文件夾存在 '因此應(yīng)該總是返回其路徑 '以防萬一,檢查GetTempPath的返回值 Dim strTempPath As String Dim lngTempPath As Long '使用空字符填充字符串 strTempPath = String(144, vbNullChar) '獲得字符串的長度 lngTempPath = Len(strTempPath) '調(diào)用GetTempPath,傳遞字符串長度和字符串 If (GetTempPath(lngTempPath, strTempPath) > 0) Then 'GetTempPath返回路徑到字符串中. '截去字符串開始的空字符 GetTempFolder = Left(strTempPath, InStr(1, strTempPath, vbNullChar) - 1) Else GetTempFolder = "" End IfEnd Property
注意,當(dāng)傳遞字符串到函數(shù)中時,使用空字符填充該字符串。函數(shù)寫入返回的字符串值“C:\Temp”到字符串變量的第一部分中,并且剩下的保留空字符填充,接著使用Left函數(shù)截取字符串。
GetTempPath函數(shù)的實際返回值是已經(jīng)被寫到字符串變量中的字符數(shù)。如果返回的字符串是“C:\Temp\”,那么GetTempPath函數(shù)返回8。
注意,這僅對從函數(shù)返回字符串時傳遞空結(jié)尾字符串及其大小是必需的。如果函數(shù)不返回字符串到字符串參數(shù)中,而是接受對函數(shù)指定信息的字符串,那么只需傳遞正常的VBA字符串變量。
傳遞用戶定義類型到DLL函數(shù)
許多DLL函數(shù)需要通過使用預(yù)定義的格式傳遞數(shù)據(jù)結(jié)構(gòu)。當(dāng)從VBA中調(diào)用DLL函數(shù)時,根據(jù)函數(shù)的需求傳遞已經(jīng)定義的用戶定義類型。
通過查看函數(shù)的聲明語句,您能夠理解什么時候需要傳遞用戶定義類型以及需要在代碼中包括哪種類型定義。需要數(shù)據(jù)結(jié)構(gòu)的參數(shù)總是被聲明為長指針:指向內(nèi)存中數(shù)據(jù)結(jié)構(gòu)的32位數(shù)字值。為長指針參數(shù)約定的前綴是“l(fā)p”。此外,參數(shù)的數(shù)據(jù)類型是數(shù)據(jù)結(jié)構(gòu)的名稱。
例如,看看GetLocalTime函數(shù)和SetLocalTime函數(shù)的聲明語句:
Private Declare Sub GetLocalTime Lib "kernel32" _ (lpSystem As SYSTEMTIME)Private Declare Function SetLocalTime Lib "kernel32" _(lpSystem As SYSTEMTIME) As Long
兩個函數(shù)都接受SYSTEMTIME類型的參數(shù),即包含日期和時間信息的數(shù)據(jù)結(jié)構(gòu)。下面是SYSTEMTIME類型的定義:
Private Type SYSTEMTIME wYear As Integer wMonth As Integer wDayOfWeek As Integer wDay As Integer wHour As Integer wMinute As Integer wSecond As Integer wMilliseconds As IntegerEnd Type
要將數(shù)據(jù)結(jié)構(gòu)傳遞給函數(shù),必須聲明SYSTEMTIME類型的變量,如下所示:
Private sysLocalTime As SYSTEMTIME
當(dāng)調(diào)用GetLocalTime時,傳遞SYSTEMTIME類型的變量到該函數(shù),并且使用表示當(dāng)前本地的年、月、日、星期幾、小時、分、秒、毫秒的數(shù)字值填充該數(shù)據(jù)結(jié)構(gòu)。例如,下面的Property Get程序調(diào)用GetLocalTime返回表明當(dāng)前小時的值:
Public Property Get Hour() As Integer '返回當(dāng)前時間,然后返回小時 GetLocalTime sysLocalTime Hour = sysLocalTime.wHourEnd Property
當(dāng)調(diào)用SetLocalTime時,也傳遞了SYSTEMTIME類型的變量,但首先提供數(shù)據(jù)結(jié)構(gòu)的一個或多個元素的值。例如,下面的Property Let程序設(shè)置本地系統(tǒng)時間的小時值。首先,調(diào)用GetLocalTime函數(shù)獲取本地時間的當(dāng)前值到數(shù)據(jù)結(jié)構(gòu)中,然后使用傳遞給屬性過程的值更新數(shù)據(jù)結(jié)構(gòu)的sysLocalTime.wHour的值。最后,調(diào)用SetLocalTime函數(shù),傳遞相同的數(shù)據(jù)結(jié)構(gòu),包含通過GetLocalTime加新小時值而取得的值。
Public Property Let Hour(intHour As Integer) '獲取當(dāng)前時間以便所有值都是當(dāng)前的 '然后設(shè)計本地時間的小時部分 GetLocalTime sysLocalTime sysLocalTime.wHour = intHour SetLocalTime sysLocalTimeEnd Property
GetLocalTime函數(shù)和SetLocalTime函數(shù)與GetSystemTime函數(shù)和SetSystemTime函數(shù)相似。主要的不同在于,GetSystemTime函數(shù)和SetSystemTime函數(shù)表達(dá)的時間為格林威治標(biāo)準(zhǔn)時間。例如,如果本地時間是午夜12時,而您居住在西海岸,那么格林威治標(biāo)準(zhǔn)時間就是上午8時,有8小時的時差。GetSystemTime函數(shù)返回當(dāng)前時間即8:00 A.M,而GetLocalTime返回午夜12:00。
理解Any數(shù)據(jù)類型
一些帶有一個參數(shù)的DLL函數(shù)可以接受多個數(shù)據(jù)類型。在DLL函數(shù)的聲明語句中,這樣的參數(shù)被聲明為類型Any。VBA允許傳遞任何數(shù)據(jù)類型到這個參數(shù)。然而,DLL函數(shù)可能被設(shè)計為接受僅僅兩個或三個不同的數(shù)據(jù)類型,因此傳遞錯誤的數(shù)據(jù)類型可能會導(dǎo)致應(yīng)用程序錯誤。
通常,當(dāng)在VBA工程中編譯代碼時,VBA對傳遞給每個參數(shù)的值執(zhí)行類型檢查。也就是說,確保傳遞的值的數(shù)據(jù)類型與函數(shù)定義中的參數(shù)的數(shù)據(jù)類型相匹配。例如,如果參數(shù)定義為Long型,而試圖傳遞String型的數(shù)值,則會發(fā)生編譯時錯誤。這適用于調(diào)用內(nèi)置的VBA函數(shù)、用戶定義函數(shù)、或者DLL函數(shù)。當(dāng)將參數(shù)聲明為類型Any時,不會進(jìn)行類型檢查,因此當(dāng)傳遞值到這種類型的參數(shù)時應(yīng)該謹(jǐn)慎。
一些具有一個參數(shù)的DLL函數(shù)可以接受字符串或者指向字符串的空指針。指向字符串的空指針是一個特別的指針,指令Windows忽略所給的參數(shù)。它與零長度字符串(“”)不同。在VBA的早期版本中,程序員必須聲明參數(shù)為類型Any,或者聲明DLL函數(shù)的兩個版本,即一個版本定義參數(shù)類型為String,一個版本定義參數(shù)類型為Long?,F(xiàn)在VBA包括vbNullString常量,代表指向字符串的空指針,這樣可以聲明參數(shù)為String類型,并且在需要傳遞空指針的情形下傳遞vbNullString常量。
獲取錯誤信息
DLL函數(shù)中發(fā)生的運(yùn)行時錯誤的行為不同于VBA中的運(yùn)行時錯誤,即沒有錯誤消息框顯示。當(dāng)運(yùn)行時錯誤發(fā)生時,DLL函數(shù)返回某值表時發(fā)生了錯誤,而且錯誤不會中斷VBA代碼的執(zhí)行。
Windows API中的一些函數(shù)存儲運(yùn)行時錯誤的錯誤信息。如果使用C/C++編程,可以使用GetLastError函數(shù)獲取關(guān)于發(fā)生的最后一次錯誤的信息。然而,從VBA中,GetLastError函數(shù)可能返回不確切的結(jié)果。要從VBA獲得關(guān)于DLL錯誤的信息,可以使用VBA的Err對象的LastDLLError屬性。LastDLLError屬性返回發(fā)生的錯誤號。
為了使用LastDLLError屬性,需要知道與錯誤相對應(yīng)的錯誤號。在Win32API.txt文件沒有這方面的可用信息,而Microsoft Platform SDK中可以找到。
下面的示例展示在已經(jīng)調(diào)用了Windows API中的函數(shù)后如何使用LastDLLError屬性。PrintWindowCoordinates程序接受窗口句柄,并調(diào)用GetWindowRect函數(shù)。GetWindowRect使用組成窗口的矩形的邊的長度填充RECT數(shù)據(jù)結(jié)構(gòu)。如果傳遞了無效的句柄,將發(fā)生錯誤,并且可以通過LastDLLError屬性獲得錯誤號。
Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, _ lpRect As RECT) As Long Type RECT Left As Long Top As Long Right As Long Bottom As LongEnd Type Const ERROR_INVALID_WINDOW_HANDLE As Long = 1400Const ERROR_INVALID_WINDOW_HANDLE_DESCR As String = "無效的窗口句柄." Sub PrintWindowCoordinates(hwnd As Long) '以像素為單位打印窗口左側(cè),右側(cè),頂部和底部位置 Dim rectWindow As RECT '傳遞窗口句柄和空的數(shù)據(jù)結(jié)構(gòu) '如果函數(shù)返回0,那么錯誤就發(fā)生了 If GetWindowRect(hwnd, rectWindow) = 0 Then '因為傳遞了無效的句柄 '所以如果發(fā)生錯誤則檢查LastDLLError并顯示對話框 If Err.LastDllError = ERROR_INVALID_WINDOW_HANDLE Then MsgBox ERROR_INVALID_WINDOW_HANDLE_DESCR, _ Title:="錯誤!" End If Else Debug.Print rectWindow.Bottom Debug.Print rectWindow.Left Debug.Print rectWindow.Right Debug.Print rectWindow.Top End IfEnd Sub
要獲得活動窗口的坐標(biāo),可以通過使用GetActiveWindow函數(shù)返回活動窗口的句柄,并將結(jié)果傳遞到前面示例定義的過程中。要使用GetActiveWindow函數(shù),包括下面的聲明語句:
Declare Function GetActiveWindow Lib "user32" () As Long
輸入下面的過程后運(yùn)行:
Sub test() PrintWindowCoordinates (GetActiveWindow)End Sub
要生成一條錯誤消息,隨便使用一個長整型數(shù)值調(diào)用這個過程。
參考資源:
David Shank,《Office VBA and the Windows API
Excel 2007 VBA參考大全
《Professional Excel Development》
《VBA and Macros for Microsoft Excel》
相關(guān)文章
2010年01月26日 -- 讓Excel自動響應(yīng)消息框中的提示 (2)
這是以前收錄的一段程序示例: 使用VBA在調(diào)用工作簿中打開被調(diào)用工作簿,并運(yùn)行其中的宏。該宏將彈出一個消息框,如果用戶沒有響應(yīng),那么程序會在指定時間后自動響應(yīng)。 調(diào)用工作簿中的程序代碼如下: Public Declare Function SetTimer& Lib "user32" (ByVal hwnd&, _ ByVal nIDEvent&, ByVal uElapse&...
2012年08月10日 -- 將圖表復(fù)制為圖片 (0)
Copy Chart as a Picture 作者:Rob van Gelder 有時,需要將圖表復(fù)制為圖片,并且是一個增強(qiáng)的圖元文件(EMF),即一種矢量圖形圖像格式。在頁面尺寸縮放時,EMF圖形比例也相應(yīng)縮放。 下面的代碼可以實現(xiàn)上述功能。 首先,選擇圖表,運(yùn)行下面的代碼,將會出現(xiàn)一個對話框詢問在哪里存放圖片。非常簡單方便! 代碼使用了剪粘板來實現(xiàn)轉(zhuǎn)換。 Declare F...
2009年07月22日 -- 使用注冊表API保存和恢復(fù)設(shè)置 (1)
本文來源于Microsoft知識庫文章How To Use the Registry API to Save and Retrieve Setting,僅供參考。 雖然VB包括用來從注冊表中保存和恢復(fù)信息的函數(shù)SaveSetting和GetSetting,但是這些函數(shù)僅操作注冊表的特定部分,即HKEY_CURRENT_USER根鍵下的Visual Basic and VBA Program Se...
2009年08月31日 -- 使用VBA操作文件(12):如何使用VBA查找文件 (2)
下面的代碼主要介紹如何使用Windows API函數(shù)及內(nèi)置的VBA函數(shù)查找和列出文件。當(dāng)然,VBA也包含了用于查找和列出文件的Application.FileSearch對象。 方法1:使用Windows API 步驟1 在VBE中,插入一個標(biāo)準(zhǔn)模塊,并輸入下面的代碼: Declare Function FindFirstFile Lib "kernel32" Alias _ "Fi...
2009年03月28日 -- 從Excel中導(dǎo)出圖片 (3)
前不久,有兩位朋友都提出過類似的問題: 問題1 請問能否將從工作表中截獲的圖片(對Range進(jìn)行了CopyPicture操作)直接放入UserForm的TextBox里(該窗體并非在工作表中建立的,而是在工程中建立的)?如果不可行,有無其他方式實現(xiàn)? 問題2 同樣對于一個Range進(jìn)行了CopyPicture和Paste操作后,能否將截獲的圖片直接放入單元格的批注中?在實現(xiàn)過程中是否必...
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
vba:?剖析?Declare?語句
如何寫 C dll 和調(diào)用它們從 Visual Basic
《windows核心編程系列》四談?wù)勥M(jìn)程的建立和終止
Delphi開發(fā)DLL常見問題
C#系統(tǒng)鉤子的實現(xiàn)
Python中四種運(yùn)行其他程序的方式
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服