Open password protected workbook via WorkbookOpen event - excel

I have many workbooks that prompt for a password to open so I want to skip the step by using VBA to enter it for me. Is this possible? I am guessing no because the WorkbookOpen event doesn't fire until the book is open yes?
I have a class module in my personal.xlsb with the following code:
Private WithEvents appEvent As Application
Private Sub Class_Initialize()
Set appEvent = Application
End Sub
Private Sub AppEvent_WorkbookOpen(ByVal wb As Excel.Workbook)
If wb.name = "PERSONAL.XLSB" Then Exit Sub
Dim prefix As String
Dim bookName As String
Dim path As String
Dim password As String
Dim dd As String
Dim book As Workbook
prefix = Left(wb.name, 3)
If prefix = "DD0" Then
dd = Mid(wb.name, 4, 5)
path = wb.path & "\"
bookName = wb.name
skipPass path, bookName, dd
End If
End Sub
Then I have a module in my personal.xlsb with the following:
Sub skipPass(p As String, n As String, center As String)
Dim book As Workbook
Set book = Workbooks.Open(filename:=p & n, UpdateLinks:=0, password:=pass(p, center))
End Sub
Function pass(path As String, ddN As String)
Select Case path
...
end function
The first time I open the workbook, it prompts me for the password. Then the code runs fine except it just loops forever. I think I can solve the loop problem by setting a global flag but how do I fix the first problem?

This approach won't work since, as you've guessed, the AppEvent_WorkbookOpen event won't fire until you've supplied the password manually.
You have to handle the file opening yourself from the very beginning, i.e. by programming a sub that uses Application.GetOpenFileName to obtain one or more file names to open, and then supply passwords according to your logic. Your sub could be invoked by a key combination; search for Application.OnKey examples.
Note that string comparisons in VBA are case sensitive; use the StrComp function whenever you need to make case-insensitive comparisons.

Created a class named coa with the following:
Private Type ddData
path As String
passw As String
End Type
Private this As ddData
Public Property Get path() As String
path = this.path
End Property
Public Property Let path(ByVal value As String)
this.path = value
End Property
Public Property Get passw() As String
passw = this.passw
End Property
Public Property Let passw(ByVal value As String)
this.passw = value
End Property
Then the following in a module:
Private Sub noPass()
Dim ddN As String
Dim wb As Workbook
Dim dd As coa
ddN = InputBox("File?")
If ddN = "" Then Exit Sub
dd = grabddData(ddN)
Set wb = Workbooks.Open(filename:=dd.path & ddN & ".xlsm", UpdateLinks:=0, password:=dd.passw)
End Sub
Private Function grabddData(ByVal ddNumber) As coa 'returns our class
Dim result As New coa 'create an object of our class
Select Case ddNumber
...
Set grabddData = result 'return our class object
End Function
Not ideal but oh well.

Related

Fill a FileDialog from another macro

Edit : Sorry i forgot to mention that is VBA for Excel
First time i post on this sub reddit. I would like to something very simple, yet I have no heckin idea how to do it.
Let me give you a bit of context : In my company we have a standard model tool, which uses a standard excel file as input.
When you want to update your inputs from an old template, you download a standard file from a platform, and use a sub that doesn't take any arguments (called "upgrade engine"). Wen you call Upgrade engine, there is a file dialog tab that opens, and helps you select the source file you want to upgrade.
I am in a testing team for the standard model and i have to create a lot of templatse for each new release of the model for non regression testing purpose. So i would like to automatize the process. I cannot , and this is the important detail here, change the code of the standard template.
So i created a kind of masterfile with all my non regression test use cases, their address etc to update them one by one.
Here is my current code:
Public gParamTab As Variant
Public gHypTab As Variant
Public gSourcefolder As String
Public gBlankFolder As String
Public gTgtfolder As String
Public Const gParamTabColUseCase As Byte = 1
Public Const gParamTabColTTtgt As Byte = 2
Public Const gParamTabColTTSource As Byte = 3
Public Const gParamTabColFlagRetrieve As Byte = 4
Public Const gParamTabColTTCase As Byte = 5
Public Const gParamTabColFlagUpgrade As Byte = 6
Public Const gBlankTTName As String = "Table_Template_MVP_case"
Public Const gExtension As String = ".xlsb"
Sub init()
gParamTab = Sheets("Parameters").Range("gParamTab")
gHypTab = Sheets("NDD HYP").Range("gHypTab")
gSourcefolder = Sheets("Parameters").Range("gSourcefolder")
gTgtfolder = Sheets("Parameters").Range("gTgtfolder")
gBlankFolder = Sheets("Parameters").Range("gBlankFolder")
End Sub
Sub updateTT()
Call init
Dim lFullname_blank As String, lFullname_source As String, lFullname_tgt As String
Dim lGlobalrange As Variant
Dim lGlobaltable() As Variant
Dim lBlankTT As Workbook
Dim lLastRow As Long
Dim lSearchedVariable As Variant
Dim lBlankTTupgradeengine As String
lcol = 2
For lUsecase = 2 To UBound(gParamTab, 1)
If gParamTab(lUsecase, gParamTabColFlagUpgrade) = 1 Then
lFullname_blank = gBlankFolder & "\" & gBlankTTName & gParamTab(lUsecase, gParamTabColTTCase) & gExtension
lFullname_source = gSourcefolder & "\" & gParamTab(lUsecase, gParamTabColTTSource) & gExtension
lFullname_tgt = gTgtfolder & "\" & gParamTab(lUsecase, gParamTabColTTtgt) & gExtension
Set lBlankTT = Workbooks.Open(lFullname_blank)
lBlankTTupgradeengine = gBlankTTName & gParamTab(lUsecase, gParamTabColTTCase) & gExtension & "!UpgradeEngine.UpgradeEngine"
Application.Run lBlankTTupgradeengine
End If
Next
End Sub
So i come the main issue, how can I, from another macro, after the statement "Application.Run lBlankTTupgradeengine" , the upgrade engine macro starts, and calls the following function embedded in the "BlankTT" :
Sub UpgradeEngine()
Set wkb_target = ThisWorkbook
Set wkb_source = macros_Fn.Open_wkb()
[...]
Function Open_wkb() As Workbook
Dim fileName As Variant
With Application.FileDialog(msoFileDialogFilePicker)
' Makes sure the user can select only one file
.AllowMultiSelect = False
' Filter to just keep the relevants types of files
.filters.Add "Excel Files", "*.xlsm; *.xlsb", 1
.Show
' Extact path
If .SelectedItems.Count > 0 Then
fileName = .SelectedItems.Item(1)
Else
End
End If
End With
If (fileName <> False) Then
Set Open_wkb = Workbooks.Open(fileName:=fileName, IgnoreReadOnlyRecommended:=False, Editable:=False, ReadOnly:=True, UpdateLinks:=False)
Else
MsgBox "This file is already open. Please close it before launching the function."
End
End If
End Function
This function opens as I said before, a dialog box with a brows button to select the excel spreadsheet to use as ssource.
My question is, how can i fill automatically this Filedialog from my code, without changing the code of the standard excel file?
Thanks a lot for your help!
I tried to search everywhere but i did not find anything about this situation.
I'm trying to move a copy of the upgrade engine, but with an argument in the sub instead of the filedialog but the macro is too complex ..
Your best bet would be to add an optional parameter to UpgradeEngine - something like:
Sub UpgradeEngine(Optional wbPath as String = "")
'...
Set wkb_target = ThisWorkbook
If Len(wbPath) > 0 Then
Set wkb_source = Workbooks.Open(wbPath) 'open using provided file path
Else
Set wkb_source = macros_Fn.Open_wkb() 'open user-selected file
End If
'...
'...
Then you can call it and pass in the path you want.
FYI the code in Open_wkb seems off (at least, the "already open" message seems wrong). fileName <> False only checks if the user made a selection: it doesn't indicate anything about whether a selected file is already open or not.

Excel Drag/Drop to Get Filename and Path

I have a user form "UserForm1" and am using the following code to obtain the filename and path of a file that the user has dragged and dropped into the TreeView located on the userform.
Public Sub TreeView1_OLEDragDrop(Data As MSComctlLib.DataObject, Effect As Long, Button As Integer, Shift As Integer, x As Single, y As Single)
StrPath = Data.Files(1)
Debug.Print StrPath
Call PrintPath
End Sub
Then in the UserForm_Initialize I have
TreeView1.OLEDropMode = ccOLEDropManual
I know this code is getting the path and name because I'm able to debug.print it. However, my issue is I can't get this filename and path to be utilized in a module. For instance I have tried to do the following for the simplest of uses (to print the filename and path to cell A1):
Public Sub PrintPath()
UserForm1.TreeView1.StrPath = Range("A1").Value
'StrPath.Value = Range("A1").Value
'UserForm1.StrPath.Value = Range("A1").Value
'Range("A1").Value = UserForm1.Data.Files(1)
End Sub
All of the commented lines are other versions I have attempted with no avail.
I typically get Object does not exist. Sometimes 424 errors.
Can anyone point me in the right direction?
Please and thank you!
Chris
The typical way to do this woould be to pass the path as an argument to PrintPath
Public Sub TreeView1_OLEDragDrop(Data As MSComctlLib.DataObject, Effect As Long, _
Button As Integer, Shift As Integer, x As Single, y As Single)
Dim strPath
strPath = Data.Files(1)
Debug.Print strPath
PrintPath strPath '<< pass in the path
End Sub
Public Sub PrintPath(sPath)
ActiveSheet.Range("A1").Value = sPath
End Sub
I have just now figured out the answer. In the UserForm1 Code I did
Option Explicit
Public StrPath As Variant
Then in the module I was able to use it with
UserForm1.StrPath
i.e.
Range("A1").Value = UserForm1.StrPath

VBA: Excel stops working after extracting data from other workbooks

I'm trying to extract data from other 4 workbooks (some of them may have thousands of rows)
The Excel stops working, and restarts, after the extraction is completed.
I have the data extracted in the sheets so I assume that the excel is chrashing after the last workbook data is extracted.
I also tested with only one workbook and it crashes after closing.
I have read that we could use "DoEvents" and "Application.Wait" after copy/paste or close workbook, to let Excel finish some background work. I've tried that but with no success.
Any ideas why the Excel stops running / restarts?
Here is my code:
Public sysExtractParamsDictionary As Scripting.dictionary
'Sub rotine triggered when pressing button
Sub Extract()
Set sysExtractParamsDictionary = mUtils.FillDictionary("sysParams", "tExtractParams") 'Sub rotine belonging to mUtils module to fill dictionary with values from my sysParams sheet. Contains the sheets name.
mClean.Clean 'Sub rotine belonging to mClean module to clear sheets
ExtractData [sysInputDirectory], "Input Sheet" 'Cell Name sysInputDirectory
ExtractData [sysR2Directory], "R1 Sheet"
ExtractData [sysR2Directory], "R2 Sheet"
ExtractData [sysR3Directory], "R3 Sheet"
End Sub
Sub ExtractData(sFilePath As String, sDictionaryKey As String)
Dim oWorkbook As cWorkBook 'Class Module
Set oWorkbook = New cWorkBook
mUtils.SetStatusBarMessage True, "Extracting " & sDictionaryKey & " ..." 'Sub rotine belonging to my mUtils module to set on or off status bar message
oWorkbook.WorkBookDirectory = sFilePath
oWorkbook.OpenWorkBook oWorkbook.WorkBookDirectory
oWorkbook.CopiesSourceSheetValuesToDestinationSheet sysExtractParamsDictionary(sDictionaryKey)
oWorkbook.CloseWorkBook (False)
DoEvents
DoEvents
Application.Wait (Now + TimeValue("0:00:05"))
DoEvents
Set oWorkbook = Nothing
End Sub
'#### Class Module
Private wbWorkBook As Workbook
Private sWorkBookDirectory As String
Private sWorkBookName As String
Private wsWorksheet As Worksheet
Public Property Set Workbook(wbNew As Workbook)
Set wbWorkBook = wbNew
End Property
Public Property Get Workbook() As Workbook
Set Workbook = wbWorkBook
End Property
Public Property Let WorkBookDirectory(sFilePath As String)
sWorkBookDirectory = sFilePath
End Property
Public Property Get WorkBookDirectory() As String
WorkBookDirectory = sWorkBookDirectory
End Property
Public Property Let WorkBookName(sFileName As String)
sWorkBookName = sFileName
End Property
Public Property Get WorkBookName() As String
WorkBookName = sWorkBookName
End Property
Public Property Set Worksheet(wsNew As Worksheet)
Set wsWorksheet = wsNew
End Property
Public Property Get Worksheet() As Worksheet
Worksheet = wsWorksheet
End Property
Public Property Let WorkBookDirectory(sFilePath As String)
sWorkBookDirectory = sFilePath
End Property
Public Property Get WorkBookDirectory() As String
WorkBookDirectory = sWorkBookDirectory
End Property
'Class Module Function to Open WorkBook
Public Sub OpenWorkBook(sFilePath As String)
Dim oFSO As New FileSystemObject
Dim sFileName As String
Dim sLog As String
sFileName = oFSO.GetFileName(sFilePath) 'Get the File Name from Path
If sFileName = "" Then
sLog = "Error. Not possible to retrieve File Name from Directory."
Else
Me.WorkBookName = sFileName
Set Me.Workbook = Workbooks.Open(sFilePath)
If wbWorkBook Is Nothing Then
sLog = "Error opening file: " & Me.WorkBookName
Else
sLog = "File successfully openned!"
End If
End If
Set oFSO = Nothing
End Sub
'Class Module Function to Copy Values from source to destination
Public Sub CopiesSourceSheetValuesToDestinationSheet(wsDestinationName As Variant)
Dim wsDestination As Worksheet
Dim rStartRange As range
Dim rFullRangeToPaste As range
Set wsDestination = ThisWorkbook.Sheets(CStr(wsDestinationName)) ' Destination Sheet
Set Me.Worksheet = Me.Workbook.Sheets(1) 'Source Sheet
Set rStartRange = wsWorksheet.range("A1")
Set rFullRangeToPaste = wsWorksheet.range(rStartRange, mUtils.FindLast(3)) 'FindLast is a function belonging to mUtils module to find the last cell in worksheet
rFullRangeToPaste.Copy wsDestination.Cells(wsDestination.Rows.Count, "A").End(xlUp)
End Sub
'Class Module Function to Close Workbook
Public Sub CloseWorkBook(bSaveChanges As Boolean)
wbWorkBook.Saved = True
wbWorkBook.Close SaveChanges:=False
End Sub
'#### End Class Module
I've also tried to do it without Class Module (just in case something was wrong with objects), but i still have the same issue.
Sub Extract()
ExtractCopyClose "C:\MyFiles\InputData.csv", "Input"
End Sub
Sub ExtractCopyClose(sFilePath As String, wsDestinationName As String)
Dim wb As New Workbook
Dim wsDestination As Worksheet
Dim wsSource As Worksheet
Dim oFSO As New FileSystemObject
Dim sLog As String
Dim rStartRange As range
Dim rFullRangeToPaste As range
sFileName = oFSO.GetFileName(sFilePath) 'Get the File Name from Path
If sFileName = "" Then
sLog = "Error. Not possible to retrieve File Name from Directory."
Else
Set wb = Workbooks.Open(sFilePath)
If wb Is Nothing Then
sLog = "Error opening file: " & sWorkBookName
Else
sLog = "File successfully openned!"
End If
End If
Set oFSO = Nothing
Set wsDestination = ThisWorkbook.Sheets(wsDestinationName) ' Destination Sheet
Set wsSource = wb.Sheets(1) 'Source Sheet
Set rStartRange = wsSource.range("A1")
Set rFullRangeToPaste = wsSource.range(rStartRange, mUtils.FindLast(3))
rFullRangeToPaste.Copy wsDestination.Cells(wsDestination.Rows.Count, "A").End(xlUp)
wb.Saved = True
wb.Close SaveChanges:=False
End Sub
I have found that the sheet I was importing from the other workbook had external connections and was creating Connections and new References in my Workbook. Don't know why, but somehow this was affecting my Excel and causing it to restart since I was copying all the sheet content.
Instead of copying the full source sheet to my workbook...
rFullRangeToPaste.Copy wsDestination.Cells(wsDestination.Rows.Count, "A").End(xlUp)
I copied only the values and formats of the source sheet...
Dim rDestinationRange As Range
'the rest of the code in question
rFullRangeToPaste.Copy wsDestination.Cells(wsDestination.Rows.Count, "A").End(xlUp)
Set rDestinationRange = wsDestination.Cells(wsDestination.Rows.Count, "A").End(xlUp)
rFullRangeToPaste.Copy
wsDestination.PasteSpecial xlPasteValuesAndNumberFormats
Note: This worked after my workbook recovered from the previous extraction (without broken external connections and null references). Then I made the changes in the code and save it.

VBA module call in userform to diff sheets

new and would like to ask if someone could possibly check my code to see where i'm making a mistake.
first, i've created a form with two textboxes and two buttons that will go and get two different directories and the associated files. this is done through a call to a function that loads the dir to the textboxes.
a button to call a function to navigate dir and get the file
Private Sub CommandButton3_Click()
'call selectFile function to select file
selectFile
End Sub
function to get workbooks into textboxes 1 and 2:
Public Function selectFile()
Dim fileNamePath1 As String
Dim fileNamePath2 As String
Dim workbookFilePath1 As String
Dim workbookFilePath2 As String
On Error GoTo exit_
If workbookFilePath1 = Empty And workbookFilePath2 = Empty Then
fileNamePath1 = Application.GetOpenFilename(FileFilter:="Excel Files (*.xls), *.xls", Title:="Open Workbook 1", MultiSelect:=False)
workbookFilePath1 = Dir(fileNamePath1)
'TextBox1.Text = workbookFilePath1
TextBox1.Value = fileNamePath1
fileNamePath2 = Application.GetOpenFilename(FileFilter:="Excel Files (*.xls), *.xls", Title:="Open Workbook 2", MultiSelect:=False)
workbookFilePath2 = Dir(fileNamePath2)
TextBox2.Value = fileNamePath2
If fileNamePath1 = False Or fileNamePath2 = False Then
MsgBox ("File selection was canceled.")
Exit Function
End If
End If
exit_:
End Function
up to here, the code is ok... can do better, but
here's where problems occur... i'd like to pass the directories as objects into the module to diff
button that executes module to diff:
Private Sub CommandButton1_Click()
getTheWorkbooksToCompare(fileNamePath1, fileNamePath2)
End Sub
i know that i've changed myPath1 and myPath2 to Workbooks, where I've had them as strings before
diffing module
Public Sub gettheWorkbooksToCompare(myPath1 As Workbook, myPath2 As Workbook)
Dim myExcelObj
Dim WorkbookObj1
Dim WorkbookObj2
Dim WorksheetObj1
Dim WorksheetObj2
Dim file1 As String
Dim file2 As String
Dim myWorksheetCounter As Integer
Dim i As Worksheet
Set myExcelObj = CreateObject("Excel.Application")
myExcelObj.Visible = True
Set file1 = Dir(myPath1)
Set file2 = Dir(myPath2)
Set WorkbookObj1 = myExcelObj.Workbooks.Open(file1)
Set WorkbookObj2 = myExcelObj.Workbooks.Open(file2)
Set NewWorkbook = myExcelObj.Workbooks.Add
While WorkbookObj1 <> Null And WorkbookObj2 <> Null
'While WorkbookObj1.ActiveWorkbook.Worksheets.count = WorkbookOjb2.ActiveWorkbook.Worksheets.count
myWorksheetCounter = ActiveWorkbook.Worksheets.count
myWorksheetCount = ActiveWorkbook.Worksheets.count
If WorksheetObj1.Worksheets.myWorksheetCounter = WorkbookObj2.Worksheets.myWorksheetCounter Then
Set WorksheetObj1 = WorkbookObj1.Worksheets(myWorksheetCounter)
Set WorksheetObj2 = WorkbookObj2.Worksheets(myWorksheetCounter)
Set myNewWorksheetObj = NewWorkbook.Worksheets(myWorksheetCounter)
For myWorksheetCounter = i To WorksheetObj1
For myWorksheetCount = j To WorksheetOjb2
'If cell.Value myWorksheetObj2.Range(cell.Address).Value Then
If cell.Value = myWorksheetObj2.Range(cell.address).Value Then
myNewWorksheetObj.Range(cell.address).Value = cell.address.Value
myNewWorksheetObj.Range(cell.address).Interior.ColorIndex = 3
Else
cell.Interior.ColorIndex = 0
End If
Next
'if doesn't work... use SaveChanges = True
myNewWorksheetObj.Workbooks.Save() = True
Next
Else
MsgBox ("The worksheets are not the same worksheets." & vbNewLine & "Please try again.")
End If
Wend
Set myExcelObj = Nothing
End Sub
So my question is... can someone please assist in seeing where i'm going wrong? essentially, i'm having some issues in trying to get this working.
much appreciated
i've gone through and cleaned up some areas a little bit... but now have a: "run time error '438': object doesn't support this propety or method" at the while loop code that i've updated the post with
I see a typo on CommandButton1_Click
Private Sub CommandButton1_Click()
getTheWorkbooksToCompare(fileNamePath1, fileNamePath2)
End Sub
Public Sub gettheWorkbooksToCompare(myPath1 As Workbook, myPath2 As Workbook)
There might be something more, but your not capitalizing the "T" in getThe, but you call it that way.

Call excel function in access vba

I've a sub in excel that needs to be called from access.
Excel vba
Public Function testme(value As String) As String
Dim xlpath As String
Dim concate As String
xlpath=ActiveWorkbook.Path
value = ActiveWorkbook.Name
concate = xlpath & "\" & value
Let testme = concate
End Function
i need to call above method in one of the access method.How do i call it.
Sub Connect1()
Dim xlApp As Variant
'Set xlApp = CreateObject("Excel.Application")
'this will launch a blank copy of excel; you'll have to load workbooks
'xlApp.Visible = True
Set xlApp = GetObject(, "Excel.Application")
Let ans = xlApp.Application.Run("MyXLVBAProject.MyXLVBAModule.testme", 400)
'here ans has the string "500"
End Sub
You'll probably want to use Application.Run from Excel's object model. You pass it a string such as "QuickRDA.JavaCallBacks.GetQuickTab" for the macro name, where QuickRDA is the name of the Excel VBA project, JavaCallBacks is the name of the VBA module in that VBA project, and GetQuickTab is the name of the function in that VBA module.
In Access
Sub Connect()
Dim xlApp As Variant
Set xlApp = GetObject(, "Excel.Application")
'this will connect to an already open copy of excel, a bit easier for quick & dirty testing
Let ans = xlApp.Application.Run("MyXLVBAProject.MyXLVBAModule.testme")
End Sub
In Excel
Public Function testme() As String
Dim xlpath As String
Dim concate As String
Dim value as String
xlpath = ActiveWorkbook.Path
value = ActiveWorkbook.Name
concate = xlpath & "\" & value
Let testme = concate
End Function
-or simply-
Public Function testme() As String
Let testme = ActiveWorkbook.FullName
End Function
Remember that in Excel the function testme should be put in a module whose name is MyXLVBAModule, and that the project containing the module should be called MyXLVBAProject.
So, you want to trigger an Excel function from Access, or run an Excel subroutine from Access?
To run a function, you can do something like this.
Public Function FV(dblRate As Double, intNper As Integer, _
dblPmt As Double, dblPv As Double, _
intType As Integer) As Double
Dim xl As Object
Set xl = CreateObject("Excel.Application")
FV = xl.WorksheetFunction.FV(dblRate, intNper, dblPmt, dblPv, intType)
Set xl = Nothing
End Function
To run an Excel subroutine from Access, you can do the following.
Sub RunExcelMacro()
Dim xl As Object
'Step 1: Start Excel, then open the target workbook.
Set xl = CreateObject("Excel.Application")
xl.Workbooks.Open ("C:\Book1.xlsm")
'Step 2: Make Excel visible
xl.Visible = True
'Step 3: Run the target macro
xl.Run "MyMacro"
'Step 4: Close and save the workbook, then close Excel
xl.ActiveWorkbook.Close (True)
xl.Quit
'Step 5: Memory Clean up.
Set xl = Nothing
End Sub

Resources