Home > Mobile >  VBA Outlook Print to PDF - NOT "SAVE"
VBA Outlook Print to PDF - NOT "SAVE"

Time:06-04

App Versions:

Outlook: Microsoft 365 Apps for enterprise
Adobe Acrobat Pro DC: version 2022.001.20117

#########################################################################
DISCLAIMER: MY COMPANY HAS DISABLED "SAVE AS" FUNCTIONALITY WITHIN OUTLOOK.
PLEASE DO NOT SUGGEST ANY VBA METHODS THAT INVOLVE ".SaveAs", BECAUSE THEY
DO NOT WORK.
#########################################################################

Question:

I am writing a VBA macro to print an Outlook email to PDF using the Adobe PDF (driver?) printer:

enter image description here

Here is the basic process flow I want to automate:

  1. I will open/select an email that I want to print to PDF
  2. I will ctrl P to print and then select the Adobe PDF as the printer
  3. A "Save PDF File As" dialogue box appears
  4. Within the dialogue, set the save location and set the filename and submit

I have successfully coded steps 1-3. Step 4 is where my problems begin.

I have not found a way to simulate the dialogue box process. I tried AppActivate & SendKeys: the code runs but then it shifts the focus back to the VBE and therefore doesn't do what I need it to within the print dialogue.

I tried finding VBA code that replicates the backend process of the dialogue. I think the dialogue is a function of Adobe so finding VBA to talk to the process is hard.

The only thing I am trying to do with step 4 is to set the save location using a variable then set the filename field using a variable then click save to finish the print process. See screenshot below for dialogue box and relevant fields:

enter image description here

I will post the code I have below. Skip to the code heading titled, "Print/save email as PDF" to get to the good stuff:

Sub saveEmail()

'================================================================================
' Initialize variables
'================================================================================
    Dim olSelection As Outlook.selection
    Dim myItem As Outlook.MailItem
    Dim olAtt As Outlook.Attachment
    Dim olTempFolder As String
    Dim myDate As String: myDate = Year(Now) & Month(Now) & Day(Now) & _
                            Hour(Now) & Minute(Now) & Second(Now)
    Dim myPrinter As String
    
    ' Assign PDF printer to variable
    myPrinter = "Adobe PDF"
    
    ' Assign the window title of the save as pdf dialogue
    myDialogueTitle = "Save PDF File As"
    
    
'================================================================================
' Create email download path
'================================================================================
    ' Get the local temp folder path
    tempPath = ""
    tempPath = VBA.Environ("temp")
    
    ' Add Outlook Attachments subfolder to temp path
    olTempFolder = tempPath & "\Outlook Attachments"
    Debug.Print olTempFolder ' Print the folder path to immediate window
    
    ' If the path exists, check to make sure path is a directory, else create
    dirExists = Dir(olTempFolder, vbDirectory)
    If dirExists <> "" Then
        dirAttr = GetAttr(olTempFolder)
        
        ' Check if path is directory (attribute "16")
        If dirAttr <> 16 Then
            MsgBox "There is an error with the specified path. Check code " & _
                "try again."
        End If
        
    Else
    ' If folder does not exist, create
        MkDir (olTempFolder)
        
    End If
    
'================================================================================
' Create unique folder for this run
'================================================================================
    olTempFolder = olTempFolder & "\emailToPDF-" & myDate
    MkDir (olTempFolder)

'================================================================================
' Print/save email as PDF
'================================================================================
    
    ' Set the default printer
    Set mynetwork = CreateObject("WScript.network")
    mynetwork.setdefaultprinter myPrinter
    
    ' Print the email
    myItem.PrintOut
    
    ' Send keystrokes to Save As dialogue
    AppActivate myDialogueTitle ' Activate the printer dialogue window
    
    SendKeys myDate, True ' Change file name to be saved
    SendKeys "{F4}", True ' Activate path text box
    SendKeys "^a", True ' Select all contents of path text box
    SendKeys "{DEL}", True ' Delete selected contents of text box
    SendKeys olTempFolder, True ' Set desired save path in the path location box
    SendKeys "{ENTER}", True ' Press enter to set the path
    SendKeys "{ENTER}", True ' Press enter to submit/save as

'================================================================================
'
'================================================================================

End Sub

Again, please do not suggest a solution involving the ".SaveAs" method. Our IT administrators have disabled this functionality in Outlook so VBA code calling it does not work.

CodePudding user response:

In order to handle the Print to pdf dialog proceed in the next way:

  1. Copy the next API functions declaration on top of the module (in the declarations area):
 Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
                    (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
 Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias _
            "FindWindowExA" (ByVal hwnd1 As LongPtr, _
            ByVal hwnd2 As LongPtr, ByVal lpsz1 As String, _
            ByVal lpsz2 As String) As LongPtr
    Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As LongPtr, _
                                        ByVal wMsg As Long, ByVal wParam As LongPtr, lParam As Any) As Long

There are declarations for 64 bit systems (VBA 7). It can be adjusted to work for both cases.

  1. Use this way to deal with the dialog handlers, to change the pdf file name and press Save:
Sub testFindPdfPrinterWindow()
  Dim pdfHwnd As LongPtr, hwnd1 As LongPtr, hwnd2 As LongPtr, hwnd3 As LongPtr
  Dim hwndCombo As LongPtr, hwndEdit As LongPtr, hwndSave As LongPtr
  pdfHwnd = FindWindow("#32770", "Save PDF File As"): Debug.Print Hex(pdfHwnd)
    hwnd1 = FindWindowEx(pdfHwnd, 0, "DUIViewWndClassName", vbNullString): Debug.Print Hex(hwnd1)
      hwnd2 = FindWindowEx(hwnd1, 0, "DirectUIHWND", vbNullString): Debug.Print Hex(hwnd2)
        hwnd3 = FindWindowEx(hwnd2, 0, "FloatNotifySink", vbNullString): Debug.Print Hex(hwnd3)
          hwndCombo = FindWindowEx(hwnd3, 0, "ComboBox", vbNullString): Debug.Print Hex(hwndCombo)
           hwndEdit = FindWindowEx(hwndCombo, 0, "Edit", vbNullString): Debug.Print Hex(hwndEdit)
           
           Const WM_SETTEXT = &HC
           SendMessage hwndEdit, WM_SETTEXT, 0&, ByVal "MyMail pdf" 'use here what you need as pdf docment to be saved name
           
           hwndSave = FindWindowEx(pdfHwnd, 0, vbNullString, "&Save"): Debug.Print Hex(hwndSave)
           Const WM_LBUTTON_DOWN = &H201, BM_CLICK = &HF5
           SendMessage hwndSave, WM_LBUTTON_DOWN, 0&, 0&
           SendMessage hwndSave, BM_CLICK, 0, ByVal 0&
End Sub

You should play with your code until the moment the dialog is shown and may stop the macro.

Then run the above code.

CodePudding user response:

In the code I didn't find a place where Outlook objects declared at the beginning of the functions are declared.

Dim olSelection As Outlook.selection
Dim myItem As Outlook.MailItem
Dim olAtt As Outlook.Attachment

It seems you need to get the currently selected item in the Explorer window. Use the Selection property of the Explorer class which returns a Selection object that contains the item or items that are selected in the explorer window.

Set myOlExp = Application.ActiveExplorer 
Set myOlSel = myOlExp.Selection 
For x = 1 To myOlSel.Count 
  If myOlSel.Item(x).Class = OlObjectClass.olMail Then 

Then you can deal with a selected item. The Word object model can be used for dealing with message bodies. See Chapter 17: Working with Item Bodies for more information. So, you are free to use the Document.SaveAs2 method which saves the specified document with a new name or format. Some of the arguments for this method correspond to the options in the Save As dialog box (File tab).

Also you may find the Document.ExportAsFixedFormat2 method which saves a document as PDF or XPS format.

  • Related