VBA Nâng cao: WinAPI - Khai báo Long và LongPtr tương thích đa nền tảng

Liên hệ QC

HeSanbi

Nam Nhân✨Hiếu Lễ Nghĩa Trí Tín✨
Tham gia
24/2/13
Bài viết
2,382
Được thích
3,536
Giới tính
Nam
Nếu các bạn đang hăng say học VBA hoặc đang lập trình VBA và vọc mã WinAPI thì hãy học ngay mẹo này để viết cho ứng dụng của bạn gọn nhẹ hơn. Khi ứng dụng của bạn viết đa nền tảng và đa phiên bản thì gặp phải nhiều vấn đề về tương thích. Nhất là khai báo Long, LongPtr, LongLong, hoặc các hàm VarPtr, StrPtr, ...
Hoặc các bạn cần bộ nhớ kiểu biến lớn hơn là LongLong trong dự án của bạn. Để tận dụng vào các thuật toán mà bạn tạo ra.

Với mẹo vô cùng đơn giản dưới đây là các bạn có thể bỏ qua các dòng mã rườm rà làm mã của bạn rối và khó đọc.

Đơn giản thôi các bạn hãy thêm dòng mã sau vào bất kì dự án nào của bạn có sử dụng các API 32 và 64 bit.


JavaScript:
#If VBA7 = 0 Then
   Public Enum LongLong:[_]:End Enum
   #If Win64 = 0 Then
   Public Enum LongPtr:[_]:End Enum
   #End If
#End If

***Lưu ý: Khi các bạn chép mã vào VBA, nếu các dòng mã Hiện màu đỏ là bình thường nhé. VBA sẽ không thông dịch mã đó, vì hệ điều hành của các bạn tương thích mã đủ điều kiện.
(Mã này không nên đặt vào module có khai báo cục bộ là Option Private Module.
Vì sẽ không thể khai báo tham chiếu biến trong Class và Module Object (Sheet, Form).

Hãy chạy thử thủ tục TestPretreatment dưới đây để xem thông tin máy tính và Office

JavaScript:
Sub TestPretreatment ()
#If VBA7 Then
#If Win64 Then
     Debug.Print "VBA7 64bit"
#Else
     Debug.Print "VBA7 32Bit"
#End If
#ElseIf VBA6 Then
#If Win64 Then
     Debug.Print "VBA6 64bit"
#Else
     Debug.Print "VBA6 32Bit"
#End If
#Else
     Debug.Print "________"
#End If
End Sub



Như đã nói trên, chỉ cần các bạn khai báo như vậy là có thể viết những dòng mã tương thích đa nền tảng mà không cần phải nhờ đến hai PC hoặc hai ứng dụng khác phiên bản để kiểm thử mã, sau khi đã viết mã tương thích.

Ví dụ khai báo như sau, sẽ làm cho mã bị rối và dài:


JavaScript:
#If VBA7 And Win64 Then
Private Sub TimeProc_ApiWindowFlexMove(ByVal hwnd As LongPtr, ByVal wMsg^, ByVal idEvent As LongPtr, ByVal dwTime^)
#ElseIf VBA7 Then
Private Sub TimeProc_ApiWindowFlexMove(ByVal hwnd As LongPtr, ByVal wMsg&, ByVal idEvent As LongPtr, ByVal dwTime&)
#Else
Private Sub TimeProc_ApiWindowFlexMove(ByVal hwnd&, ByVal wMsg&, ByVal idEvent&, ByVal dwTime&)
#End If
End Sub

Bạn chỉ cần khai báo như sau, khi đã chép mã đã nói trên:
JavaScript:
Private Sub TimeProc_ApiWindowFlexMove(ByVal hwnd As LongPtr, ByVal wMsg As LongLong, ByVal idEvent As LongPtr, ByVal dwTime As LongLong)

End Sub


Các khai báo trước đây, như dưới đây hãy bỏ nó đi:

JavaScript:
#If VBA7  Then
Dim hwnd As LongPtr
#Else
Dim hwnd As Long
#End If

Và bây giờ các bạn chỉ cần khai báo, khi có mã đã nói trên, là đủ để tương thích, mà không cần khai báo tiền xử lý #:
JavaScript:
Dim hwnd As LongPtr

Với mẹo khai báo biến Long như vậy, các bạn có thể chép lại mã có các API với các tham số biến LongPtr, LongLong rất đơn giản.

Nếu các bạn chép mã API đang ở nền tảng win64, thì chỉ cần bỏ PtrSafe trong dòng mã để tương thích với Nền tảng win32 (Còn tùy thuộc vào hàm API, có hàm API không có ở Win32).
Bạn không cần sửa LongPtr, LongLong thành Long để tương thích với win32 nữa. Khi đã có mã nói trên.


Lưu ý: Sửa từ API không có PtrSafe sang API có PtrSafe thì có những trường hợp Long phải sửa thành LongPtr hoặc LongLong

Ví dụ khai báo tương thích và các hàm API tương thích đa nền tảng:

JavaScript:
' Khai báo tương thích đa nền tảng
#If VBA7 = 0 Then
   Public Enum LongLong:[_]:End Enum
   #If Win64 = 0 Then
   Public Enum LongPtr:[_]:End Enum
   #End If
#End If
' Các hàm API tương thích đa nền tảng
#If VBA7 Then
Private Declare PtrSafe Function IUnknown_GetWindow Lib "shlwapi" Alias "#172" (ByVal pIUnk As Any, ByVal hwnd As LongPtr) As Long
#Else
Private Declare Function IUnknown_GetWindow Lib "shlwapi" Alias "#172" (ByVal pIUnk As Any, ByVal hwnd As LongPtr) As Long
#End If

#If VBA7 Then
  #If Win64 Then
  Private Declare PtrSafe Function GetWindowLong Lib "user32" Alias "GetWindowLongPtrA" (ByVal hWnd As LongPtr, ByVal nIndex As Long) As LongPtr
  Private Declare PtrSafe Function SetWindowLong Lib "user32" Alias "SetWindowLongPtrA" (ByVal hWnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
  Declare PtrSafe Function GetClassLong Lib "user32" Alias "GetClassLongPtrA" (ByVal hWnd As LongPtr, ByVal nIndex As Long) As LongPtr
  Private Declare PtrSafe Function SetClassLong Lib "user32" Alias "SetClassLongPtrA" (ByVal hWnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
  #Else
  Private Declare PtrSafe Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As LongPtr, ByVal nIndex As Long) As Long
  Private Declare PtrSafe Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
  Declare PtrSafe Function GetClassLong Lib "user32" Alias "GetClassLongA" (ByVal hWnd As LongPtr, ByVal nIndex As Long) As Long
  Private Declare PtrSafe Function SetClassLong Lib "user32" Alias "SetClassLongA" (ByVal hWnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
  #End If
#Else
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Declare Function GetClassLong Lib "user32" Alias "GetClassLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetClassLong Lib "user32" Alias "SetClassLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
#End If

Có thể các bạn đang hỏi tại sao lại có kiểu LongPtr. Đơn giản thôi, nó là kiểu khai báo tương thích. Nếu LongPtr ở môi trường 32 bit thì nó là Long, nếu nó ở 64bit thì nó là LongLong. Nó không thực sự là Long và LongLong.

Ngay từ lúc này tôi khuyên các bạn nên tận dụng Kiểu LongLong vì nó khai thác bộ nhớ lớn hơn Long khá nhiều.
Vì khi bạn đang sử dụng Win64 mà lại dùng kiểu Long cho một thuật toán mạnh mẽ thì thật là tiếc nuối cho đà phát triển của bạn.


Mẹo tôi hướng dẫn trên đây sẽ giúp các bạn đơn giản việc viết mã đa nền tảng, các bạn có thể tận dụng nó trên con đường lập trình của mình.
Chúc các bạn thành công!

-------------------------------------------
Các bạn có thể tham khảo thêm bài viết của tôi tại tag
#sanbi udf
 
Lần chỉnh sửa cuối:
Hay quá! Để lúc nào lôi cái mã 32 ra cải tạo lại xem.
 
Upvote 0
Em cũng có file, trước được thầy viết trên nền Office 32bit, giờ máy lại cài Office 64bit, nên chạy lỗi.
Mong anh @HeSanbi có thể giúp đỡ.
 
Upvote 0
Chỗ khai báo LongPtr này không được bạn à?
1680054150970.png
 
Upvote 0
Win11 64 bit và Office 2019 32bit
Bác kiểm thử mã dưới.
Vì kiểu khai báo LongPtr vẫn có trong Win64 và VBA Office32bit nên buộc phải làm như vậy


JavaScript:
#If VBA7 Then
#Else
Public Enum LongLong: [_]: End Enum
#If Win64 Then
#ElseIf Win32 Then
#Else
Public Enum LongPtr: [_]: End Enum
#End If
#End If
 
Lần chỉnh sửa cuối:
Upvote 0
Bác kiểm thử mã dưới.
Vì kiểu khai báo LongPtr vẫn có trong Win64 và VBA Office32bit nên buộc phải làm như vậy


JavaScript:
#If VBA7 Then
#Else
Public Enum LongLong: [_]: End Enum
#const office32 = true
#If office32 Then
#Else
Public Enum LongPtr: [_]: End Enum
#End If
#End If
Cũng vậy bạn ơi. Máy vẫn không đồng ý với LongPtr
 
Upvote 0
Win11 64 bit và Office 2019 32bit
Nếu không được nữa thì bác tiếp tục thử mã dưới đây, vì tôi chỉ có một pc 64bit và office 64bit nên không thể kiểm tra được hết. Mã tôi viết chỉ dựa theo kinh nghiệm lập trình.

JavaScript:
#If VBA7 Then
  #If Win64 Then
  #ElseIf Win32 Then
  #Else
  #End If
#Else
  Public Enum LongLong:[_]:End Enum
  #If Win32 Then
  #Else
    Public Enum LongPtr:[_]:End Enum
  #End If
#End If
 
Upvote 0
Nếu không được nữa thì bác tiếp tục thử mã dưới đây, vì tôi chỉ có một pc 64bit và office 64bit nên không thể kiểm tra được hết. Mã tôi viết chỉ dựa theo kinh nghiệm lập trình.

JavaScript:
#If VBA7 Then
  #If Win64 Then
  #ElseIf Win32 Then
  #Else
  #End If
#Else
  Public Enum LongLong:[_]:End Enum
  #If Win32 Then
  #Else
    Public Enum LongPtr:[_]:End Enum
  #End If
#End If
LongPtr để vào đâu cũng không được chấp nhận. Có lẽ câu lệnh đó không đúng.
 
Upvote 0
Không biết áp dụng code có đúng chưa nhưng tôi thử nghiệm thì thấy chạy bình thường trên:
- Windows 10 64, Office 2103 32
- Windows 11 64, Office 2021 64

Screen Shot 2023-03-29 at 10.54.55.png
 
Upvote 0
Tại trên GPE này họ ít quan tâm tới VB6 vì xem là thứ đã bỏ đi lâu rồi ... còn Tôi lâu lâu vẫn ngó tới nó

Kỹ thuật này khoãng 6 năm trước tay code Nga ngố đã dùng rồi kiểu như sau

Mã:
#Const HasPtrSafe = (VBA7 <> 0)
#If HasPtrSafe Then
    Private Declare PtrSafe Function SHCreateStreamOnFile Lib "shlwapi" Alias "SHCreateStreamOnFileW" (ByVal pszFile As LongPtr, ByVal grfMode As Long, ppStm As stdole.IUnknown) As Long
    Private Declare PtrSafe Function DispCallFunc Lib "oleaut32" (ByVal pvInstance As LongPtr, ByVal oVft As LongPtr, ByVal lCc As Long, ByVal vtReturn As VbVarType, ByVal cActuals As Long, prgVt As Any, prgpVarg As Any, pvargResult As Variant) As Long
#Else
    Private Enum LongPtr
        [_]
    End Enum
    Private Declare Function SHCreateStreamOnFile Lib "shlwapi" Alias "SHCreateStreamOnFileW" (ByVal pszFile As LongPtr, ByVal grfMode As Long, ppStm As stdole.IUnknown) As Long
    Private Declare Function DispCallFunc Lib "oleaut32" (ByVal pvInstance As LongPtr, ByVal oVft As LongPtr, ByVal lCc As Long, ByVal vtReturn As VbVarType, ByVal cActuals As Long, prgVt As Any, prgpVarg As Any, pvargResult As Variant) As Long
#End If

chịu khó tìm chút có File WinAPI.tlb trong đó họ khai báo hết các hàm API của Windows và các hằng của nó ... còn ta chỉ xơi
Trên VBA Add nó vào là dùng mà không cần khai báo API và các hằng nữa
xem hình

1680063547271.png
 
Upvote 0
Người ta đang cố gắng bớt khai báo và sử dụng API từ VBA cho tốc độ code chạy nhanh hơn còn mình cắm đầu khai báo cho lắm lại càng ngu

Khi Excel mở lên nó tính toán lại mọi cái trong File ... càng khai báo nhiều API là càng tăng thêm phần Ngu
 
Upvote 0
Tự nhận mình "ngu" thì về học những cái ngu thôi
 
Upvote 0
trong 1 File .TLB có file lớn có cả 1000 hàm API + các hằng khai báo sẳn khi Add vào Excel nó bình thường như những File Excel chưa gì trong đó
xong Lưu lại xem là thấy

Còn 1 File Excel khai khoãng 1000 hàm API + các hằng trong đó ... mở lên xem mới thấy ....

2 cái nó khác nhau hoàn toàn 1 cái sử dụng TLB còn 1 cái viết cả 1000 hàm + Hằng trên Module VBA
 
Lần chỉnh sửa cuối:
Upvote 0
@ptm0412
Tôi tưởng rằng thánh "khoe hàng" không bao giờ rãnh rỗi ghé bài viết tôi khoe "giống", nay độc lạ xuất hiện, tôi hơi ngỡ ngàng, nên mời bác vào xem trưng bày. Tiễn được bác tiễn giùm tôi sang "Dubai chơi siêu xe" giúp tôi.

Thánh này được "người ngoài hành tinh" phái xuống trái đất khoe "công nghệ ngoài hệ mặt trời" tôi không thể tiếp nhận kịp công nghệ đó. Nên mời thánh lên đĩa bay về lại không gian.
 
Upvote 0
Web KT
Back
Top Bottom