受欢迎的博客标签

Excel VBA代码封装成Dll(VB6.0):VBA 引用dll并调用DLL函数多种方式

Published

为了保护自己辛辛苦苦编写的Excel VBA代码不被盗用,我们需要对Excel VBA代码进行加密。

通用做法

因为excel的vba保护很弱,vbe加密码、模组隐藏、代码混淆等等手段,这些网上有很多破文介绍和软体下载,被破解只是时间和精力问题。

各种加密方案详见: Office Excel VBA代码加密方案汇总(如何尽可能的保护VBA代码?)

解决方案

通过将Excel VBA代码封装成DLL动态链接库,可有效防止代码被非法查看。

step 1:将Vba的函数和过程封装成ActiveX Dll或ActiveX控件。

step 2:封装之后要使用的化,如果是ActiveX Dll就需要线注册再生命函数,和API函数一样。

ActiveX控件需要线注册再在部件里添加,并添加到窗体里,不需要声明。

 

实现途径

1.用VB6(Microsoft Visual Basic 6.0)来封装。主要原因是VB6的操作界面及语法与Excel的VBA具有极高的相似度。2002年,随着VB.NET的引入,大部分人都放弃使用VB而选择VB.NET,VB6终将被淘汰。

Microsoft Visual Basic 6.0 Service Pack 6 Cumulative Update
https://www.microsoft.com/en-us/download/details.aspx?id=7030

Visual Basic 6.0 Documentation
https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-basic-6/visual-basic-6.0-documentation

2.用Microsoft Visual Basic 2010封装VBA。我们可以在VS里建立com类项目,把NET类库的一些方法重新包装后暴露给VBA使用。

 

The steps I followed are below. 

1) Created a simple VS2019 VB Class Library Project
2) Checked Project > Properties > Assembly > Make Comm-Visible
3) Set Project > Compile > Target CPU to x64
4) Set Solution > Configuation > Release Platform to x64
5) Cleaned Solution
6) Built Solution
7) Copied the *.tbl file to Windows\System32
8) Added Reference to *.tlb in Excel VBA
Everything work with no problems, I created an instance of the Class; however VBA did not display the member of the class when entering "class."

 

DLL文件必须位于以下三个目录之一:

https://blog.csdn.net/samuelwang_ccnu/article/details/6669353

在VBA开发过程中,为了能够使用系统已经提供的函数,或已经用C++语言开发的功能,本文对VBA调用C++ DLL进行了总结。

1.        函数声明

Function prototype:

DWORD WINAPI GetCurrentDirectory(

 __in   DWORD nBufferLength,

 __out  LPTSTR lpBuffer

);

函数声明如下:

Public Declare Function GetCurrentDirectoryLib "kernel32" Alias "GetCurrentDirectoryA" (ByValnBufferLength As Long, ByVal lpBuffer As String) As Long

Public  用于声明对所有模块中的所有其它过程都可以使用的函数。  Private   用于声明只能在包含该声明的模块中使用的函数。 

Lib包含所声明函数的动态链接库名或代码资源名。    

Alias 表示将被调用的函数在动态链接库(DLL)   中还有另外的名称。

 

2.        DLL的位置

DLL文件必须位于以下三个目录之一:

(1)Windows的系统目录:\Windows\system32

(2)DOS中path所指出的任何目录

(3)Windows XP系统下:C:\Documentsand Settings\%USERNAME%\My Documents

为了VBA可以调用DLL中的函数,必须把DLL放在以上三个位置中的任何一个。

有两种办法可以解决这个问题:

1.      在调用DLL 函数之前,把DLL copy到以上三个目录中的任何一个。

Dim fso AsObject

Dim dllFileNameAs String

dllFileName = Environ("SYSTEMROOT")+ “\system32\LicenseVerify.dll”

Set fso =CreateObject("Scripting.FileSystemObject")

Iffso.FileExists(dllFileName) = False Then

fso. CopyFile ThisWorkbook.Path + “\ LicenseVerify.dll”,dllFileName

End If

 

2.      改变当前进程的当前路径。

例如,DLL与当前EXCEL文件放在同一个目录下,这个时候当前进程的当前路径设置如下:

Public Declare Function SetCurrentDirectoryLib "kernel32" Alias "SetCurrentDirectoryA" (ByVallpPathName As String) As Long ‘ function declaration

SetCurrentDirectory (ThisWorkbook.Path) ‘set the current directory to Thisworkbook.Path

OK,这样设置后,就可以访问DLL了。这样方便程序的发布,不需要用户把DLL复制到系统目录下。

 

3.        返回值

如果返回值是字符串,需要在函数调用前为字符串分配内存空间。

Public Declare Function GetCurrentDirectoryLib "kernel32" Alias "GetCurrentDirectoryA" (ByValnBufferLength As Long, ByVal lpBuffer As String) As Long

其中,lpBuffer 是输出参数。

例子:

Public Declare Function GetCurrentDirectoryLib "kernel32" Alias "GetCurrentDirectoryA" (ByValnBufferLength As Long, ByVal lpBuffer As String) As Long

 

Private Sub DoVerify()

    Dimresult As Integer

    Dim retValue AsString

 

    retValue = String(1024, vbNullChar) 'allocate the buffer for out parameter.
    result= GetCurrentDirectory(1024, retValue)   

End Sub

VBA调用DLL相对路径的使用

Today I have met some problems on specifying a relative path into a excel vba header, linking a dll.You must specify a absolute one instead of the relative path.

For example:

Declare Function LoadProject Lib "C:\Program Files\AccessHist.dll" (ByVal projectpath As String) As Boolean

At last I found the solution, just put the dll in the same folder as the xls file and in the Workbook_open() function put the following:

chdrive(thisworkbook.path)
chdir(thisworkbook.path)

You can linking the dll like this way:

Declare Function LoadProject Lib "AccessHist.dll" (ByVal projectpath As String) As Boolean 

用程序代码api 函数注册 

此方法的设计思路是:先将 activeX 控件载入内存,然后验证其有效性,最后直接在内存地址中执行其注册函数(DllRegisterServer、 DllUnregisterServer)。
其编程方法是:

1、使用Windows api 函数Loadlibrary 载入activeX 控件;
2、使用GetProcAddress 函数获取activeX 控件中注册函数DllRegisterServer(注销函数为 DllUnregisterServer)指针;
3、使用CallwindowProc 函数执行已载入内存的activeX 控件注册函数(DllRegisterServer、 DllUnregisterServer)。

较好的方法是在程序中嵌入注册代码,实现应用程序自注册。其编程方法是:
使用WindowsAPI函数LoadLibrary载入ActiveX控件;
使用GetProcAddress函数获取ActiveX控件中注册函数DllRegisterServer(注销函数为DllUnregisterServer)指针;
调用注册函数DllRegisterServer(或注销函数DllUnregisterServer)。

BOOL RegisterOCX(LPCTSTR OcxFileName)
{
    LPCTSTR pszDllName = OcxFileName ; //ActiveX控件的路径及文件名
    HINSTANCE hLib = LoadLibrary(pszDllName); //装载ActiveX控件
    if (hLib < (HINSTANCE)HINSTANCE_ERROR)
    {
        return FALSE ;
    }
    FARPROC lpDllEntryPoint;
    lpDllEntryPoint = GetProcAddress(hLib,("DllRegisterServer")); //获取注册函数DllRegisterServer地址
    if(lpDllEntryPoint!=NULL) //调用注册函数DllRegisterServer
    {
        if(FAILED((*lpDllEntryPoint)()))
        {
            DWORD dwError = GetLastError();
            FreeLibrary(hLib);
            return FALSE ;
        }
        return TRUE ;
    }
    else
        return FALSE ;
}

 

VB 如何判断一个OCX 控件 是否注册

on error resume next
 
dim tmpOjb as object
 
set tmpobj=createobject("库名.类名")
 
if tmpobj=nothing then 
(if tmpobj is nothing then )
    msgbox "未注册"
else
    msgbox "已注册"
end if

 

VBA 调用DLL动态链接库常见的方法有三种

[引用和部件的区别]

     "引用"一般是引用函数,这些函数一般封装在dll文件中的,在VB中看不到这些函数,像经常用的API函数,也包括自己封装的函数.
     "部件"一般是指控件,在VB可以看见这些控件,有一个图标,一般是ocx文件.

怎么在VB中调用DLL、格式是什么?结构的每个部分都是什么意思

要看Dll的类型 如果是API就 Declare声明 如果是ActiveX要生成类的实例

API
Declare Function/Sub Lib “DLL文件名” (参数列表)
ActiveX
Dim obj = CreatObject(“。DLL,.OCX”)
Set obj = New 类名

 

 


2.在ArcMap中引用动态链接库


       我在VB6下编译生成了一个动态链接库文件VBAPrj.dll,其中有一类模块VBACls,此类模块有一个方法Test(Doc As Object)。
        常见的方法有三种

1.打开VBA编辑器,点"工具"菜单下的"引用"命令,在引用对话框中引用该动态链接库。
        调用代码如下: 
     

 Dim VBACls As New VBAPrj.VBACls 
         VBACls.Test(ThisDocument) 


  2.如果知道该动态链接库文件的位置,可以在ThisDocument代码窗口以代码形式引用, 代码如下: 
       

 Private Sub Document_Open()
                   On Error Resume Next
                   Me.VBProject.References.AddFromFile "D:\VBAPrj.dll"
End Sub


    3.将动态链接库文件拷贝到文档同一目录下,可在ThisDocument代码窗口中建立如下引用函数:
       

Private Function GetProjectDoc() As Object
                 On Error Resume Next
                 Dim VBACls As Object
                 Set VBACls = CreateObject("VBAPrj.VBACls")
                 If VBACls Is Nothing Then
              MsgBox "VBAPrj.dll必须和文档在同一目录下!"
              Exit Function
                End If
                Set GetProjectDoc = VBACls
         End Function


        然后以以下代码形式调用Test:
       

Dim objPrjDoc As Object
         Set objPrjDoc = GetProjectDoc
         Call objPrjDoc.Test(ThisDocument)
         Set objPrjDoc = Nothing


       使用第一种方法调试提示找不到类库,第二种方法我没试过,用了第三种方法调试成功。我也觉得第三种还是蛮好的,除了多几行代码。成功调用DLL后原来很多在VB下写的东东简单改一下就可以在VBA下用了,效率又高,保密性又好

come from:https://www.cnblogs.com/lbnnbs/p/4784950.html

VBA不注册调用ActiveX Dll

https://blog.csdn.net/weixin_34416649/article/details/86036374?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242

Add Object Library reference to VBAProject programmatically (good)

 

Excel VBA代码封装成Dll(VB6.0):

Download Visual Basic 6 

https://masonacm.org/vb6/

 

Useful links

使用程序:
1、Microsoft Office Excel 2003
2、Microsoft Visual Basic 6.0

https://blog.csdn.net/qwlovedzm/article/details/44261101

 

VBA窗体的VB6封装DLL与制作

(https://max.book118.com/html/2017/0106/80522650.shtm)

自己用c#写DLL文件,供excel的VBA调用

这个dll不但可以用于excel,在word..coreldraw.ppt中也都是可以使用的。

http://club.excelhome.net/thread-1544291-1-1.html

用Microsoft Visual Studio 2010封装EXCEL VBA为DLL_COM组件