[Hỏi] Class bị "vỡ" khi dùng trên file có Macro nhưng không đượ kích hoạt (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

huuthang_bd

Chuyên gia GPE
Tham gia
10/9/08
Bài viết
8,933
Được thích
11,357
Donate (Momo)
Donate
Giới tính
Nam
Nghề nghiệp
Thợ đụng
Trong quá trình tìm hiểu và áp dụng Class module mình gặp phải vấn đề khó hiểu như tiêu đề mình đã nêu: Class bị "vỡ" khi dùng trên file có Macro nhưng không được kích hoạt, làm thế nào để khắc phục hiện tượng này?

Hiện tượng này mình gặp phải trên Excel 2007. Mình xin mô tả lại hiện tượng như thế này.

Mình có 1 file Add in tên là Main.xla và một file có chứa macro tên là Test.xls (được đính kèm theo bài viết)

Đầu tiên mình mở file Main.xla và kích hoạt Macro cho file này, lúc này sẽ xuất hiện thêm tab Add-Ins trên hệ thống Ribbon, ở đó có một nút lệnh để thí nghiệm.

Trường hợp 1: Mở file Test.xls kích hoạt macro, thử thay đổi vùng chọn sẽ thấy xuất hiện hộp thông báo với nội dung "GPE" (điều này có nghĩa là Class đang hoạt động tốt). Bây giờ mình click vào nút lệnh mới trên tab Add-Ins sẽ xuất hiện UserForm1, click vào nút lệnh Insert Sheet trên UserForm này sẽ thêm 1 Sheet trên file hiện hành. Đóng UserForm và thử thay đổi vùng chọn thì thấy vẫn còn xuất hiện thông báo "GPE" tức là Class vẫn hoạt động bình thường.
Bây giờ mình đóng file Test.xls để thử trường hợp 2.

Trường hợp 2: Mở file Test.xls nhưng không kích hoạt macro, thử thay đổi vùng chọn sẽ thấy xuất hiện hộp thông báo với nội dung "GPE" (điều này có nghĩa là Class đang hoạt động tốt). Bây giờ mình click vào nút lệnh mới trên tab Add-Ins sẽ xuất hiện UserForm1, click vào nút lệnh Insert Sheet trên UserForm này sẽ thêm 1 Sheet trên file hiện hành nhưng đồng thời UserForm1 cũng biến mất. Bây giờ thay đổi vùng chọn thì không còn xuất hiện hộp thông báo nữa, Class đã bị vỡ.
Một điều lạ là nếu không kích hoạt macro nhưng sau khi mở file có macro mình mở cửa sổ VBE sau đó quay lại bảng tính để thực hiện thì Class lại không bị.
Bây giờ mình đóng file Test.xls để thử trường hợp 3.

Trường hợp 3: Mở file Test.xls nhưng không kích hoạt macro, nhấn Alt + F11 để mở cửa sổ VBE rồi nhấn Alt + q để đóng cửa sổ VBE quay lại trang tính. Bây giờ mình click vào nút lệnh mới trên tab Add-Ins sẽ xuất hiện UserForm1, click vào nút lệnh Insert Sheet trên UserForm này sẽ thêm 1 Sheet trên file hiện hành. Đóng UserForm và thử thay đổi vùng chọn thì thấy vẫn còn xuất hiện thông báo "GPE" tức là Class vẫn hoạt động bình thường.

Anh, chị, bạn nào biết cách khắc phục vui lòng hướng dẫn giúp.

Xin chân thành cảm ơn.
 

File đính kèm

Trong quá trình tìm hiểu và áp dụng Class module mình gặp phải vấn đề khó hiểu như tiêu đề mình đã nêu: Class bị "vỡ" khi dùng trên file có Macro nhưng không được kích hoạt, làm thế nào để khắc phục hiện tượng này?

Hiện tượng này mình gặp phải trên Excel 2007. Mình xin mô tả lại hiện tượng như thế này.

Mình có 1 file Add in tên là Main.xla và một file có chứa macro tên là Test.xls (được đính kèm theo bài viết)

Đầu tiên mình mở file Main.xla và kích hoạt Macro cho file này, lúc này sẽ xuất hiện thêm tab Add-Ins trên hệ thống Ribbon, ở đó có một nút lệnh để thí nghiệm.

Trường hợp 1: Mở file Test.xls kích hoạt macro, thử thay đổi vùng chọn sẽ thấy xuất hiện hộp thông báo với nội dung "GPE" (điều này có nghĩa là Class đang hoạt động tốt). Bây giờ mình click vào nút lệnh mới trên tab Add-Ins sẽ xuất hiện UserForm1, click vào nút lệnh Insert Sheet trên UserForm này sẽ thêm 1 Sheet trên file hiện hành. Đóng UserForm và thử thay đổi vùng chọn thì thấy vẫn còn xuất hiện thông báo "GPE" tức là Class vẫn hoạt động bình thường.
Bây giờ mình đóng file Test.xls để thử trường hợp 2.

Trường hợp 2: Mở file Test.xls nhưng không kích hoạt macro, thử thay đổi vùng chọn sẽ thấy xuất hiện hộp thông báo với nội dung "GPE" (điều này có nghĩa là Class đang hoạt động tốt). Bây giờ mình click vào nút lệnh mới trên tab Add-Ins sẽ xuất hiện UserForm1, click vào nút lệnh Insert Sheet trên UserForm này sẽ thêm 1 Sheet trên file hiện hành nhưng đồng thời UserForm1 cũng biến mất. Bây giờ thay đổi vùng chọn thì không còn xuất hiện hộp thông báo nữa, Class đã bị vỡ.
Một điều lạ là nếu không kích hoạt macro nhưng sau khi mở file có macro mình mở cửa sổ VBE sau đó quay lại bảng tính để thực hiện thì Class lại không bị.
Bây giờ mình đóng file Test.xls để thử trường hợp 3.

Trường hợp 3: Mở file Test.xls nhưng không kích hoạt macro, nhấn Alt + F11 để mở cửa sổ VBE rồi nhấn Alt + q để đóng cửa sổ VBE quay lại trang tính. Bây giờ mình click vào nút lệnh mới trên tab Add-Ins sẽ xuất hiện UserForm1, click vào nút lệnh Insert Sheet trên UserForm này sẽ thêm 1 Sheet trên file hiện hành. Đóng UserForm và thử thay đổi vùng chọn thì thấy vẫn còn xuất hiện thông báo "GPE" tức là Class vẫn hoạt động bình thường.

Anh, chị, bạn nào biết cách khắc phục vui lòng hướng dẫn giúp.

Xin chân thành cảm ơn.

Tôi nghĩ ra 2 cách củ chuối.

1. Từ điểm 3 ta có thể thử: Xử lý cả ExcelApp_WorkbookOpen. Code sẽ thử mở VBE rồi đóng VBE. Tôi nói thử vì có thể mở, đóng VBE bằng code khác với mở, đóng VBE "bằng tay" (thao tác bởi người dùng). Nhưng cách này củ chuối quá.

2. Thôi đành phải tạo lại đối tượng
Mã:
Sub ReCreateObject()
    If App Is Nothing Then
        Set App = New clsExcelApp
        App.Wrap Application
    End If
End Sub

Vấn đề mấu chốt là khi nào gọi ReCreateObject. Chắc chắn không thể đặt trong các ExcelApp_*** được vì khi đã sẩy ra sự cố thì đối tượng App đi toi rồi còn đâu.

Nếu ta sửa sub Test thành

Mã:
Private Sub Test()
    UserForm1.Show
    ReCreateObject
End Sub

thì khi sẩy ra sự cố, cũng là trường hợp duy nhất mà ReCreateObject có ích, thì ReCreateObject không được thực hiện. Vì "sự cố" tức là "chết đột ngột" nên ReCreateObject không được thực hiện

Nếu sửa thành

Mã:
Private Sub Test()
    ReCreateObject
    UserForm1.Show
End Sub

thì chỉ khi mở UserForm lần thứ 2 mới có tác dụng. Nếu UserForm không được mở thêm lần nào, tức chỉ mở 1 lần duy nhất, thì bó tay.

Tôi nghĩ là có lẽ phải dùng đồng hồ

Mã:
Private Sub Add_Click()
    Application.OnTime Now + TimeValue("00:00:2"), "ReCreateObject"
    ActiveWorkbook.Sheets.Add After:=ActiveSheet
End Sub

Mong rằng sẽ có cách lịch sự hơn.
 
Upvote 0
Tôi nghĩ ra 2 cách củ chuối.

1. Từ điểm 3 ta có thể thử: Xử lý cả ExcelApp_WorkbookOpen. Code sẽ thử mở VBE rồi đóng VBE. Tôi nói thử vì có thể mở, đóng VBE bằng code khác với mở, đóng VBE "bằng tay" (thao tác bởi người dùng). Nhưng cách này củ chuối quá.

2. Thôi đành phải tạo lại đối tượng
Mã:
Sub ReCreateObject()
    If App Is Nothing Then
        Set App = New clsExcelApp
        App.Wrap Application
    End If
End Sub

Vấn đề mấu chốt là khi nào gọi ReCreateObject. Chắc chắn không thể đặt trong các ExcelApp_*** được vì khi đã sẩy ra sự cố thì đối tượng App đi toi rồi còn đâu.

Nếu ta sửa sub Test thành

Mã:
Private Sub Test()
    UserForm1.Show
    ReCreateObject
End Sub

thì khi sẩy ra sự cố, cũng là trường hợp duy nhất mà ReCreateObject có ích, thì ReCreateObject không được thực hiện. Vì "sự cố" tức là "chết đột ngột" nên ReCreateObject không được thực hiện

Nếu sửa thành

Mã:
Private Sub Test()
    ReCreateObject
    UserForm1.Show
End Sub

thì chỉ khi mở UserForm lần thứ 2 mới có tác dụng. Nếu UserForm không được mở thêm lần nào, tức chỉ mở 1 lần duy nhất, thì bó tay.

Tôi nghĩ là có lẽ phải dùng đồng hồ

Mã:
Private Sub Add_Click()
    Application.OnTime Now + TimeValue("00:00:2"), "ReCreateObject"
    ActiveWorkbook.Sheets.Add After:=ActiveSheet
End Sub

Mong rằng sẽ có cách lịch sự hơn.

Cảm ơn câu trả lời của anh. Nhưng đúng là giải quyết như vậy thì chưa ổn.

Cách 1: Khi mở một file mà chưa kích hoạt Macro nếu mở cửa sổ VBE thì không thể kích hoạt Macro được nữa trừ khi đóng và mở lại file đó. Nếu anh chưa vào sự kiện Open động tác mở cửa sổ VBE thì tất cả các file khi mở lên sẽ không kích hoạt được Macro. Em đã từng thử qua cách sau tuy Class không bị vỡ nhưng lại gặp rắc rối ngược lại như cách trên, tức là tất cả các file có Macro khi mở lên đều được kích hoạt Macro làm cho ta không kiểm soát được. Code như sau:
PHP:
Private Sub ExcelApp_WorkbookOpen(ByVal Wb As Workbook)
On Error Resume Next
Dim VBC As Object
Set VBC = Wb.VBProject.VBComponents
End Sub
Cách 2: Tùy theo từng thủ tục thời gian thực hiện là khác nhau nên việc canh thời gian để tạo lại đối tượng sẽ gặp nhiều bất cập. Hơn nữa, khi Class bị vỡ cũng ảnh hưởng đến một số đối tượng khác như các biến toàn cục đều bị mất giá trị, Ribbon tự tạo bị mất hiệu lực.

Hi vọng sẽ có một giải pháp khác triệt để hơn. Tốt hơn hết là làm sao cho Class không bị vỡ để không bị ảnh hưởng đến các đối tượng khác.
 
Upvote 0
Hi vọng sẽ có một giải pháp khác triệt để hơn. Tốt hơn hết là làm sao cho Class không bị vỡ để không bị ảnh hưởng đến các đối tượng khác.

Nếu không có cách nào khác thì tôi sẽ dùng SetTimer, KillTimer (hàm API) để chạy ngầm. Nếu phát hiện biến App = Nothing thì Set nó trở lại
Đương nhiên, nếu vì lý do gì đó mà Excel bị "vỡ toàn tập" thì ngay cả SetTimer cũng phải tiêu luôn
 
Upvote 0
Cảm ơn câu trả lời của anh. Nhưng đúng là giải quyết như vậy thì chưa ổn.

Thì thế mới gọi là "củ chuối mà, he he.

Cách 1: Khi mở một file mà chưa kích hoạt Macro nếu mở cửa sổ VBE thì không thể kích hoạt Macro được nữa trừ khi đóng và mở lại file đó. Nếu anh chưa vào sự kiện Open động tác mở cửa sổ VBE thì tất cả các file khi mở lên sẽ không kích hoạt được Macro. Em đã từng thử qua cách sau tuy Class không bị vỡ nhưng lại gặp rắc rối ngược lại như cách trên, tức là tất cả các file có Macro khi mở lên đều được kích hoạt Macro làm cho ta không kiểm soát được. Code như sau:
PHP:
Private Sub ExcelApp_WorkbookOpen(ByVal Wb As Workbook)
On Error Resume Next
Dim VBC As Object
Set VBC = Wb.VBProject.VBComponents
End Sub

Chuyện "không kiểm soát được" tôi nghĩ chỉ là chuyện phụ. Vì khi mở tập tin thì người dùng có 2 lựa chọn: hoặc kích hoạt Macro hoặc quyết định không kích hoạt Macro. Trường hợp 1 thì khỏi bàn. Còn trường hợp 2 thì dù người dùng "có lý do" hay không nếu anh ta quyết định như thế thì phải tôn trọng quyết định của anh ta. Không phải là Excel bầy trò Disable Macro để rồi khi anh ta chọn "không kích hoạt Macro" thì vẫn chạy được các Macro - Disable Macro hay không thì vẫn như nhau. Vậy thậm chí nếu tìm được cách kiểm soát thì cũng không nên làm thế.

Câu hỏi vẫn là: Người dùng không kích hoạt Macro và code cũng không tìm cách kích hoạt Macro, vậy có cách nào để đối tượng không bị vỡ không?

Hi vọng sẽ có một giải pháp khác triệt để hơn. Tốt hơn hết là làm sao cho Class không bị vỡ để không bị ảnh hưởng đến các đối tượng khác.

Tất nhiên là hi vọng vì hi vọng chết cuối cùng mà.
 
Upvote 0
Mình thử cả Excel 2007, 2010 đều không lỗi gì cả. Bạn kiểm tra xem Excel có đang cài add-in nào khác nữa không, nếu có tạm gỡ ra để đảm bảo môi trường "sạch" từ đó mới biết do mình hay do thằng khác.
 
Upvote 0
Mình thử cả Excel 2007, 2010 đều không lỗi gì cả. Bạn kiểm tra xem Excel có đang cài add-in nào khác nữa không, nếu có tạm gỡ ra để đảm bảo môi trường "sạch" từ đó mới biết do mình hay do thằng khác.
Khi thử mình đã gỡ hết tất cả các Add-in rồi. Mình đã thử nhiều lần và rút ra được 3 trường hợp như bài #1. Không hiểu sao bạn thử lại không bị nhỉ?

Không biết anh switom và anh ndu96081631 có thử không? Nếu đã thử thì có phải bị như các trường hợp ở bài #1 không?
 
Upvote 0
Khi thử mình đã gỡ hết tất cả các Add-in rồi. Mình đã thử nhiều lần và rút ra được 3 trường hợp như bài #1. Không hiểu sao bạn thử lại không bị nhỉ?

Không biết anh switom và anh ndu96081631 có thử không? Nếu đã thử thì có phải bị như các trường hợp ở bài #1 không?

Mình làm add-in nhiều và toàn làm class với mức độ rất sâu, sản phẩm làm ra bao giờ cũng test các trên các loại Office nhưng chưa bao giờ bị như bạn.
 
Upvote 0
Khi thử mình đã gỡ hết tất cả các Add-in rồi. Mình đã thử nhiều lần và rút ra được 3 trường hợp như bài #1. Không hiểu sao bạn thử lại không bị nhỉ?

Không biết anh switom và anh ndu96081631 có thử không? Nếu đã thử thì có phải bị như các trường hợp ở bài #1 không?

Có chứ. Tôi đã trả lời ai thì luôn:

1. Đọc kỹ bài mình định trả lời.
2. Nếu không phải là code đã từng viết hoặc trường hợp đã từng gặp thì kiểm tra kỹ.

Tôi còn thấy là class sẽ nguyên vẹn nếu:

1. chọn Disable Macro có thông báo (không thông báo cũng được)
2. Mở tập tin Test nhưng không kích hoạt Macro
3. Chuột phải trên tab Sheet và "Insert" để thên Sheet2. Sau đó xóa Sheet2 hoặc không

Bây giờ hiển thị Form rồi nhấn CommandButton sẽ kông bị gì.

Mọi người kiểm tra hộ.
 
Upvote 0
Mình làm add-in nhiều và toàn làm class với mức độ rất sâu, sản phẩm làm ra bao giờ cũng test các trên các loại Office nhưng chưa bao giờ bị như bạn.

Thế thì lạ nhỉ. Mọi người làm thử đều bị lỗi như vậy. Mình cũng xin nói luôn là lỗi chỉ xảy ra ở một số lệnh nào đó, cụ thể ở đây là thêm sheet bằng code (có thể có lỗi với lệnh khác nhưng mình chưa gặp nên cũng không biết). Lỗi này xuất hiện từ bộ Add-in mình đang làm, lỗi chỉ xảy ra khi thêm sheet bằng code còn lại thì mọi thứ đều ổn.
 
Upvote 0
Thế thì lạ nhỉ. Mọi người làm thử đều bị lỗi như vậy. Mình cũng xin nói luôn là lỗi chỉ xảy ra ở một số lệnh nào đó, cụ thể ở đây là thêm sheet bằng code (có thể có lỗi với lệnh khác nhưng mình chưa gặp nên cũng không biết). Lỗi này xuất hiện từ bộ Add-in mình đang làm, lỗi chỉ xảy ra khi thêm sheet bằng code còn lại thì mọi thứ đều ổn.

Đúng rồi, lệnh thêm sheet trong Excel không được ổn định đâu, nó lỗi trong hoàn cảnh nào đó. Bạn thử các cách thêm sheet sau xem cái nào ok nhé.

ActiveWorkbook.sheets.Add()
ActiveWorkbook.Worksheets.Add()

Dim wb As Workbook
Set wb = Workbooks(i) '/ Workbooks("Tên wb")

wb.sheets.Add()
wb.Worksheets.Add()
 
Upvote 0
Đúng rồi, lệnh thêm sheet trong Excel không được ổn định đâu, nó lỗi trong hoàn cảnh nào đó. Bạn thử các cách thêm sheet sau xem cái nào ok nhé.

ActiveWorkbook.sheets.Add()
ActiveWorkbook.Worksheets.Add()

Dim wb As Workbook
Set wb = Workbooks(i) '/ Workbooks("Tên wb")

wb.sheets.Add()
wb.Worksheets.Add()

Mình đã thử hết các cách trên nhưng không có cách nào được cả. Dù sao cũng cảm ơn bạn.

Có lẽ đây là một lỗi của Excel và không có cách khắc phục.

Mình muốn chuyển sang một hướng giải quyết khác là trước khi thực hiện lệnh chèn Sheet sẽ kiểm tra xem file hiện hành có phải là file có macro và chưa được kích hoạt hay không. Nếu phải thì cho người dùng chọn kích hoạt hoặc không kích hoạt, code sẽ thực hiện việc kích hoạt hoặc không kích hoạt macro để sau đó chèn Sheet thì Class sẽ không bị vỡ; ngược lại, nếu file không có macro hoặc có macro và đã được kích hoạt thì lệnh được thực thi bình thường. Tuy nhiên mình không biết có thể thực hiện việc kiểm tra này hay không và cách kiểm tra như thế nào.

Vậy anh, chị, bạn nào biết xin hướng dẫn giúp.

Xin cám ơn.
 
Upvote 0
Có lẽ đây là một lỗi của Excel và không có cách khắc phục.

Add-in A-Tools mình viết thường xuyên làm việc thêm, xóa sheet trên bất kỳ workbook nào không bị protect đó. Tôi viết bằng Delphi nó còn không hỗ trợ tốt như VBA. Tiếc là file của bạn tôi test trên các máy chỗ tôi chạy k lỗi.
 
Upvote 0

Bài viết mới nhất

Back
Top Bottom