Why has this audit logger VBA code stopped working? - excel

I use the following code that I copied from (https://datapluscode.com/general/add-an-audit-trail-to-an-excel-spreadsheet-using-vba) to record a logfile of changes in excel files that are used to collect data for clinical research.
This worked brilliantly until earlier this year when something (perhaps an update to Excel) has bricked it. It no longer records anything, although the code seems to run without obvious error.
There are two facets to the code.
Firstly, a class module called csLogger
Option Explicit
Option Compare Text
Private Type udtLogEntry
Date As String * 22
NewCellValue As String * 30
OldCellValue As String * 30
CellRef As String * 15
UserName As String * 10
SheetName As String * 20
NewFormula As String * 40
OldFormula As String * 40
ChangeType As String * 12
End Type
Private mudtEntry As udtLogEntry
Private Const CSTR_CELL_ADJUSTMENT_TYPE As String = "Cell"
Private Const CSTR_LOG_FILENAME_SUFFIX As String = "_log.txt"
Public Sub LogSheetChangeEvent(ByVal Sh As Object, ByVal Target As Range)
On Error GoTo ERR_HANDLER:
Dim strText As String
If Not ThisWorkbook.ReadOnly Then
If (Target.Rows.Count = 1) And (Target.Columns.Count = 1) Then
mudtEntry.SheetName = CStr(Sh.Name)
mudtEntry.CellRef = CStr(Target.Address)
mudtEntry.ChangeType = CSTR_CELL_ADJUSTMENT_TYPE
mudtEntry.Date = CStr(Now())
mudtEntry.NewCellValue = CStr(Target.Value)
mudtEntry.UserName = Environ("username")
mudtEntry.NewFormula = CStr(Target.Formula)
strText = BuildLogString(mudtEntry.Date, mudtEntry.NewCellValue, _
mudtEntry.OldCellValue, mudtEntry.CellRef, _
mudtEntry.UserName, mudtEntry.SheetName, mudtEntry.OldFormula, _
mudtEntry.NewFormula, mudtEntry.ChangeType)
Call fnAddToFile(strText)
End If
End If
EXIT_HERE:
Exit Sub
ERR_HANDLER:
GoTo EXIT_HERE
End Sub
Public Sub LogSheetSelectionChangeEvent(ByVal Sh As Object, ByVal Target As Range)
On Error Resume Next
If Not ThisWorkbook.ReadOnly Then
If (Target.Rows.Count = 1) And (Target.Columns.Count = 1) Then
mudtEntry.OldCellValue = CStr(Target.Value)
mudtEntry.OldFormula = CStr(Target.Formula)
End If
End If
End Sub
Public Sub LogEventAction(ByVal strEvent As String)
Dim udtEntry As udtLogEntry
udtEntry.Date = Now()
udtEntry.ChangeType = strEvent
udtEntry.UserName = Environ("username")
If Not fnAddToFile(udtEntry.Date & "," & udtEntry.UserName & "," & udtEntry.ChangeType) Then
Debug.Print "Failed to log event"
End If
End Sub
Private Function fnAddToFile(ByVal strText As String) As Boolean
On Error GoTo ERR_HANDLER:
Dim intHandle As Integer
Dim strFileName As String
fnAddToFile = False
If ThisWorkbook.ReadOnly Then
fnAddToFile = False
GoTo EXIT_HERE
End If
intHandle = FreeFile
strFileName = Mid(ThisWorkbook.Name, 1, InStr(1, ThisWorkbook.Name, ".") - 1)
strFileName = strFileName & CSTR_LOG_FILENAME_SUFFIX
strFileName = ThisWorkbook.Path & Chr(92) & strFileName
If Not IsLogFilePresent(strFileName) Then
Open strFileName For Append As #intHandle
Dim udtHeader As udtLogEntry
Dim strTitles As String
udtHeader.SheetName = "Sheet Name"
udtHeader.Date = "Date & Time"
udtHeader.CellRef = "Cell Ref"
udtHeader.SheetName = "Sheetname"
udtHeader.UserName = "UserName"
udtHeader.NewCellValue = "New Value"
udtHeader.OldCellValue = "Old Value"
udtHeader.NewFormula = "New Value Formula"
udtHeader.OldFormula = "Old Value Formula"
udtHeader.ChangeType = "Type"
strTitles = BuildLogString(udtHeader.Date, udtHeader.NewCellValue, _
udtHeader.OldCellValue, udtHeader.CellRef, _
udtHeader.UserName, udtHeader.SheetName, _
udtHeader.OldFormula, udtHeader.NewFormula, _
udtHeader.ChangeType)
Print #intHandle, strTitles
Print #intHandle, strText
Close #intHandle
Else
Open strFileName For Append As #intHandle
Print #intHandle, strText
Close #intHandle
End If
fnAddToFile = True
EXIT_HERE:
Exit Function
ERR_HANDLER:
fnAddToFile = False
GoTo EXIT_HERE
End Function
Private Function BuildLogString(ByVal strDate As String, ByVal strNew As String, ByVal strOld As String, _
ByVal strRef As String, ByVal strName As String, ByVal strSheet As String, _
ByVal strOldFormula As String, ByVal strNewFormula As String, ByVal strChangeType As String) As String
Dim strText As String
On Error Resume Next
strSheet = UCase(strSheet)
BuildLogString = _
strDate & "," & strName & "," & strChangeType & "," & strSheet & "," & strRef & ", " & strNew & "," & strOld & _
"," & strNewFormula & "," & strOldFormula
End Function
Private Function IsLogFilePresent(ByVal strFile As String) As Boolean
On Error GoTo ERR_HANDLER:
IsLogFilePresent = False
If Trim(Dir(strFile)) <> "" Then
IsLogFilePresent = True
Else
IsLogFilePresent = False
End If
EXIT_HERE:
Exit Function
ERR_HANDLER:
IsLogFilePresent = False
GoTo EXIT_HERE
End Function
Then, code in ThisWorkbook, as follows
Option Explicit
Private mObjLogger As csLogger
Private Sub Workbook_BeforeClose(Cancel As Boolean)
If Not mObjLogger Is Nothing Then
mObjLogger.LogEventAction ("CLOSE")
Set mObjLogger = Nothing
End If
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If Not mObjLogger Is Nothing Then
mObjLogger.LogEventAction ("SAVE")
End If
End Sub
Private Sub Workbook_Open()
Set mObjLogger = New csLogger
mObjLogger.LogEventAction ("OPEN")
End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Not mObjLogger Is Nothing Then
mObjLogger.LogSheetChangeEvent Sh, Target
End If
End Sub
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
If Not mObjLogger Is Nothing Then
mObjLogger.LogSheetSelectionChangeEvent Sh, Target
End If
End Sub
If anyone has any ideas as to why it is no longer working I would be really grateful! I cannot work it out. I tried to ask on the original page but my comments are rejected by the server. The author also no longer seems to be active. Thank you.

Related

Show product mage from on image click event in another form VBA

I want to display the image of a product when it is clicked on in another form because on the first form the image size is small so I want it to show on a bigger form when its clicked on
code that shows the product image when the product is clicked on
Private Sub ListBox1_Click()
Dim strFile As String
Me.cmb_Product.Value = Me.ListBox1.List(Me.ListBox1.ListIndex, 0)
iPath = ThisWorkbook.Path & "\Item Images\" & Me.cmb_Product.Value & ".JPG"
iPathNA = ThisWorkbook.Path & "\Item Images\NA.jpg"
strFile = iPath
If Len(Dir(strFile)) <> 0 Then
ItemImage.Picture = LoadPicture(strFile)
Else
ItemImage.Picture = LoadPicture(iPathNA)
End If
End Sub
code on image click event
Private Sub ItemImage_Click()
productImage.Show False
End Sub
code in 2nd form
Private Sub productImage_BeforeDragOver(ByVal Cancel As MSForms.ReturnBoolean, ByVal Data As MSForms.DataObject, ByVal X As Single, ByVal Y As Single, ByVal DragState As MSForms.fmDragState, ByVal Effect As MSForms.ReturnEffect, ByVal Shift As Integer)
productImage.Picture = LoadPicture(frm_Inventory_Management.iPathNA)
End Sub
If I correctly understood what you try doing, please try the next way:
Declare the used variable as Public, on top of the user form code module (in the declarations area):
Public strFile As String 'the exposed variable to be used
Use your adapted list box click event as (only without declaration of the above variable):
Private Sub ListBox1_Click()
Me.cmb_Product.Value = Me.ListBox1.List(Me.ListBox1.ListIndex, 0)
iPath = ThisWorkbook.Path & "\Item Images\" & Me.cmb_Product.Value & ".JPG"
iPathNA = ThisWorkbook.Path & "\Item Images\NA.jpg"
strFile = iPath
If Len(Dir(strFile)) <> 0 Then
ItemImage.Picture = LoadPicture(strFile)
Else
ItemImage.Picture = LoadPicture(iPathNA)
End If
End Sub
If ItemImage is an Image control, it does not expose a Click event, so try using its MouseUp event:
Private Sub ItemImage_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
productImage.Show False
End Sub
If ItemImage is a control exposing the click event, use it as it is.
Note: The form frm_Inventory_Management must have the ShowModal property = False.
You should use the Initialize event of the shown userform:
Private Sub UserForm_Initialize()
Me.Picture = LoadPicture(frm_Inventory_Management.strFile)
End Sub
In this way it will load the existing picture on the specific control
Please, send some feedback after testing it.
This code worked for me later on
Private Sub UserForm_Initialize()
Dim strFile As String
iPath = ThisWorkbook.Path & "\Item Images\" & frm_Inventory_Management.cmb_Product.Value & ".JPG"
iPathNA = ThisWorkbook.Path & "\Item Images\NA.jpg"
strFile = iPath
If Len(Dir(strFile)) <> 0 Then
productImage.Picture = LoadPicture(strFile)
Else
productImage.Picture = LoadPicture(iPathNA)
End If
End Sub

Excel visual basic cuestion on if statements, my second if statement doesnt work

I'm trying to make excel send automated emails when different cells get to different values, my first if statement works, which is when cell D6 goes over 400, now my next if statement doesn't work, which is when cell D7 goes over 400. I have to at least add 2 more if statements like this for cell D8 and D9. Here is the code:
Dim R As Range
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.Count > 1 Then Exit Sub
Set R = Intersect(Range("D6"), Target)
If R Is Nothing Then Exit Sub
If IsNumeric(Target.Value) And Target.Value > 400 Then
Call send_mail_outlook
End If
'second part to check for
If Target.Cells.Count > 1 Then Exit Sub
Set R = Intersect(Range("D7"), Target)
If R Is Nothing Then Exit Sub
If IsNumeric(Target.Value) And Target.Value > 400 Then
Call send_mail_outlook1
End If
End Sub
Sub send_mail_outlook()
Dim x As Object
Dim y As Object
Dim z As String
Set x = CreateObject("Outlook.Application")
Set y = x.CreateItem(0)
z = "Hola!" & vbNewLine & vbNewLine & _
"xxx" & vbNewLine & _
"xx"
On Error Resume Next
With y
.To = "xxx#ss"
.cc = ""
.BCC = ""
.Subject = "xxx"
.Body = z
.Display
End With
On Error GoTo 0
Set y = Nothing
Set x = Nothing
End Sub
Sub send_mail_outlook1()
Dim x As Object
Dim y As Object
Dim z As String
Set x = CreateObject("Outlook.Application")
Set y = x.CreateItem(0)
z = "ss!" & vbNewLine & vbNewLine & _
"sss" & vbNewLine & _
"sss"
On Error Resume Next
With y
.To = "xx#ss"
.cc = ""
.BCC = ""
.Subject = "xxx"
.Body = z
.Display
End With
On Error GoTo 0
Set y = Nothing
Set x = Nothing
End Sub
Not totally clear on your use case, but something like this should work:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim v
If Target.Cells.Count > 1 Then Exit Sub 'single-cell changes only...
v = Target.Value
If Len(v) = 0 Then Exit Sub 'no value entered
If IsNumeric(v) Then
If v > 400 Then
Select Case Target.Address(False, False) 'which cell was changed?
Case "D6": send_mail_outlook 'use of Call is deprecated
Case "D7": send_mail_outlook1
End Select
End If
End If
End Sub
A Worksheet Change: Send Mail
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.CountLarge > 1 Then Exit Sub
ValidateAndSendMail Target
End Sub
Sub ValidateAndSendMail(ByVal Target As Range)
' Make sure that all of the arrays contain the same number of elements!
' 'VBA.' in front of 'Array' is used to ensure a zero-based array.
Dim tAddresses() As Variant: tAddresses = VBA.Array("D6", "D7", "D8", "D9")
Dim tNumbers() As Variant: tNumbers = VBA.Array(400, 400, 400, 400)
Dim tTo() As Variant: tTo = VBA.Array("xxx#ss", "xx#ss", "aa#ss", "bb#ss")
Dim tCC() As Variant: tCC = VBA.Array("", "", "", "")
Dim tBCC() As Variant: tBCC = VBA.Array("", "", "", "")
Dim tSubject() As Variant: tSubject = VBA.Array("xxx", "xxx", "xxx", "xxx")
Dim tBody() As String: ReDim tBody(0 To 3)
tBody(0) = "Hola!" & vbLf & vbLf & "xxx" & vbLf & "xx"
tBody(1) = "ss!" & vbLf & vbLf & "sss" & vbLf & "sss"
tBody(2) = "aa!" & vbLf & vbLf & "aaa" & vbLf & "aaa"
tBody(3) = "bb!" & vbLf & vbLf & "bbb" & vbLf & "bbb"
Dim tAddress As String: tAddress = Target.Address(0, 0)
Dim tIndex As Variant: tIndex = Application.Match(tAddress, tAddresses, 0)
If IsError(tIndex) Then Exit Sub ' target address not found in array
Dim tValue As Variant: tValue = Target.Value
If Not VarType(tValue) = vbDouble Then Exit Sub ' not a number
Dim tNumber As Double: tNumber = CDbl(tValue)
Dim i As Long: i = CLng(tIndex) - 1
If tNumber > tNumbers(i) Then
SendMail tTo(i), tCC(i), tBCC(i), tSubject(i), tBody(i)
End If
End Sub
Sub SendMail( _
ByVal smTo As String, _
ByVal smCC As String, _
ByVal smBCC As String, _
ByVal smSubject As String, _
ByVal smBody As String)
With CreateObject("Outlook.Application")
With .CreateItem(0)
On Error Resume Next
.To = smTo
.CC = smCC
.BCC = smBCC
.Subject = smSubject
.Body = smBody
.Display
On Error GoTo 0
End With
End With
End Sub

Looping for dynamic pictures

So I have created a dynamic selection list for excel using vba. see below
Below is the code
Private Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
If Target.Address = "$A$2" Then
Call PanggilPhoto
End If
End Sub
Sub PanggilPhoto()
Application.ScreenUpdating = False
Dim myObj
Dim Foto
Set myObj = ActiveSheet.DrawingObjects
For Each Foto In myObj
If Left(Foto.Name, 7) = "Picture" Then
Foto.Select
Foto.Delete
End If
Next
Dim CommodityName1 As String, CommodityName2 As String, T As String
myDir = ThisWorkbook.Path & "\"
CommodityName1 = Range("A2")
T = ".png"
Range("C15").Value = CommodityName
On Error GoTo errormessage:
ActiveSheet.Shapes.AddPicture Filename:=myDir & CommodityName1 & T, _
linktofile:=msoFalse, savewithdocument:=msoTrue, Left:=190, Top:=10, Width:=140,
Height:=90
errormessage:If Err.Number = 1004 Then
Exit Sub
MsgBox "File does not exist." & vbCrLf & "Check the name of the Commodity!"
Range("A2").Value = ""
Range("C10").Value = ""
End If
Application.ScreenUpdating = True
End Sub
foto is a predefined data list in the sheet.
So the question is instead of doing it for one cell how can I create a loop of some sort to do it for multiple cells? I need it to import mulitple images on one macro run
found a solution
Private Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
If Target.Address = "$A$2" Then
Call schedules
End If
End Sub
Sub schedules()
Worksheets("Picture").Activate
Application.ScreenUpdating = False
Dim myObj
Dim Foto
Set myObj = ActiveSheet.DrawingObjects
For Each Foto In myObj
If Left(Foto.Name, 7) = "Picture" Then
Foto.Select
Foto.Delete
End If
Next
Dim CommodityName1 As String, CommodityName2 As String, T1 As String, T2 As String
Dim i As Integer, j As Integer, k As Integer
j = 0
For i = 2 To 100
myDir = "C:\Users\User\Desktop\ESTIMATING SHEETS\test\rebar shapes" & "\"
CommodityName1 = Range("A" & i)
T1 = ".png"
On Error GoTo errormessage:
ActiveSheet.Shapes.AddPicture Filename:=myDir & CommodityName1 & T1, _
linktofile:=msoFalse, savewithdocument:=msoTrue, Left:=230, Top:=j, Width:=140, Height:=80
errormessage:
If Err.Number = 1004 Then
Exit Sub
MsgBox "File does not exist." & vbCrLf & "Check the name of the rebar!"
Range("A" & i).Value = ""
Range("C10").Value = ""
End If
Application.ScreenUpdating = True
i = i + 11
j = j + 190
Next i
End Sub

Can we attach multiple images to a useform in VBA, save in a folder with a specific naming convention and retrieve later using that name?

I have a VBA project where I need to create a userform on which there should be an attachment button to select multiple images and save them in a folder with a specific name. Later, if a person looks up that name from the search box, it should call all the information saved along with the images. The names should be as follows Sh-0001-01 (where 0001 represents invoice number and 01 denotes attachment number).
I have got a file from another forum that can load images into the image box and scroll across them but there is no mechanism to add new images except copying new images to the back-end folder. And also, no functionality to save attachments with a specific name and look them up using that name.
The outcome is attached as an image. The example code file can be accessed via this link:
https://drive.google.com/file/d/1HXLjDIpjNmgxLxegYiexxEykh4f_54sY/view?usp=sharing
As it was mandatory by Stackoverflow to include a sample code, here is part of the code that is in the file in the drive:
Public Const fPath As String = "C:\Test\"
Sub LaunchForm()
UserForm1.Show
End Sub
Function PhotoNum(numx As Integer) As String
Dim PhotoNames As String, iFile As String
Dim i As Integer
Dim ArrayPhoto() As Variant
iFile = "*.*"
PhotoNames = Dir(fPath & iFile)
i = 0
Do Until PhotoNames = ""
i = i + 1
ReDim Preserve ArrayPhoto(1 To i)
ArrayPhoto(i) = PhotoNames
PhotoNames = Dir
Loop
PhotoNum = ArrayPhoto(numx)
End Function
Function MaxPhoto() As Integer
Dim PhotoNames As String, iFile As String
Dim i As Integer
Dim ArrayPhoto() As Variant
iFile = "*.*"
PhotoNames = Dir(fPath & iFile)
i = 0
Do Until PhotoNames = ""
i = i + 1
ReDim Preserve ArrayPhoto(1 To i)
ArrayPhoto(i) = PhotoNames
PhotoNames = Dir
Loop
MaxPhoto = UBound(ArrayPhoto)
End Function
Any help is appreciated.
Please, try the next way. A text box named "tbOrder" must exist. In it the order/invoice number must be entered (manually or by code). The rest of controls are the one used in your sent testing workbook. Please, copy the next code in the form code module. Only a sub showing the form should exist in a standard module. A new button (btAttach) to add attachment has been added and a check box (chkManyAtt) where to specify the multiple selection option:
Option Explicit
Private Const fPath As String = "C:\test\"
Private photoNo As Long, arrPhoto() As Variant, boolNoEvents As Boolean, prevVal As Long, boolFound As Boolean
Private boolManyAttch As Boolean
Private Sub btAttach_Click()
If Len(tbOrder.Text) <> 7 Then MsgBox "An invoice number is mandatory in its specific text box (7 digits long)": Exit Sub
Dim noPhotos As Long, runFunc As String
runFunc = bringPicture(Left(tbOrder.Text, 7), True)
If Not boolFound Then noPhotos = -1
Dim sourceFile As String, destFile As String, attName As String, strExt As String, i As Long
With Application.FileDialog(msoFileDialogFilePicker)
.Title = "Please, select the picture to be added as attachment for invoice " & Me.tbOrder.Text & " (" & photoNo & ")"
.AllowMultiSelect = IIf(boolManyAttch = True, True, False)
.Filters.Add "Picture Files", "*.jpg", 1
If .Show = -1 Then
For i = 1 To .SelectedItems.Count
sourceFile = .SelectedItems(i): 'Stop
attName = Me.tbOrder.Text & "-" & Format(IIf(noPhotos = -1, 1, photoNo + 1), "00")
strExt = "." & Split(sourceFile, ".")(UBound(Split(sourceFile, ".")))
destFile = fPath & attName & strExt
FileCopy sourceFile, destFile
ReDim Preserve arrPhoto(IIf(noPhotos = -1, 0, UBound(arrPhoto) + 1)): noPhotos = 0
arrPhoto(UBound(arrPhoto)) = attName & strExt
photoNo = photoNo + 1
Next i
Else
Exit Sub
End If
End With
Me.TextBox2.Text = photoNo: Me.TextBox2.Enabled = False
Me.TextBox1.Text = photoNo
End Sub
Private Sub chkManyAtt_Click()
If Me.chkManyAtt.Value Then
boolManyAttch = True
Else
boolManyAttch = False
End If
End Sub
Private Sub CommandButton1_Click() 'Prev button
Dim currPic As Long
currPic = Me.TextBox1.Value
If currPic > 1 Then
Me.Image1.Picture = LoadPicture(fPath & arrPhoto(currPic - 2))
boolNoEvents = True 'stop the events when TextBox1 is changed
Me.TextBox1.Text = currPic - 1
prevVal = Me.TextBox1.Value
boolNoEvents = False 'restart events
End If
End Sub
Private Sub CommandButton2_Click() 'Next button
Dim currPic As Long
currPic = Me.TextBox1.Value
If currPic < photoNo Then
Me.Image1.Picture = LoadPicture(fPath & arrPhoto(currPic))
boolNoEvents = True
Me.TextBox1.Text = currPic + 1
prevVal = Me.TextBox1.Value
boolNoEvents = False
Else
MsgBox "Please, select a valid image number..."
End If
End Sub
Private Sub tbOrder_Change() 'the textbox where to input the order/invoice nubmer
Dim firstPict As String
If Len(tbOrder.Text) >= 7 Then
photoNo = 0: Erase arrPhoto 'clear the variable keeping the number of found photos and the array keeping them
firstPict = bringPicture(Left(tbOrder.Text, 7)) 'to make it working even if you paste "Sh-0002-20"
If firstPict <> "" Then 'determining the first picture to be placed
With Me.Image1
.Picture = LoadPicture(fPath & firstPict)
.PictureSizeMode = fmPictureSizeModeZoom
End With
boolNoEvents = True 'avoiding the event to be triggeret twice
Me.TextBox1.Text = 1
With Me.TextBox2
.Enabled = True
.Text = photoNo
.Enabled = False
End With
boolNoEvents = False
Else
Me.Image1.Picture = LoadPicture(vbNullString) 'clear the picture if no order/invoice have been written in the text box
Me.TextBox2.Text = "": Me.TextBox1.Text = ""
End If
End If
End Sub
Function bringPicture(strName As String, Optional boolAttach As Boolean = False) As String
Dim PhotoNames As String, arrPh, noPict As Long, firstPict As String, ph As Long
PhotoNames = Dir(fPath & strName & "*.*") 'find the first photo with the necessary pattern name
If boolAttach Then
ReDim arrPhoto(0): photoNo = 0
Else
ReDim arrPhoto(photoNo) 'firstly ReDim the array
End If
boolFound = False
Do While PhotoNames <> ""
boolFound = True
arrPhoto(photoNo) = PhotoNames: photoNo = photoNo + 1
ReDim Preserve arrPhoto(photoNo)
PhotoNames = Dir()
Loop
If photoNo > 0 Then
ReDim Preserve arrPhoto(photoNo - 1) 'eliminate the last empty array element
bringPicture = arrPhoto(0) 'return the first photo in the array
End If
End Function
Private Sub TextBox1_Change() 'manually change the picture number
If Not boolNoEvents Then 'to not be treggered when changed by code
If IsNumeric(Me.TextBox1.Value) Then 'to allow only numbers
If Len(Me.TextBox1.Value) >= Len(CStr(photoNo)) Then 'to allow numbers less or equal with the maximum available
If CLng(TextBox1.Text) > photoNo Then
MsgBox "Select valid image number"
boolNoEvents = True
Me.TextBox1.Text = prevVal
boolNoEvents = False
Else
Me.Image1.Picture = LoadPicture(fPath & arrPhoto(Me.TextBox1.Value - 1))
Me.Image1.PictureSizeMode = fmPictureSizeModeZoom
End If
prevVal = Me.TextBox1.Value
End If
Else
Me.TextBox1.Text = ""
End If
End If
End Sub
If something not clear enough, please do not hesitate to ask for clarifications.

How to get Excel VBA to Run a PPT Macro WITH Parameters?

I am trying to run a PowerPoint Macro through Excel VBA, I used to be able to run a macro on a powerpoint file with ease but I am having trouble passing a parameter in excel.
Sub Test()
Dim arr(1 To 1), macname As String, objPP As Object, PPTFilePath As String, ObjPPFile As Object,
PPtFileName As String
PPTFileName ="Report.pptm"
PPTFilePath ThisWorkbook.Path & PPTFileName
Set objPP = CreateObject("PowerPoint.Application")
objPP.Visible = True
Set objPPFile = objPP.Presentations.Open(PPTFilePath)
Application.EnableEvents = False
arr(1) = ThisWorkbook.Path
macname = "'" & PPTFileName & "'!Module3.UpdateSpecificLinks"
objPP.Run macname, arr
objPPFile.Save
waiting (3)
Application.EnableEvents = True
End Sub
I get an error on objPP.Run macname, arr , it is: Run-time error '-2147188160 (80048240)': Application.Run :Invalid request. Sub or Function not defined.
How do I properly Pass a parameter to the powerpoint macro: Sub UpdateSpecificLinks(LNK as String)
If your SubUpdateSpecificLinks is e.g. in a private module, the call to it will fail; it must be public.
I think this is the problem, though:
macname = "'" & PPTFileName & "'!Module3.UpdateSpecificLinks"
Try this instead:
macname = PPTFileName & "!Module3.UpdateSpecificLinks"
A couple of examples, calling from a PPTM file to another (closed) PPTM file:
Here are the calling macros:
Sub TestWithString()
Dim sFileName As String
Dim oPres As Presentation
sFileName = "C:\temp\runme.pptm"
Set oPres = Presentations.Open(sFileName, , , False)
Application.Run "C:\temp\RunMe.pptm!RunMe", "This is the passed parameter"
oPres.Close
End Sub
Sub TestWithArray()
Dim sFileName As String
Dim oPres As Presentation
Dim aStrings(1 To 3) As String
sFileName = "C:\temp\runme.pptm"
Set oPres = Presentations.Open(sFileName, , , False)
aStrings(1) = "String 1"
aStrings(2) = "String 2"
aStrings(3) = "String 3"
Application.Run "C:\temp\RunMe.pptm!HowAboutAnArray", aStrings
oPres.Close
End Sub
And here are the macros they call:
Sub RunMe(sMsg As String)
MsgBox "You said " & sMsg
End Sub
Sub HowAboutAnArray(vParm As Variant)
Dim x As Long
For x = 1 To ubound(vParm)
MsgBox vParm(x)
Next
End Sub

Resources