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:
@Maika8008
Bác kiểm tra giúp đoạn mã xem có còn lỗi gì không.
Bác nhớ vào Debug nhấn Compile .... xem có cảnh báo identifier nữa không.

JavaScript:
#If VBA7 Then
#ElseIf VBA6 Then
  Public Enum LongLong:[_]:End Enum
  #If Win64 = 0 Then
    Public Enum LongPtr:[_]:End Enum
  #End If
#Else
  Public Enum LongLong:[_]:End Enum
  Public Enum LongPtr:[_]:End Enum
#End If
 
Upvote 0
@Maika8008
Bác kiểm tra giúp đoạn mã xem có còn lỗi gì không.
Bác nhớ vào Debug nhấn Compile .... xem có cảnh báo identifier nữa không.

JavaScript:
#If VBA7 Then
#ElseIf VBA6 Then
  Public Enum LongLong:[_]:End Enum
  #If Win64 = 0 Then
    Public Enum LongPtr:[_]:End Enum
  #End If
#Else
  Public Enum LongLong:[_]:End Enum
  Public Enum LongPtr:[_]:End Enum
#End If
Ổn cả rồi bạn .
1697355269356.png
 
Upvote 0
Lần chỉnh sửa cuối:
Upvote 0
Giải pháp
Rất cảm ơn Bác @Maika8008 đã kiểm tra.

Mã cuối cùng tương thích đa nền tảng được rút gọn lại là:

JavaScript:
#If VBA7 = 0 Then
   Public Enum LongLong:[_]:End Enum
   #If VBA6 = 0 OR Win64 = 0 Then
   Public Enum LongPtr:[_]:End Enum
   #End If
#End If
Em áp dụng mã của anh mà lúc biên dịch báo lỗi:
#If VBA7 = 0 Then
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As Any) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
#If VBA6 = 0 Or Win64 = 0 Then
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As Any) As Long
Private Declare PtrSafe Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
#End If
#End If

Private Const WM_CLOSE = &H10
Public Sub CloseExplorer()
CloseByClass "CabinetWClass"
End Sub
Private Sub CloseByClass(className As String)
PostMessage FindWindow("CabinetWClass", vbNullString), WM_CLOSE, 0, 0
End Sub
 
Upvote 0
Rất cảm ơn Bác @Maika8008 đã kiểm tra.

Mã cuối cùng tương thích đa nền tảng được rút gọn lại là:

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

Tớ hỏi thêm:
Nếu chỉ sử dụng Office 2010 trở lên thì có thể không cần đoạn đầu này luôn:

1697428761086.png

Và sẽ khai báo đồng bộ tất cả các hàm API như thế này:
'---------------------------
Private Declare PtrSafe Sub TimeProc_ApiWindowFlexMove(ByVal hwnd As LongPtr, ByVal wMsg As LongPtr, ByVal idEvent As LongPtr, ByVal dwTime As LongPtr)
'---------------------------

Như vậy, có được không bạn nhỉ?
Theo hướng dẫn này nè:
1697429111430.png
 
Upvote 0
@cantl
Xin chịu thua thôi, không giải thích được.

Bác biết về vấn đề chồng chéo cần giải viết khi lập trình API, song hành cùng các hàm VBA, các hàm tự tạo, tương thích các mã win64 và win32, trong Win64 vùng nhớ các kiểu dữ liệu lại lớn hơn win32, từ phiên bản không có con trỏ bộ nhớ đến có con trỏ bộ nhớ?

Nếu Bác biết rồi, thì mới bàn thêm được.
 
Upvote 0
Cháu mạn phép phát biểu như này, có thì các bác và anh chị tha thứ cho cháu nhé.
Mặc dù code của anh @HeSanbi có chuẩn sác đi bao nhiêu chăng nữa, nhưng riêng cháu không dám dùng.
Lý do không biết đâu mà lần.
 
Upvote 0
Cháu mạn phép phát biểu như này, có thì các bác và anh chị tha thứ cho cháu nhé.
Mặc dù code của anh @HeSanbi có chuẩn sác đi bao nhiêu chăng nữa, nhưng riêng cháu không dám dùng.
Lý do không biết đâu mà lần.
Thì sau này khi lập trình đụng đến nó thì tìm lại bài cũ mà xài... :D
 
Upvote 0
Có người bỏ cả cuộc đời đi cài lại windows hoặc office giữa 64 và 32 bit chỉ để chạy một sổ làm việc Excel.
Có những người tha thiết nhờ vã chuyển mã 32bit sang 64bit cho sổ làm việc của họ.


Hãy tìm những người đó "hỏi thăm sức khỏe"!
 
Upvote 0
Tôi vẫn dùng code chuẩn Microsoft hướng dẫn, nó chạy ổn định trên nhiều máy tính. Đi theo lối mòn thì an toàn mà :)
Còn Tác giả muốn đi con đường riêng dù chấp nhận chông gai, ban đầu chắc chắn chưa phù hợp với nhiều máy tính (không tránh được). Một bài toán được giải theo nhiều cách cũng là cái hay cho người dùng trải nghiệm.
 
Lần chỉnh sửa cuối:
Upvote 0
@PhanTuHuong

Em đúc kết kinh nghiệm đã có được, để nhận thức cách khai báo tốt nhất cho lập trình WinAPI. Mà không ảnh hưởng đến quá trình thông dịch của chúng.
Và từ đó tạo ra cách khai báo tốt nhất trong mã.
Đi chuyên sâu để giải thích tại sao lại có cách khai báo như vậy.
Vì Enum được tận dụng nên trước hết nói về Enum, chính xác là Enumrates, là một kiểu liệt kê hằng số được định nghĩa với bộ nhớ lưu trữ tương đương kiểu Long trên một hằng giá trị.
Khai báo Enum LongPtr ở trên chỉ đủ điều kiện thông dịch khi hệ điều hành và phiên bản Office tương thích.
Cũng giống như Microsoft đã định nghĩa LongPtr như một con trỏ bộ nhớ tương thích tùy vào điều kiện hệ điều hành và phiên bản office mà nó có độ dài vùng nhớ là Long hay LongLong. Từ đó mà trình thông dịch sẽ dịch LongPtr thành Long hay LongLong.
Cách khai báo ở bài viết này cũng tương tự. Nhờ vậy mà phù hợp hầu hết các nền tảng và phiên bản Office.
 
Upvote 0
Tớ hỏi thêm:
Nếu chỉ sử dụng Office 2010 trở lên thì có thể không cần đoạn đầu này luôn:

View attachment 295767

Và sẽ khai báo đồng bộ tất cả các hàm API như thế này:
'---------------------------
Private Declare PtrSafe Sub TimeProc_ApiWindowFlexMove(ByVal hwnd As LongPtr, ByVal wMsg As LongPtr, ByVal idEvent As LongPtr, ByVal dwTime As LongPtr)
'---------------------------

Như vậy, có được không bạn nhỉ?
Theo hướng dẫn này nè:
View attachment 295768
Nếu có thời gian hay đam mê mong muốn chinh phục đỉnh cao của code ấy thì chỉ có các Tools lập trình hiện đại nhất đang còn Phát triển sẻ hổ trợ tốt nhất cho Bạn như C/c++, Delphi, Python, C# ...

Từng bước bỏ dần VBA đi ... nếu có chỉ khai báo các hàm tái sử dụng lại các hàm trong DLL do mình viết Thì mới an toàn và không lỗi thời tù túng và ọp ẹp khi viết mọi thứ trên VBA


Nếu muốn học API thì dò học Delphi thì bạn sẻ thấy trong Delphi có các unit dựng sẳn khai báo các hằng tùy chỉnh cho 32 bít và 64 bít còn bạn chỉ sử dụng đã được các kỹ sư lập trình tầm quốc tế viết nên khá yên tâm không phải mất thời gian Ngu dò mà viết nữa

bên cạnh đó có nhiều hàm API trung gian bạn có thể xem nó hay copy ra unit mới dựa vào đó tùy chỉnh viết lại theo ý mình

cái gì cũng cứ lôi API của Ms ra tái sử dụng chỉ chứng minh 1 điều khả năng không viết được ( dốt ) nên mới tái sử dụng nó tất cả .. đó là sự
thật

Còn muốn tìm hiểu khai báo các hằng API kiểu mò hay dò mà viết thì tìm các diễn đàn VB6 mà xem từ rất lâu đã có rồi và hơn thế nữa

VB6 lỗi thời Ms đã bỏ từ lâu nhưng nó tốt và hay hơn VBA nhiều thứ ...
 
Lần chỉnh sửa cuối:
Upvote 0
@Maika8008 Bác có thể kiểm tra giúp tôi cho những trường hợp sau trên máy của Bác được không?
Vì khi khai báo trên, chạy được trên máy của Bác thì lại không chạy được trên máy khác.

Trường hợp 1:
JavaScript:
#If VBA7 = 0 Then
   #If VBA6 = 0 OR Win64 = 0 Then
   Private Enum LongPtr:[_]:End Enum
   #End If
#End If
    #If VBA7 Then
        Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    #Else
        Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    #End If

Trường hợp 2:
JavaScript:
#If VBA7 = 0 And Win64 = 0 Then
   Private Enum LongPtr:[_]:End Enum
#End If
    #If VBA7 Then
        Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    #Else
        Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    #End If

Trường hợp 3:
JavaScript:
#If VBA7 = 0 Or Win64 = 0 Then
   Private Enum LongPtr:[_]:End Enum
#End If
    #If VBA7 Then
        Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    #Else
        Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    #End If

Trường hợp 4:
JavaScript:
#If Win64 = 0 Then
   Private Enum LongPtr:[_]:End Enum
#End If
    #If VBA7 Then
        Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    #Else
        Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    #End If

(Sau khi chép mã Bác nhấn vào Debug, nhấn Compile....)
 
Lần chỉnh sửa cuối:
Upvote 0
@Maika8008 Bác có thể kiểm tra giúp tôi cho những trường hợp sau trên máy của Bác được không?
Vì khi khai báo trên, chạy được trên máy của Bác thì lại không chạy được trên máy khác.

Trường hợp 1:
JavaScript:
#If VBA7 = 0 Then
   #If VBA6 = 0 OR Win64 = 0 Then
   Private Enum LongPtr:[_]:End Enum
   #End If
#End If
    #If VBA7 Then
        Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    #Else
        Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    #End If

Trường hợp 2:
JavaScript:
#If VBA7 = 0 And Win64 = 0 Then
   Private Enum LongPtr:[_]:End Enum
#End If
    #If VBA7 Then
        Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    #Else
        Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    #End If

Trường hợp 3:
JavaScript:
#If VBA7 = 0 Or Win64 = 0 Then
   Private Enum LongPtr:[_]:End Enum
#End If
    #If VBA7 Then
        Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    #Else
        Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
    #End If

(Sau khi chép mã Bác nhấn vào Debug, nhấn Compile....)
Trường hợp 3 bị báo lỗi identifier. còn 2 trường hợp đầu thì OK.
 
Upvote 0
Trường hợp 3 bị báo lỗi identifier. còn 2 trường hợp đầu thì OK.
Nếu vậy thì khai báo như dưới đây trên máy của Bác vẫn sẽ hoạt động


JavaScript:
#If Win64 = 0 Then
    Private Enum LongPtr:[_]:End Enum
#End If
#If VBA7 Then
    Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
#Else
    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
#End If

(@ongke0711 anh ghé qua test từ #55 giúp nhé anh)
 
Upvote 0
@Maika8008 Bác giúp chạy đoạn mã dưới đây trên máy của Bác, Bác chụp giúp màn hình, đây là đề xuất của một lập trình viên nước ngoài, làm phiền Bác lần nữa. Họ cần sự chắc chắn.

JavaScript:
Sub TestPreCompilerConstants()
    Dim m As String
    Dim b As String
    Dim v As String
    '
    #If Mac Then
        m = "Mac"
    #Else
        m = "Windows"
    #End If
    '
    #If Win64 Then
        b = "x64"
    #Else
        b = "x32"
    #End If
    '
    #If VBA7 Then
        v = "VBA7"
    #Else
        v = "VBA6 (or prior)"
    #End If
    '
    MsgBox "You are on " & m & " OS, on " & b & " Office, on " & v
End Sub
 
Upvote 0
@Maika8008 Bác giúp chạy đoạn mã dưới đây trên máy của Bác, Bác chụp giúp màn hình, đây là đề xuất của một lập trình viên nước ngoài, làm phiền Bác lần nữa. Họ cần sự chắc chắn.

JavaScript:
Sub TestPreCompilerConstants()
    Dim m As String
    Dim b As String
    Dim v As String
    '
    #If Mac Then
        m = "Mac"
    #Else
        m = "Windows"
    #End If
    '
    #If Win64 Then
        b = "x64"
    #Else
        b = "x32"
    #End If
    '
    #If VBA7 Then
        v = "VBA7"
    #Else
        v = "VBA6 (or prior)"
    #End If
    '
    MsgBox "You are on " & m & " OS, on " & b & " Office, on " & v
End Sub
1. Khai báo của bài #57 (tức là trường hợp 4 của #55) vẫn bị báo lỗi identifier.
2. Dùng trường hợp 1 và 2 của bài #55 để chạy code của bài #58 thì kết quả như sau:
1698719522007.png
 
Upvote 0
Web KT
Back
Top Bottom