Access
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Access

Câu lệnh DefType trong VBA:Mặt tối của khả năng tương thích ngược

Chỉ vì bạn có thể làm điều gì đó, không có nghĩa là bạn nên làm.

Tôi tin tưởng sâu sắc vào sự thần thánh của khả năng tương thích ngược. Nhưng nó đi kèm với một mặt tối. Đôi khi những cách làm cũ không còn được ưa chuộng nữa. Việc sử dụng chúng trở nên phức tạp đến mức chúng ta có xu hướng quên chúng thậm chí còn tồn tại.

Vì vậy, nó đi kèm với các câu lệnh DefType.

Điều bạn không biết có thể làm tổn thương bạn

Vài tháng trước, tôi đã viết một bài báo về mô-đun lớp Hoạt động đăng ký của Romke Soldaat.

Tôi đã xuất bản những thay đổi mà tôi đã thực hiện đối với các khai báo API của Romke để làm cho mã chạy trong VBA 64-bit. Mọi lệnh gọi API được gói trong #If VBA7 các thẻ biên dịch có điều kiện và được cập nhật với PtrSafe từ khóa.

Chỉ có một vấn đề.

Tôi đã quên bao gồm một thay đổi quan trọng mà tôi đã thực hiện đối với một trong các khai báo cấp mô-đun trong mã của Romke. Nếu không có thay đổi này, mã đã sửa đổi của Romke sẽ không biên dịch theo VBA 64-bit. Đã xảy ra lỗi biên dịch trên dòng sau:

Thông báo lỗi là " Loại đối số ByRef không khớp "và biến được đánh dấu là hCurKey .

Đây là dòng mã vi phạm từ mô-đun lớp ban đầu của Romke:

Private hCurKey

Để khắc phục lỗi biên dịch, dòng mã trên có thể được thay đổi thành sau:

Private hCurKey As Variant

Nhưng khoan đã, bạn nói, không phải hai dòng mã đó làm cùng một việc?!?! Mọi người đều biết rằng nếu bạn không khai báo kiểu của một biến trong VBA thì nó sẽ được khai báo ngầm là một Biến thể. ... Hay là nó?

Rõ ràng Tốt hơn Ngụ ý

Vậy điều gì đang thực sự xảy ra ở đây?

Vấn đề là dòng mã đầu tiên ở trên– Private hCurKey –Đang xác định biến hCurKey là một Long loại dữ liệu.

Làm sao chuyện này có thể?

Đó là vì dòng kỳ lạ này ở đầu mô-đun lớp của Romke:

DefLng H-I, L, N

Dòng đó đang làm gì? Nó nói rằng mọi biến được khai báo trong mô-đun hiện tại không có kiểu được khai báo rõ ràng có tên biến bắt đầu bằng H , I , L hoặc N , sẽ được trình biên dịch coi là Long kiểu dữ liệu.

Và như vậy, dòng Private hCurKey đã ngầm hiểu khai báo một kiểu cho biến hCurKey, nhưng khai báo ngầm định là kiểu dữ liệu Dài thay vì một Biến thể.

Tại sao Biến thể Biên dịch But Long Không?

Về lý do tại sao mã biên dịch khi hCurKey là một Biến thể nhưng không thành công khi nó dài, đó là vấn đề của quá trình chuyển đổi từ 32 bit sang 64 bit.

Để tìm ra nguồn gốc của vấn đề, chúng tôi cần kiểm tra mã đã di chuyển cho khai báo API RegCreateKeyEx:

#If VBA7 Then
    Private Declare PtrSafe Function RegCreateKeyEx _
      Lib "advapi32.dll" Alias "RegCreateKeyExA" ( _
          ByVal hKey As LongPtr, ByVal lpSubKey As String, _
          ByVal Reserved As Long, ByVal lpClass As String, _
          ByVal dwOptions As Long, ByVal samDesired As Long, _
          lpSecurityAttributes As SECURITY_ATTRIBUTES, _
          phkResult As LongPtr, lpdwDisposition As Long) As Long
#Else
    Private Declare Function RegCreateKeyEx _
      Lib "advapi32.dll" Alias "RegCreateKeyExA" ( _
          ByVal hKey As Long, ByVal lpSubKey As String, _
          ByVal Reserved As Long, ByVal lpClass As String, _
          ByVal dwOptions As Long, ByVal samDesired As Long, _
          lpSecurityAttributes As SECURITY_ATTRIBUTES, _
          phkResult As Long, lpdwDisposition As Long) As Long
#End If

Khi chúng tôi gọi RegCreateKeyEx từ mã, chúng tôi đang chuyển hCurKey biến làm đối số thứ hai đến cuối cùng trong hàm. Nói cách khác, nó được chuyển dưới dạng phkResult lý lẽ. Lưu ý rằng trong phiên bản trước VBA7 (Access 2007 trở về trước), phkResult được khai báo là Long, nhưng trong phiên bản VBA7, nó được khai báo là LongPtr .

Đó là bởi vì phkResult nhận được một tay cầm vào khóa đăng ký đã tạo hoặc đã mở. Bất cứ khi nào bạn thấy từ "xử lý" được liên kết với lệnh gọi API, bạn có thể dịch từ đó một cách an toàn trong đầu thành "địa chỉ bộ nhớ". Đó là lý do tại sao đối số được xác định lại thành LongPtr trong mã VBA7:khi thực thi trong môi trường 32 bit, LongPtr được coi là Long 32 bit số nguyên, nhưng trong môi trường 64 bit, LongPtr được coi là LongLong 64 bit số nguyên.

Khai báo hCurKey như Biến thể là một chút đường tắt. Sự thích ứng sau đây cũng sẽ hoạt động (và hoạt động nhanh hơn, mặc dù sự gia tăng tốc độ có thể không được người dùng nhận thấy trừ khi nó được gọi nhiều lần trong vòng lặp):

#If VBA7 Then
    Private hCurKey As LongPtr
#Else
    Private hCurKey As Long
#End If

Như tôi đã nói, cách tiếp cận ở trên rõ ràng hơn trong việc truyền đạt ý định của nhà phát triển, hoạt động tốt hơn và sẽ gây ra nhiều lỗi thời gian biên dịch hơn so với Private hCurKey As Variant thay thế.

Nhưng tôi được biết đến là người lười biếng và Private hCurKey As Variant gần như tốt với việc nhập ít hơn nhiều.

Sử dụng Kiến thức của Bạn cho Tốt

Bây giờ, hãy nhớ những gì tôi đã nói ở đầu bài viết này?

Chỉ vì bạn có thể làm điều gì đó, không có nghĩa là bạn nên làm.

Tôi viết bài này vì hai lý do:

  1. Để khuyến khích bạn rõ ràng khai báo các biến Variant As Variant
  2. Để nâng cao nhận thức về một khía cạnh bí ẩn của VBA có thể khiến bạn khó chịu nếu bạn đang duy trì (hoặc sao chép dán) mã của người khác

TÔI KHÔNG CHƯA viết bài này để truyền cảm hứng cho bạn viết các câu lệnh DefType trong mã của riêng bạn. ĐỪNG LÀM THẾ!!! Hãy nhớ rằng, chỉ vì bạn có thể làm điều gì đó không có nghĩa là bạn nên làm.

Tham chiếu bên ngoài

Định kiểu câu lệnh (VBA) Chủ đề tham chiếu VBA OfficeMicrosoft Docso365devx Khai báo API Windows trong VBA cho 64-bitCách chuyển đổi Khai báo API của bạn thành 64-bit. - Những huyền thoại phổ biến đã bị bóc trần, các yếu tố chính được giải thích! CodekabinettPhilipp Stiefel

Bài viết được tham khảo

Sự tôn trọng đối với khả năng tương thích ngược Một tính năng được một tỷ lệ rất nhỏ người dùng thành thạo sử dụng nhiều đã được duy trì trong suốt năm lần nâng cấp tiếp theo (và còn tiếp tục tăng). Bây giờ điều đó đang thể hiện sự tôn kính đối với khả năng tương thích ngược. Không còn lâu nữa SetMike Wolfe Lớp RegOp cho VBA 64-bit Cập nhật mô-đun lớp đọc và ghi sổ đăng ký VBA cổ điển để tương thích 64-bit. Không còn lâu nữa SetMike Wolfe
  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. 5 mẹo cơ sở dữ liệu thực tế cho người mới bắt đầu

  2. Mẹo về Bảng Microsoft Access - Thủ thuật &Nguyên tắc Phần 2

  3. 10 lý do hàng đầu để sử dụng Access và Excel cùng nhau

  4. Cách xóa mật khẩu khỏi cơ sở dữ liệu trong Access 2016

  5. Khai báo và khởi tạo các biến trong cùng một dòng trong VBA