Creating a Windows DLL with Visual Basic
Pages: 1, 2, 3
Creating the Windows DLL
So, after examining an ActiveX DLL's export table, intercepting Visual Basic's call to the compiler, intercepting Visual Basic's call to the linker, and comparing the arguments passed to the linker with those required by a C/C++ compiler to generate a Windows DLL, we've finally identified why we aren't able to successfully create a Windows DLL with Visual Basic. And fortunately, we can work around that restriction. We should be able to create a standard Windows DLL if we do the following:
Create a .def file for our project. We can specify our exported functions in the .def file in several ways, but it's best to keep it simple:
NAME MathLib LIBRARY MathMod DESCRIPTION "Add-on Library of Mathematical Routines" EXPORTS DllMain @1 Increment @2 Decrement @3 Square @4The
NAMEstatement defines the name of the DLL. TheLIBRARYstatement must either precede the list of exported functions or appear on the same line as the first function. The .def file should also list the ordinal position of each exported function preceded by an@symbol.Decide how we want to intercept the call to the linker. Two major techniques are available to do this:
Patching the Import Address Table (IAT), which requires that we build a Visual Basic add-in that modifies the IAT in order to intercept particular calls by Visual Basic to the Win32 API. Although it's certainly the most elegant method, its complexity makes it a worthy subject for a separate article.
Building a proxy linker that intercepts the call to the real linker, modifies the command-line arguments to be passed to the linker, and then calls the linker with the correct command-line arguments. This is the approach we used to discover what arguments Visual Basic was passing to the compiler and linker, and it's the approach we'll adopt to create a Windows DLL.
In building our proxy linker, we want a sufficiently flexible design so that we can generate other kinds of files, if need be.
Modify the arguments to the linker to add the
/DEFswitch along with the path and filename of our .def file. To do this, you must create a Visual Basic Standard EXE project, add a reference to the Microsoft Scripting Runtime Library, remove the form from the project, and add a code module. The source code for the proxy linker is as follows:Option Explicit Public Sub Main() Dim SpecialLink As Boolean, fCPL As Boolean, fResource As Boolean Dim intPos As Integer Dim strCmd As String Dim strPath As String Dim strFileContents As String Dim strDefFile As String, strResFile As String Dim oFS As New Scripting.FileSystemObject Dim fld As Folder Dim fil As File Dim ts As TextStream, tsDef As TextStream strCmd = Command Set ts = oFS.CreateTextFile(App.Path & "\lnklog.txt") ts.WriteLine "Beginning execution at " & Date & " " & Time() ts.WriteBlankLines 1 ts.WriteLine "Command line arguments to LINK call:" ts.WriteBlankLines 1 ts.WriteLine " " & strCmd ts.WriteBlankLines 2 ' Determine if .DEF file exists ' ' Extract path from first .obj argument intPos = InStr(1, strCmd, ".OBJ", vbTextCompare) strPath = Mid(strCmd, 2, intPos + 2) intPos = InStrRev(strPath, "\") strPath = Left(strPath, intPos - 1) ' Open folder Set fld = oFS.GetFolder(strPath) ' Get files in folder For Each fil In fld.Files If UCase(oFS.GetExtensionName(fil)) = "DEF" Then strDefFile = fil SpecialLink = True End If If UCase(oFS.GetExtensionName(fil)) = "RES" Then strResFile = fil fResource = True End If If SpecialLink And fResource Then Exit For Next ' Change command line arguments if flag set If SpecialLink Then ' Determine contents of .DEF file Set tsDef = oFS.OpenTextFile(strDefFile) strFileContents = tsDef.ReadAll If InStr(1, strFileContents, "CplApplet", vbTextCompare) > 0 Then fCPL = True End If ' Add module definition before /DLL switch intPos = InStr(1, strCmd, "/DLL", vbTextCompare) If intPos > 0 Then strCmd = Left(strCmd, intPos - 1) & _ " /DEF:" & Chr(34) & strDefFile & Chr(34) & " " & _ Mid(strCmd, intPos) End If ' Include .RES file if one exists If fResource Then intPos = InStr(1, strCmd, "/ENTRY", vbTextCompare) strCmd = Left(strCmd, intPos - 1) & Chr(34) & strResFile & _ Chr(34) & " " & Mid(strCmd, intPos) End If ' If Control Panel applet, change "DLL" extension to "CPL" If fCPL Then strCmd = Replace(strCmd, ".dll", ".cpl", 1, , vbTextCompare) End If ' Write linker options to output file ts.WriteLine "Command line arguments after modification:" ts.WriteBlankLines 1 ts.WriteLine " " & strCmd ts.WriteBlankLines 2 End If ts.WriteLine "Calling LINK.EXE linker" Shell "linklnk.exe " & strCmd If Err.Number <> 0 Then ts.WriteLine "Error in calling linker..." Err.Clear End If ts.WriteBlankLines 1 ts.WriteLine "Returned from linker call" ts.Close End SubThis proxy linker modifies only the command-line arguments passed to the linker if a .def file is present in the directory that contains the Visual Basic project; otherwise it simply passes the command-line arguments on to the linker unchanged. If a .def file is present, it adds a
/DEFswitch to the command line. It also determines whether any resource files are to be added to the linked file list. Finally, it examines the export table to determine if a function namedCplAppletis present; if it is, it changes the output file's extension from .dll to .cpl.To install the proxy linker, rename the original Visual Basic linker LinkLnk.exe, copy the proxy linker to the Visual Basic directory, and name it Link.exe.
Once we create our proxy linker, we can reload our MathLib project and compile it into a DLL by selecting the Make MathLib.exe option from the File menu.
Testing the DLL
Once we create our Windows DLL, the final step is to test it to make sure that it works. To do this, create a new Standard EXE project (let's call it MathLibTest) and add a code module. To make sure that code in our project can access the functions exported by the DLL, we use the standard Visual Basic Declare statement. We declare our three exported math routines in the code module as follows:
Option Explicit
Public Declare Function Increment Lib "C:\VBProjects\MathLib\mathlib.dll" ( _
value As Integer) As Integer
Public Declare Function Decrement Lib "C:\VBProjects\MathLib\mathlib.dll" ( _
value As Integer) As Integer
Public Declare Function Square Lib "C:\VBProjects\MathLib\mathlib.dll" ( _
value As Long) As Long
We can then use the following code in the form module to call the routines in the DLL:
Option Explicit
Private Sub cmdDecrement_Click()
txtDecrement.Text = Decrement(CInt(txtDecrement.Text))
End Sub
Private Sub cmdIncrement_Click()
txtIncrement.Text = Increment(CInt(txtIncrement.Text))
End Sub
Private Sub cmdSquare_Click()
txtSquare.Text = Square(CLng(txtSquare.Text))
End Sub
Private Sub Form_Load()
txtIncrement.Text = 0
txtDecrement.Text = 100
txtSquare.Text = 2
End Sub
When we call each of the MathLib functions, the application window might appear as it does in Figure 2, confirming that the calls to the MathLib routines work as expected.

Figure 2: Testing calls to MathLib.dll
Ron Petrusha is the author and coauthor of many books, including "VBScript in a Nutshell."
Return to the Windows DevCenter.
-
Load from Rundll32.exe
2010-07-24 04:05:35 RizonBarns [View]
-
Standard DLL Visual Basic 6
2010-07-16 21:14:08 RizonBarns [View]
-
Maybe I being thick.
2010-03-29 01:33:17 Ngrayson [View]
-
Maybe I being thick.
2010-03-29 08:04:51 Ngrayson [View]
-
VB6 Library Options
2009-03-24 14:00:39 TheBursar [View]
-
DLL Creation
2009-02-10 21:48:24 GopiGrowlogic [View]
-
using this to create descriptions in Excel function wizard
2008-07-31 02:24:53 smallweed [View]
-
VB6 DLL's and runtime crashes
2007-12-15 15:07:08 Mathimagics [View]
-
Compile Error
2007-11-13 15:16:41 MikeH. [View]
-
Great article
2007-10-23 05:44:31 hericksonn [View]
-
DLL as a reference
2007-06-20 08:56:19 collinsauve [View]
-
Arrays in DLL
2007-06-19 07:01:20 pontiveros [View]
-
Arrays in DLL
2007-11-19 15:35:06 Ivanmp [View]
-
Dll programically
2007-06-09 03:01:25 MatthewS [View]
-
DLL generation and GUID
2007-04-06 09:56:38 Bejoyjohn [View]
-
DLL generation and GUID
2007-06-12 04:35:36 pinpi [View]
-
Is anyone still interested
2007-01-18 08:05:05 speechguy [View]
-
Is anyone still interested
2007-01-31 13:16:47 martiniB [View]
-
Application crashes
2006-10-20 11:16:15 mmdawson [View]
-
Passing strings to a DLL in VB 6.0
2006-06-29 10:42:14 sunnyrock75 [View]
-
Passing strings to a DLL in VB 6.0
2006-06-29 11:05:42 sunnyrock75 [View]
-
Classes
2006-06-08 12:07:04 MLxSol [View]
-
Def File
2006-05-30 09:43:18 MLxSol [View]
-
Calling .dll from Delphi app
2006-05-30 06:14:50 archer1960 [View]
-
Calling .dll from Delphi app
2006-05-30 10:10:37 archer1960 [View]
-
Calling .dll from Delphi app
2007-02-25 04:25:17 jalal_panah_amand [View]
-
Cannot Creat DLL
2006-05-09 04:20:40 sudintha [View]
-
Problem with DEF file
2006-04-10 12:21:37 xfile101 [View]
-
Problem with DEF file
2006-04-11 09:54:32 xfile101 [View]
-
Visual Basic 2005 Classes
2006-03-22 09:42:36 wjh [View]
-
Visual Basic 2005 Classes
2006-05-30 09:48:45 MLxSol [View]
-
Good Article!!
2006-01-31 01:06:16 Askatu_83 [View]
-
DLL not found
2006-01-17 03:54:59 draftsman [View]
-
DLL not found
2006-08-30 02:17:47 ManabScreen [View]
-
source code for the proxy linker
2005-12-27 04:30:56 draagoon [View]
-
DLL works in VB exe but not in VBA
2005-11-22 06:12:37 mike2508 [View]
-
DLL works in VB exe but not in VBA
2006-01-17 22:44:12 mandanaL [View]
-
DLL works in VB exe but not in VBA
2007-08-28 02:31:35 Lukie [View]
-
DLL Call Back Funciton
2005-09-04 20:34:47 Jeffrey168 [View]
-
Error in loading DLL
2005-08-14 11:48:14 sourcerer [View]
-
Error in loading DLL
2005-10-05 14:25:20 country [View]
-
Is DllMain being Called?
2005-07-27 07:31:57 LaVolpe [View]
-
Is DllMain being Called?
2005-08-28 21:19:38 mizanaz [View]
-
Is DllMain being Called?
2005-08-28 21:14:30 mizanaz [View]
-
Is DllMain being Called?
2005-07-28 05:56:24 LaVolpe [View]
-
How can I return Strings?
2005-07-18 09:20:14 teschste [View]
-
How can I return Strings?
2005-07-26 14:20:57 teschste [View]
-
Fully functional VB6 API dll's - with Forms
2005-07-18 03:14:07 Mathimagics [View]
-
Fully functional VB6 API dll's - with Forms
2007-02-05 00:55:37 Yazoo [View]
-
Fully functional VB6 API dll's - with Forms
2006-05-22 08:42:19 bill.h [View]
-
Fully functional VB6 API dll's - with Forms
2007-05-01 09:12:36 zzz123 [View]
-
Fully functional VB6 API dll's - with Forms
2009-01-28 04:23:19 GopiGrowlogic [View]
-
Fully functional VB6 API dll's - with Forms
2007-05-01 05:55:36 zzz123 [View]
-
Fully functional VB6 API dll's - with Forms
2005-11-25 17:58:09 Kutis [View]
-
Can I Creating a Windows DLL with Visual Basic.NET
2005-07-17 11:12:41 tarekafifi [View]
-
How to call exported functions from Visual C++??
2005-07-07 02:54:41 ponian [View]
-
How to call exported functions from Visual C++??
2006-01-24 06:51:16 JohnChristopherS [View]
-
Works GREAT in both VB and VBA
2005-06-14 11:44:28 Lawrence19103 [View]
-
Works GREAT in both VB and VBA
2005-07-08 06:59:42 JohnDrinkall [View]
-
Main vb6 exe crashs by calling a dll function
2005-06-10 02:08:28 Jörg [View]
-
Main vb6 exe crashs by calling a dll function
2006-10-20 11:25:27 mmdawson [View]
-
Strange ...
2005-06-02 08:37:41 Jeffi80 [View]
-
Showing forms within API DLL
2005-05-31 23:10:17 ijwelch [View]
-
Showing forms within API DLL
2005-08-01 03:49:36 Hossein.mohammadi [View]
-
Showing forms within API DLL
2005-07-08 07:03:14 JohnDrinkall [View]
-
Showing forms within API DLL
2006-01-16 21:57:54 draftsman [View]
-
Using external resource files with VB exes
2005-05-19 06:11:32 JohnDrinkall [View]
-
Using external resource files with VB exes
2006-03-10 09:12:29 marioavc [View]
-
can vb6 class/form be in windows dll ?
2005-05-12 05:13:59 Jeffrey168 [View]
-
can vb6 class/form be in windows dll ?
2005-05-16 07:28:03 Yehuda [View]
-
can vb6 class/form be in windows dll ?
2005-05-19 07:26:10 JohnDrinkall [View]
-
Debugging the finished DLL
2005-04-28 06:15:42 chizzy [View]

