Enter Date & Time Stamp In PDF File

Did someone asked you to have a date and time stamp on a PDF file? Here’s a page from Adobe that shows how a stamp can be added into a PDF file. This looked nice and easy to me – I can put the system’s date and time onto the PDF file directly without having any code. The complexity increased when my boss asked me to put the date and time stamp of the email from which the PDF file was downloaded.

I searched the internet, found a piece of code in Adobe Support Community’s Using Excel VBA to add text to a PDF file link and taking a look at the Adobe Acrobat’s JavaScript Scripting Reference and Adobe Acrobat’s API Reference PDF files, I found that I can add a Text(box) field object in the PDF file by executing a JavaScript using VBA.

Please note that the code works in Adobe Acrobat DC Pro (not Adobe Reader DC). You need to test in the previous versions of Adobe Acrobat.

Here is the code that I prepared:

Function InsertDateAndTimeStamp(FilePathAndName As String, DateAndTime As Date)
    '   Function/Procedure Name :   InsertDateAndTimeStamp
    '                               Variable Name(s)    Data Type   Description
    '   Variable(s)             :   FilePathAndName     String      PDF Filename Along With Full Path
    '                               DateAndTime         Date        Date & Time To Be Stamped On The First Page Of PDF File
    '   Return Value            :   None
    '   Description             :   This Function/Procedure puts a date and time stamp on the specified PDF file.
    '                               The code runs a JavaScript that creates a textbox field with a message and
    '                               date and time stamp.
    '   Requirements            :   Requires Adobe Acrobat DC (Not Acrobat Reader DC) Application/Software.
    Dim objAdobeAcrobat As Object
    Dim objPDFDocument As Object
    Dim objPDFForm As Object
    Dim objViewPDFDocument As Object
    Dim objFileSystem As Object
    Dim strOriginalFilename As String
    Dim strSaveAsFilename As String
    Dim strTempFolderPath As String
    Dim strPath As String
    Dim strJavaScript As String
    Set objAdobeAcrobat = CreateObject("AcroExch.App")          'Adobe Acrobat Application
    Set objPDFDocument = CreateObject("AcroExch.PDDoc")         'PDF Document
    Set objViewPDFDocument = CreateObject("AcroExch.AVDoc")     'PDF Document (View)
    Set objPDFForm = CreateObject("AFormAut.App")               'From AFormAPI
    If objViewPDFDocument.Open(FilePathAndName, "") Then
        Set objPDFDocument = objViewPDFDocument.GetPDDoc
        'Write JavaScript Code On A VBA Variable
        strJavaScript = "f = this.addField(" & Chr(34) & "ReceivedByDG" & Chr(34) & ", " & _
            Chr(34) & "text" & Chr(34) & ", 0, [250, 25, 20, 0]);" & _
            "f.readonly = true;" & _
            "f.flatten;" & _
            "f.fillColor = color.transparent;" & _
            "f.textSize = 0; " & _
            "f.textFont = font.CourB;" & _
            "f.textColor = color.red;" & _
            "f.strokeColor = color.red;" & _
            "f.multiline = true;" & _
            "f.value = " & _
            Chr(34) & "Received By Dolphin Godfred\n" & _
            "Date & Time: " & Format(DateAndTime, "d-mmm-yyyy hh:mm:ss AM/PM") & Chr(34) & ";"
        'Execute The JavaScript Code
        objPDFForm.Fields.ExecuteThisJavaScript strJavaScript
        strOriginalFilename = objPDFDocument.GetFileName
        strSaveAsFilename = "TS_" & strOriginalFilename
        strPath = Environ("Temp") & Application.PathSeparator & _
        Set objFileSystem = CreateObject("Scripting.FileSystemObject")
        If objFileSystem.FileExists(strPath) Then _
            Call objFileSystem.DeleteFile(strPath, True)
        Call objPDFDocument.Save(1, strPath)
        objViewPDFDocument.Close 1
    End If
    Call objFileSystem.CopyFile(strPath, FilePathAndName, True)
    Set objFileSystem = Nothing
    Set objPDFForm = Nothing
    Set objViewPDFDocument = Nothing
    Set objPDFDocument = Nothing
    Set objAdobeAcrobat = Nothing
End Function

Merge Two PDF Files – One Of Them Is A Signed File

While I was working with PDF files, I found that the generic code that combines/merges two PDF files fails if one of the PDF file is a Signed Document. I have took the site, wellsr.com code and tested.

Please note that the code works in Adobe Acrobat DC Pro (not Adobe Reader DC). You need to test in the previous versions of Adobe Acrobat.

Here is the code that I modified:

Private Function MergePDFs(SourceFileOne As String, SourceFileTwo As String, SaveAsFilename As String) As Boolean
    '   Function/Procedure Name :   MergePDFs
    '                               Variable Name(s)    Data Type   Description
    '   Variable(s)             :   SourceFileOne       String      PDF Filename Along With Full Path (Source #1 - Signed PDF Document)
    '                               SourceFileTwo       String      PDF Filename Along With Full Path (Source #2)
    '                               SaveAsFilename      String      PDF Filename Along With Full Path To Save (Target)
    '   Return Value            :   Boolean
    '   Description             :   This Function/Procedure merges two PDF files into
    '                               one file and save it at a location set/given by the user.
    '                               Returns True if the merge is successful.
    '                               Returns False if the merge is not successful.
    '   Requirements            :   Requires Adobe Acrobat DC (Not Acrobat Reader DC) Application/Software.
    Dim objAdobeAcrobat As Object
    Dim objPDFDocumentOne As Object
    Dim objPDFDocumentTwo As Object
    On Error GoTo NoAcrobat
    'Initialize the Adobe Acrobat objects
    Set objAdobeAcrobat = CreateObject("AcroExch.App")          'Adobe Acrobat Application
    Set objPDFDocumentOne = CreateObject("AcroExch.PDDoc")      'Destination File
    Set objPDFDocumentTwo = CreateObject("AcroExch.PDDoc")      'Source File
    'Open PDF Document Two
    Call objPDFDocumentTwo.Open(SourceFileTwo)
    'Open PDF Document One
    Call objPDFDocumentOne.Open(SourceFileOne)
    'Merge PDF Document One Into PDF Document Two
    If objPDFDocumentTwo.InsertPages((objPDFDocumentTwo.GetNumPages - 1), _
        objPDFDocumentOne, 0, objPDFDocumentOne.GetNumPages, 0) Then
        MergePDFs = True
    End If
    'Save PDF Document Two With A New Filename
    Call objPDFDocumentTwo.Save(1, SaveAsFilename)
    On Error GoTo 0
    Set objPDFDocumentTwo = Nothing
    Set objPDFDocumentOne = Nothing
    Set objAdobeAcrobat = Nothing

End Function

Get Default Mail Client

Are your clients/co-workers work on Mail Clients (Microsoft Outlook, Outlook Express or Lotus Notes)?
Don’t worry, you can know their mail client with this simple code below:

Function CheckDefaultMailClient() As String
    'Reads the value for the default email client from Registry
    'If the key cannot be found, the return value is ""

    Dim objWindowsScript As Object
    Dim strDefaultMailClient As String
    Dim strRegistryKey As String

    strRegistryKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Clients\Mail\"

    On Error Resume Next
    'Access Windows scripting
    Set objWindowsScript = CreateObject("WScript.Shell")
    'Read key from registry
    strDefaultMailClient = objWindowsScript.RegRead(strRegistryKey)

    If strDefaultMailClient = vbNullString Or strDefaultMailClient = "" Then
        CheckDefaultMailClient = ""
        CheckDefaultMailClient = strDefaultMailClient
    End If
End Function

Get FileType And Executable File Path Of A File

Ever wondered if you needed the FileType and Executable File Path of a particular file? Well, I had to. So, I started to look into my famous, all time (24 X 7) library – internet. And found out that I can use the FileSystemObject and an API declaration to finish my work. So, here it goes.

For FileType, I used FileSystemObject and File object. And, for Executable File Path, I declared an API Function, FindExecutable using shell.dll library.

Here goes the code:

Private Declare Function FindExecutable Lib “shell32.dll” Alias “FindExecutableA” _
    (ByVal lpFile As String, ByVal lpDirectory As String, ByVal lpResult As String) As Long

Sub Check()
    Dim strExecutableProgramPath As String
    Dim strFilePathAndName As String, strFileType As String
    Dim objFileSystem As Object, objFile As Object
    'Create FileSystemObject
    Set objFileSystem = CreateObject(“Scripting.FileSystemObject”)
    strFilePathAndName = Worksheets(“Sheet1”).Range(“B1”).Value
    'Create File object and get FileType
    Set objFile = objFileSystem.GetFile(strFilePathAndName)
    strFileType = objFile.Type
    strExecutableProgramPath = FindExecutableProgram(strFilePathAndName)
    Worksheets(“Sheet1”).Range(“B2”).Value = strFileType
    Worksheets(“Sheet1”).Range(“B3”).Value = strExecutableProgramPath
    Set objFile = Nothing
    Set objFileSystem = Nothing
End Sub

Private Function FindExecutableProgram(FilePathAndNameWithExtension As String) As String
    Dim lngReturnValue As Long
    Dim strBuffer As String
    strBuffer = Space(260)
    'Retrieve the name and handle of the executable, associated with this file
    'Returns a value greater than 32 if successful.
    'Or a value less than or equal to 32 representing an error.
    'Return Value/Code Description
    '2 SE_ERR_FNF The specified file was not found.
    '3 SE_ERR_PNF The specified path is invalid.
    '5 SE_ERR_ACCESSDENIED The specified file cannot be accessed.
    '8 SE_ERR_OOM The system is out of memory or resources.
    '31 SE_ERR_NOASSOC There is no association for the specified file type with an executable file.
    lngReturnValue = FindExecutable(FilePathAndNameWithExtension, vbNullString, strBuffer)
    If lngReturnValue > 32 Then
        FindExecutableProgram = Left$(strBuffer, InStr(strBuffer, Chr$(0)) – 1)
        FindExecutableProgram = “No association found!”
    End If
End Function

Get Column Letter From Column Number

To get the Letter of a column, there are two ways.

#1 (Simplest way, I think):

Function GetColumnLetter(ColumnNumber As Long) As String
    GetColumnLetter = Split(Columns(ColumnNumber).Address(), “$”)(2)
End Function


Function GetColumnLetter(ByVal ColumnNumber As Long, _
  Optional ColumnName As String = “”) As String
    If ColumnNumber = 0 Then
        GetColumnLetter = ColumnName
        ColumnName = Chr(65 + (ColumnNumber – 1) Mod 26) & ColumnName
        ColumnNumber = (ColumnNumber – 1) \ 26
        GetColumnLetter = GetColumnLetter(ColumnNumber, ColumnName)
    End If
End Function