Lỗi thực thi khi thao tác với CodeName nhưng VBA được Protect (1 người xem)

  • Thread starter Thread starter bivily
  • Ngày gửi Ngày gửi
Liên hệ QC

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

bivily

Thành viên hoạt động
Tham gia
11/10/07
Bài viết
110
Được thích
26
Mình làm một cái bảng tính trong đó có rất nhiều Sheet. Nhằm tránh trường hợp người sử dụng thay đổi Name của Sheet nên mình nghĩ tới việc sử dụng CodeName của Sheet nhưng oái ăm thay là nếu sử dụng CodeName thì lệnh sẽ không thực thi được khi ta đặt Password để bảo vệ Code cho VBA.

Mình gửi đoạn code và file đính kèm. Có ai đã từng gặp phải vấn đề này như mình chưa. Xin hãy chia sẻ!

Password VBA của file đính kèm là 1

PHP:
Private Sub Workbook_Open()
    Dim i As Long, ws As Worksheet
    With ThisWorkbook
        For i = 1 To 3
            Set ws = .Sheets(.VBProject.VBComponents("Sheet" & i).Properties("Name").Value)
            'MsgBox ws.CodeName
            ws.Range("A" & i) = i
        Next i
    End With
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Mình làm một cái bảng tính trong đó có rất nhiều Sheet. Nhằm tránh trường hợp người sử dụng thay đổi Name của Sheet nên mình nghĩ tới việc sử dụng CodeName của Sheet nhưng oái ăm thay là nếu sử dụng CodeName thì lệnh sẽ không thực thi được khi ta đặt Password để bảo vệ Code cho VBA.

Mình gửi đoạn code và file đính kèm. Có ai đã từng gặp phải vấn đề này như mình chưa. Xin hãy chia sẻ!

Password VBA của file đính kèm là 1

Nếu sợ người ta đổi tên sheet làm ảnh hưởng đến code thì trong code, bạn cứ gọi sheet bằng SheetCode Name thôi... Họ có đổi tên sheet thì SheetCode Name nó vẫn thế
Ví dụ:
- Code Name có tên là Sh1 và Sheet Name có tên là TONGHOP
- Vậy trong code của bạn, cứ gọi Sh1 là được rồi
-------------
Còn code của bạn, chưa hiểu để làm cái gì?
 
Upvote 0
Nếu sợ người ta đổi tên sheet làm ảnh hưởng đến code thì trong code, bạn cứ gọi sheet bằng SheetCode Name thôi... Họ có đổi tên sheet thì SheetCode Name nó vẫn thế
Ví dụ:
- Code Name có tên là Sh1 và Sheet Name có tên là TONGHOP
- Vậy trong code của bạn, cứ gọi Sh1 là được rồi
-------------
Còn code của bạn, chưa hiểu để làm cái gì?

Cám ơn anh đã gợi ý giúp đỡ. Ví dụ trên là em chỉ trích rút 1 phần code ở vị trí cần hỏi. Bảng tính của em có rất nhiều Sheet có CodeName lần lượt là GT_1, GT_2, đến GT_n. Ở trên mỗi Sheet em cần lấy dữ liệu tại một ô cố định được chỉ rõ trong một mảng ListOfCell = Array ("", "M14", "N13", "Y8",... )

Em định dùng vòng lặp For để duyệt lần lượt từ 1 đến n. Câu lệnh sau
PHP:
For i = 1 To 3
    Set ws = .Sheets(.VBProject.VBComponents("GT_" & i).Properties("Name").Value)
    ws.Range(ListOfCell(i)) = "Mot gia tri nao do"
Next i

là để trỏ lần lượt đến các Sheet GT_01, GT_02,... Nếu không đặt Pass để Protect VBA thì câu lệnh trên chạy ngon lành. Nhưng nếu đặt Pass thì không thực thi được.

Nếu theo cách của anh thì phải làm lần lượt
GT_1.Range("M14") = "Mot gia tri nao do"
GT_2.Range("N13") = "Mot gia tri nao do"
GT_3.Range("Y8") = "Mot gia tri nao do"

Chứ không thể dùng vòng lặp được.

Trong quá trình tìm cách khắc phục lỗi trên thì phát hiện ra điều này: Chúng ta không thể thay đổi CodeName của một sheet bằng câu lệnh VBA khi đặt Pass bảo vệ Code.
PHP:
ThisWorkbook.VBProject.VBComponents("Sheet1").Name = "NewCodeName"
 
Lần chỉnh sửa cuối:
Upvote 0
Bảng tính của em có rất nhiều Sheet có CodeName lần lượt là GT_1, GT_2, đến GT_n. Ở trên mỗi Sheet em cần lấy dữ liệu tại một ô cố định được chỉ rõ trong một mảng ListOfCell = Array ("", "M14", "N13", "Y8",... )

Em định dùng vòng lặp For để duyệt lần lượt từ 1 đến n. Câu lệnh sau
PHP:
For i = 1 To 3
    Set ws = .Sheets(.VBProject.VBComponents("GT_" & i).Properties("Name").Value)
    ws.Range(ListOfCell(i)) = "Mot gia tri nao do"
Next i

là để trỏ lần lượt đến các Sheet GT_01, GT_02,... Nếu không đặt Pass để Protect VBA thì câu lệnh trên chạy ngon lành. Nhưng nếu đặt Pass thì không thực thi được.

Bạn thử code sau xem sao

Mã:
Private Sub Workbook_Open()
Dim i As Long, ws As Worksheet, s As String
On Error Resume Next
        For Each ws In ThisWorkbook.Sheets
            s = ws.CodeName
            i = InStrRev(s, "_")
            If i > 0 Then
                i = Mid(s, i + 1)
                ws.Range(ListOfCell(i)) = "Mot gia tri nao do"
            End If
        Next
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn thử code sau xem sao

Mã:
Private Sub Workbook_Open()
Dim i As Long, ws As Worksheet, s As String
On Error Resume Next
        For Each ws In ThisWorkbook.Sheets
            s = ws.CodeName
            i = InStrRev(s, "_")
            If i > 0 Then
                i = Mid(s, i + 1)
                ws.Range(ListOfCell(i)) = "Mot gia tri nao do"
            End If
        Next
End Sub

Cám ơn bạn nhiều! Lúc chiều mình cũng đã chữa cháy bằng cách tương tự như thế này rồi. Nhưng code của bạn nhìn rõ ràng và dễ hiểu thật.


Bạn có biết làm thế nào để thay đổi CodeName của một Sheet bằng dòng lệnh VBA khi đã Protect VBA không?
 
Upvote 0
Mình thay đổi code của Siwtom 1 chút và thấy chạy bình thường ấy chứ. Banj thử xem sao

VBA pass=123
Lệnh chạy Macro=Ctrl+m

[GPECODE=vb]Sub Test()
Dim ListOfCell()
Dim n, Sh As Worksheet
ListOfCell = Array("A5", "C7")
For Each Sh In ThisWorkbook.Worksheets
If InStr(1, Sh.CodeName, "_") > 0 Then
n = Val(Right(Sh.CodeName, Len(Sh.CodeName) - InStr(1, Sh.CodeName, "_")))
Sh.Range(ListOfCell(n - 1)) = "GPE" & n
End If
Next
End Sub[/GPECODE]
 

File đính kèm

Upvote 0
Cám ơn bạn nhiều! Lúc chiều mình cũng đã chữa cháy bằng cách tương tự như thế này rồi. Nhưng code của bạn nhìn rõ ràng và dễ hiểu thật.


Bạn có biết làm thế nào để thay đổi CodeName của một Sheet bằng dòng lệnh VBA khi đã Protect VBA không?

Bạn nên viết chính xác một tí.
WorkSheet.CodeName là thuộc tính "read-only".

Còn nếu bạn định nói tới:
Mã:
ThisWorkbook.VBProject.VBComponents("Sheet1").Name = "NewCodeName"

Thì tôi nghĩ là không làm được. Tôi tư duy như thế này:
Giả sử làm được. Vậy chỉ cần từ 1 workbook khác chạy code để truy cập tới wb.VBProject.VBComponents với wb là workbook có code Protect. Điều đó có nghĩa là có thể truy cập tới mỗi Module và đọc code của mỗi Module và ghi vào "sổ tay". Nếu làm được thế thì bầy trò Protect để mà làm gì???

Đấy là tư duy của tôi. Tôi không áp đặt cho ai đâu nhé.
 
Upvote 0
Bạn nên viết chính xác một tí.
WorkSheet.CodeName là thuộc tính "read-only".

Còn nếu bạn định nói tới:
Mã:
ThisWorkbook.VBProject.VBComponents("Sheet1").Name = "NewCodeName"

Thì tôi nghĩ là không làm được. Tôi tư duy như thế này:
Giả sử làm được. Vậy chỉ cần từ 1 workbook khác chạy code để truy cập tới wb.VBProject.VBComponents với wb là workbook có code Protect. Điều đó có nghĩa là có thể truy cập tới mỗi Module và đọc code của mỗi Module và ghi vào "sổ tay". Nếu làm được thế thì bầy trò Protect để mà làm gì???

Đấy là tư duy của tôi. Tôi không áp đặt cho ai đâu nhé.

Bạn à! Nếu chúng ta không Protect thì vẫn có thể thay đổi được CodeName bằng câu lệnh trên. Nhưng nếu chúng ta Protect thì cách trên là không thực hiện được. Ở đây mình muốn thay đổi CodeName của một Sheet bằng câu lệnh đặt trong cùng một Workbook với Sheet đó chứ không phải truy cập từ một Workbook khác.


Với đoạn code bên dưới, nếu bạn không đặt Password để bảo vệ code thì lúc bạn đóng và mở lại Workbook thì CodeName của Sheet1 sẽ được đổi thành NewCodeName. Còn nếu có đặt Password để bảo vệ code thì lúc mở lại Workbook sẽ báo lỗi là Run-time error '50289': Can't perform operation since the project is protected.


PHP:
Private Sub Workbook_Open()
    ThisWorkbook.VBProject.VBComponents("Sheet1").Name = "NewCodeName"
End Sub
 
Upvote 0
Bạn à! Nếu chúng ta không Protect thì vẫn có thể thay đổi được CodeName bằng câu lệnh trên. Nhưng nếu chúng ta Protect thì cách trên là không thực hiện được. Ở đây mình muốn thay đổi CodeName của một Sheet bằng câu lệnh đặt trong cùng một Workbook với Sheet đó chứ không phải truy cập từ một Workbook khác.


Với đoạn code bên dưới, nếu bạn không đặt Password để bảo vệ code thì lúc bạn đóng và mở lại Workbook thì CodeName của Sheet1 sẽ được đổi thành NewCodeName. Còn nếu có đặt Password để bảo vệ code thì lúc mở lại Workbook sẽ báo lỗi là Run-time error '50289': Can't perform operation since the project is protected.


PHP:
Private Sub Workbook_Open()
    ThisWorkbook.VBProject.VBComponents("Sheet1").Name = "NewCodeName"
End Sub

Bạn à, thì tôi đã nói rồi: do Protect nên tôi không thể truy cập từ workbook khác được. Vì nếu được thì người ta bầy trò Protect làm gì?
Tôi chỉ kéo dài kết luận cho cả trường hợp khi truy cập từ trong cùng workbook mà thôi. Bởi vì cả khi chạy code ở ngoài cũng như khi chạy code của workbook thì thông báo đều nói về Protect.- "Can't perform operation since the project is protected" - nên tôi cho là nguyên nhân duy nhất là Protect chứ không phải cái gì khác.
Còn nếu bạn cứ cho là làm được thì làm đi. Tôi có khăng khăng cho là tôi đúng đâu?
 
Lần chỉnh sửa cuối:
Upvote 0
Mình thay đổi code của Siwtom 1 chút và thấy chạy bình thường ấy chứ. Banj thử xem sao VBA pass=123 Lệnh chạy Macro=Ctrl+m [GPECODE=vb]Sub Test() Dim ListOfCell() Dim n, Sh As Worksheet ListOfCell = Array("A5", "C7") For Each Sh In ThisWorkbook.Worksheets If InStr(1, Sh.CodeName, "_") > 0 Then n = Val(Right(Sh.CodeName, Len(Sh.CodeName) - InStr(1, Sh.CodeName, "_"))) Sh.Range(ListOfCell(n - 1)) = "GPE" & n End If Next End Sub[/GPECODE]
Vài lời góp ý. Ý kiến thôi chứ không áp đặt đâu nhé.

1. Code với WorkSheet.CodeName tất nhiên là chạy bình thường. Chỉ có code dùng tới ... VBProject.VBComponents ... mới có lỗi.

2. Bạn nên lưu ý là đọc giá trị từ biến ra bao giờ cũng nhanh hơn là gọi hàm tính toán hay đọc từ thuộc tính của đối tượng. Nói nôm na thì muốn đọc thuộc tính thì trước hết phải truy cập tới đối tượng rồi mới có thể truy cập tới 1 trong những trường của đối tượng đó.
Trong code của bạn có

Mã:
 If InStr(1, Sh.CodeName, "_") > 0

Nếu đk thỏa thì trong block IF ... END IF bạn lại phải gọi hàm Instr để tính giá trị một lần nữa. Bạn "tính" Sh.CodeName tổng cộng 4 lần. Nếu lần đầu bạn có s = Sh.CodeName thì 3 lần sau chỉ đọc từ biến ra mà thôi.

Tất nhiên trong trường hợp này những thứ đó là "vụn vặt" nhưng nếu trong trường hợp khác những "vụn vặt" ấy nó nằm trong vòng lặp lớn thì sẽ là "đáng kể" rồi.
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT

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

Back
Top Bottom