Để nhiều người khỏi hiểu lầm thì tôi nói rõ. Không phải là tập tin chỉ làm cho 64 bit. Tập tin làm để chạy trên cả 32 bit và 64 bit. 32 bit thì tôi có nên đã kiểm tra rồi. Chỉ không có 64 bit nên muốn nhờ kiểm tra trên 64 bit.
Để nhiều người khỏi hiểu lầm thì tôi nói rõ. Không phải là tập tin chỉ làm cho 64 bit. Tập tin làm để chạy trên cả 32 bit và 64 bit. 32 bit thì tôi có nên đã kiểm tra rồi. Chỉ không có 64 bit nên muốn nhờ kiểm tra trên 64 bit.
cháu ghi lại màn hình chú xem nhé, nhanh quá cháu kịp bấm vào được cái gì cả,hình như là khi đặt chuột ở các ô trên bảng tính thì mới bị, đúng rồi bật lên để không thì không sao nếu di chuyển trên bảng tính là bị lỗi vậy.
cháu ghi lại màn hình chú xem nhé, nhanh quá cháu kịp bấm vào được cái gì cả,hình như là khi đặt chuột ở các ô trên bảng tính thì mới bị, đúng rồi bật lên để không thì không sao nếu di chuyển trên bảng tính là bị lỗi vậy.
Để nhiều người khỏi hiểu lầm thì tôi nói rõ. Không phải là tập tin chỉ làm cho 64 bit. Tập tin làm để chạy trên cả 32 bit và 64 bit. 32 bit thì tôi có nên đã kiểm tra rồi. Chỉ không có 64 bit nên muốn nhờ kiểm tra trên 64 bit.
#If VBA7 Then
Private Sub SetStyleBit(style As LongPtr, ByVal bit As Long, ByVal bSet As Boolean)
#Else
Private Sub SetStyleBit(style As Long, ByVal bit As Long, ByVal bSet As Boolean)
#End If
#If VBA7 Then
Private Sub SetStyleBit(style As LongPtr, ByVal bit As Long, ByVal bSet As Boolean)
#Else
Private Sub SetStyleBit(style As Long, ByVal bit As Long, ByVal bSet As Boolean)
#End If
Đã sửa như bài #53 và chạy êm ru.
Em sửa cái hàm SetStyleBit như kiểu trên vì LongPtr vẫn nhận dạng được trong Office 32bit + Windows 64bit (còn trong Windows 32bit + Office 32bit thì không có tạo máy ảo đế test).
#If VBA7 Then
Private Sub SetStyleBit(style As LongPtr, ByVal bit As Long, ByVal bSet As Boolean)
#Else
Private Sub SetStyleBit(style As Long, ByVal bit As Long, ByVal bSet As Boolean)
#End If
Private Sub SetStyleBit(style As Long, ByVal bit As Long, ByVal bSet As Boolean)
Sửa thành
Mã:
#If VBA7 Then
Private Sub SetStyleBit(style As LongPtr, ByVal bit As Long, ByVal bSet As Boolean)
#Else
Private Sub SetStyleBit(style As Long, ByVal bit As Long, ByVal bSet As Boolean)
#End If
Tóm lại ngoài khai báo style có thiếu sót thì khi CLICK trên sheet có lỗi là do có "xung đột".
Giải thích thêm cho những người thích Windows API hiểu.
1. Tại sao trong tập tin dùng OnTime không có lỗi khi CLICK trên sheet? OnTime dùng để chạy sub doi_mau. OnTime của VBA nên do Excel chạy, cứ sau 1 s thì Excel sẽ gọi doi_moi. Khi Excel bận thì dù 1 s đã qua thì nó cũng không gọi doi_moi mà làm xong các việc bận mới gọi doi_moi. Excel tự gọi nên nó làm chủ được tình huống. Không có xung đột gì ở đây.
2. Tại sao dùng SetTimer của Windows API thì lỗi khi CLICK trên sheet?
Ta phân tích dòng code
Mã:
ID = SetTimer(0, 0, 200, AddressOf TimerProc)
Dòng code trên có nghĩa là ta đã gọi hàm SetTimer của system Windows, kiểu như: báo cáo sếp (Windows), tôi đặt nhiệm vụ là cứ 200 ms thì thực hiện code của tôi, tức TimerProc, ở địa chỉ xyz trong bộ nhớ. Lúc đó system Windows sẽ tạo 1 "đồng hồ", cứ 200 ms sẽ gọi sub TimerProc. Tất nhiên 200 ms là thời gian mặc định. Khi 200 ms trôi qua mà đúng lúc system bận (ngoài process của ta còn vô vàn process khác trong system, bản thân system có những lúc bận) thì system sẽ gọi TimerProc vào lúc sau. Nhưng đây là nói về việc system bận, còn chuyện Excel lúc đó có bận hay không thì system không quan tâm, cứ 200 ms là gọi TimerProc. Hàm SetTimer trả về một giá trị được ghi nhớ trong biến ID. Khi cần "hủy" đồng hồ thì gọi KillTimer và truyền ID vào để hủy đồng hồ. Tại sao KillTimer không đủ để hủy đồng hồ mà lại phải truyền ID vào? Đơn giản là mỗi app có thể tạo nhiều đồng hồ do có nhu cầu. Khi muốn hủy 1 đồng hồ nào đấy mà chỉ cần gọi KillTimer không có tham số thì cụ thánh của system Windpows cũng chịu không biết "người ta" cần hủy đồng hồ nào. Vì thế mỗi đồng hồ được tạo bởi SetTimer sẽ được gán cho một con số định danh, và SetTimer khi tạo đồng hồ sẽ trả về con số định danh (ID) đó của đồng hồ được tạo. Khi cần hủy đồng hồ nào thì gọi KillTimer và truyền con số định danh (ID) của nó vào.
Khi chạy chương trình thì code và dữ liệu (data) sẽ được load vào bộ nhớ. Mọi chuyện sảy ra là sảy ra trong bộ nhớ. Sub TimerProc nằm đâu đó trong bộ nhớ. Trong trường hợp này TimerProc được gọi bởi system Windows chứ không bởi Excel. Vì mình có "khai báo" gì với Excel đâu mà nó biết khi nào phải gọi cái gọi là TimerProc. Để Windows có thể gọi TimerProc thì phải cung cấp cho Windows địa chỉ của TimerProc trong bộ nhớ. Windows biết TimerProc ở đâu thì cứ "đến giở" là gọi nó thôi. Ta cung cấp cho Windows địa chỉ trong RAM của TimerProc bằng hàm: AddressOf TimerProc sẽ trả về địa chỉ của TimerProc trong RAM. Khi đến giờ là Windows gọi TimerProc để thực thi. Nếu đúng lúc đó người dùng CLICK trên sheet thì code của Excerl cũng được thực thi (nếu vd. Excel phát hiện có Worksheet_SelectionChange thì code của Worksheet_SelectionChange sẽ được thực thi). 2 vị khác nhau cùng thực hiện việc của mình thì sảy ra "xung đột".
Hàm mà khi gọi một hàm nào đó của Windows API ta phải cung cấp cho Windows địa chỉ của nó, để Windows biết nó nằm ở đâu trong RAM để sau đó gọi nó, hàm đó được gọi là call back. TimerProc là một call back.