I am completely new to scripting, so please forgive my ignorance.
(Running Windows 10)
I found a working solution to convert .xls files to .csv using the .vbs from this post:
Convert xls to csv.
The files I'm working with have multiple sheets, and the vbs works by dragging the file(s) onto the vbs file icon to execute. I don't understand how the vbs gets the input arguments. I copied this code posted by Chris Rudd
'Courtesy of Chris Rudd on stackoverflow.com
'Modified by Christian Lemer
'plang
'ScottF
' https://stackoverflow.com/questions/1858195/convert-xls-to-csv-on-command-line
'* Usage: Drop .xl* files on me to export each sheet as CSV
'* Global Settings and Variables
'Dim gSkip
Set args = Wscript.Arguments
For Each sFilename In args
iErr = ExportExcelFileToCSV(sFilename)
' 0 for normal success
' 404 for file not found
' 10 for file skipped (or user abort if script returns 10)
Next
WScript.Quit(0)
Function ExportExcelFileToCSV(sFilename)
'* Settings
Dim oExcel, oFSO, oExcelFile
Set oExcel = CreateObject("Excel.Application")
Set oFSO = CreateObject("Scripting.FileSystemObject")
iCSV_Format = 6
'* Set Up
sExtension = oFSO.GetExtensionName(sFilename)
if sExtension = "" then
ExportExcelFileToCSV = 404
Exit Function
end if
sTest = Mid(sExtension,1,2) '* first 2 letters of the extension, vb's missing a Like operator
if not (sTest = "xl") then
if (PromptForSkip(sFilename,oExcel)) then
ExportExcelFileToCSV = 10
Exit Function
end if
End If
sAbsoluteSource = oFSO.GetAbsolutePathName(sFilename)
sAbsoluteDestination = Replace(sAbsoluteSource,sExtension,"{sheet}.csv")
'* Do Work
Set oExcelFile = oExcel.Workbooks.Open(sAbsoluteSource)
For Each oSheet in oExcelFile.Sheets
sThisDestination = Replace(sAbsoluteDestination,"{sheet}",oSheet.Name)
oExcelFile.Sheets(oSheet.Name).Select
oExcelFile.SaveAs sThisDestination, iCSV_Format
Next
'* Take Down
oExcelFile.Close False
oExcel.Quit
ExportExcelFileToCSV = 0
Exit Function
End Function
Function PromptForSkip(sFilename,oExcel)
if not (VarType(gSkip) = vbEmpty) then
PromptForSkip = gSkip
Exit Function
end if
Dim oFSO
Set oFSO = CreateObject("Scripting.FileSystemObject")
sPrompt = vbCRLF & _
"A filename was received that doesn't appear to be an Excel Document." & vbCRLF & _
"Do you want to skip this and all other unrecognized files? (Will only prompt this once)" & vbCRLF & _
"" & vbCRLF & _
"Yes - Will skip all further files that don't have a .xl* extension" & vbCRLF & _
"No - Will pass the file to excel regardless of extension" & vbCRLF & _
"Cancel - Abort any further conversions and exit this script" & vbCRLF & _
"" & vbCRLF & _
"The unrecognized file was:" & vbCRLF & _
sFilename & vbCRLF & _
"" & vbCRLF & _
"The path returned by the system was:" & vbCRLF & _
oFSO.GetAbsolutePathName(sFilename) & vbCRLF
sTitle = "Unrecognized File Type Encountered"
sResponse = MsgBox (sPrompt,vbYesNoCancel,sTitle)
Select Case sResponse
Case vbYes
gSkip = True
Case vbNo
gSkip = False
Case vbCancel
oExcel.Quit
WScript.Quit(10) '* 10 Is the error code I use to indicate there was a user abort (1 because wasn't successful, + 0 because the user chose to exit)
End Select
PromptForSkip = gSkip
Exit Function
End Function
This works well for my needs, but I want to run it hourly and save the .csv files to a new directory.
I tried to run the .vbs using the Task Scheduler, but it only opens the file in my text editor, it doesn't execute. My thought was to create a .batch file that runs the .vbs. I thought I could call the .vbs with PowerShell commands like this:
Start "XlsToCsv"
Start "XlsToCsv.vbs"
But both of those have the same effect of opening the .vbs in the text editor.
Perhaps a simpler question is, "How do I run a .vbs file from the PowerShell or the Command Prompt?"
Any help would be greatly appreciated.
This method works consistently in the batch environment, however cannot use doublequotes as would be advisable for filepaths with spaces.
Start filepath\name.vbs
no Doublequotes.
This method works Consistently in cmd.exe console, however fails in .bat programs:
WSscript.exe "filepath\name.vbs"
Wscript/Window Script host provides an environment to execute scripts in a variety of languages and Cscript starts a script in command line environment.
So, If you want to run your script in console use cscript.exe and wscript.exe if you don't want the console window. So, as T3RR0R mentioned you need to use WScript command to run it.
Sometimes, executing a VBscript in windows opens text editor rather than running it. This is due to changes in the default file associations. Some time antivirus will also do this in order to protect your system. In that case, you need to change the registry check this link https://superuser.com/questions/1108349/change-default-program-for-opening-vbs-files
Take look in this file.gif:
I'm understood that this only works if you're using the file vbs by Drag and Drop passing as arguments...
You can see instructions left by author about how to use in the vbs in 7rd line:
Drop .xl* files on me to export each sheet as CSV
Obs.: .xl* is equal to "any file with (.xl)"+any" == *.xlsx, *.xlsm...
Take look in this file.gif that you can see how to pass arguments in vbs, (is the same to cmd & bat) files by Drag and Drop:
This file.png show how to use arguments with the
The code you have tried are not using/passing any arguments (parameters), without pass any arguments, (one or more files) this will always fail!
If you need try using some like:
"XlsToCsv.vbs" "one_file_dot.extensio_equal_xlsx_.xlsx" "one_more_another_file_dot.extensio_equal_xlsx_too.xlsx"
rem :: observing if you are try in a different folder where the vbs + xlsx file are, try this:
"d:\folder\where\vbs\are\XlsToCsv.vbs" "d:\folder\where\xlsx\file1\are\1file_dot.extension_equal_xlsx_.xlsx" "d:\folder\where\xlsx\file1\are\one\more\are\too\one_more_another_file_dot.extensio_equal_xlsx_too.xlsx"
__
This is who I have using your vbs files in same folder where the files **.xlsx* are, so, no need passing the drive\folder path:
wscript 58924333.vbs "012019.xlsx" "022019.xlsx"
rem :: or ::
cscript 58924333.vbs "012019.xlsx" "022019.xlsx"
So sorry my limited English
Related
I'm preparing a Visual Basic for Applications (VBA) script in a .accdb file. (I don't have any requirement to do so, I just opened what I have: the Microsoft Access 2016 application, and opened its Visual Basic editor and started coding.)
Goal: The script is meant to move a table from an .MDB file to another .MDB file.
I couldn't find a way to do it directly, so I did that in 2 steps.
What the script does:
1st step: Transfers, or copies, a given table (stored in variable named srcTableName)
from a local .MDB file (whose path+name+extension is in variable
srcPath) into my script's file (an .accdb file called Script.accdb
and stored in the same folder as the source .MDB file)
2nd step:
Transfers, or copies, the table newly copied (named
intermediaryTableName) from the script's current file to some .MDB
file which is in some Drive (path+name+extension in destPath)
I couldn't merge the 2 steps into one (that is: to copy the table directly from srcTableName to destPath)
So, this is it:
table in .MDB file, in local -> table in current file (local, contains script, extension .accdb) -> table in .MDB file, in some other drive
It works.
My problem is: each time I run my script, the script's file (which I sometimes call also. the "current file", or the .accdb one) grows 30MB more. This is unnaceptable. (I don't even save the file. Why does the file need to enlarge like this?)
I detected the problem comes from the command: DoCmd.TransferDatabase. This command seems to increase the file size a lot.
After running the script: the script's file (a 500 KB file) has become a 27 776 KB one.
Followings runs:
27 776KB -> 54 912 KB (difference before and after run: 27 136KB)
54 912 KB -> 82 048 KB (difference: 27 135KB)
I have no idea what this command writes. I couldn't find any information on this on the documentation or in pretty much any google result.
When I delete the table copied in the current file (the script's file) the size of the file almost does not shrink. So DoCmd.TransferDatabase seems to write something else (some metadata I didn't find, maybe)
I wish I could do the 1st step in some other way. Looking for workarounds:
I was not able to configure programatically an ADODB.Connection in
order for it to import the table from the old .MDB file (the
srcPath one)
DoCmd.CopyObject is a function that seems to please me, since it
seems to create no "rubbish"/enlarge the file mysteriously. The
available MSDN microsof's documentation provides no further details about the effects of applying this function or the arguments' formats, but it seems to be
prepared to manipulate only objects that belong to the current file,
and not an external file. I want to try to set its argument
SourceObjectName to an external (that is: in another drive), detailed path, but it seems to only
accept the table's (short) name. I tried to look some long-path name for access objects like tables, but also: the fields of the structure
that contains the table I want to import
(srcDB.TableDefs(srcTableName).Connect) seem to be empty for this
table, and the "name" attribute only displays the name of the table I
already know ("sh5") and can see as a user of Access, which seems to be of no use to
specify the path to it from an external file.
I was able to copy tables, or to export+import tables, from a "normal" access file (.accdb extension) to another .accdb file. As
such, I tried to convert a .MDB file to .accdb, but was not successful. I got a
""The project cannot be converted into this format. The project can
only be converted to Access 2000 or newer format." error message while using a
Microsoft.Office.Interop.Access.Application.ConvertAccessProject
function.
I also tried to "compact and repair" the current/the script's file, setting the "Auto compact" option of the Access Application to True, but it didn't make much difference:
Next run: file size before this block of code: 82 048 KB
file size after that block of code: 82 048 KB
file size after script: 109 056 KB (difference before and after run: 27 008KB)
After all this:
Does someone have an idea to prevent DoCmd.TransferDatabase from enlarging the file like this?
Or another workaround to copy the table from one file to another?
Here is my code, should it provide any more useful details:
Option Explicit
Option Compare Database
'Copies one given table from the <srcPath> to a file <destPath> (This file serves as an intermediary. it contains the script and copies the table into a format I can manipulate and send to the destiny file.)
Sub CopyTableFromOneFileToTheOther()
Dim srcFileTitle As String 'file name (with no extension nor path) from which we want to copy the table
Dim srcTableName As String 'name of the table we want to move
Dim srcPath As String 'includes srcTableName, plus: old .MDB extension and path
Dim srcDB As DAO.Database
Dim destFileTitle As String 'file name (with no extension nor path) into which we want to move the table
Dim destPath As String 'includes destFileTitle, plus: extension and path
Dim destDB As DAO.Database 'file (access database) to which we want to copy the table to
Dim destTableName As String
Dim currentFilePath 'detailed path (included path, title, extension)
Dim intermediaryTableName 'name of the table held temporarily in the current file (the script's file)
Dim accessApp As Access.Application
Dim testTableName As String
'Initializations
srcFileTitle = "Actifs" 'This file is expected to be on local (in the same folder you put this file with script).
srcTableName = "sh5" 'table we want to copy / move
destFileTitle = "Actifs_toUpdate" 'title of the file to which we want to move the table. This file is expected to be somewhere remote. please update destPath as well.
srcPath = CurrentProject.Path & "\" & srcFileTitle & ".MDB"
destTableName = srcTableName & "_copy"
destPath = "G:\Users\b\bernarcl\Documents" & "\" & destFileTitle & ".MDB"
currentFilePath = CurrentProject.Path & "\" & CurrentProject.Name
intermediaryTableName = srcTableName
Debug.Print "srcPath = " & srcPath & " | srcTableName= " & srcTableName
DebugPrint "currentFilePath = " & currentFilePath & "|" & "intermediaryTableName = " & intermediaryTableName
Debug.Print "destPath = " & destPath & " | destTableName = " & destTableName & vbNewLine
'Compact and repair current file, to see if enabling this prevents the file to grow 30MB
Set accessApp = New Access.Application
With accessApp
.OpenCurrentDatabase CurrentProject.Path & "\" & CurrentProject.Name
.SetOption "Auto compact", True
.CloseCurrentDatabase
.Quit
End With
'Delete table form current file, if it already exists. Otherwise the file will store more and more of these, becoming too heavy.
If TableExists(srcTableName, CurrentDb) Then
Set srcDB = DBEngine.Workspaces(0).OpenDatabase(srcPath)
'testTableName = srcDB.TableDefs(srcTableName).Connect
'Debug.Print "testTableName= " & testTableName
'Dim t As TableDefs
' Set t = srcDB.TableDefs
Debug.Print "Table " & srcTableName & " exists in file " & CurrentDb.Name & ". Let's delete it, and import the most updated one afterwards."
DoCmd.DeleteObject acTable, srcTableName
End If 'table exists
'Importing table of old file, in order to have it in a macro-compatible format
'PROBLEM of memory spending here. The file grows 30MB each time it runs this instruction.
'I didn't find equivalent and successful ways to transfer database table from one file to another: tried DoCmd.CopyObject, configuring ADODB.Connection's parameters,
DoCmd.TransferDatabase TransferType:=acImport, DatabaseType:="Microsoft Access", _
DatabaseName:=srcPath, ObjectType:=acTable, _
Source:=srcTableName, Destination:=srcTableName, _
StoreLogin:=True
If (fileExists(destPath)) Then
Debug.Print "File " & destFileTitle & " already exists."
Set destDB = DBEngine.Workspaces(0).OpenDatabase(destPath)
If TableExists(destTableName, destDB) Then
Debug.Print "Table " & destTableName & " exists in file " & destFileTitle & ". Let's update it."
'DoCmd.DeleteObject acTable, destTableName
DoCmd.CopyObject destPath, destTableName, acTable, srcTableName 'This also warns the user and substitues the previous/current table with the to-be-copied one
Else
Debug.Print "Table " & destTableName & " does NOT exist in file " & destFileTitle & ". Let's create it."
DoCmd.CopyObject destPath, destTableName, acTable, srcTableName 'creates table in destPath for the first time
End If 'table exists
Else
'create new file, before copying
Debug.Print "file named= " & destFileTitle & " does not exist, then let's create it."
Set accessApp = New Access.Application
Set destDB = accessApp.DBEngine.CreateDatabase(Name:=destPath, Locale:=DB_LANG_GENERAL)
End If 'fileExists(destPath)
DoCmd.DeleteObject acTable, srcTableName 'deletes from current file. We don't need it here, anymore.
destDB.Close
End Sub
'Auxiliary functions
Private Function fileExists(ByVal strFile As String, Optional bFindFolders As Boolean) As Boolean
Dim lngAttributes As Long
lngAttributes = (vbReadOnly Or vbHidden Or vbSystem) 'Include read-only files, hidden files, system files.
If bFindFolders Then
lngAttributes = (lngAttributes Or vbDirectory) 'Include folders as well.
Else
Do While Right$(strFile, 1) = "\"
strFile = Left$(strFile, Len(strFile) - 1)
Loop
End If
On Error Resume Next
fileExists = (Len(Dir(strFile, lngAttributes)) > 0) 'If Dir() returns something, the file exists.
End Function
Private Function TableExists(ByVal srcTableName As String, db As DAO.Database) As Boolean
On Error Resume Next
Dim tdef As TableDef
db.TableDefs.Refresh
For Each tdef In db.TableDefs
If tdef.Name = srcTableName Then
TableExists = True
Exit For
End If
Next tdef
End Function
You can use an SQL query to move a table from one database to another.
Execute this on the source DB:
SELECT * INTO MyTable IN 'C:\MyOtherDb.MDB'
FROM MyTable;
I have used this a lot, and have never had these size problems.
You can also use SQL to pull in tables to the current Db.
SELECT * INTO MyTable FROM [C:\MySourceDb.mdb].MyTable;
Obviously, you can use VBA to execute this query.
Note that some meta-information (indexes other than the primary one, lookup fields) might be lost.
I am writing a script right now which makes use of the File System Object to read a text file and later delete it. The part of the code in which this occurs I have written as a function. I have tested this function, along with some other functions which it depends on, and it works fine. But in the final product it is just one part of a script with 16 different functions/subroutines. After incorporating it into the final product, this file fails to work. Or, at least Windows script host tells me that it doesn't.
I have tested using Echo statements to track down the issue, since the line that WSH references should have executed properly, based on the fact that code after the line in question works when I run the script. I get an Echo when I echo after the function call (I have written a simple function to make the script wait before calling more functions, and the echo statement is after that, so the function definitely completes execution before the error occurs). I have also tried inserting an echo statement into the beginning of the next function to be called (literally directly after I instantiate the second function), and then I don't get an echo.
Here is the function in question. The line the error references is the one with Set objRECID.
Function PullRecords
Set objWSH = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
strIP = "192.168.1.185"
strOutFileCMD = ".output OUT" & strIP & ".txt"
strOutFile = "C:\Users\" & GetLoggedOnUsername & "\Documents\SQLite3\" & "OUT" & strIP & ".txt" 'Output of each element grab
strCommand = "FROM ZCDataField WHERE RECORD_ID="
strRECIDPath = "C:\Users\" & GetLoggedOnUsername & "\Documents\SQLite3\" & "RECID" & strIP & ".txt" 'Output of GetRECID
strFinalCSVPath = "C:\Users\" & GetLoggedOnUsername & "\Documents\SQLite3\" & strIP & ".csv"
strSQLite3Path = "C:\Users\" & GetLoggedOnUsername & "\Documents\SQLite3\"
strProcName = "SQLite3.exe"
'Element ID's (for reference)
'intpt_item = "275426222"
'intpt_description = "275466434"
'intpt_custitem = "275466431"
'intpt_qty = "275466713"
'intpt_name = "275466710"
'intpt_date = "275435183"
'intpt_unixmil = "275578832"
'Options for text files
intForReading = 1
intForWriting = 2
intForAppending = 8
boolOverwriteTrue = True
boolOverwriteFalse = False
Set objCSV = objFSO.CreateTextFile(strFinalCSVPath,boolOverwriteTrue) 'Creates final CSV to be written to/
Set objRECID = objFSO.OpenTextFile(strRECIDPath,intForReading)
'Cycles through records
Do Until objRECID.AtEndOfStream
strRECID = objRECID.ReadLine
Set objELID = objFSO.OpenTextFile(strSQLite3Path & "Element IDs.txt",intForReading) 'Need this here so that script restarts at beginning of file each time.
'Cycles through elements
Do Until objELID.AtEndOfStream
Set objBAT = objFSO.CreateTextFile(strSQLite3Path & strIP & dblUnixT & ".bat",boolOverwriteTrue)
objBAT.Write ("cd /D C:\Users\" & GetLoggedOnUsername & "\Documents\SQLite3")
objBAT.WriteLine
objBAT.Write ("sqlite3 " & strIP & ".db < " & strIP & ".txt")
objBAT.Close
Set objBAT = Nothing
Set objCMDS = objFSO.CreateTextFile(strSQLite3Path & strIP & ".txt",boolOverwriteTrue)
objCMDS.Write (".mode tabs")
objCMDS.WriteLine
objCMDS.Write (strOutFileCMD)
objCMDS.WriteLine
strELID = objELID.ReadLine 'Gets ELEMENT_ID
objCMDS.Write ("SELECT VALUE_TXT,VALUE_NUM " & strCommand & strRECID & " AND ELEMENT_ID=" & strELID & ";") 'Gets element
objCMDS.WriteLine
objCMDS.Write (".exit") 'Exits SQLite3
objCMDS.Close
Set objCMDS = Nothing
objWSH.Run(strSQLite3Path & strIP & dblUnixT & ".bat")
'Makes script wait until BAT is done.
intRunning = 1
Do Until intRunning = 0
intRunning = IsRunning(strProcName)
Loop
Wscript.Sleep(500)
Set objOut = objFSO.OpenTextFile(strOutFile)
strOut = objOut.ReadLine
objOut.Close
Set objOut = Nothing
objCSV.Write strOut & ","
Loop
'Make string of line and then delete 1 character on right to get rid of ,. Then replace line.
objCSV.Write Chr(8)
objCSV.WriteLine
objELID.Close
Set objELID = Nothing
Loop
objCSV.Close
objRECID.Close
Set objCSV = Nothing
Set objRECID = Nothing
objFSO.DeleteFile strRECIDPath
'objFSO.DeleteFile strOutFile
InvertText(strFinalCSVPath)
PullRecords = strFinalCSVPath
Call FuncSubEndToken
End Function
In case it is useful, here is the FuncSubEndToken function that I call.
Function FuncSubEndToken
intFuncSubEndToken = 1
End Function
And here is how I am using it when I call the PullRecords Function.
Call PullRecords
'FuncSubEndTokenWait
Do Until intFuncSubEndToken = 1
Loop
intFuncSubEndToken = 0
Any help would be greatly appreciated.
Edit: I have tried using On Error Resume Next and I just get wscript hanging after the parts that I posted. It doesn't even enter the next function.
Edit 2: I have tried commenting out the line that deletes the file that is needed for the PullRecords function, even though that line is executed after the function is done with the file. It now is apparent that is calling this function twice and another function twice (and then it errors out part way through that). I have looked and both of these functions are only ever called once (and they are not in loops, so that is definitely not the issue). I do call a function and pass it the output of both of these functions, in the order that they seem to be running. But I am not here calling the functions themselves. But perhaps wscript thinks that I am?
Edit 3: I have deleted the function that uses the return of the other two functions (well, commented it out), and I still get the same issue.
So, I have now figured out the issue. It would seem that I was somewhat misinformed on how functions work when trying to get their output. I thought that you called a function and then the function name was the output. But, it would seem that you do not need to use a call statement to execute a function. So, while trying to use the output of my functions I have been inadvertently calling them.
I have designed a system that is used to track customer activity and log calls to a department. The front end and back end database are written in access. This system is due to go to the USA division of the company i work for.
The front end needs to automatically refresh the tables and if the backend database has moved (which it will when i send it to the US) the code will then look at a function to read the location of the new database. Sample of the read text file function code shown below:
Function ReadDbPassword()
'--
' Filetostring(FILEInput$ as variant) ' to make this a callable function
Dim FILEInput As Variant
'--
On Error GoTo FileToString_Error
FILEInput = "C:\Users\Public\databaseUser\PassCon"
Passmyfile = FreeFile
Open FILEInput For Input As Passmyfile
Passthedata4 = Input(LOF(Passmyfile), Passmyfile)
Close Passmyfile
On Error GoTo 0
Exit Function
FileToString_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ")"
End Function
The text file contains a path like the one below:
P:\Projects\Database.accdb
I have found code that uses a similar idea to what i want and i have been looking at the code on the link below, however i do not fully understand how this code works in order to alter it to what I need to use the read text file.
http:/ /access.mvps.org/access/tables/tbl0009.htm
-------EDIT --------
I have tried to edit the following section to use the read text function
Function fGetMDBName(strIn As String) As String
'Calls GetOpenFileName dialog
Dim strFilter As String
strFilter = ahtAddFilterItem(strFilter, _
"Access Database(*.mdb;*.mda;*.mde;*.mdw) ", _
"*.mdb; *.mda; *.mde; *.mdw")
strFilter = ahtAddFilterItem(strFilter, _
"All Files (*.*)", _
"*.*")
fGetMDBName = ahtCommonFileOpenSave(Filter:=strFilter, _
OpenFile:=True, _
DialogTitle:=strIn, _
Flags:=ahtOFN_HIDEREADONLY)
End Function
By replacing all the code with
fGetMDBName = Passmyfile
You are mixing apples and oranges in what you are trying to do. Here are my suggestions:
Make sure your module has 'Option Explicit' then compile all your code. I see variables referenced but have no idea what TYPE they are.
Change your Function 'ReadDbPassword()' to return a string variable, then set it to return Passthedata4.
The second Function you listed (fGetMDBName) is opening a File Dialog box to allow you to select a file name. You do not need that since you already will have the file path/name from your first Function.
Then adapt the code you found that does the relink to use the path/name from your subroutine.
I have been using the following command to open another MDB Access file via VBA:
Shell "cmd /c " & Chr(34) & strNewFullPath & Chr(34), vbHide
strNewFullPath is the full path of the MDB file.
Works fine when using Access 2010, but doesn't run on Access 2003.
If I run the command in a XP DOS terminal it DOES run.
What other command can I use that should work on Access 2003 up and with the Access Runtime?
If you want want to use Access VBA to open a database in another Access application instance, you can do this:
Dim objApp As Access.Application
Set objApp = New Access.Application
objApp.UserControl = True
objApp.OpenCurrentDatabase "C:\Access\sample.mdb"
Set objApp = Nothing
Setting UserControl to True leaves the new application instance open after the procedure finishes.
If you want the new Access instance hidden, include:
objApp.Visible = False
I'm suggesting this approach because it also gives you a way to automate the new application instance through the objApp object variable. But, if you're not interested in automating the new instance, this approach will probably only be useful if you can't make any other method work.
Try using Windows Scripting Host Object Model (WSHOM):
Sub RunFile(filename As String)
Dim oShell As Object
Set oShell = GetShell
If Not oShell Is Nothing Then
oShell.Run filename
End If
End Sub
Function GetShell() As Object
On Error Resume Next
Set GetShell = CreateObject("WScript.Shell")
End Function
The Windows file association should allow both types of files to open in their native application.
Sample Usage:
RunFile strNewFullPath
Optional Arguments:
There are two optional arguments for the Run method. Please note that much of this is copied from MSDN:
intWindowStyle (integer)
A number from 0 to 10:
0 - Hides the window and activates another window.
1 - Activates and displays a window. If the window is minimized or maximized, the system
restores it to its original size and position. An application should
specify this flag when displaying the window for the first time.
2 - Activates the window and displays it as a minimized window.
3 - Activates the window and displays it as a maximized window.
4 - Displays a window in its most recent size and position. The active
window remains active.
5 - Activates the window and displays it in its current size and position.
6 - Minimizes the specified window and activates the next top-level window in the Z order.
7 - Displays the window as a minimized window. The active window remains active.
8 - Displays the window in its current state. The active window remains active.
9 - Activates and displays the window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when restoring a minimized window.
10 - Sets the show-state based on the state of the program that started the application.
I am not aware of the default value for this parameter. Note that some programs simply ignore whatever value you set (I couldn't tell you which ones).
bWaitOnReturn (boolean)
Set to False for asynchronous code. The Run method returns control to the calling program before completing. Default is False.
You can use the Win32 API to find the EXE name associated with the file type and prepend it to your shell command like this:
Private Declare Function FindExecutable Lib "shell32.dll" Alias "FindExecutableA" (ByVal lpFile As String, ByVal lpDirectory As String, ByVal lpResult As String) As Long
Public Function GetExecutableForFile(strFileName As String) As String
Dim lngRetval As Long
Dim strExecName As String * 255
lngRetval = FindExecutable(strFileName, vbNullString, strExecName)
GetExecutableForFile = Left$(strExecName, InStr(strExecName, Chr$(0)) - 1)
End Function
Sub RunIt(strNewFullPath As String)
Dim exeName As String
exeName = GetExecutableForFile(strNewFullPath)
Shell exeName & " " & Chr(34) & strNewFullPath & Chr(34), vbNormalFocus
End Sub
The problem with your shell command is the cmd prompt don't always support using the file extension to start a program. In fact, you better off to use
Start "path to some file with .extension"
The above is quite much the same as clicking.
However, what you really want to do is launch the msacces.exe and SUPPLY the path name to the file for it to open. This is especially the case with a runtime install.
So your code should look like this:
Sub testjump()
' jumps to a mde file called "upgrade.mde"
' it exists in the same directly as the currently running program
Dim strShellProg As String
Dim strCurrentDir As String
Const q As String = """"
strCurrentDir = CurrentProject.path & "\"
' path to msaccess is required here
strShellProg = q & SysCmd(acSysCmdAccessDir) & "msaccess.exe" & q
strShellProg = strShellProg & " " & q & strCurrentDir & "RidesUpGrade.mdE" & q
If Shell(strShellProg, vbNormalFocus) > 0 Then
' code here for shell ok
Application.Quit
Else
' code here for shell not ok
MsgBox "Un able to run Rides upgrade", vbCritical, AppName
Application.Quit
End If
End Sub
So the above uses the full path name to msaccess.exe. It been tested on xp, vista, win7 etc, and it always worked for me.
And in the case of more than one version of Access, or that of using a runtime, you may not want to use the extension to launch the file. So this ensures that you are using the SAME version and same .exe that you are currently running. So the above code pulls the current msaccess.exe path you are using, not one based on file extension.
I use this function when working in Access 2003:
Public Function RunExternalMDB(MDBName As String, WG As String, UsrNm As String, Pwd As String)
Shell "MsAccess.exe " & """" & MDBName & """" & " /wrkgrp " & """" & WG & """" & " /user " & UsrNm & " /pwd " & Pwd
End Function
This does work in Runtime mode : )
Here is a slight revision I used to make it work with accdr, where it is required that there be a runtime switch used.
strShellProg = q & SysCmd(acSysCmdAccessDir) & "msaccess.exe" & q & " /runtime"
strShellProg = strShellProg & " " & q & strCurrentDir & "spfe.accdr" & q
If Shell(strShellProg, vbNormalFocus) > 0 Then
DoCmd.Hourglass False
' DoCmd.Quit
Application.Quit
Else
' code here for shell not ok
MsgBox "Unable to run upgrade", vbCritical, AppName
DoCmd.Hourglass False
Application.Quit
End If
Is there a way in Access to search for a certain text in object properties and so on? Just not only in the VBA source code.
I'm asking this because if I change for example the name of a field in a table I've to check a lot of object properties (Record Source, Control Source, Order By, ...). This can be done by trail-and-error or by checking all properties of each control of the forms, but that takes a lot of time.
One option is the Find and Replace tool (nice tool!), but it's a bit of overkill for me. I don't need a text replace (only 'find') and it's 37 dollar for a tool I'll only use a few times a year.
Other suggestions?
There is something I often use to find out where some function or query may be hidding somewhere unexpected (in a bound control's RowSource of within a sub-query for instance).
I use an undocumented feature to export all Access objects as raw text files.
Using a text editor that can search within files recursively under a folder(like the free Notepad++ for instance) I am then confident that I find all occurrences, however buried, of a particular string.
The Code for exporting all objects includes my IsBlank() function:
'====================================================================
' Name: DocDatabase
' Purpose: Documents the database to a series of text files
' From: http://www.datastrat.com/Code/DocDatabase.txt
' Author: Arvin Meyer
' Date: June 02, 1999
' Comment: Uses the undocumented [Application.SaveAsText] syntax
' To reload use the syntax [Application.LoadFromText]
' Modified to set a reference to DAO 8/22/2005
' Modified by Renaud Bompuis to export Queries as proper SQL
'====================================================================
Public Sub DocDatabase(Optional path As Variant = Null)
If IsBlank(path) Then
path = Application.CurrentProject.path & "\" & Application.CurrentProject.Name & " - exploded view\"
End If
On Error Resume Next
MkDir path
MkDir path & "\Forms\"
MkDir path & "\Queries\"
MkDir path & "\Queries(SQL)\"
MkDir path & "\Reports\"
MkDir path & "\Modules\"
MkDir path & "\Scripts\"
On Error GoTo Err_DocDatabase
Dim dbs As DAO.Database
Dim cnt As DAO.Container
Dim doc As DAO.Document
Dim i As Integer
Set dbs = CurrentDb() ' use CurrentDb() to refresh Collections
Set cnt = dbs.Containers("Forms")
For Each doc In cnt.Documents
Application.SaveAsText acForm, doc.Name, path & "\Forms\" & doc.Name & ".txt"
Next doc
Set cnt = dbs.Containers("Reports")
For Each doc In cnt.Documents
Application.SaveAsText acReport, doc.Name, path & "\Reports\" & doc.Name & ".txt"
Next doc
Set cnt = dbs.Containers("Scripts")
For Each doc In cnt.Documents
Application.SaveAsText acMacro, doc.Name, path & "\Scripts\" & doc.Name & ".txt"
Next doc
Set cnt = dbs.Containers("Modules")
For Each doc In cnt.Documents
Application.SaveAsText acModule, doc.Name, path & "\Modules\" & doc.Name & ".txt"
Next doc
Dim intfile As Long
Dim filename as String
For i = 0 To dbs.QueryDefs.count - 1
Application.SaveAsText acQuery, dbs.QueryDefs(i).Name, path & "\Queries\" & dbs.QueryDefs(i).Name & ".txt"
filename = path & "\Queries(SQL)\" & dbs.QueryDefs(i).Name & ".txt"
intfile = FreeFile()
Open filename For Output As #intfile
Print #intfile, dbs.QueryDefs(i).sql
Close #intfile
Next i
Set doc = Nothing
Set cnt = Nothing
Set dbs = Nothing
Exit_DocDatabase:
Debug.Print "Done."
Exit Sub
Err_DocDatabase:
Select Case Err
Case Else
MsgBox Err.Description
Resume Exit_DocDatabase
End Select
End Sub
To use it, just call DocDatabase from the Immediate window in the Access IDE, it will create a set of directories under and 'Exploded View' folder that will contain all the files.
Another option is to temporarily turn on the NAME AUTOCORRECT option. It's a badly implemented feature and can damage your database if left on for production deployment, but I very often use it when taking over an Access app created by somebody else in order convert it to use my naming conventions.
You basically turn it on, let it build the dependencies table, then make your changes. You can then walk the tree of dependencies to confirm that it got them all. When you're done, you turn it off.
However, it doesn't work for VBA code. But for changing field names and the like, it's pretty useful if used carefully.
I amended the code above to strip out temporary objects with "~" in the object name as follows:
Set cnt = dbs.Containers("Scripts")
For Each doc In cnt.Documents
If Not doc.Name Like "~*" Then
Application.SaveAsText acMacro, doc.Name, path & "\Scripts\" & doc.Name & ".txt"
End If
Next doc