Z postu z dnia 25 grudnia 2015 r. • VBA 7.0 i MS Access 2010+ „mniej więcej wiemy” (co nie znaczy, że mniej niż więcej ☺, że w pakiecie Office 2010+ wprowadzono nową wersję Microsoft Visual Basic for Applications (VBA) oznaczoną jako VBA 7.0. Wersja ta poprawia wydajność aplikacji w 64 bitowych środowiskach. Równocześnie umożliwia tworzenie aplikacji zgodnych z wcześniejszymi wersjami pakietu Office (2007 i wersje niższe). Aby umożliwić przystosowanie kodu do konkretnej wersji pakietu Office wprowadzono dwie nowe stałe kompilacji warunkowej:
- VBA7
- • pozwala ustalić, czy używane jest nowe środowisko VBA 7.0, czy też starsze wersje VBA.
- Win64
- • umożliwia sprawdzenie, czy środowisko VBA jest 64 bitowe, czy 32 bitowe.
oraz nowy kwalifikator:
- PtrSafe
- • używany do deklarowania procedur i funkcji z zewnętrznych bibliotek DLL w VBA 7 (zawsze w 64 bitowym środowisku VBA7, opcjonalnie w 32 bitowym)
• Jak zadeklarować i uruchomić funkcje API w MS Access 2010+
API - Application Programming Interface jest to zbiór funkcji i procedur znajdujących się w plikach dll (Dynamic Link Library). Inaczej mówiąc są to biblioteki dołączane dynamicznie.
- Podstawowe biblioteki w systemie Windows to:
- • USER32.dll - funkcje zarządzania środowiskiem Windows
- • KERNEL32.dll - funkcje zarządzania funkcjami systemu operacyjnego
- • GDI32.dll - Graphics Device Interface - funkcje zarządzające wyprowadzaniem danych na zewnętrzne urządzenia.
Jak zadeklarować i wywołać funkcje API, tak by prawidłowo działały zarówno w 32-bitowym, jak i 64-bitowym środowisku VBA 7.0 oraz w wersjach niższych VBA możemy dowiedzieć się na portalu MSDN (Microsoft Developer Network), na stronie: Working with VBA in the 32-bit and 64-bit Versions of Office 2010. Skorzystajmy więc z rad Microsoftu:
Applies to: Microsoft Office 2010
Published: May 2010
Provided by: Frank Rice, Microsoft CorporationJak używać stałej kompilacji VBA7 dowiemy się na podstawie przykładowej funkcji DisplayExcelWindowSize zwracającej położenie i wymiary okna głównego programu Excel 2010. W tym celu musimy zadeklarować strukturę RECT oraz dwie funkcje API:
• funkcję FindWindow znajdującą okno o określonej klasie i (lub) tytule,
• funkcję GetWindowRect określającą położenie i wymiary okna.Ponieważ deklaracje tych funkcji są różne w wersji 32 i 64 bitowej, należy zastosować stałą kompilacji warunkowej VBA7 przekierowującą kompilator do odpowiedniej sekcji kodu.
Funkcja DisplayExcelWindowSize wywołuje FindWindowi GetWindowRect i wyświetla okno komunikatu z położeniem i wymiarami okna programu Excel 2010.
' A user-defined type to store the window dimensions. Type RECT Left As Long Top As Long Right As Long Bottom As Long End Type ' Test which version of VBA you are using. #If VBA7 Then ' API function to locate a window. Declare PtrSafe Function FindWindow Lib "user32" _ Alias "FindWindowA" ( _ ByVal lpClassName As String, _ ByVal lpWindowName As String) As LongPtr ' API function to retrieve a window's dimensions. Declare PtrSafe Function GetWindowRect Lib "user32" ( _ ByVal hwnd As LongPtr, _ lpRect As RECT) As Long #Else ' API function to locate a window. Declare Function FindWindow Lib "user32" _ Alias "FindWindowA" ( _ ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long ' API function to retrieve a window's dimensions. Declare Function GetWindowRect Lib "user32" ( _ ByVal hwnd As Long, _ lpRect As RECT) As Long #End If Sub DisplayExcelWindowSize() Dim hwnd As Long, uRect As RECT ' Get the handle identifier of the main Excel window. hwnd = FindWindow("XLMAIN", Application.Caption) ' Get the window's dimensions into the RECT UDT. GetWindowRect hwnd, uRect ' Display the result. MsgBox "The Excel window has these dimensions:" & _ vbCrLf & " Left: " & uRect.Left & _ vbCrLf & " Right: " & uRect.Right & _ vbCrLf & " Top: " & uRect.Top & _ vbCrLf & " Bottom: " & uRect.Bottom & _ vbCrLf & " Width: " & (uRect.Right - uRect.Left) & _ vbCrLf & " Height: " & (uRect.Bottom - uRect.Top) End Sub
Po zapoznaniu się z kodem ze strony Microsoftu, pozostało tylko przekopiowanie kodu do modułu programu Excel 2010 (wersja 64 bitowa)
i uruchomienie funkcji DisplayExcelWindowSize (...), by uzyskać informacje o położeniu i wymiarach głównego okna programu Excel 2010.
W dobrym zwyczaju jest skompilowanie kodu przed jego uruchomieniem.
No i ZONK !
Kompilator zgłasza błąd „Niezgodność typów”. I co najgorsze (nie dla mnie), kompilator ma rację.
Zgodnie z deklaracją, funkcja FindWindow (...) zwraca typ LongPtr, który w 64 bitowym środowisku jest liczbą
typu LongLong.
„Zamiatając pod dywan”, szybko zmieniamy deklarację uchwytu okna hwnd:
Dim hwnd As Long
na
Dim hwnd As LongPtr
lub
Dim hwnd As LongLong
i możemy cieszyć się wynikiem:
Wszystko by było dobrze, gdyby nie pakiet Office w wersjach 2007 i niższych. Próba kompilacji poprawionego kodu w środowisku VB6 kończy się niepowodzeniem.
Kompilator wyświetla okno komunikatu informujące, że napotkał „Niezdefiniowany typ użytkownika” i podświetla linię kodu zawierającą deklarację uchwytu okna:
Dim hwnd As LongPtr.
Podobny błąd wystąpi, gdybyśmy zadeklarowali uchwyt okna hwnd jako typ LongLong.
I nie ma się czemu dziwić, ponieważ wersja VBA 6.0 Office 2007 i wersji niższych nie obsługuje typów LongPtr
i LongLong.
Aby kod działał prawidłowo w VBA 7.0 i wersjach niższych VBA musimy więc poprawić deklarację uchwytu okna hwnd, tak by był
prawidłowego typu w obu wersjach VBA.
W tym celu powinniśmy skorzystać ze stałej kompilacji warunkowej Win64 i typu LongLong
Sub DisplayExcelWindowSize() #If Win64 Then Dim hwnd As LongLong #Else Dim hwnd As Long #End If
lub ze stałej kompilacji warunkowej VBA7 i typu LongPtr
Sub DisplayExcelWindowSize() #If VBA7 Then Dim hwnd As LongPtr #Else Dim hwnd As Long #End If Dim uRect As RECT ' Get the handle identifier of the main Excel window. hwnd = FindWindow("XLMAIN", Application.Caption) ' Get the window's dimensions into the RECT UDT. GetWindowRect hwnd, uRect ' Display the result. MsgBox "The Excel window has these dimensions:" & _ vbCrLf & " Left: " & uRect.Left & _ vbCrLf & " Right: " & uRect.Right & _ vbCrLf & " Top: " & uRect.Top & _ vbCrLf & " Bottom: " & uRect.Bottom & _ vbCrLf & " Width: " & (uRect.Right - uRect.Left) & _ vbCrLf & " Height: " & (uRect.Bottom - uRect.Top) End Sub
Brak komentarzy:
Prześlij komentarz