Wednesday, May 6, 2009

Make a standard DLL

This examples builds a standard DLL that you can call by using the normal DLL calling conventions. For full details, see the article Creating a Windows DLL with Visual Basic.


Thanks to Luke Emmet for pointing this article out.

The basic staps are:

  1. Hack the linking process.
    1. Make an executable program to call the linker. Reomve the default Form1 and create the following Sub Main.
 
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 Sub
 
This program does roughly the same thing that Visual Basic does when it creates a DLL except it adds the /DEF flag to the command.
  • Compile the executable.
  • Rename the normal Visual Basic linker from Link.exe to LinkLnk.exe. On my system, it's at C:\Program Files\Microsoft Visual Studio\VB98.
  • Copy the executable program that you compiled into this directory and name it Link.exe. When Visual Basic links the DLL, it calls this program, which calls the renamed LinkLnk.exe program, adding the new /DEF parameter.
  • Export the DLL's routines.
    1. Create a file named .def where is the name of the DLL. In this example, the DLL is named Fibonacci.dll so this file is called Fibonacci.def.
    2. Add code to this file similar to the following:
  •  
    NAME MathLib LIBRARY MathMod DESCRIPTION "Add-on Library of Mathematical Routines" EXPORTS DllMain @1         Fibo @2
     
    This tells the linker about the main entry point DllMain and this example's function Fibo, both of which are created shortly.
  • Build the DLL.
    1. Create a new ActiveX DLL project.
    2. Leave the default Class1 class alone. You will not use it but Visual Basic needs it to it has something to compile into the ActiveX DLL.
    3. Add a code module and insert this code:
  •  
    Public Const DLL_PROCESS_DETACH = 0 Public Const DLL_PROCESS_ATTACH = 1 Public Const DLL_THREAD_ATTACH = 2 Public Const DLL_THREAD_DETACH = 3  Public Function DllMain(hInst As Long, fdwReason As Long, _     lpvReserved As Long) As Boolean    Select Case fdwReason       Case DLL_PROCESS_DETACH          ' No per-process cleanup needed       Case DLL_PROCESS_ATTACH          DllMain = True       Case DLL_THREAD_ATTACH          ' No per-thread initialization needed       Case DLL_THREAD_DETACH          ' No per-thread cleanup needed    End Select End Function  ' Return a Fibonacci number. Public Function Fibo(ByVal N As Integer) As Long     If N <= 1 Then         Fibo = 1     Else         Fibo = Fibo(N - 1) + Fibo(N - 2)     End If End Function
     
    DllMain is the DLL entry point. Fibo is a function that the DLL is exporting.
  • Compile the DLL. This should invoke the new Link.exe you built. If you look in that program's directory, you should see the log file it generates.
  • Build a test program to call the DLL.
    1. Make a standard Visual Basic EXE.
    2. Declare the routine exported by the DLL as in the following code:
  •  
    Private Declare Function Fibo Lib _     "C:\WebSite\HowToSrc\a2\Fibonacci.dll" (ByVal N As _     Integer) As Long
     
    Insert the path to the DLL on your computer.
  • Run the program.

    That should do it. Watch out for typos. If the .DEF file doesn't spell the function's name correctly, the DLL won't compile and the error messages are not very good.

  • Wednesday, April 29, 2009

    Creating PDF files in Visual Basic

    PDF stands for portable document format. It is a format that every operating system on virtually any computer can read. Its become the default standard for transferring and viewing files in an easy way. The problem is that Visual Basic has no built in VB6 PDF functions. Because of this it has been very hard in the past to create PDF files from VB. Hopefully by the end of this Visual Basic Tutorial, PDF creation will be an easy thing for you to understand and do first hand.



    PDF is a pretty complex data format. Because, of this usually you have to buy a third party control from someone who's invested a large amount of time in navigating through the PDF format and written an easy way for you to access it. This tutorial explains how you can create a simple PDF file without a third party control. If you run into limitations down the road you might still end up having to purchase a control. However, you will then know exactly what to look for in the control and know how much you are willing to spend to get the functionality you need. Hopefully you won't even need to purchase one. If there is something you are trying to do, add a comment here or in the forum, and we will try to help you with it

    Private Sub Command1_Click()
    ' Create a simple PDF file using the mjwPDF class
    Dim objPDF As New mjwPDF

    ' Set the PDF title and filename
    objPDF.PDFTitle = "Test PDF Document"
    objPDF.PDFFileName = App.Path & "\test.pdf"

    ' We must tell the class where the PDF fonts are located
    objPDF.PDFLoadAfm = App.Path & "\Fonts"

    ' View the PDF file after we create it
    objPDF.PDFView = True

    ' Begin our PDF document
    objPDF.PDFBeginDoc
    ' Set the font name, size, and style
    objPDF.PDFSetFont FONT_ARIAL, 15, FONT_BOLD

    ' Set the text color
    objPDF.PDFSetTextColor = vbBlue

    ' Set the text we want to print
    objPDF.PDFTextOut _
    "Hello, World! From mjwPDF (www.vb6.us)"

    ' End our PDF document (this will save it to the filename)
    objPDF.PDFEndDoc
    End Sub



    From http://www.vb6.us