Kỹ thuật lập trình DLL cho Excel trên Visual Studio 2015

tuhocvba

Administrator
Thành viên BQT
Nói tới DLL là gì có lẽ các bạn có thể quay về để tìm hiểu lại.
Đây được coi là phương án bảo vệ code tốt nhất cho VBA, do đó tôi xin bắt đầu luôn mà không rườm rà.
1. Trên máy tính bạn hãy tìm tới ứng dụng Visual Studio và chạy với quyền admin.
Bạn cần đăng nhập để thấy đính kèm


Visual mở lên, bạn vào File => New => Project
Bạn cần đăng nhập để thấy đính kèm


Bạn tìm tới Templates => Visual Basic:
Tại đây chọn Class Library.
Nhập tên project là SP2.
Bạn cần đăng nhập để thấy đính kèm


Bạn ấn OK.
Tiếp theo bạn vào View => Solution Explorer
Bạn cần đăng nhập để thấy đính kèm


Chuột phải vào SP2 chọn Properties.
Bạn cần đăng nhập để thấy đính kèm


Vào tab compile
Bạn cần đăng nhập để thấy đính kèm

Tích chọn vào Register for COM interop.
Bạn cần đăng nhập để thấy đính kèm


Vào Apllication => Assembly Information kiểm tra:
Bạn cần đăng nhập để thấy đính kèm


Nếu như dấu tích Make assembly COM-Visible được tích chọn rồi thì OK. Nếu chưa thì bạn phải tích chọn vào.
Vì Office của tôi là 64bit nên trước hết tôi muốn tạo DLL cho 64 bit.

Hãy tìm tới vùng trên này:
Bạn cần đăng nhập để thấy đính kèm


Chọn vào x64.
Xin lưu ý bướ này rất quan trọng. Bản thân tôi khi tham khảo, chạy hoài không được, thì ra chỗ này chính là nguyên nhân, họ không có nói cái này mà tôi phải tự lần mò ra, quá khổ sở!!!
Click vào Class1.vb để viết code:
Bạn cần đăng nhập để thấy đính kèm

Hãy dán đoạn code sau vào:
Mã:
Imports System
Namespace MyClass1
    Public Class MyClass1
        Public Function Hello(ByVal sName As String) As String
            Return "Hello!! " & sName
        End Function
    End Class
End Namespace
Sau đó ấn Start.
Bạn cần đăng nhập để thấy đính kèm

Nó ra cảnh báo kệ nó thôi. Không sau đâu. Cứ ấn OK. File DLL được tạo ra rồi đấy.

2. Viết code trên Excel.
Mở Excel lên:
Bạn cần đăng nhập để thấy đính kèm

Tạo module mới. Vào Tools => References.
File DLL đã được đăng ký rồi cho nên tìm tới SP2 trong danh sách và tích chọn vào thôi.
Bạn cần đăng nhập để thấy đính kèm


Ấn OK.
Trên đó tôi viết code VBA như sau:
Mã:
Sub ab()
    Dim a  As New SP2.MyClass1
    
    MsgBox a.Hello("OK")
End Sub
Kết quả:
Bạn cần đăng nhập để thấy đính kèm


Nguồn tham khảo:
 

tuhocvba

Administrator
Thành viên BQT
3. Hiện gợi ý khi viết code trên VBA
Bạn cần đăng nhập để thấy đính kèm

Khi chúng ta gọi DLL và sử dụng hàm hay thủ tục của DLL, chúng ta mong muốn sẽ hiển thị gợi ý tên hàm hay thủ tục.
Như vậy ta cần phải thông qua Interface (cổng giao tiếp) của COM Object. Nào ta sẽ bắt đầu luôn.
Đầu tiên hãy đóng file Excel lại. Nó đang kết nối với SP2 cho nên hãy đóng lại.
Chúng ta bắt đầu lại, hãy dán đoạn code sau lên Visual Studio:
Mã:
Imports System
Imports System.Runtime.InteropServices
Namespace MyClass1
    <ComVisible(True)>
    Public Interface IMyClass1
        Function Hello(ByVal sName As String) As String
    End Interface
    <ClassInterface(ClassInterfaceType.None)>
    Public Class MyClass1
        Implements IMyClass1
        Public Function Hello(ByVal sName As String) As String Implements IMyClass1.Hello
            Return "Hello!! " & sName
        End Function
    End Class
End Namespace
Biên dịch DLL lại nào.
Và giờ hãy mở Excel và làm lại như trên. Lúc này bạn gõ code đã hiện gợi ý rồi đấy.
 

tuhocvba

Administrator
Thành viên BQT
4. Sử dụng DLL trên máy tính khác
File DLL di chuyển sang máy tính khác mà vẫn chạy được thì ta cần hai bước.
Một, chúng ta cần phát hành DLL thông qua bước Release.
Hai, khi copy DLL sang máy tính khác, chúng ta cần đăng ký file DLL. Hiểu một cách hình tượng thì giống như chúng ta khai báo nhân thân của DLL cho windows hiểu.

Đầu tiên tôi nói về bước phát hành (Release) DLL.
Bạn cần đăng nhập để thấy đính kèm


Click chọn Release và ấn Start.
Bạn cần đăng nhập để thấy đính kèm


Như trên là thành công. Ấn OK tắt cảnh báo đi.
Tìm tới đường dẫn mà file DLL được cất.
Bạn cần đăng nhập để thấy đính kèm


Như vậy, file DLL đã có thể mang sang máy tính khác và sử dụng.
File DLL tôi đã tao ra tôi để ở đây:
 

tuhocvba

Administrator
Thành viên BQT
5. Đăng ký DLL
Khi mang file DLL sang máy tính khác chúng ta phải đăng ký với Windows.
Mã:
'*********************************************************
' Keo tha DLL vao RegAsm de dang ky
' Bien dich boi Admin tuhocvba  website: tuhocvba.net
' 2011/04/05 kinuasa
'*********************************************************

Option Explicit

Dim Args
Dim FSO
Dim f
Dim DllFilePath
Dim WindowsFolderPath
Dim FrameworkFolderPath
Dim SubFrameworkFolderPath
Dim RegAsmFilePath
Dim ArgStr
Const Opt = " /tlb /codebase" 'Trao Option cho RegAsm
Const MsgTitle = "RegAsmThucThi"

RegAsmFilePath = "" 'Gia tri khoi tao

Set Args = WScript.Arguments
If Args.Count < 1 Then
  MsgBox "Hay keo file DLL de vao day de dang ky", 16, MsgTitle
  WScript.Quit
End If
Set FSO = CreateObject("Scripting.FileSystemObject")
Select Case LCase(FSO.GetExtensionName(Args(0)))
  Case "dll"
    DllFilePath = Args(0)
  Case Else
    MsgBox "Hay keo file DLL de vao day de dang ky", 16, MsgTitle
    WScript.Quit
End Select
Set Args = Nothing

'.NET Framework : Lay duong dan folder
WindowsFolderPath = FSO.GetSpecialFolder(0).Path
If Right(WindowsFolderPath, 1) <> "\" Then WindowsFolderPath = WindowsFolderPath & "\"
FrameworkFolderPath = WindowsFolderPath & "Microsoft.NET\Framework\"
If FSO.FolderExists(FrameworkFolderPath) <> True Then
  MsgBox "Khong tim thay duong dan folder .NET Framework" & vbCrLf & _
         "Dang xu ly", 16, MsgTitle
  WScript.Quit
End If
'Lay duong dan RegAsm.exe
With CreateObject("ADODB.Recordset")
  .Fields.Append "Path", 200, 255
  .Open
  For Each f In FSO.GetFolder(FrameworkFolderPath).SubFolders
    .AddNew
    .Fields("Path").Value = f.Path
    .Update
  Next
  .Sort = "Path DESC" 'Sap xep ten Folder trong Framework
  .MoveFirst
  Do Until .EOF
    SubFrameworkFolderPath = .Fields(0)
    If Right(SubFrameworkFolderPath, 1) <> "\" Then SubFrameworkFolderPath = SubFrameworkFolderPath & "\"
    If FSO.FileExists(SubFrameworkFolderPath & "RegAsm.exe") Then
      If MsgBox("Dang ky bang [" & SubFrameworkFolderPath & "RegAsm.exe] ?", vbYesNo, MsgTitle) = vbYes Then
        RegAsmFilePath = SubFrameworkFolderPath & "RegAsm.exe"
        Exit Do
      End If
    End If
    .MoveNext
  Loop
  .Close
End With
Set FSO = Nothing
If Len(RegAsmFilePath) < 1 Then
  MsgBox "Khong tim thay [RegAsm.exe]" & vbCrLf & _
         "Dang xu ly", 16, MsgTitle
  WScript.Quit
End If

ArgStr = """" & DllFilePath & """" & Opt
CreateObject("Shell.Application").ShellExecute RegAsmFilePath, ArgStr, "", "runas" 'Chay runas
Hãy copy code trên cho vào Notepad và lưu lại, chú ý chọn đuôi file là vbs:
Bạn cần đăng nhập để thấy đính kèm

Bây giờ muốn đăng ký DLL, bạn chỉ cần kéo thả file dll vào file vbs này là được.
Nguồn:
 

tuhocvba

Administrator
Thành viên BQT
6. Hủy đăng ký DLL
Tương tự như bước đăng ký, chúng ta sẽ tạo ra một file có phần mở rộng là .vbs
Mã:
'*************************************************************
' Huy dang ky DLL bang RegAsm
' Bien dich boi admin tuhocvba website tuhocvba.net
' 2011/04/05 kinuasa
'*************************************************************
 
Option Explicit
 
Dim Args
Dim FSO
Dim f
Dim DllFilePath
Dim WindowsFolderPath
Dim FrameworkFolderPath
Dim SubFrameworkFolderPath
Dim RegAsmFilePath
Dim ArgStr
Const Opt = " /tlb /u" 'Trao Option cho RegAsm
Const MsgTitle = "RegAsmThucThi"
 
RegAsmFilePath = "" 'Gia tri khoi tao
 
Set Args = WScript.Arguments
If Args.Count < 1 Then
  MsgBox "Hay keo tha file DLL vao day", 16, MsgTitle
  WScript.Quit
End If
Set FSO = CreateObject("Scripting.FileSystemObject")
Select Case LCase(FSO.GetExtensionName(Args(0)))
  Case "dll"
    DllFilePath = Args(0)
  Case Else
    MsgBox "Hay keo tha file DLL vao day", 16, MsgTitle
    WScript.Quit
End Select
Set Args = Nothing
 
'Lay duong dan folder cua .NET Framework
WindowsFolderPath = FSO.GetSpecialFolder(0).Path
If Right(WindowsFolderPath, 1) <> "\" Then WindowsFolderPath = WindowsFolderPath & "\"
FrameworkFolderPath = WindowsFolderPath & "Microsoft.NET\Framework\"
If FSO.FolderExists(FrameworkFolderPath) <> True Then
  MsgBox "Khong tim thay folder .NET Framework" & vbCrLf & _
         "Dang thuc thi", 16, MsgTitle
  WScript.Quit
End If
'Lay duong dan RegAsm.exe
With CreateObject("ADODB.Recordset")
  .Fields.Append "Path", 200, 255
  .Open
  For Each f In FSO.GetFolder(FrameworkFolderPath).SubFolders
    .AddNew
    .Fields("Path").Value = f.Path
    .Update
  Next
  .Sort = "Path DESC" 'Sap xep ten cac folder cua Framework
  .MoveFirst
  Do Until .EOF
    SubFrameworkFolderPath = .Fields(0)
    If Right(SubFrameworkFolderPath, 1) <> "\" Then SubFrameworkFolderPath = SubFrameworkFolderPath & "\"
    If FSO.FileExists(SubFrameworkFolderPath & "RegAsm.exe") Then
      If MsgBox("Ban muon huy[" & SubFrameworkFolderPath & " bang RegAsm.exe] ?", vbYesNo, MsgTitle) = vbYes Then
        RegAsmFilePath = SubFrameworkFolderPath & "RegAsm.exe"
        Exit Do
      End If
    End If
    .MoveNext
  Loop
  .Close
End With
Set FSO = Nothing
If Len(RegAsmFilePath) < 1 Then
  MsgBox "Khong tim thay [RegAsm.exe]" & vbCrLf & _
         "Dang xu ly", 16, MsgTitle
  WScript.Quit
End If
 
ArgStr = """" & DllFilePath & """" & Opt
CreateObject("Shell.Application").ShellExecute RegAsmFilePath, ArgStr, "", "runas" 'Thuc thi bang runas
Nguồn:
 

NhanSu

SMod
Thành viên BQT
Để biên dịch COM DLL để sử dụng cả 32 và 64 bits, chúng ta nên biên dịch tất cả một lúc bằng chức năng Batch build, hình dưới mình sử dụng VS2019, với phiên bản khác của VS có thể khác
Bạn cần đăng nhập để thấy hình ảnh

Bạn cần đăng nhập để thấy hình ảnh
 

NhanSu

SMod
Thành viên BQT
Code C# dll
Mã:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace TestDll
{
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    public class TestClass
    {
        [ComVisible(true)]
        public long Fibonacci(long n)
        {
            if (n < 3)
                return 1;
            long a = 1;
            long b = 1;
            for (long i = 3; i <= n; i++)
            {
                long c = a;
                a = b;
                b += c;
            }
            return b;
        }
    }
}
Code VBA
Mã:
Sub a()
Dim TestObj As TestClass
Set TestObj = New TestClass
Debug.Print TestObj.Fibonacci(92)
End Sub
DLL 32 bit và 64 bits trong các folder bin\x86\Release và bin\x64\Release
 
Sửa lần cuối:

NhanSu

SMod
Thành viên BQT
@tuhocvba batch build là chức năng trong menu Build, VS2015 mình không biết. Nâng lên 2019 có nhiều tính năng hơn.
 

tuhocvba

Administrator
Thành viên BQT
@tuhocvba batch build là chức năng trong menu Build, VS2015 mình không biết. Nâng lên 2019 có nhiều tính năng hơn.
Thôi vậy build hai lần, không sao.
Mà sao trong thư mục lắm file linh tinh thế, mình tưởng chỉ cần phân phối file .dll là đủ rồi.
 

NhanSu

SMod
Thành viên BQT
Đây có cả source code mà, người dùng chỉ cần dll. Open file sln sẽ mở solution để xem sửa code.
 

tuhocvba

Administrator
Thành viên BQT
7. Một số chú ý:
Trong topic này cũng đã diễn ra thảo luận, các bạn cũng thấy. Không hiểu sao mình không build cùng lúc cả 32bit và 64bit. Nhưng mà không sao, chúng ta có thể buid từng lần cho 32bit và 64bit.
Chú ý x64 la 64bit. x86 là 32bit.
Bạn cần đăng nhập để thấy đính kèm

Mọi người click vào Configuration Manager.
Bạn cần đăng nhập để thấy đính kèm

Tiếp theo mọi người chọn New.
Các bạn nhập x86 vào:
Bạn cần đăng nhập để thấy đính kèm

Ấn OK là được.

Xin lưu ý : DLL này thì bảo mật tốt hơn VBA, tức là người có thể bẻ DLL thì thu hẹp hơn so với bẻ VBA, chứ không hẳn là không bẻ được. VB.net rất gần gũi với VBA, nên việc di chuyển một số hàm hay thủ tục cho vào DLL rất thuận tiện, mọi người nên làm rối code ngay trong DLL, tuy không thể tránh được việc bẻ, nhưng tránh được (hoặc hạn chế hoặc làm mất thời gian tìm hiểu hơn) rò rỉ logic hay thuật toán của các bạn.
Topic này xin phép được khép lại ở đây.
 

qhthong

Yêu THVBA
5. Đăng ký DLL
Khi mang file DLL sang máy tính khác chúng ta phải đăng ký với Windows.
Mã:
'*********************************************************
' Keo tha DLL vao RegAsm de dang ky
' Bien dich boi Admin tuhocvba  website: tuhocvba.net
' 2011/04/05 kinuasa
'*********************************************************

Option Explicit

Dim Args
Dim FSO
Dim f
Dim DllFilePath
Dim WindowsFolderPath
Dim FrameworkFolderPath
Dim SubFrameworkFolderPath
Dim RegAsmFilePath
Dim ArgStr
Const Opt = " /tlb /codebase" 'Trao Option cho RegAsm
Const MsgTitle = "RegAsmThucThi"

RegAsmFilePath = "" 'Gia tri khoi tao

Set Args = WScript.Arguments
If Args.Count < 1 Then
  MsgBox "Hay keo file DLL de vao day de dang ky", 16, MsgTitle
  WScript.Quit
End If
Set FSO = CreateObject("Scripting.FileSystemObject")
Select Case LCase(FSO.GetExtensionName(Args(0)))
  Case "dll"
    DllFilePath = Args(0)
  Case Else
    MsgBox "Hay keo file DLL de vao day de dang ky", 16, MsgTitle
    WScript.Quit
End Select
Set Args = Nothing

'.NET Framework : Lay duong dan folder
WindowsFolderPath = FSO.GetSpecialFolder(0).Path
If Right(WindowsFolderPath, 1) <> "\" Then WindowsFolderPath = WindowsFolderPath & "\"
FrameworkFolderPath = WindowsFolderPath & "Microsoft.NET\Framework\"
If FSO.FolderExists(FrameworkFolderPath) <> True Then
  MsgBox "Khong tim thay duong dan folder .NET Framework" & vbCrLf & _
         "Dang xu ly", 16, MsgTitle
  WScript.Quit
End If
'Lay duong dan RegAsm.exe
With CreateObject("ADODB.Recordset")
  .Fields.Append "Path", 200, 255
  .Open
  For Each f In FSO.GetFolder(FrameworkFolderPath).SubFolders
    .AddNew
    .Fields("Path").Value = f.Path
    .Update
  Next
  .Sort = "Path DESC" 'Sap xep ten Folder trong Framework
  .MoveFirst
  Do Until .EOF
    SubFrameworkFolderPath = .Fields(0)
    If Right(SubFrameworkFolderPath, 1) <> "\" Then SubFrameworkFolderPath = SubFrameworkFolderPath & "\"
    If FSO.FileExists(SubFrameworkFolderPath & "RegAsm.exe") Then
      If MsgBox("Dang ky bang [" & SubFrameworkFolderPath & "RegAsm.exe] ?", vbYesNo, MsgTitle) = vbYes Then
        RegAsmFilePath = SubFrameworkFolderPath & "RegAsm.exe"
        Exit Do
      End If
    End If
    .MoveNext
  Loop
  .Close
End With
Set FSO = Nothing
If Len(RegAsmFilePath) < 1 Then
  MsgBox "Khong tim thay [RegAsm.exe]" & vbCrLf & _
         "Dang xu ly", 16, MsgTitle
  WScript.Quit
End If

ArgStr = """" & DllFilePath & """" & Opt
CreateObject("Shell.Application").ShellExecute RegAsmFilePath, ArgStr, "", "runas" 'Chay runas
Hãy copy code trên cho vào Notepad và lưu lại, chú ý chọn đuôi file là vbs:
Bạn cần đăng nhập để thấy đính kèm

Bây giờ muốn đăng ký DLL, bạn chỉ cần kéo thả file dll vào file vbs này là được.
Nguồn:
Admin ơi! Tui làm theo từng bước rồi:
+ Bước chạy tại máy đang chạy VS2015 thì OK
+ Bước chạy DLL qua máy khác, khi mở VBE của Excel-> reference -> browse đến DLL (đã kéo thả vào file vbs) thì báo lỗi "can't add a reference to the specified file."
Admin gỡ dùm với. Cảm ơn nhiều nhé!
 

Mabel_328

Yêu THVBA
vẫn quá phức tạp cho việc đăng ký qua máy khác
không khả thi cho việc cập nhật ứng dụng liên tục
 

Mabel_328

Yêu THVBA
Mình viết xong qua máy khác thì máy đó phải cài visual studio mới cho vào để release ra, vào thư viện VBA tìm đế vị trí DLL, sau đó hide module và unviewable, tuơng đối dài và phức tạp
 

NhanSu

SMod
Thành viên BQT
@Mabel_328 hiện nay các DLL assembly của .NET thường sử dụng .NET Framwork 4.0+, để sử dụng DLL này ta cần đăng ký. Cách đăng ký: Chạy Command prompt với quyền Admin, vào folder C:\Windows\Microsoft.NET\Framework\v4.0.30319\ chạy RegAsm.exe path\name.dll (path\name.dll là đường dẫn và tên file dll cần đăng ký). Để gỡ bỏ nó thì dùng thêm tham số /U. Còn DLL do C++ tạo ra thì không cần đăng ký nhưng khi sử dụng phải khai báo bằng lệnh Declare như các hàm WIN API khác.
 

Mabel_328

Yêu THVBA
@Mabel_328 hiện nay các DLL assembly của .NET thường sử dụng .NET Framwork 4.0+, để sử dụng DLL này ta cần đăng ký. Cách đăng ký: Chạy Command prompt với quyền Admin, vào folder C:\Windows\Microsoft.NET\Framework\v4.0.30319\ chạy RegAsm.exe path\name.dll (path\name.dll là đường dẫn và tên file dll cần đăng ký). Để gỡ bỏ nó thì dùng thêm tham số /U. Còn DLL do C++ tạo ra thì không cần đăng ký nhưng khi sử dụng phải khai báo bằng lệnh Declare như các hàm WIN API khác.
E cảm ơn a đã chỉ dẫn, lúc nào e làm thử ạ
 
Top