Thao tác với VBE bằng VBA

giaiphapvba

Administrator
Thành viên BQT
Trên diễn đàn đã có chủ đề , hay , hay đang nhận được nhiều quan tâm hiện nay. Tất cả những cái đó đều là thao tác trên VBE. Tuy nhiên cứ tản mạn như thế thì thật thiếu hệ thống. Thông qua topic này tôi muốn hệ thống kiến thức làm sao để chúng ta có cái nhìn tổng quan hơn.

1. Cấu trúc VBE Object
Đối tượng VBE chỉ chịu đứng dưới Application.
Bạn cần đăng nhập để thấy đính kèm

Trong VBE nó chứa đối tượng VBProject. Đây là đối tượng Book chứa trong nó toàn thể macro trong nó.
Để dễ hình dung nên bức tranh, bạn hãy coi Book = VBProject.
Bên trong đối tượng VBProject, ta có đối tượng VBComponent. Vậy VBComponent là gì, nó là tất cả code của sheet1 hay code của ThisWorkbook, hay của UserForm, hay một Module tiêu chuẩn.
Bạn cần đăng nhập để thấy đính kèm

Liên quan tới VBComponent, nó lại chứa đối tượng CodeModule. Bên trong đối tượng CodeModule, nơi diễn ra hoạt động viết code macro gọi là CodePane.
Bạn cần đăng nhập để thấy đính kèm

Như vậy tôi đã giới thiệu xong về cấu tạo của VBE Object. Hình trên có lẽ chưa phải là biểu diễn chính xác. Hơn nữa chúng ta lại đang nói tới khái niệm mà chúng ta không được sờ hoặc nói tới Object, thì nhiều người sẽ cảm thấy khó hiểu.
Tạm thời, các bạn hãy cứ hiểu ở mức độ này đã nhé. Chừng đó là chúng ta đủ để thao tác với VBE rồi.
(Còn nữa)
Nguồn tham khảo:
 

tuhocvba

Administrator
Thành viên BQT
2. Thao tác với VBProject
Cũng giống như khi chúng ta thao tác với Cells thì đầu tiên chúng ta cần chỉ định rõ đang làm việc với Book nào, với thao tác với VBProject cũng vậy, chúng ta cần ý thức VBProject là một đối tượng của VBE. Hãy nhớ điều này khi truy cập làm việc với VBProject.
Để lấy tất cả các VBProject đang được mở trên VBE, chúng ta sẽ thao tác với VBProject Collection.
Phần tiếp theo, trong số các VBProject đang được mở, chẳng hạn chúng ta sẽ cho hiển thị thông tin VBProject đầu tiên. Lưu ý rằng Book tuy đang được mở nhưng đang ở trạng thái chưa được lưu, khi đó thuộc tính Filename có thể sẽ xảy ra lỗi (file chưa thực sự tồn tại).
Mã:
Sub Sample1()
    Dim buf As String
    With Application.VBE
        buf = buf & .VBProjects.Count & vbCrLf
        buf = buf & .VBProjects(1).Name & vbCrLf
        buf = buf & .VBProjects(1).Filename & vbCrLf
        buf = buf & .VBProjects(1).Protection & vbCrLf
    End With
    MsgBox buf
End Sub
Bạn cần đăng nhập để thấy đính kèm

Thuộc tính Protection sẽ trả về giá trị là 1 nếu như VBProject đang được mặt mật khẩu không cho người dùng xem được nội dung bên trong VBProject.
Trong trường hợp, bạn đặt mật khẩu VBProject nhưng vẫn cho phép người dùng xem nội dung bên trong, tức là chỉ cấm chỉnh sửa nội dung code, thì thuộc tính này sẽ trả về là 0.
Tất nhiên, nếu VBProject không thiết định mật khẩu, thì giá trị trả về của thuộc tính này cũng là 0.
Thuộc tính Protection chỉ là đọc lấy thông tin, cho nên bạn không thể sử dụng thuộc tính này thiết định giá trị là 0 cho nó hòng phá hủy mật khẩu đang được thiết định cho VBProject.
VBProject Object hiển thị VBProject của các Book (các file excel). Như trên đã nói, VBE Object có thể truy cập vào tất cả VBProject đang được mở.
Ngoài ra, từ Book (Workbook), ta có thể viết code để truy cập vào VBProject của chính nó (của chính file này). Đoạn code sau sẽ minh họa điều ấy:

Mã:
Sub Sample2()
    Dim buf As String
    With ActiveWorkbook
        buf = buf & .VBProject.Name & vbCrLf
        buf = buf & .VBProject.Filename & vbCrLf
        buf = buf & .VBProject.Protection & vbCrLf
    End With
    MsgBox buf
End Sub
Như vậy, trong bài học này, chúng ta có thể tóm gọn bằng hình ảnh dưới đây:
Bạn cần đăng nhập để thấy đính kèm


Nguồn:
 

Euler

Administrator
Thành viên BQT
3. Thao tác với VBComponent
VBComponent Object cho biết các Document Module :Thisworkbook, sheet1,sheet2,.. và UserForm, Module tiêu chuẩn.
Đoạn code dưới đây sẽ thao tác với VBComponent của workbook đang active.
Bạn cần đăng nhập để thấy đính kèm


Mã:
Sub Sample3()
    Dim i As Long
    With ActiveWorkbook.VBProject
        For i = 1 To .VBComponents.Count
            Cells(i, 1) = .VBComponents(i).Name
            Cells(i, 2) = .VBComponents(i).Type
        Next i
    End With
End Sub
Kết quả:
Bạn cần đăng nhập để thấy đính kèm

Giá trị thuộc tính Type của VBComponent Object được mô tả theo như bảng dưới đây.
ValueNội dung
1​
Module tiêu chuẩn
2​
Class Module
3​
Microsoft Form
11​
ActiveX Design
100​
Document Module
Đoạn code dưới đây sẽ truy tìm các Module tiêu chuẩn của một workbook đang được active.
Mã:
Sub Sample4()
    Dim i As Long, buf As String, mdlName As String
    With ActiveWorkbook.VBProject
        For i = 1 To .VBComponents.Count
            If .VBComponents(i).Type = 1 Then
                mdlName = mdlName & .VBComponents(i).Name & vbCrLf
            End If
        Next i
        If mdlName <> "" Then
            MsgBox "Co chua Module tieu chuan la: " & vbCrLf & mdlName
        Else
            MsgBox "Khong co Module tieu chuan nao"
        End If
    End With
End Sub
Bạn cần đăng nhập để thấy đính kèm

Khi sử dụng phương thức Add của VBComponents Collection, nó sẽ thêm Component vào VBProject.
Lúc này, chú ý ta cần chỉ định tham số cho phương thức Add. Hãy tham khảo bảng tham số và chủng loại của Component dưới đây.
ValueNội dung
1​
Module tiêu chuẩn
2​
Class Module
3​
Microsoft Form
Đoạn code dưới đây sẽ thêm Module tiêu chuẩn mới vào Workbook đang active nếu nó chưa có Module tiêu chuẩn nào.
Mã:
Sub Sample5()
    Dim i As Long, flag As Boolean
    With ActiveWorkbook.VBProject
        For i = 1 To .VBComponents.Count
            If .VBComponents(i).Type = 1 Then
                flag = True
                Exit For
            End If
        Next i
        If Not flag Then .VBComponents.Add 1
    End With
End Sub
Ta cũng có thể dùng phương thức Export của VBComponent Object khi cần xuất Component của một file excel macro. Ngoài ra, chúng ta cũng có thể import nó vào một file khác bằng cách sử dụng phương thức Import của VBComponents Collection.
Đoạn code dưới đây sẽ xuất Book1のModule1 và lưu dưới tên 「C:\Work\Book1_Module.bas」. Sau đó nó sẽ import 「C:\Work\Book1_Module.bas」 vào file Book2. Chú ý cả hai file Book1, Book2 đều đang mở thì mới thực thi được code này.
Mã:
Sub Sample6()
    Const Filename As String = "C:\Work\Book1_Module.bas"
    Workbooks("Book1.xls").VBProject.VBComponents("Module1").Export Filename
    Workbooks("Book2.xls").VBProject.VBComponents.Import Filename
End Sub
Vấn đề này đã từng có bài viết trên diễn đàn, các bạn tham khảo ở đây:
Nguồn:
 

giaiphapvba

Administrator
Thành viên BQT
4. Thuộc tính của CodeModule
CodeModule Object có thể lấy được code macro được ghi trong nó. Sau đây chúng ta sẽ cùng tìm hiểu các thuộc tính thường sử dụng của CodeModule.
4.1 Thuộc tính CountOfLinesCountOfDeclarationLines
Đoạn code dưới đây sẽ lấy thông tin tổng số dòng code được ghi trong Module.
Mã:
Sub Sample7()
    Dim Cnt As Long
    Cnt = ThisWorkbook.VBProject.VBComponents("Module1").CodeModule.CountOfLines
    MsgBox Cnt
End Sub
Với Module như thế này:
Bạn cần đăng nhập để thấy đính kèm

Ta được kết quả là:
Bạn cần đăng nhập để thấy đính kèm


Thuộc tính CountOfLines sẽ cho ta biết số dòng code trong, bao gồm cả dòng code khai báo. Và tất nhiên với những dòng code trống bằng cách gõ Enter thì dòng trống đó cũng được tính vào tổng số dòng code. Đuơng nhiên nó cũng bao gồm cả các dòng comment.
Nếu như bạn quan tâm tổng số dòng code khai báo biến, bằng thuộc tính CountOfDeclarationLines, bạn có thể lấy được thông tin này.

Mã:
Sub Sample8()
    Dim CodeLine As Long, DeclarationLines As Long
    With ThisWorkbook.VBProject.VBComponents("Module200313").CodeModule
        DeclarationLines = .CountOfDeclarationLines
        CodeLine = .CountOfLines
    End With
    MsgBox "So dong code khai bao bien la:" & DeclarationLines & vbCrLf & _
           "So dong code cua chuong trinh la:" & CodeLine - DeclarationLines
End Sub
Bạn cần đăng nhập để thấy đính kèm

Kết quả:
Bạn cần đăng nhập để thấy đính kèm


4.2 Thuộc tính Lines
Thuộc tính này theo cấu trúc như sau:
CodeModule.Lines(startline, count)
Từ dòng code startline sẽ lấy số dòng code là count.
Mã:
Sub Sample9()
    Dim Code As String
    Code = ThisWorkbook.VBProject.VBComponents("Module1").CodeModule.Lines(7, 5)
    MsgBox Code
End Sub
Bạn cần đăng nhập để thấy đính kèm

Kết quả:
Bạn cần đăng nhập để thấy đính kèm


4.3 Thuộc tính ProcBodyLine, ProcCountLines, ProcOfLine, ProcStartLine
Thuộc tính ProcBodyLine sẽ trả về dòng đầu tiên của thủ tục (hàm) do chúng ta chỉ định.
Tham số truyền vào sẽ có 2 tham số.
Mã:
CodeModule.ProcBodyLine(procname, prockind)
Tham số procname: Chúng ta sẽ chỉ định tên thủ tục (hàm) mà chúng ta muốn tìm dòng đầu tiên của nó.
Tham số prockind: Chúng ta sẽ chỉ định trị số kiểu chủng loại thủ tục (hàm) mà chúng ta điều tra.
Trị sốNội dung
3Lấy giá trị của thuộc tính
1Thiết định giá trị cho thuộc tính
2Thiết định tham chiếu Object
0Ngoài các trường hợp trên

Thông thường chúng ta chỉ định lấy thông tin của Sub hay Function, thì chúng ta thiết định tham số là 0.
Mã:
Sub Sample10()
    Dim Cnt As Long
    Cnt = ThisWorkbook.VBProject.VBComponents("Module1"). _
                                 CodeModule.ProcBodyLine("Sample10", 0)
    MsgBox Cnt
End Sub
Bạn cần đăng nhập để thấy đính kèm


Thuộc tính ProcCountLines sẽ trả về số dòng code của thủ tục (hàm) mà chúng ta chỉ định điều tra.
Tham số chỉ định giống với tham số chỉ định cho thuộc tính ProcBodyLine.

Thuộc tính ProcCountLines: Từ trước dòng khai báo thủ tục hay hàm (Sub ○○ hay Function××), nó sẽ trả về tổng số dòng code cho tới khi kết thúc thủ tục hay hàm (End Sub hay End Function ), bao gồm cả dòng trống và dòng có comment.
Trong Module, ngay cả khi đã kết thúc hàm hay thủ tục, nếu ở dưới còn các dòng trống, thì các dòng này cũng tính vào kết quả tính toán ở trên.

Mã:
Sub Sample11()
    Dim Cnt As Long
    Cnt = ThisWorkbook.VBProject.VBComponents("Module1"). _
                                 CodeModule.ProcCountLines("Sample11", 0)
    MsgBox Cnt
End Sub
Bạn cần đăng nhập để thấy đính kèm


Thuộc tính ProcOfLine: Trả về tên tủ tục (hàm) chứa dòng code mà bạn chỉ định.
Mã:
CodeModule.ProcOfLine(line, prockind)
Tham số line: Chỉ định dòng code.
Tham sốprockind: Giống với thuộc tính ProcBodyLine, chỉ định trị số kiểu chủng loại của hàm (thủ tục).
Mã:
Sub Sample12()
    Dim ProcName As String
    ProcName = ThisWorkbook.VBProject.VBComponents("Module1").CodeModule.ProcOfLine(9, 0)
    MsgBox ProcName
End Sub
Đoạn code này có nghĩa là tìm tên hàm hay thủ tục (tham số 0) chứa dòng code thứ 9 (tham số 9) của Module1.
Bạn cần đăng nhập để thấy đính kèm


Thuộc tính ProcStartLine: Trả về dòng bắt đầu của thủ tục (hàm) mà chúng ta cần điều tra.
Tham số truyền vào giống với thuộc tính ProcCountLines.
Mã:
Sub Sample13()
    Dim Cnt As Long
    Cnt = ThisWorkbook.VBProject.VBComponents("Module1"). _
                                 CodeModule.ProcStartLine("Sample13", 0)
    MsgBox Cnt
End Sub
Bạn cần đăng nhập để thấy đính kèm

Dòng bắt đầu của thủ tục (hàm) khác với dòng khai báo thủ tục (hàm) (Sub ○○ hay Function××). Dòng bắt đầu của thủ tục (hàm) được xác định là dòng tiếp theo ngay sau khi phần khai báo biến kết thúc. Hoặc là dòng code tiếp theo ngay sau khi dòng kết thúc thủ tục (hàm) xuất hiện ( End Sub hay End Function ). Ở ví dụ trên, ngay trước dòng 「Sub Sample13()」là một dòng trống, và dòng này được nhìn nhận là dòng bắt đầu của thủ tục Sample13.

4.4 Ví dụ về việc lấy toàn bộ tên các thủ tục và hàm:
Đối với CodeModule Object, không có thuộc tính nào để ngay lập tức lấy được tên toàn bộ các thủ tục hay hàm mà nó chứa. Sau đây chúng ta sẽ xây dựng chương trình để lấy toàn bộ tên thủ tục (hàm) mà CodeModule chứa.
Mã:
Sub Sample14()
    Dim buf As String, ProcNames As String, i As Long
    With ThisWorkbook.VBProject.VBComponents("Module1").CodeModule 'Tìm trong Module1'
        For i = 1 To .CountOfLines
            If buf <> .ProcOfLine(i, 0) Then
                buf = .ProcOfLine(i, 0)
                ProcNames = ProcNames & buf & vbCrLf
            End If
        Next i
    End With
    MsgBox ProcNames
End Sub
Bạn cần đăng nhập để thấy đính kèm


Nguồn:
 

tuhocvba

Administrator
Thành viên BQT
5. Phương thức với CodeModule
Sau đây tôi sẽ giới thiệu các phương thức thường được sử dụng ở CodeModule Object.
5.1 Phương thức: AddFromFile, AddFromString

Phương thức AddFromFile sẽ chèn nội dung file do bạn chỉ định vào trong Module. Vị trí chèn là nơi bắt đầu của thủ tục hay hàm. Bạn không thể chỉ định được vị trí chèn.
Đoạn code dưới đây sẽ chèn nội dung file C:\VBA\1.txt vào trong Module 1.
Bạn cần đăng nhập để thấy đính kèm

Mã:
Sub Sample15()
    With ThisWorkbook.VBProject.VBComponents("Module1").CodeModule
        .AddFromFile "C:\VBA\1.txt"
    End With
End Sub
Kết quả:
Bạn cần đăng nhập để thấy đính kèm


Phương thức AddFromString tương tự như phương thức AddFromFile, nó sẽ chèn nội dung string vào trong Module. Vị trí chèn cũng giống như AddFromFile.
Mã:
Sub Sample16()
    With ThisWorkbook.VBProject.VBComponents("Module1").CodeModule
        .AddFromString "Public buf As String"
    End With
End Sub
Trước khi chạy code, Module1 có trạng thái là:
Bạn cần đăng nhập để thấy đính kèm

Sau khi chạy thủ tục Sample16, thì được kết quả là:
Bạn cần đăng nhập để thấy đính kèm


5.2 Phương thức InsertLines, DeleteLines, ReplaceLine:
Phương thức InsertLines:
Sẽ chèn string vào dòng mà bạn chỉ định. Cấu trúc như sau:
Mã:
CodeModule.InsertLines(line, code)
Tham số line: Bạn chỉ định chèn vào dòng nào.
Tham số code : Là string mà bạn chỉ định sẽ chèn vào Module.
Mã:
Sub Sample17()
    With ThisWorkbook.VBProject.VBComponents("Module1").CodeModule
        .InsertLines 7, vbTab & "Debug.Print Now()"
    End With
End Sub
Trạng thái Module1 trước khi chạy code là:
Bạn cần đăng nhập để thấy đính kèm

Sau khi chạy thủ tục Sample17 thì kết quả là:
Bạn cần đăng nhập để thấy đính kèm


Phương thức DeleteLines : Xóa dòng code mà bạn chỉ định. Cấu trúc là:
Mã:
CodeModule.DeleteLines (startline [, count])
Tham số startline : Chỉ dịnh vị trí dòng code đầu tiên cần xóa.
Thám số count : Có thể giản lược không cần viết. Đây là số lượng dòng code cần xóa. Nếu giản lược không viết, nó chỉ xóa 1 dòng code, đó chính là dòng startline.
Ở ví dụ trên, bây giờ ta sẽ xóa dòng code 「Debug.Print Now()」.
Mã:
Sub Sample18()
    With ThisWorkbook.VBProject.VBComponents("Module1").CodeModule
        .DeleteLines 7
    End With
    Debug.Print Now()
End Sub
Phương thức ReplaceLine : Thay thế dòng code mà bạn chỉ định bằng string do bạn đưa vào. Cấu trúc là:
Mã:
CodeModule.ReplaceLine(line, code)
Tham số line : Là dòng code tiến hành chuyển đổi. Bạn không thể chỉ định nhiều dòng code một lúc.
Tham số code : Là string mà bạn đưa vào thay thế dòng code ở trên.
Mã:
Sub Sample19()
    With ThisWorkbook.VBProject.VBComponents("Module1").CodeModule
        .ReplaceLine 7, vbTab & "'Viet comment cho code"
    End With
    Debug.Print Now()
End Sub
Trạng thái trước khi chạy code:
Bạn cần đăng nhập để thấy đính kèm

Kết quả:
Bạn cần đăng nhập để thấy đính kèm

(Hết)
 
Top