vba macros load image file name into slide & not the image - vba

I'm just new here and wish your kind help please.
I had a macro add-in for PowerPoint was working fine with older versions.
The new 365 office didn't run it; and with a few tricks I was able to solve most of it.
Now the only thing left is when try to open and select image files from a folder, it loads the image name to each slide and not the images!
Sub Insert1PicViaForm()
' Added on 21.05.06 to load single file using code from
'
' http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnovba00/html/CommonDialogsPartI.asp
'
'
Dim OFN As OPENFILENAME
Dim Ret
Dim N As Integer
Dim ddd
Dim oSld As Slide
Dim oPic As Shape
With OFN
.lStructSize = LenB(OFN) ' Size of structure.
.nMaxFile = 574 ' Size of buffer.
' Create buffer.
.lpstrFile = String(.nMaxFile - 1, 0)
Ret = GetOpenFileName(OFN) ' Call function.
If Ret <> 0 Then ' Non-zero is success.
' Find first null char.
N = InStr(.lpstrFile, vbNullChar)
' Return what's before it.
' MsgBox Left(.lpstrFile, n - 1)
' Full path and filename
ddd = Left(.lpstrFile, N - 1)
' Add slide at end of presentation
Set oSld = ActivePresentation.Slides.Add(ActivePresentation.Slides.count + 1, ppLayoutBlank)
' Insert pic as selected
Set oPic = oSld.Shapes.AddPicture(FileName:=ddd, _
LinkToFile:=msoCTrue, _
SaveWithDocument:=msoCTrue, _
Left:=60, _
Top:=35, _
Width:=98, _
Height:=48)
End If
End With
End Sub

Some remarks about your code:
You're missing the GetOpenFileName function.
Opening the file dialog and returning the file path is now straightforward. No need to read and buffer the picture file
Please read the code's comments and ajust it to fit your needs
Public Sub InsertPicture()
' Declare and set a variable to ask for a file
Dim fileDialogObject As FileDialog
Set fileDialogObject = Application.FileDialog(msoFileDialogFilePicker)
' Adjust file dialog properties
With fileDialogObject
.InitialFileName = "C:\Temp"
.Title = "Insert Picture"
.ButtonName = "Insert picture"
.InitialView = msoFileDialogViewDetails
.Filters.Add "Images", "*.gif; *.jpg; *.jpeg,*.png,*.eps,*.tif,*.tiff", 1
End With
' Show the file dialog to user and wait for response
If fileDialogObject.Show = False Then Exit Sub
' Loop through each selected file (selectedFile returns the file path string)
Dim selectedFile As Variant
For Each selectedFile In fileDialogObject.SelectedItems
' Set new slide layout
Dim pptLayout As CustomLayout
Set pptLayout = ActivePresentation.Slides(1).CustomLayout
' Add a sile and reference it
Dim newSlide As Slide
Set newSlide = ActivePresentation.Slides.AddSlide(ActivePresentation.Slides.Count + 1, pptLayout)
' Insert picture in new slide
Dim newPicture As Shape
Set newPicture = newSlide.Shapes.AddPicture(FileName:=selectedFile, _
LinkToFile:=msoCTrue, _
SaveWithDocument:=msoCTrue, _
Left:=60, _
Top:=35, _
Width:=98, _
Height:=48)
Next selectedFile
End Sub
Let me know if it works

I just also added something for a blank slide when importing the images
Please see below. and again many thanks.
Public Sub InsertPicture()
' Declare and set a variable to ask for a file
Dim fileDialogObject As FileDialog
Set fileDialogObject = Application.FileDialog(msoFileDialogFilePicker)
' Adjust file dialog properties
With fileDialogObject
.InitialFileName = "C:\Temp"
.Title = "Insert Picture"
.ButtonName = "Insert picture"
.InitialView = msoFileDialogViewDetails
.Filters.Add "Images", "*.gif; *.jpg; *.jpeg,*.png,*.eps,*.tif,*.tiff", 1
End With
' Show the file dialog to user and wait for response
If fileDialogObject.Show = False Then Exit Sub
' Loop through each selected file (selectedFile returns the file path string)
Dim selectedFile As Variant
For Each selectedFile In fileDialogObject.SelectedItems
' Set new slide layout
' Dim pptLayout As CustomLayout
' Set pptLayout = ActivePresentation.Slides(1).CustomLayout
' Add a sile and reference it
Dim newSlide As Slide
Set newSlide = ActivePresentation.Slides.Add(ActivePresentation.Slides.Count + 1, ppLayoutBlank)
' Insert picture in new slide
Dim newPicture As Shape
Set newPicture = newSlide.Shapes.AddPicture(FileName:=selectedFile, _
LinkToFile:=msoCTrue, _
SaveWithDocument:=msoCTrue, _
Left:=60, _
Top:=35, _
Width:=98, _
Height:=48)
Next selectedFile
End Sub

Related

Qualified Reference to Word Enumerations

I built a macro in Outlook that refers to the Word object library.
The macro is very large and consists of several subs and functions. The end goal of this macro is to convert the selected Outlook mailitem into a PDF via (via Word) and combine it with all PDF attachments.
I keep getting a runtime error 462 "the remote server machine does not exist or is unavailable."
I have narrowed down the line where this error is occurring. Code as follows:
wdApp.Selection.ParagraphFormat.TabStops.Add Position:=InchesToPoints(1.5), _
Alignment:=wdAlignTabLeft, Leader:=wdTabLeaderSpaces
As you can see, I am creating a qualified reference to the Word Application ("wdApp.Selection..."), but I suspect that somehow, I need to qualify the enumerators as well. How would I do this? Or if I am mistaken and the issue is with another part of the code, please let me know.
Here is the rest of my code (it is very lengthy).
Option Explicit
Sub wordToPDF()
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' ANOTHER NOTE: you MUST disable sandbox protections in Adobe Acrobat or this
' macro will not work. You must uncheck "Enable Protected Mode at startup"
' within the "Sandbox Protections" section in the Adobe enhanced secutiy pref-
' erences.
' https://www.adobe.com/devnet-docs/acrobatetk/tools/AppSec/sandboxprotections.html#:~:text=Go%20to%20Edit%20%3E%20Preferences%20%3E%20Security,the%20feature%20controls%20as%20needed.
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' Site below explains how to run Outlook VBA from Excel (applies here)
' https://hackernoon.com/how-to-create-word-documents-within-excel-vba-d13333jl
' Site below explains how to control multiple Office apps from one macro
' https://learn.microsoft.com/en-us/office/vba/excel/concepts/working-with- _
other -applications / controlling - one - microsoft - office - Application - From - another
On Error GoTo errHandler1
' Set "True" if you want to run macro in debug mode
Dim boolDebug As Boolean: boolDebug = False
If boolDebug Then
Debug.Print "#######################################################" & _
vbCrLf & "BEGINNING MACRO" & _
"#######################################################"
End If
'================================================================================
' Initialize variables
'================================================================================
' Declare OUTLOOK objects
Dim olSel As Outlook.Selection, olMI As Outlook.MailItem, _
olAtt As Outlook.Attachment, olAtts As Outlook.Attachments
' Declare WORD objects
Dim wdApp As Word.Application
Dim wdDocs As Word.Documents
Dim wdAllDocs As Word.Documents
Dim wdDoc As Word.Document
Dim wdItDoc As Word.Document
Dim rgSel As Variant
' Declare other objects/variabels
Dim myDate As String, olTempFolder As String, myPrinter As String, sUser As String, _
sFrom As String, sTo As String, sCC As String, sBCC As String, _
sSubj As String, dirExists As String, dirAttr As String, tempPath As String, _
myDialogueTitle As String, sFileNamePDF As String, attFullPath As String, _
sSenderEmail As String, arrHeader(1, 6) As String, sDay As String, sMonth As String, _
sFinalPDF As String, sPdfRoot As String
Dim dtSent As Date
Dim Shex As Object
Dim i As Integer
Dim vItem As Variant
' Set Outlook objects
Set olMI = GetCurrentItem ' Custom function
' Make day variable 2 characters in length
If Len(Day(Now)) < 2 Then
sDay = "0" & Day(Now)
Else
sDay = Day(Now)
End If
' Make month variable 2 characters in length
If Len(Month(Now)) < 2 Then
sMonth = "0" & Month(Now)
Else
sMonth = Month(Now)
End If
' Initialize date variable
myDate = Year(Now) & sMonth & sDay & Hour(Now) & Minute(Now) & _
Second(Now)
' 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."
Exit Sub
End If
Else
' If folder does not exist, create
MkDir (olTempFolder)
End If
'================================================================================
' Delete items older than 14 days
'================================================================================
Dim dNow, dLimit, dCreated As Date
Dim fso, fsoF, oSubFolder, oFile As Object
Dim sDebugFPath As String
' Assign current time and two weeks ago time
dNow = Now()
dLimit = DateAdd("d", -7, dNow)
' Get the outlook folder where items are being saved
Set fso = CreateObject("Scripting.FileSystemObject")
Set fsoF = fso.GetFolder(olTempFolder)
' Check each subfolder in temp outlook folder and delete if too old
For Each oSubFolder In fsoF.SubFolders
' Get date created of iteration subfolder
dCreated = oSubFolder.DateCreated
' If subfolder exceeds the file age limit, delete
If dCreated < dLimit Then
sDebugFPath = oSubFolder
Debug.Print oSubFolder
oSubFolder.Delete (True)
Debug.Print "Deleted the following folder: " & sDebugFPath
End If
Next
' Delete any non-folder files in the temporary outlook folder
For Each oFile In fsoF.Files
fso.deletefile oFile
Next
Set fso = Nothing
Set fsoF = Nothing
'================================================================================
' Create unique folder for this run
'================================================================================
olTempFolder = olTempFolder & "\emailToPDF-" & myDate
MkDir (olTempFolder)
'Set filename.pdf
sFileNamePDF = olTempFolder & "\!EmailMessage.pdf" '<-"!" for sorting
'================================================================================
' Save attachments from selected email
'================================================================================
For Each olAtt In olMI.Attachments
If Not isEmbedded(olAtt) Then
attFullPath = olTempFolder & "\" & olAtt.DisplayName
olAtt.SaveAsFile (attFullPath)
End If
Next
'================================================================================
' Initialize header variables
'================================================================================
' Get active user
Dim myNamespace As Outlook.NameSpace
Set myNamespace = Application.GetNamespace("MAPI")
sUser = myNamespace.CurrentUser
' Get sender email
sSenderEmail = getEmail(olMI)
' Assign header variables to array
arrHeader(0, 0) = "From:"
arrHeader(1, 0) = olMI.SenderName & " <" & sSenderEmail & ">" ' From
arrHeader(0, 1) = "Sent:"
arrHeader(1, 1) = olMI.ReceivedTime ' Rec'd Date/Time
arrHeader(0, 2) = "To:"
arrHeader(1, 2) = olMI.To ' To
arrHeader(0, 3) = "Cc:"
arrHeader(1, 3) = olMI.CC ' CC
arrHeader(0, 4) = "Bcc:"
arrHeader(1, 4) = olMI.BCC ' BCC
arrHeader(0, 5) = "Subject:"
arrHeader(1, 5) = olMI.Subject ' Subject
arrHeader(0, 6) = "Attachments:"
i = 0
For Each olAtt In olMI.Attachments ' Create string list of attachments
' If attachment is not embedded, add it to attachment string variable
If Not isEmbedded(olAtt) Then
' Add semicolon before any non-embedded attachments after the first
If i > 0 Then
arrHeader(1, 6) = arrHeader(1, 6) & "; "
End If
' Build attachment string within the header variable array
arrHeader(1, 6) = arrHeader(1, 6) & olAtt
i = i + 1
End If
Next
i = 0
If boolDebug Then
For Each vItem In arrHeader
Debug.Print vItem
Next
End If
'================================================================================
' Create word object and insert header
'================================================================================
' Set Word objects
'Set wdApp = GetObject(, "Word.Application")
Set wdApp = New Word.Application
wdApp.Documents.Add
wdApp.ActiveDocument.ActiveWindow.Visible = False
' Type the Username
wdApp.Selection.Font.Bold = wdToggle
wdApp.Selection.Font.Size = 13
wdApp.Selection.TypeText Text:=sUser
wdApp.Selection.Font.Size = 11
wdApp.Selection.Font.Bold = wdToggle
wdApp.Selection.TypeParagraph
wdApp.Selection.MoveLeft unit:=wdCharacter, Count:=1
' Assign the selection to Range object
Set rgSel = wdApp.Selection.Range
' Insert the border beneath username
' on Error GoTo appError
' rgSel.Borders(wdBorderBottom).LineStyle = Options.DefaultBorderLineStyle
' rgSel.Borders(wdBorderBottom).LineWidth = wdLineWidth300pt
' rgSel.Borders(wdBorderBottom).Color = Options.DefaultBorderColor
' GoTo borderComplete
' ' Try with wdApp.Selection
'appError:
wdApp.Selection.Borders(wdBorderBottom).LineStyle = wdApp.Options.DefaultBorderLineStyle
wdApp.Selection.Borders(wdBorderBottom).LineWidth = wdLineWidth300pt
wdApp.Selection.Borders(wdBorderBottom).Color = wdApp.Options.DefaultBorderColor
' On Error GoTo 0
'borderComplete:
'
'On Error GoTo errHandler1
'
'' Err.Raise 1000
'
' Move down and add paragraph
wdApp.Selection.MoveDown unit:=wdLine, Count:=1
wdApp.Selection.TypeParagraph
' ========================================
' Loop through array, adding elements if they exist
' ========================================
i = 0
For i = 0 To 6 '<==== probably need to find a way to make dynamic
If arrHeader(1, i) <> "" Then
wdApp.Selection.Font.Bold = wdToggle
wdApp.Selection.TypeText Text:=arrHeader(0, i)
wdApp.Selection.Font.Bold = wdToggle
wdApp.Selection.TypeText Text:=vbTab & arrHeader(1, i)
wdApp.Selection.TypeParagraph
End If
Next
For i = 1 To 3
wdApp.Selection.TypeParagraph
Next
' Format the header
wdApp.Selection.WholeStory
MsgBox True
wdApp.Selection.ParagraphFormat.TabStops.Add Position:=InchesToPoints(1.5), _
Alignment:=wdAlignTabLeft, Leader:=wdTabLeaderSpaces
MsgBox True
wdApp.Selection.ParagraphFormat.LineSpacing = LinesToPoints(100)
' Format the .ParagraphFormat
wdApp.Selection.ParagraphFormat.LeftIndent = InchesToPoints(1.5)
wdApp.Selection.ParagraphFormat.RightIndent = InchesToPoints(0)
wdApp.Selection.ParagraphFormat.SpaceBefore = 0
wdApp.Selection.ParagraphFormat.SpaceBeforeAuto = False
wdApp.Selection.ParagraphFormat.SpaceAfter = 0
wdApp.Selection.ParagraphFormat.SpaceAfterAuto = False
wdApp.Selection.ParagraphFormat.LineSpacingRule = wdLineSpaceSingle
wdApp.Selection.ParagraphFormat.Alignment = wdAlignParagraphLeft
wdApp.Selection.ParagraphFormat.WidowControl = True
wdApp.Selection.ParagraphFormat.KeepWithNext = False
wdApp.Selection.ParagraphFormat.KeepTogether = False
wdApp.Selection.ParagraphFormat.PageBreakBefore = False
wdApp.Selection.ParagraphFormat.NoLineNumber = False
wdApp.Selection.ParagraphFormat.Hyphenation = True
wdApp.Selection.ParagraphFormat.FirstLineIndent = InchesToPoints(-1.5)
wdApp.Selection.ParagraphFormat.OutlineLevel = wdOutlineLevelBodyText
wdApp.Selection.ParagraphFormat.CharacterUnitLeftIndent = 0
wdApp.Selection.ParagraphFormat.CharacterUnitRightIndent = 0
wdApp.Selection.ParagraphFormat.CharacterUnitFirstLineIndent = 0
wdApp.Selection.ParagraphFormat.LineUnitBefore = 0
wdApp.Selection.ParagraphFormat.LineUnitAfter = 0
wdApp.Selection.ParagraphFormat.MirrorIndents = False
wdApp.Selection.ParagraphFormat.TextboxTightWrap = wdTightNone
wdApp.Selection.ParagraphFormat.CollapsedByDefault = False
' Format the .PageSetup
wdApp.Selection.PageSetup.LineNumbering.Active = False
wdApp.Selection.PageSetup.Orientation = wdOrientPortrait
wdApp.Selection.PageSetup.TopMargin = InchesToPoints(0.5)
wdApp.Selection.PageSetup.BottomMargin = InchesToPoints(0.5)
wdApp.Selection.PageSetup.LeftMargin = InchesToPoints(0.5)
wdApp.Selection.PageSetup.RightMargin = InchesToPoints(0.5)
wdApp.Selection.PageSetup.Gutter = InchesToPoints(0)
wdApp.Selection.PageSetup.HeaderDistance = InchesToPoints(0.5)
wdApp.Selection.PageSetup.FooterDistance = InchesToPoints(0.5)
wdApp.Selection.PageSetup.PageWidth = InchesToPoints(8.5)
wdApp.Selection.PageSetup.PageHeight = InchesToPoints(11)
wdApp.Selection.PageSetup.FirstPageTray = wdPrinterDefaultBin
wdApp.Selection.PageSetup.OtherPagesTray = wdPrinterDefaultBin
wdApp.Selection.PageSetup.SectionStart = wdSectionNewPage
wdApp.Selection.PageSetup.OddAndEvenPagesHeaderFooter = False
wdApp.Selection.PageSetup.DifferentFirstPageHeaderFooter = False
wdApp.Selection.PageSetup.VerticalAlignment = wdAlignVerticalTop
wdApp.Selection.PageSetup.SuppressEndnotes = False
wdApp.Selection.PageSetup.MirrorMargins = False
wdApp.Selection.PageSetup.TwoPagesOnOne = False
wdApp.Selection.PageSetup.BookFoldPrinting = False
wdApp.Selection.PageSetup.BookFoldRevPrinting = False
wdApp.Selection.PageSetup.BookFoldPrintingSheets = 1
wdApp.Selection.PageSetup.GutterPos = wdGutterPosLeft
' Copy formatted email body of text
Dim wdItemWordEditor As Object
Set wdItemWordEditor = olMI.GetInspector.WordEditor
wdItemWordEditor.Range.Copy
' Paste email body into word doc after header
wdApp.Selection.MoveStart unit:=wdCharacter, Count:=1000000
wdApp.Selection.Paste
' Re-select the whole word doc
wdApp.ActiveDocument.Select
' Remove paragraph spacing
wdApp.Selection.ParagraphFormat.SpaceBefore = 0
wdApp.Selection.ParagraphFormat.SpaceBeforeAuto = False
wdApp.Selection.ParagraphFormat.SpaceAfter = 0
wdApp.Selection.ParagraphFormat.SpaceAfterAuto = False
wdApp.Selection.ParagraphFormat.LineSpacingRule = wdLineSpaceSingle
'================================================================================
' Print/save email as PDF
'================================================================================
' Print doc to PDF
wdApp.ActiveDocument.SaveAs2 FileName:=sFileNamePDF, FileFormat:=wdFormatPDF
' Close doc and close word
wdApp.ActiveDocument.Close savechanges:=wdDoNotSaveChanges
wdApp.Quit savechanges:=wdDoNotSaveChanges
Set wdApp = Nothing
'================================================================================
' Print/save email as PDF
'================================================================================
sPdfRoot = olTempFolder
' Run custom function to merge PDFs and return the final PDF path
sFinalPDF = mergePDF(sPdfRoot)
'================================================================================
' Open the newly created PDF
'================================================================================
' Create shell object
Set Shex = CreateObject("Shell.Application")
' Redundancy IF statement. If function successful, use that path. Otherwise _
use the default path in main sub.
If Not sFinalPDF = "" Then
Shex.Open (sFinalPDF)
Else
Shex.Open (sFileNamePDF)
' This route is less reliable because the merge PDF function selects _
only one of the PDFs in the temp folder as the primary. After _
merge, it deletes the rest of the PDFs in the folder. If it _
selected a primary file other than the sFileNamePDF path, then _
this route will not open the file in Adobe because sFileName PDF _
will not exist.
End If
Exit Sub
'================================================================================
' Error handling
'================================================================================
' General error handling statement
errHandler1:
MsgBox "There was an unexpected error with the macro." & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Message: " & Err.Description
End Sub
Private Function isEmbedded(Att As Outlook.Attachment) As Boolean
' This function determines whether the passed mailitem.attachment is embedded
' https://stackoverflow.com/questions/59075501/ _
find-out-if-an-attachment-is-embedded-or-attached
Dim PropAccessor As Outlook.PropertyAccessor
On Error GoTo outlook_att_IsEmbedded_error
isEmbedded = False
Set PropAccessor = Att.PropertyAccessor
If PropAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001E") <> "" Or _
PropAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3713001E") <> "" Then
If PropAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x37140003") = 4 Then
isEmbedded = True
End If
End If
outlook_att_IsEmbedded_exit:
Set PropAccessor = Nothing
Exit Function
outlook_att_IsEmbedded_error:
isEmbedded = False
Resume outlook_att_IsEmbedded_exit
End Function
Private Function GetCurrentItem() As Object
' Purpose: this function returns the active MailItem, whether from the Explorer or Inspector.
'================================================================================
' Initialize variables
'================================================================================
Dim olApp As Outlook.Application
Dim sMailTest As String
Set olApp = Application
'================================================================================
' Initialize variables
'================================================================================
On Error Resume Next
' Determine whether active item is Explorer or Inspector object
Select Case TypeName(olApp.ActiveWindow)
' If explorer item selected, return explorer MailItem
Case "Explorer"
sMailTest = TypeName(olApp.ActiveExplorer.Selection.Item(1))
If Not sMailTest = "MailItem" Then
MsgBox "The selected item is not an Email. Please select another item."
End
End If
Set GetCurrentItem = olApp.ActiveExplorer.Selection.Item(1)
' If inspector item selected, return inspector MailItem
Case "Inspector"
sMailTest = TypeName(olApp.ActiveInspector.CurrentItem)
If Not sMailTest = "MailItem" Then
MsgBox "The selected item is not an Email. Please select another item."
End
End If
Set GetCurrentItem = olApp.ActiveInspector.CurrentItem
End Select
Set olApp = Nothing
End Function
Private Function getEmail(mail As Outlook.MailItem) As String
' Purpose: Return the readable email address of an Outlook user
' Modified version of the following solution: _
https://stackoverflow.com/a/26171979/17312223
'================================================================================
' Declare variables
'================================================================================
Dim PR_SMTP_ADDRESS As String
'================================================================================
' If mail item not selected, exit function
'================================================================================
If mail Is Nothing Then
getEmail = vbNullString
Exit Function
End If
'================================================================================
' Retrieve sender email from mail item
'================================================================================
If mail.SenderEmailType = "EX" Then
Dim sender As Outlook.AddressEntry
Set sender = mail.sender
If Not sender Is Nothing Then
'Now we have an AddressEntry representing the Sender
If sender.AddressEntryUserType = Outlook.OlAddressEntryUserType. _
olExchangeUserAddressEntry Or sender.AddressEntryUserType = _
Outlook.OlAddressEntryUserType.olExchangeRemoteUserAddressEntry Then
'Use the ExchangeUser object PrimarySMTPAddress
Dim exchUser As Outlook.ExchangeUser
Set exchUser = sender.GetExchangeUser()
If Not exchUser Is Nothing Then
getEmail = exchUser.PrimarySmtpAddress
Else
getEmail = vbNullString
End If
Else
getEmail = sender.PropertyAccessor.GetProperty(PR_SMTP_ADDRESS)
End If
Else
getEmail = vbNullString
End If
Else
getEmail = mail.SenderEmailAddress
End If
End Function
Private Function mergePDF(sPdfRoot As String)
' Purpose: to merge multiple PDFs together into one.
' Macro influenced by the following solution: _
https://stackoverflow.com/a/51690835/17312223
' If having issues with saving the merged pdf, see the following URL: _
https://stackoverflow.com/questions/71580519/pddoc-save-adobe-acrobat-method-not-working-in-excel-vba
On Error GoTo errHandler1
' ================================================================================
' Declare variables / create objects
' ================================================================================
Dim app As Object
Dim sFile As String
Dim iFwd As Integer
Dim iBwd As Integer
Dim iLArr As Integer
Dim i As Integer
Dim arrayFilePaths() As Variant
ReDim arrayFilePaths(0) ' Enable LBound and UBound calling
Dim primaryDoc As Object
Dim OK As Variant
Dim arrayIndex As Integer
Dim numPages As Integer
Dim numberOfPagesToInsert As Integer
Dim sourceDoc As Object
Dim PDSaveFull As Variant
' Create Adobe app object
'Set app = CreateObject("Acroexch.app")
' Create Adobe PDF object
Set primaryDoc = CreateObject("AcroExch.PDDoc")
' ================================================================================
' Initialize variables
' ================================================================================
' Assign position of ending slash to variable
iFwd = InStrRev(sPdfRoot, "/") ' Forward slash
iBwd = InStrRev(sPdfRoot, "\") ' Backward slash
' Check for ending slash existence
If Not iFwd > 0 Or Not iBwd > 0 Then
' If no ending slash, add
sPdfRoot = sPdfRoot & "\"
End If
' ================================================================================
' Loop through root, assigning PDF files to array
' ================================================================================
' Assign directory and wildcard to search for within
sFile = Dir(sPdfRoot & "*.pdf*")
' Get lowest boundary of array dimension
iLArr = LBound(arrayFilePaths)
' Assign lower array boundary to beginning iteration counter
i = iLArr
' Loop through the entire array
Do While sFile <> ""
' Add additional space to array variable
ReDim Preserve arrayFilePaths(iLArr To i)
' Assign the iteration file to the new array space
arrayFilePaths(i) = sPdfRoot & sFile
' Iterate counter by 1
i = i + 1
' Iterate to next file in directory
sFile = Dir()
Loop
i = 0
' Set the primary PDF document
OK = primaryDoc.Open(arrayFilePaths(0))
Debug.Print "PRIMARY DOC OPENED & PDDOC SET: " & OK
' Return the path of primary document
mergePDF = arrayFilePaths(0)
' ================================================================================
' Loop through non-primary PDFs
' ================================================================================
For arrayIndex = 1 To UBound(arrayFilePaths)
' Get number of pages of primary PDF _
(minus one bc "insertPages" index starts at 0)
numPages = primaryDoc.GetNumPages() - 1
'Debug.Print "Number of pages in primary doc = " & numPages
' Set iteration PDF to be merged into primary
Set sourceDoc = CreateObject("AcroExch.PDDoc")
' Open iteration PDF
OK = sourceDoc.Open(arrayFilePaths(arrayIndex))
'Debug.Print "source doc = " & arrayFilePaths(arrayIndex)
' Get number of pages of iteration PDF
Debug.Print "SOURCE DOC OPENED & PDDOC SET: " & OK
numberOfPagesToInsert = sourceDoc.GetNumPages
'Debug.Print "# Pages to insert = " & numberOfPagesToInsert
' Insert iteration PDF into primary document
OK = primaryDoc.InsertPages _
(numPages, sourceDoc, 0, numberOfPagesToInsert, False)
Debug.Print _
"============================================" & vbCrLf & _
"# total pages: " & numPages + 1 & vbCrLf & _
"source doc name: " & sourceDoc.GetFileName() & vbCrLf & _
"# pages to insert: " & numberOfPagesToInsert
Debug.Print "PAGES INSERTED SUCCESSFULLY: " & OK
' Save primary PDF that now contains iteration PDF
OK = primaryDoc.Save(PDSaveFull, mergePDF) 'arrayFilePaths(0)
Debug.Print "PRIMARYDOC SAVED PROPERLY: " & OK
' Close the iteration document
OK = sourceDoc.Close
' Delete the iteration document (since it is merged into primary)
Kill (arrayFilePaths(arrayIndex))
' Clear iteration object
Set sourceDoc = Nothing
Next arrayIndex
' ================================================================================
' Clear objects/variables
' ================================================================================
Set primaryDoc = Nothing
'app.Exit
'Set app = Nothing
' ================================================================================
' Error handling
' ================================================================================
Exit Function
errHandler1:
Debug.Print "###########################################################" & _
vbCrLf & "There was an error within the PDF portion of the macro." _
& vbCrLf & "Error #: " & Err.Number & "Error Msg: " & Err.Description & _
vbCrLf & "###########################################################"
' ================================================================================
' End sub
' ================================================================================
End Function

MS Word populate text after is inserted via VBA form

I have created word macro enabled template.
At opening form pops-up and user can fill in form. After pressing OK bookmarks inside document are updated and shown.
What I need is to populate entered values trough entire document on multiple locations. I have tried cross-referencing bookmarks but they are not updated with values entered in form.
image of opening form
Private Sub cancelBut_Click()
stInfo.Hide
End Sub
Private Sub Label11_Click()
End Sub
Private Sub OKbut_Click()
Dim katcest As Range
Set katcest = ActiveDocument.Bookmarks("katcest").Range
katcest.Text = Me.TextBox1.Value
Dim katopcina As Range
Set katopcina = ActiveDocument.Bookmarks("katopcina").Range
katopcina.Text = Me.TextBox2.Value
Dim zkcest As Range
Set zkcest = ActiveDocument.Bookmarks("zkcest").Range
zkcest.Text = Me.TextBox3.Value
Dim zkopcina As Range
Set zkopcina = ActiveDocument.Bookmarks("zkopcina").Range
zkopcina.Text = Me.TextBox4.Value
Dim zkulozak As Range
Set zkulozak = ActiveDocument.Bookmarks("zkulozak").Range
zkulozak.Text = Me.TextBox5.Value
Dim povrsina As Range
Set povrsina = ActiveDocument.Bookmarks("povrsina").Range
povrsina.Text = Me.TextBox6.Value
Dim vlasnik As Range
Set vlasnik = ActiveDocument.Bookmarks("vlasnik").Range
vlasnik.Text = Me.TextBox7.Value
Dim vladresa As Range
Set vladresa = ActiveDocument.Bookmarks("vladresa").Range
vladresa.Text = Me.TextBox8.Value
Dim datocevida As Range
Set datocevida = ActiveDocument.Bookmarks("datocevida").Range
datocevida.Text = Me.TextBox9.Value
Dim klasa As Range
Set klasa = ActiveDocument.Bookmarks("klasa").Range
klasa.Text = Me.TextBox10.Value
Dim urbroj As Range
Set urbroj = ActiveDocument.Bookmarks("urbroj").Range
urbroj.Text = Me.TextBox11.Value
Me.Repaint
Dim strDocName As String
Dim intPos As Integer
' Find position of extension in file name
strDocName = ""
intPos = InStrRev(strDocName, ".")
If intPos = 0 Then
' If the document has not yet been saved
' Ask the user to provide a file name
strDocName = InputBox("Upisi naziv " & _
"vaseg dokumenta.")
Else
' Strip off extension and add ".txt" extension
strDocName = Left(strDocName, intPos - 1)
strDocName = strDocName & ".docx"
End If
' Save file with new extension
ActiveDocument.SaveAs2 FileName:=strDocName, _
FileFormat:=wdFormatDocumentDefault
stInfo.Hide
infoForm.Show
End Sub

Apply specific layout PPT

I have an existing piece of code (see below) for importing a batch of photos and creating a slide show. At present, the code is creating these slides on a blank background with a title only. How can I modify it so it will choose a specific slide layout from the Master slides? I know it has something to do with this line in the code:
Set oSld = ActivePresentation.Slides.Add(ActivePresentation.Slides.Count + 1, ppLayoutTitleOnly)
I looked here and tried some ideas but I just keep getting bugs: Applying layout to a slide from specific Master
Here's the full program:
Sub ImportStuffFromTextFile()
Dim strTemp As String
Dim strPath As String
Dim strFileSpec As String
Dim oSld As Slide
Dim oPic As Shape
Dim fs As Object
Dim f As Object
Dim PicDesc() As String
Dim strFile As String
Dim fd As FileDialog
Set fd = Application.FileDialog(msoFileDialogFilePicker)
With fd
.Filters.Add "Text Files", "*.txt"
.AllowMultiSelect = False
.InitialFileName = ActivePresentation.Path
If .Show = -1 Then
strFile = .SelectedItems.Item(1)
End If
If strFile = "" Then Exit Sub
End With
Set fs = CreateObject("Scripting.FileSystemObject")
Set f = fs.OpenTextFile(strFile, 1, 0)
Do While Not f.AtEndOfStream
PicDesc = Split(f.readline, Chr(9))
Set oSld = ActivePresentation.Slides.Add(ActivePresentation.Slides.Count + 1, ppLayoutTitleOnly)
Set oPic = oSld.Shapes.AddPicture(FileName:=PicDesc(0), _
LinkToFile:=msoFalse, _
SaveWithDocument:=msoTrue, _
Left:=0, _
Top:=0)
If oSld.Shapes.HasTitle Then
oSld.Shapes.Title.TextFrame.TextRange.Text = PicDesc(1)
With oPic
.Height = 469.875
.Width = 626.325
.Left = ActivePresentation.PageSetup.SlideWidth / 2 - .Width / 2
.Top = oSld.Shapes.Title.Top + oSld.Shapes.Title.Height + 7
End With
End If
Set oPic = Nothing
Set oSld = Nothing
Loop
Set f = Nothing
Set fs = Nothing
End Sub
When you say you keep getting bugs, what do you mean?
Are you getting error messages? If so, what are the error numbers/descriptions? Where does the code break?
If not, and you're getting 'bugs', what should the final output look like and how does this differ from that?
I would say that one big unknown here is the text file input. According to your code, it seems as though it needs to have a series of filenames and corresponding picture descriptions on each line of the text file, separated by a tab. Critically, it must be a tab and not 2 spaces or 4 spaces or 10 spaces or a hyphen ... it must be a tab. Is that the structure of the text file you're using as input?
PowerPoint treats built-in layouts differently than custom ones. You can't call a custom layout by name. Instead, you have to loop through each custom layout to find the one that has the right name, then use it:
Sub AddSlideFromCustomLayout()
Dim oLayout As CustomLayout
Dim oSlide As Slide
For Each oLayout In ActivePresentation.SlideMaster.CustomLayouts
If oLayout.Name = "Custom Layout Name" Then
Set oSlide = ActivePresentation.Slides.AddSlide(ActivePresentation.Slides.Count + 1, oLayout)
End If
Next oLayout
End Sub
Here's your listing with the code replacing the Set oSld line:
Sub ImportStuffFromTextFile()
Dim oLayout As CustomLayout
Dim strTemp As String
Dim strPath As String
Dim strFileSpec As String
Dim oSld As Slide
Dim oPic As Shape
Dim fs As Object
Dim f As Object
Dim PicDesc() As String
Dim strFile As String
Dim fd As FileDialog
Set fd = Application.FileDialog(msoFileDialogFilePicker)
With fd
.Filters.Add "Text Files", "*.txt"
.AllowMultiSelect = False
.InitialFileName = ActivePresentation.Path
If .Show = -1 Then
strFile = .SelectedItems.Item(1)
End If
If strFile = "" Then Exit Sub
End With
Set fs = CreateObject("Scripting.FileSystemObject")
Set f = fs.OpenTextFile(strFile, 1, 0)
Do While Not f.AtEndOfStream
PicDesc = Split(f.readline, Chr(9))
For Each oLayout In ActivePresentation.SlideMaster.CustomLayouts
If oLayout.Name = "Custom Layout Name" Then
Set oSld = ActivePresentation.Slides.AddSlide(ActivePresentation.Slides.Count + 1, oLayout)
End If
Next oLayout
Set oPic = oSld.Shapes.AddPicture(FileName:=PicDesc(0), LinkToFile:=msoFalse, SaveWithDocument:=msoTrue, Left:=0, Top:=0)
If oSld.Shapes.HasTitle Then
oSld.Shapes.Title.TextFrame.TextRange.Text = PicDesc(1)
With oPic
.Height = 469.875
.Width = 626.325
.Left = ActivePresentation.PageSetup.SlideWidth / 2 - .Width / 2
.Top = oSld.Shapes.Title.Top + oSld.Shapes.Title.Height + 7
End With
End If
Set oPic = Nothing
Set oSld = Nothing
Loop
Set f = Nothing
Set fs = Nothing
End Sub

Powerpoint VBA Select Folder of images, place those images on slides

How can I make the second set of code reference the selection made in the first set, instead of the hard coded location it currently uses? these two sets do exactly what I like and ultimately I want to combine them, but just just cant figure out how to make the second set use the path from the first.. Ive searched for days, and tried everything I could think of. Its got to be 1 simple thing I've overlooked.
Sub SelectFolder()
Dim sFolder As String
' Open the select folder prompt
With Application.FileDialog(msoFileDialogFolderPicker)
If .Show = -1 Then ' if OK is pressed
sFolder = .SelectedItems(1)
End If
End With
If sFolder <> "" Then ' if a file was chosen
' *********************
' put your code in here
' *********************
End If
End Sub
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub EveryPresentationInFolder()'Performs some operation on every
'presentation file in a folder adapted from PPTools.com
Dim sFolder As String ' Full path to folder we'll examine
Dim sFileSpec As String ' Filespec, e.g. *.PNG
Dim sFileName As String ' Name of a file in the folder
Dim oPres As Presentation
Dim lngSld As Long
Dim rayNum() As String
Dim sngL As Single
Dim sngT As Single
Dim sngW As Single
Dim opic As Shape
sFolder = Environ("USERPROFILE") & "\Desktop\Images\" ' This is where I want the folder ive picked
sFileSpec = "*.PNG"
Set oPres = ActivePresentation
sngL = 0
sngT = 0.6 * 28.3465
sngW = oPres.PageSetup.SlideWidth
sFileName = Dir$(sFolder & sFileSpec)
While sFileName <> ""
Debug.Print sFileName
rayNum = Split(sFileName, ".")
lngSld = CLng(rayNum(0))
If lngSld <= oPres.Slides.Count Then
Set opic = oPres.Slides(lngSld).Shapes.AddPicture(FileName:=sFolder & sFileName, _
LinkToFile:=False, _
SaveWithDocument:=True, _
Left:=sngL, _
Top:=sngT, _
Width:=sngW)
opic.LockAspectRatio = True
opic.Width = sngW
opic.Left = 0
opic.Top = sngT
opic.ZOrder (msoSendToBack)
End If
sFileName = Dir()
Wend
End Sub
I took the advice and tried to make the new info work for me. I know its just an ordering of the elements, and I feel like im close, but I don't understand the the problem. why wont this work?
Function SelectFolder() As String
Dim sFolder As String
' Open the select folder prompt
With Application.FileDialog(msoFileDialogFolderPicker)
If .Show = -1 Then ' if OK is pressed
sFolder = .SelectedItems(1)
End If
End With
If sFolder <> "" Then ' if a file was chosen
SelectFolder = sFolder
Else
SelectFolder = ""
End If
Dim sFileSpec As String ' Filespec, e.g. *.PNG
Dim sFileName As String ' Name of a file in the folder
Dim oPres As Presentation
Dim lngSld As Long
Dim rayNum() As String
Dim sngL As Single
Dim sngT As Single
Dim sngW As Single
Dim opic As Shape
sFolder = SelectFolder ' This is where I want the folder ive picked
sFileSpec = "*.jpg"
Set oPres = ActivePresentation
sngL = 0
sngT = 0.6 * 28.3465
sngW = oPres.PageSetup.SlideWidth
sFileName = Dir$(sFolder & sFileSpec)
While sFileName <> ""
Debug.Print sFileName
rayNum = Split(sFileName, ".")
lngSld = CLng(rayNum(0))
If lngSld <= oPres.Slides.Count Then
Set opic = oPres.Slides(lngSld).Shapes.AddPicture(FileName:=sFolder & sFileName, _
LinkToFile:=False, _
SaveWithDocument:=True, _
Left:=sngL, _
Top:=sngT, _
Width:=sngW)
opic.LockAspectRatio = True
opic.Width = sngW
opic.Left = 0
opic.Top = sngT
opic.ZOrder (msoSendToBack)
End If
sFileName = Dir()
Wend
End Function
Re "How do I call the location instead of sFolder=Environ"
Change it to this:
sFolder = SelectFolder
Then change Sub SelectFolder to a Function instead:
Function SelectFolder() as String
Dim sFolder As String
' Open the select folder prompt
With Application.FileDialog(msoFileDialogFolderPicker)
If .Show = -1 Then ' if OK is pressed
sFolder = .SelectedItems(1)
End If
End With
If sFolder <> "" Then ' if a file was chosen
SelectFolder = sFolder
' *********************
' put your code in here
' *********************
Else
SelectFolder = ""
End If
End Function

Word VBA save files in new folder

I have VBA in Word that opens multiple files from a folder that I select, replaces the logo in the header with a new file that I direct it to, and then saves the files in a different folder.
I have the files saving in a different folder not because I want to, but because they are opening as read-only and I can't figure out how to make that not happen. I have tried everything I can find on here. I'm fine with them saving to a new folder. That's not the issue for me right now.
Right now, this code works, but I have to click "Save" for each document. I would like that to be automated. The code right here is the saveas
End With
With Dialogs(wdDialogFileSaveAs)
.Name = "\\i-worx-san-07.i-worx.ca\wardell$\Redirection\billy.bones\Desktop\Test 3\" & ActiveDocument.Name
.Show
End With
End With
objDocument.SaveAs
objDocument.Close (True)
The following is the complete VBA code. I'm an absolute novice, so go easy. I want to know how to go about making the saveas include the original filename, a new specified folder (can be specified in the code, doesn't have to be specified by the user) and do it without the user having to press "save" a brazillion times. I appreciate your help.
Sub Example1()
'Declaring the required variables
Dim intResult As Integer
Dim strPath As String
Dim arrFiles() As String
Dim i As Integer
'the dialog is displayed to the user
intResult = Application.FileDialog(msoFileDialogFolderPicker).Show
'checks if user has cancled the dialog
If intResult <> 0 Then
'dispaly message box
strPath = Application.FileDialog( _
msoFileDialogFolderPicker).SelectedItems(1)
'Get all the files paths and store it in an array
arrFiles() = GetAllFilePaths(strPath)
'Modifying all the files in the array path
For i = LBound(arrFiles) To UBound(arrFiles)
Call ModifyFile(arrFiles(i))
Next i
End If
End Sub
Private Sub ModifyFile(ByVal strPath As String)
Dim objDocument As Document
Set objDocument = Documents.Open(strPath)
With ActiveDocument.Sections(1)
With ActiveDocument.Sections(1)
.Headers(WdHeaderFooterIndex.wdHeaderFooterPrimary).Range.Delete
End With
Dim imagePath As String
'Please enter the relative path of the image here
imagePath = "C://FILEPATH\FILENAME.jpg"
Set oLogo = .Headers(wdHeaderFooterPrimary).Range.InlineShapes.AddPicture(FileName:=imagePath, LinkToFile:=False, SaveWithDocument:=True)
With oLogo.Range
.ParagraphFormat.Alignment = wdAlignParagraphRight
'Right alignment for logo image
.ParagraphFormat.RightIndent = InchesToPoints(-0.6)
End With
End With
With oLogo
.Height = 320
.Width = 277
With Selection.PageSetup
'Header from Top value
.HeaderDistance = InchesToPoints(0.5)
End With
With Dialogs(wdDialogFileSaveAs)
.Name = "\\i-worx-san-07.i-worx.ca\wardell$\Redirection\billy.bones\Desktop\Test 3\" & ActiveDocument.Name
.Show
End With
End With
objDocument.SaveAs
objDocument.Close (True)
End Sub
Private Function GetAllFilePaths(ByVal strPath As String) _
As String()
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim i As Integer
Dim arrOutput() As String
ReDim arrOutput(1 To 1)
'Create an instance of the FileSystemObject
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Get the folder object
Set objFolder = objFSO.GetFolder(strPath)
i = 1
'loops through each file in the directory and
'prints their names and path
For Each objFile In objFolder.Files
ReDim Preserve arrOutput(1 To i)
'print file path
arrOutput(i) = objFile.Path
i = i + 1
Next objFile
GetAllFilePaths = arrOutput
End Function
Remove this line which calls the FileSaveAs dialogue.
With Dialogs(wdDialogFileSaveAs)
.Name = "\\i-worx-san-07.i-worx.ca\wardell$\Redirection\billy.bones\Desktop\Test 3\" & ActiveDocument.Name
.Show
End With
Then modify this line:
objDocument.SaveAs
and include the filepath like this:
objDocument.SaveAs "\\i-worx-san-07.i-worx.ca\wardell$\Redirection\" _
& "billy.bones\Desktop\Test 3\" & ActiveDocument.Name
In newer version of Word, it was change to SaveAs2 but SaveAs still works.
That method takes the file path where you want the file saved as first argument.