Define varables in Excel then use in Access VBA at same time - excel

Is it possible to define a string variable in excel and then use that variable inside Access?
I have a program where in Excel a window pops up asking for where a file is located which will feed into an Access database - get processed - then shoot into Excel. The problem is that this is for a lot of different people and so each computer is going to have its own extension address of where the file is located, so it is necessary to have it be easy for users to identify where their file is located instead of hard-coding it into the VBA.
No matter what I try, I can't seem to figure out how to get the string variable to talk to the access database so it knows where to go look for the file.
I can't seem to find a solution for this. Anyone have any ideas?
Here is the code I have so far: This is what is inside the excel file----
'CommandButton1 is a button inside of a form window that pops up for the user to enter the address of the file
Public Sub CommandButton1_Click()
'both of these are public/global variables defined in a global macro
locationaddress = txbBrowse2.Value
LocationOfData = txbBrowse.Value
Dim appAccess As Object
Set appAccess = CreateObject("Access.Application")
'location of data is the location of the access file itself
location address is the string that I'm trying to feed into access
appAccess.OpenCurrentDatabase LocationOfData, exclusive:=False
appAccess.Application.Run "DoExcelImport"
End Sub
'Here is the code inside the access file, the idea is that it will modify the "Import-TEST" saved import. It will change where it pulls the excel sheet that contains a bunch of items that requires access to process.
Sub DoExcelImport()
DoCmd.SetWarnings False
Dim ies As ImportExportSpecification, i As Long, oldXML() As String, newXML As String
Set ies = CurrentProject.ImportExportSpecifications("Import-TEST")
oldXML = Split(ies.XML, vbCrLf, -1, vbBinaryCompare)
newXML = ""
For i = 0 To UBound(oldXML)
If i = 1 Then
' re-write the second line of the existing XML
newXML = newXML & _
"<ImportExportSpecification Path = """ & _
locationaddress & _
""" xmlns=""urn:www.microsoft.com/office/access/imexspec"">" & _
vbCrLf
Else
newXML = newXML & oldXML(i) & vbCrLf
End If
Next
ies.XML = newXML
ies.Execute
Set ies = Nothing
DoCmd.SetWarnings True
End Sub

Probably the easiest way might be using
SaveSettings(AppName As String, Section As String,Key As String, Setting As `String)
to store the string in the registry,
GetSettings((AppName As String, Section As String,Key As String)
to get it in Access, and
DeleteSetting (AppName as String)
to delete it.
Is probably a bit abusing the registry, but an easy way.

Related

(VBA) Can't check if file exists because Dir is case-sensitive

I'm writing a program which writes links into an excel sheet based on various data found in the sheet. My company used SOLIDWORKS PDM to store files, so I'm using the PDM API (the pdmv object) to write the links. Some of the files don't exist due to faulty data, so I need some kind of error checking before referencing the pdmv object and writing the link.
The issue I'm running into is with case-sensitive file locations. GetFolderFromPath and GetFile commands are case-insensitive, so the program writes links without problems if they exist. However, since the Dir command is case-sensitive, I can't properly check if the files exist before running the link-writing commands.
Is there any way to use Dir without worrying about case, or is there a different, case-insensitive method to checking if a file exists that might work here?
Thanks for the help.
EDIT:
evidently, Dir is case-insensitive, so the issue must be arising from the server that my company uses to store files, SOLIDWORKS PDM. Unfortunately, this doesn't fix the issue, so any ideas are welcome.
Sub writeLink(link As String, palRow As Long, asArray, pdmv As Object)
Dim textDisp As String
textDisp = asArray(1) & "-" & asArray(2) & "-1000"
Dim filename As String
filename = textDisp & ".sldasm"
testVar = Dir(link & "\" & filename)
If Not testVar = "" Then
Dim efolder As Object
Dim efile As Object
Set efolder = pdmv.GetFolderFromPath(link)
Set efile = efolder.GetFile(filename)
fileLink = "conisio://myvault/explore?projectid=" & efolder.id & "&documentid=" & efile.id & "&objecttype=1"
calc.Hyperlinks.Add Anchor:=calc.Cells(palRow, 8), _
Address:=fileLink, _
TextToDisplay:=textDisp
Else
calc.Cells(palRow, 2).Interior.Color = 65535
End If
End Sub

How to programmatically export and import code into Excel worksheet?

We will put 100s of Excel worksheets out in the field this year. The code periodically needs to be updated when bugs are found. For last year's effort, I was able to dynamically have workbooks pull updates for .bas files. This year I want to dynamically have workbooks pull updates for the code embedded in the worksheets too.
EXPORT CODE
The export code is pretty simple, but there are artifacts in the .txt files
Sub SaveSoftwareFile(path$, name$, ext$)
ThisWorkbook.VBProject.VBComponents(name).Export path & name & ext
Example Call: SaveSoftwareFile path, "ThisWorkbook", ".txt"
The problem is that the export has a lot of header information that I don't care about (in red). I just want the part in blue. Is there switch that allows me not to save it, or do I have to manually go into the export and remove it myself?
IMPORT CODE
The import code is pretty straight forward too, but it causes the error "Can't enter break mode at this time", and I'm struggling to figure out the right path forward. If I manually try and delete this code, Excel is also unhappy. So maybe my approach is altogether incorrect. Here's the code:
Sub UpgradeSoftwareFile(path$, name$, ext$)
Dim ErrorCode%, dest As Object
On Error GoTo errhandler
Select Case ThisWorkbook.VBProject.VBComponents(name).Type
Case 1, 3 'BAS, FRM
<Not relevant for this discussion>
Case 100 'Worksheets
Set dest = ThisWorkbook.VBProject.VBComponents(name).codemodule
dest.DeleteLines 1, dest.CountOfLines 'Erase existing | Generates breakpoint error
dest.AddFromFile path & name & ext '| Also generates breakpoint error
End Select
Example Call: UpgradeSoftwareFile path, "ThisWorkbook", ".txt"
Thanks in advance for your help
Please, try the next way of exporting and you will not have the problem any more:
Sub SaveSoftwareFile(path$, sheetCodeModuleName$, FileName$)
Dim WsModuleCode As String, sCM As VBIDE.CodeModule, strPath As String, FileNum As Long
Set sCM = ThisWorkbook.VBProject.VBComponents(sheetCodeModuleName).CodeModule
WsModuleCode = sCM.Lines(1, sCM.CountOfLines)
'Debug.Print WsModuleCode
strPath = ThisWorkbook.path & "\" & FileName
FileNum = FreeFile
Open strPath For Output As #FileNum
Print #FileNum, WsModuleCode
Close #FileNum
End Sub
You can use the above Sub as following:
Sub testSaveSheetCodeModule()
Dim strPath As String, strFileName As String, strCodeModuleName As String
strPath = ThisWorkbook.path
strFileName = "SheetCode_x.txt"
strCodeModuleName = Worksheets("Test2").codename 'use here your sheet name
SaveSoftwareFile strPath, strCodeModuleName, strFileName
End Sub
Now, the created text file contains only the code itself, without the attributes saved by exporting the code...
Import part:
"Can't enter break mode at this time" does not mean that it is an error in the code. There are some operations (allowed only if a reference to Microsoft Visual Basic for Applications Extensibility ... exists) in code module manipulation, which cannot simple be run step by step. VBA needs to keep references to its VBComponents and it looks, it is not possible when changes in this area and in this way are made.
The import code is simple and it must run without problems. You must simple run the code and test its output...

Excel macro saving sheet as pdf to sharepoint to location dependent on input in new folder

I am new to VBA and have to complete a task for my manager about saving sheet as a pdf into sharepoint (if firstly can be done) which creates a folder at the location with the same name as the saved PDF and saves the pdf there.
Now where it gets harder for me is at the location in sharepoint there are 3 folders, for USD, EUR and GBP and depending on a field in the excel (which will denote one of the 3 currencies) it will have to be saved at that location
(Sharepoint URL or mapped to network drive)\Quote\USD\new folder created with file name matching pdf\pdf file
(Sharepoint URL or mapped to network drive)\Quote\EUR\new folder created with file name matching pdf\pdf file
(Sharepoint URL or mapped to network drive)\Quote\GBP\new folder created with file name matching pdf\pdf file
Is it the sharepoint URL will work or is it only when mapped to the network drive (which I have with a filepath with my username which im guessing would stop working from anyone else but me)
I am using the below which saves to sharepoint but with me as User_1 I cant see how anyone else will be able to?
Sub test()
ChDir "C:\Users\user_1\company\Sales Team - Documents\Quotes"
With Sheets("Quote")
.ExportAsFixedFormat _
Type:=xlTypePDF, _
Filename:="C:\Users\user_1\company\Sales Team - Documents\Quotes\" & ActiveSheet.Range("B2").Value & " Quote.pdf", _
Quality:=xlQualityStandard, _
IncludeDocProperties:=True, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=False
End With
end sub
It took me a while to figure out the above (which im sure is really simple) but i am still learning,
Can anyone help me with this?
Thanks
OK, I probably overshot the targer a bit...
This code only works with drives mapped to the normal Filesystem, if you want to use a network path you can read some more on the topic here: Cannot save file to Sharepoint Online using VBA (Permissions error)
Unfortunately I do not have a way to test code against a Sharepoint Server until I get back to work.
First of, you need to add the Microsoft Scripting Runtime to your project, described here: https://stackoverflow.com/a/3236348
You can call the publishQuoteToDirectory sub from anywhere inside your project. I would recommend a custom Ribbon in the Application that passes the activeSheet Object, but you could also just point a Makro to runExportExample and fill in some static parameters.
sheetToPublish: Expects a Worksheet Object, you can use ActiveSheet if you want
publishingPath: The "Quotes" Folder
currencyCell: The Cell which holds the Currency
fileName: If you want to override the Filename for some reason
The Select Case structure decides which currency the Worksheet Contains, it also accepts the signs of the currencies, can be extended with whatever you want.
quoteNamePathPart I was not exactly sure how you meant this in your main question, this gives you the option to use the Workbook or the Worksheet Name, choose whichever you want.
The FileSystemObject helps us with building a valid path, there are other methodes to create this but I prefer using it over them because it gives direct access to the Microsoft Filesystem.
BuildFullPath is a separate sub because it has to call itself recursively. The FSO can not create nested Folder in one Action. An alternative would be to use the Shell (described here: https://stackoverflow.com/a/4407468).
This is the whole Magic, if you have any Question regarding the code feel free to ask.
There are definitely other easier, faster, more secure ways to solve this. My knowledge with VBA is still limited and I don't know all the best practices, but the code should get the job done. (#all the other, feel free to criticize)
Code:
'all this sits in a standart module:
Option Explicit
Private Const StandartCurrencyCell As String = "B2"
Private Const StandartFileName As String = "Quote.pdf"
Public Sub runExportExample()
publishQuoteToDirectory _
sheetToPublish:=ActiveSheet, _
publishingPath:="C:\Users\User1\company\Sales Team - Documents\Quotes\", _
currencyCell:="B2", _
fileName:="SomeOtherFileName.pdf"
End Sub
Public Sub publishQuoteToDirectory(sheetToPublish As Worksheet, Optional publishingPath As String, Optional currencyCell As String, Optional fileName As String)
'Sanitize the input if necessary
If publishingPath = "" Then publishingPath = Environ$("USERPROFILE") & "\Quotes\"
If currencyCell = "" Then currencyCell = StandartCurrencyCell
If fileName = "" Then fileName = StandartFileName
Dim currencyPathPart As String
Select Case sheetToPublish.Range(currencyCell).Value2
Case "USD", "$"
currencyPathPart = "USD"
Case "EUR", "€"
currencyPathPart = "EUR"
Case "GBP", "£"
currencyPathPart = "GBP"
Case Else
currencyPathPart = "OtherCurrencies"
End Select
Dim quoteNamePathPart
With New FileSystemObject
'I'm a bit sceptic on the correctness of this, since your PDF is called "Quote" the FOlder Name would be "Quote" as well
'Comment out whatever you don't want
'I think this should be:
quoteNamePathPart = .GetBaseName(sheetToPublish.Parent.Name) 'this will use the Workbook Name (without Suffix)
'not:
'quoteNamePathPart = sheetToPublish.Name 'This will use the Name of the Sheet
'build the path and create folder, using the FSO takes care of missing Seperators etc.
publishingPath = .BuildPath(publishingPath, currencyPathPart)
publishingPath = .BuildPath(publishingPath, quoteNamePathPart)
BuildFullPath (publishingPath)
publishingPath = .BuildPath(publishingPath, fileName)
End With
On Error GoTo ExportFailed
sheetToPublish.ExportAsFixedFormat _
Type:=xlTypePDF, _
fileName:=publishingPath, _
Quality:=xlQualityStandard, _
IncludeDocProperties:=True, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=False
Exit Sub
ExportFailed:
MsgBox prompt:="The Export of the File: " & fileName & " failed" & vbCrLf & "The expected Output Path was: " & publishingPath, Title:="Export Failed"
End Sub
Sub BuildFullPath(ByVal FullPath)
'FSO can only create one Folder at a time, so I used a recursive function found here: https://stackoverflow.com/a/4407468
Dim fso As New FileSystemObject
If Not fso.FolderExists(FullPath) Then
BuildFullPath fso.GetParentFolderName(FullPath)
fso.CreateFolder FullPath
End If
End Sub

VBA does not save changes to Outlook Template that show up with .Display

I am working on generating OFT files that will be e-mailed to customers who will then fill the To: and Subject: in and send them as e-mails to their clients.
My data comes from an Excel Workbook with one sheet containing static data (Books) and another information pasted in by the user (Pins). I've got a basic template that has placeholder text which gets replaced by the data in the aforementioned Excel sheets.
One important part of this is that I need the changed template to get saved to it's own file, so it can be stored for reference later. Originally I had the code below setup to open the template and call .SaveAs myFilename, olTemplate but that just made a broken 3KB file. You will notice I am copying the template to the actual destination file and operating on that instead.
My problem is that if I have the template item call .Display, everything is perfect. I see my image in the right place and all of the text is properly replaced. If I call .Save it saves out a copy of the original OFT template with no changes present.
Can anyone tell me what I'm doing wrong here? I've been searching here and google for hours trying to find some indication of what I'm missing. I'm trying to automate this thing as much as possible. Resaving the new OFT with Outlook's UI is a real time sink for a coworker and I'd like to eliminate that if possible. They're going to be generating dozens of these OFTs every day, so the work seems worth it in my opinion.
UPDATE
I have managed to get this to work but the solution feels like a half-answer. The code below has been updated with changes that properly save the OFT.
Here is my sub:
Sub OutlookTemplate(ByVal pins As Range, ByVal book As Range, ByVal ImageLocation As String)
Dim myolapp As Object
Dim myItem As Object
Set myolapp = CreateObject("Outlook.Application")
'myolapp.Session.Logon
For Each p In pins.Cells
If Not IsEmpty(p.Value) Then
Dim myFilename As String
myFilename = "c:\temp\" & Worksheets("PINS").Range("A2") & "-" & p.Value & ".oft"
FileCopy "c:\template.oft", myFilename
Set myItem = myolapp.CreateItemFromTemplate(myFilename)
myItem.Save <- Added immediate save after creation of myItem
myItem.Attachments.Add ImageLocation, olByValue, 0
myItem.HTMLBody = Replace(myItem.HTMLBody, "THEIMAGE", "<img src='cid:" & book.Cells(2).Value & "'" & "width='154'>")
myItem.HTMLBody = Replace(myItem.HTMLBody, "PINHERE", p.Value)
myItem.HTMLBody = Replace(myItem.HTMLBody, "THETITLE", book.Cells(1).Value)
myItem.HTMLBody = Replace(myItem.HTMLBody, "THESUBTITLE", book.Cells(3).Value)
myItem.HTMLBody = Replace(myItem.HTMLBody, "THEAUTHORS", book.Cells(4).Value)
myItem.HTMLBody = Replace(myItem.HTMLBody, "THEDESCRIPTION", book.Cells(5).Value)
' Leaving the next line off results in a broken image
' when .SaveAs is called
myItem.Display
' This saves all of the changes out to the file properly
' in combination with .Display
' Note: if I call myItem.SaveAs myFilename, olTemplate
' I get the 3KB broken OFT. Omitting ,olTemplate works
myItem.SaveAs myFilename
End If
Next
End Sub
The Save method doesn't propagate changes to the .oft file. It saves the Microsoft Outlook item to the current folder or, if this is a new item, to the Outlook default folder for the item type.
Try to open the existing .oft file without copying it anywhere. Then do the required changes and call the SaveAs method to save it as a template wherever you need.

Export Access database with multiple tables to Excel with multiple sheets

The title says it about all. I'm trying to write a VBA script that would allow me to run inside Access and it would export all database tables as separate sheets into and Excel file with the same name as the database:
Sub exportTablesToXLS()
Dim td As DAO.TableDef, db As DAO.Database
Dim out_file As String
out_file = CurrentProject.Path & "\" & db.DatabaseName & ".xls"
Set db = CurrentDb()
For Each td In db.TableDefs
If Left(td.Name, 4) = "MSys" Then
'We do not need MSys tables in excel file
Else
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, _
td.Name, out_file, True, Replace(td.Name, "dbo_", "") 'We do not need dbo prefix in sheetnames
End If
Next
End Sub
Problems I'm having I would like your help on:
see line out_file -> db.DatabaseName return an error. How can I correctly get the database name of the current Access database?
I want to output a logfile (simple textfile) as well. How can I read, for each database table, the number of rows that have been exported and report eventual errors that occured?
Any help to improve this script is greatly appreciated :-)
Your db variable doesn't refer to the current database (yet - it is set in the following line), and the property is Name (I haven't encountered DatabaseName):
Sub Test()
Dim db As DAO.Database
Set db = CurrentDb
Dim sLast As String
MsgBox db.Name
'F:\Documents and Settings\student\My Documents\Staff Database.accdb
sLast = InStrRev(db.Name, "\")
MsgBox Right(db.Name, Len(db.Name) - sLast)
'Staff Database.accdb
End Sub
Name gives the full path and filename, the second MsgBox reduces this to just the filename.
(There may be another way to get the filename without having to parse Name..)
To get the number of rows exported you could open a Recordset for the table(s), reading the RecordCount property. A text file could be created using the FileSystemObject object. Sample code:
Set fso = CreateObject("Scripting.FileSystemObject")
Set oFile = FSO.CreateTextFile(strPath)
oFile.WriteLine "test"
oFile.Close
Or even just simple file (VBA) I/O:
Open pathname For mode [Access access] [lock] As [#]filenumber [Len=reclength]
(the FileSystemObject is easier to work with)
To report errors you'll need to create your own error-handling routines, and an error-logging procedure. This has been done before and a little searching will uncover some code. Essentially, each (important) event has error-handling code that calls a logging procedure. This procedure creates a record in a table to store all relevant information: date, time, which form was open, etc., etc.
A quick Google uncovered this page about logging Access errors.

Resources