1. 程式人生 > >VBA7的誕生-VBA將會繼續存活下去

VBA7的誕生-VBA將會繼續存活下去

iamlaosong

自Office2010釋出以後,Office2010分成32位和64位兩個版本,隨之一起誕生的VBA7也和廣大使用者見面了,但由於當時64位系統普及率不夠,使用64位Office並不廣泛,當時微軟也建議使用者避開64位Office 2010,不建議使用64位Office2010。但隨著Office2013和2016推出後,64位版本更加穩定,使用的人也越來越多。為了支援64位,VBA進行了升級,而Office 2010物件模型也已經得到了更新。因此,當企業使用者自Office 2003升級至Office 2010的時候,很有可能需要處理舊的、不相容的程式程式碼。目前64位Windows已經大行其道,越來越多的使用者碰到64位系統下的VBA的使用問題。

1、64 位 Visual Basic for Applications 概述

Microsoft Visual Basic for Applications (VBA) 是 Microsoft Office 附帶的 Visual Basic 版本。在 Microsoft Office 2010 中,VBA 包括可使 VBA 程式碼同時在 32 位和 64 位環境中正確執行的語言功能。
注意:預設情況下,Office 2010 安裝 32 位版本。在安裝過程中,您必須明確選擇安裝 64 位版本。 

對於在 Office 2010 版本之前(VBA 版本 6 和更早版本)編寫的 VBA 程式碼,需要修改為在 64 位 Office 版本中執行,否則在 64 位平臺上執行時會導致錯誤。這是因為,VBA 版本 6 和更早版本完全以 32 位平臺為目標,而且通常包含 Declare 語句,這些語句呼叫的 Windows API 使用 32 位資料型別的指標和控制代碼。因為 VBA 版本 6 和更早版本沒有用於指標或控制代碼的特定資料型別,所以,它使用 Long 資料型別(一種 32 位 4 位元組的資料型別)來引用指標和控制代碼。64 位環境中的指標和控制代碼為 8 位元組 64 位數。這些 64 位數不能包含在 32 位資料型別中。
注意:只有在 64 位版本的 Microsoft Office 中執行 VBA 程式碼時,才需要修改 VBA 程式碼。

在 64 位 Office 中執行舊 VBA 程式碼的問題在於,將 64 位載入到 32 位資料型別中會截斷 64 位數。這會導致記憶體溢位、程式碼中出現意外結果,並且可能導致應用程式故障。
為解決此問題,以使 VBA 程式碼能同時在 32 位和 64 位環境中正確執行,新版 VBA 中增加了幾項語言功能。此文件底部的表總結了這些新的 VBA 語言功能。有三個重要的新增功能,分別是:LongPtr 類型別名、LongLong 資料型別和 PtrSafe 關鍵字。

LongPtr - 現在,VBA 包括一種可變類型別名:LongPtr。LongPtr 實際解析為哪種資料型別取決於它在哪種 Office 版本中執行:在 32 位版本的 Office 中 LongPtr 解析為 Long,在 64 位版本的 Office 中 LongPtr 解析為 LongLong。LongPtr 用於指標和控制代碼。 
LongLong - LongLong 資料型別為有符號的 64 位整數,僅在 64 位版本的 Office 中可用。LongLong 用於 64 位整數。必須使用轉換函式將 LongLong(包括 64 位平臺上的 LongPtr)顯式賦予較小的整型。不允許將 LongLong 隱式轉換為較小的整數。 
PtrSafe - PtrSafe 關鍵字宣告 Declare 語句可以在 64 位版本的 Office 中安全執行。 

現在,在 64 位版本的 Office 中執行時,所有 Declare 語句必須都包括 PtrSafe 關鍵字。必須理解,僅僅將 PtrSafe 關鍵字新增到 Declare 語句中只是表示 Declare 語句顯式針對 64 位,而語句中需要儲存 64 位(包括返回值和引數)的所有資料型別仍須經過修改才能儲存 64 位數。
注意:帶有 PtrSafe 關鍵字的 Declare 語句為建議的語法。包括 PtrSafe 的 Declare 語句可同時在 32 位和 64 位平臺上的 VBA7 開發環境中正確工作。為確保在 VBA7 中以及更早版本中的向後相容性,請使用下面的構造:
#If Vba7 Then
    Declare PtrSafe Sub...
#Else
    Declare Sub...
#EndIf

請考慮下列 Declare 語句示例。在 64 位版本的 Office 中執行未經修改的 Declare 語句會導致一個錯誤,該錯誤指出 Declare 語句未包括 PtrSafe 限定符。修改後的 VBA 示例中包含 PtrSafe 限定符,但請注意,返回值(指向活動視窗的一個指標)返回 Long 資料型別。在 64 位 Office 上,這是錯誤的,因為指標應為 64 位。PtrSafe 限定符告知編譯器 Declare 語句針對 64 位,因此該語句可以正常執行。但是返回值沒有更新為 64 位資料型別,因此被截斷,從而返回錯誤的值。

未修改的舊 VBA Declare 語句示例: 
Declare Function GetActiveWindow Lib "user32" () As Long
修改後的 VBA Declare 語句示例,其中包括 PtrSafe 限定符,但仍使用 32 位返回值: 
Declare PtrSafe Function GetActiveWindow Lib "user32" () As Long

再次重申,您除了必須修改 Declare 語句來包括 PtrSafe 限定符外,還必須更新語句中所有需要儲存 64 位數的變數,以便這些變數使用 64 位資料型別。
修改後的 VBA Declare 語句示例,其中包括 PtrSafe 關鍵字,並且更新為使用正確的 64 位 (LongPtr) 資料型別: 
Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr

總而言之,對於要在 64 位版本的 Office 中執行的程式碼,您需要找到並修改所有現有 Declare 語句以使用 PtrSafe 限定符。同時,還需要找到並修改這些 Declare 語句內所有引用控制代碼或指標的資料型別以使用新的 64 位相容的 LongPtr 類型別名,並且需要使用新的 LongLong 資料型別儲存 64 位整數的型別。此外,還必須更新任何包含指標或控制代碼以及 64 位整數的使用者定義型別 (UDT),使之使用 64 位資料型別,同時,必須驗證所有變數賦值是否正確,以防止發生型別不匹配錯誤。
編寫可同時在 32 位和 64 位 Office 上執行的程式碼
若要編寫可同時在 32 位和 64 位版本的 Office 上執行的程式碼,只需對所有指標和控制代碼值使用新的 LongPtr 類型別名來代替 Long 或 LongLong 即可。LongPtr 類型別名將解析為正確的 Long 或 LongLong 資料型別,具體取決於執行的是哪種 Office 版本。請注意,如果您需要執行不同的邏輯(例如,您需要在大型 Microsoft Excel 專案中使用 64 位值),可以使用 Win64 條件編譯常量,如下面一節所示。

編寫可同時在 Microsoft Office 2010(32 位或 64 位)以及以前版本的 Office 上執行的程式碼
若要編寫可同時在新版本和舊版本的 Office 中執行的程式碼,可以使用新的 VBA7 與 Win64 條件編譯器常量的組合。Vba7 條件編譯器常量用來判斷程式碼是否在 VB 編輯器版本 7(Office 2010 附帶的 VBA 版本)中執行。Win64 條件編譯常量用於判斷正在執行哪種 Office 版本(32 位還是 64 位)。
#if Vba7 then
'  程式碼正在新 VBA7 編輯器中執行
#if Win64 then
'  程式碼正在 64 位版本的 Microsoft Office 中執行
#else
'  程式碼正在 32 位版本的 Microsoft Office 中執行
#end if
#else
' 程式碼正在 VBA 版本 6 或更早版本中執行
#end if

#If Vba7 Then
    Declare PtrSafe Sub...
#Else
    Declare Sub...
#EndIf
 

2、VBA7 語言更新總結
下表總結了新增的 VBA 語言功能,並給出每個新增功能的解釋:

名稱 型別 描述 
PtrSafe  關鍵字 宣告 Declare 語句針對 64 位系統。在 64 位上是必需的。 
LongPtr 資料型別 該類型別名對映為 32 位系統上的 Long,或 64 位系統上的 LongLong。 
LongLong 資料型別 8 位元組的資料型別,只在 64 位系統上可用。數字型別。-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 範圍內的整數。LongLong 只是 64 位平臺上的有效宣告型別。此外,不能將 LongLong 隱式轉換為較小的型別(例如,不能將 LongLong 賦予 Long)。這樣做的目的是防止不慎將指標截斷。允許顯式強制轉換,所以在上例中,可以將 CLng 應用於 LongLong,並將結果賦予 Long。(只在 64 位平臺上有效。) 
^ LongLong 型別宣告字元 顯式將文字值宣告為 LongLong。宣告大於最大 Long 值的 LongLong 文字時是必需的(否則它將隱式轉換為 double)。 
CLngPtr 型別轉換函式 將簡單表示式轉換為 LongPtr。 
CLngLng 型別轉換函式 將簡單表示式轉換為 LongLong 資料型別。(只在 64 位平臺上有效。) 
vbLongLong VarType 常量 VarType 常量。 
DefLngPtr DefType 語句 將一系列變數的預設資料型別設定為 LongPtr。 
DefLngLng DefType 語句 將一系列變數的預設資料型別設定為 LongLong。

3、VBA7的新功能
據Excel產品團隊部落格的文章《Programmability Improvements in Excel 2010》,VBA增加了一些新功能。 
1)將Excel 4巨集遷移到VBA
在將VBA引入到Excel之前,有自已的巨集工具,稱之為Excel 4巨集,在Excel巨集工作表中使用。很多人都早已將他們的Excel 4巨集遷移到VBA,然而,一些Excel 4巨集的功能在VBA中消失了,這使得遷移發生了困難。
在Excel 2010中,目標是為必須完全將Excel 4巨集遷移到VBA中的人移除任何現有的阻礙。這項工作通常分為兩類: 
•在Excel的物件模型中新增新的物件、方法和屬性,代表一些現有的而在VBA中沒有等價的Excel 4巨集函式。 
•改進VBA中頁面設定操作的效能,提供Excel 4巨集中PAGE.SETUP()功能相似的效能。 
2)對圖表和形狀的巨集錄製
當Excel 2007引入新的圖表引擎時,主要集中在現代化的圖表和形狀的渲染能力。由於這項工作巨大,因此必須作一些痛苦的取捨決定,這導致Excel 2007在圖表和形狀物件模型方面失去了與Excel 2003的相容性,即巨集錄製能力。
在Excel 2010中,巨集錄製器又可用於圖表格式了,Excel 2003中的絕大多數圖表格式錄製功能又回來了。(極少數例如,包括座標軸文字格式)
3)64位支援和程式碼相容性
Office 2010將釋出32位版本和64位版本。因此,VBA7將隨Office 2010釋出,支援能夠執行32位和64位Office的程式碼的開發。

參見:32 位和 64 位版本的 Office 2010 之間的相容性