How to Refresh Excel Smart View Essbase using Macro - vba

I'm using below code to refresh Essbase feeds in my workbook and it is working nicely, however, the only downfall is that I need to enter password every time I refresh the essbase as our Essbase system is highly secured.
My question is, is it possible to incorporate the Password in the macro so that I don't have to enter the password every time I refresh the feeds.?
Solving this problem would also enable me to automate this whole process through Python and schedule a job.
Private Declare PtrSafe Function HypMenuVRefreshAll Lib "HsAddin" () As Long
Sub RefreshHFM()
Call HypMenuVRefreshAll
End Sub
Any help.?
Thanks.

The HypMenuVRefreshAll command is basically the equivalent of clicking on the refresh button, and of course it is going to prompt you for a password because that's exactly what would happen if you clicked on the menu yourself. There are other commands, however, for the other menu items as well as the actual API that can be used to connect. You can connect with the following code:
Private Sub cmdConnect_Click()
Dim lReturn As Long
Dim sMessage As String
''' try to connect
lReturn = EssVConnect("sheet name", "admin", "password", "epmvirt11124", "sample", "basic")
''' show a message if necessary
If lReturn <> 0 Then
sMessage = EssVGetLastErrorMessage()
MsgBox "EssVConnect status = " & lReturn & ". Error Message = " & sMessage
End If
End Sub
I have borrowed this code from a button that connects to a specific cube. Be sure to update the username, password, server name, application, and cube to match your environment.
Please also note that this is part of the "old" Essbase VB API that works with the "classic" Excel add-in. The code is different for Smart View, which came with a completely different VB API.

Related

Disconnecting users and removing .laccdb file - Office 365

I have .adcde frontend + .accdb backend database located on local shared drive, used by 10 users at the moment. They are using shortcuts to access frontend file. I have struggled to make regular updates as users constantly left DB open so I implemented idea from MSDN website ( https://learn.microsoft.com/en-us/office/troubleshoot/access/shut-down-custom-application-remotely )
Solution works well on my machine, however, when utilized in user environment, it seems to leave .laccdb locks on both frontend and backend (which I deduct should be closed in moment when last connection to frontend closes)
Any hints? Do I understand this structure incorrectly?
Private Sub Form_Open(Cancel As Integer)
boolCountDown = False
DoCmd.Maximize
DoCmd.Restore
Me.Visible = False
End Sub
Private Sub Form_Timer()
On Error GoTo Err_Form_Timer
Dim strFileName As String
strFileName = Dir(filelocation/chkfile.ozx)
If boolCountDown = False Then
If strFileName <> "chkfile.ozx" Then
boolCountDown = True
intCountDownMinutes = 2
End If
Else
intCountDownMinutes = intCountDownMinutes - 1
'DoCmd.OpenForm "aShutDownWarning"
Me.Visible = True
Me.SetFocus
Forms!aShutDownWarning!txtWarning.Caption = "This application will be shut down in approximately " & intCountDownMinutes & " minute(s) due to maintenance works. Please save all work."
If intCountDownMinutes < 1 Then
Application.Quit acQuitSaveAll
End If
End If
end sub
That should work but I guess, since the laccdb files are still there, that one or more user are actually not logged out.
If they logg out from their account or from their computer the Access files can still be open but not running, so your code is not really running.
I solved a similar situation by adding usernames to a table when they start the program and delete the same username when program are closed. That way I could see users that was not logged out by a similar code.
If you're able to delete the .laccdb files manually then no one is still logged in and some user's Access session was simply unable to clean up after itself when it terminated. This might be caused by a user not having delete access to the folder where the .laccdb file is. Otherwise, someone is still logged in. You can use the Jet UserRoster to see who is logged in. If you want to make your own viewer see https://learn.microsoft.com/en-us/office/troubleshoot/access/determine-who-is-logged-on-to-database or see this utility at https://www.utteraccess.com/topics/1897146

How to bypass MSAccss AutoExec macro and bypass Startup form

How do I bypass the MSAccess autoexec macro and startup form for a deep-legacy code upgrade of a large MS Access 2003 application with hundreds of forms and reports?
It is an upgrade from Access 2003 to Access 2016, 2019 or 365.
This is a mission critical system kept alive and on crutches for 15 years without any VBA code updates.
Files in the application
Multiple MSAccess files in MDB and ACCDB format
No MSAccess files in MDE or ACCDE formats with compiled VBA code
No MSAccess other files wuch as mdw security files
I run a dos command for the database - PATH_TO_MSACCESS.exe DB_NAME.mdb
I'm using MSAccess.exe 32 bit from Office 365.
Note that there are compatibility and VBA compiler errors if you run on a 64 bit MSAccess.exe if the VBA calls Windows operating system Win32 API methods. This app calls a few (5) Win32 API calls. Technical, MS Access 64 bit will treat some 32 bit data sent in/returned from the Win32 API as 64 bit causing errors.
The most difficult part is that many of the web pages and nearly all Microsoft pages related to this have been deleted from the web.
Tried but did not work
Holding down shift key when you open the MSAccess database
Hitting F11 to open the Navigation Pane in Access (does not open). If Navigation Pane opens I could edit the AutoExec macro or the startup form's Form_Open code
Tried, not perfect, and works
Run a macro which does not exist on MSAccess.exe command line, hit escape multiple times on the error messages, the click on the MSAccess ribbon to get to the VBA code. Messy, but it gets me into the VBA code.
Added a "Stop" as the first line of the macro named "autoexec" and also as the first line of the startup form's "Form_Open()" method. I had to add an empty "Form_Open()" event handler for the form
Current status:
The application runs OK on a machine with MS Access version before 2016
It fails multiple ways when only 32 bit MS Access 365/2019 is installed on the machine.
I have been finding and fixing things like bad configuration file entries, incorrect installation path, etc. but need to debug the VBA startup code and initial form load in the VBA debugger.
I cannot directly get into the VBA debugger on the first line of the AutoExec macro or start up form's Form_Open function. MSAccess always runs the autoexec macro and shows the startup form.
I can get into the VBA by running MSaccess.exe command line and specifying that it runs a macro which does not exist.
Here are possible solutions based on Google searching broken out by Access version since the code/database settings in question could be specific to any Access version from 95 to 2010.
Access 2007: Opening an MS-Access database from the command line without running any of the startup vba code?
Hold down shift key when opening MDB database
Access XP
Open access database without executing scripts or forms
Hold down shift key when opening the Access database
Remove AutoExec macro
Remove the startup form setting from the database
Access 2007:
Emulating a SHIFT key press when using VBA to open an ms-access database secured by an mdw file?
Slightly different case where the Access database is secured by a MDW security file
Same answers
Access XP/2003/2007?
How to skip Autoexec macro when opening MSAccess from MSAccess?
Method One:
Original URL is dead, Internet Archive Wayback machine has an archived copy: https://web.archive.org/web/20101204113950/http://www.mvps.org/access/api/api0068.htm
Send Shift key to Access via code to bypass startup macro if the [AllowbypassKey] is not set
Method Two:
Extract the Autoexec macro from the database, replace it with a blank AutoExec macro
Uses DoCmd.DatabaseTransfer acImport and DoCmd.DatabaseTransfer acExport
Method Three:
Rename the AutoExec macro using VBA code
OpenCurrentDatabase ("Your database")
DoCmd.Rename "Autoexec", acMacro, "tmp_Autoexec"
CloseCurrentDatabase
MS Access keyboard short cuts for getting at the VBA code or objects in an Access database. From https://support.microsoft.com/en-us/office/keyboard-shortcuts-for-access-70a673e4-4f7b-4300-b8e5-3320fa6606e2
I haven't tried the MSAccess keyboard short cuts to see if they let me open and view the Access VBA code, toolbars, table/form dedign viewer, or switch to code editing mode. I've included them here for completeness.
F2 - Switch between Edit mode (with insertion point displayed) and Navigation mode in the Datasheet or Design view
F4 - Open properties pane for an object
F5 - Switch to Form view from the form Design view
F6 - Switch between panes in the MS Access interface
F10 (?) unhide the ribbon
F11 - Show or hide the Navigation Pane
Alt-X, Alt-X,1 - Open the External Data tab in the ribbon
Alt-Y - Open the Database Tools tab in the ribbon
Alt-J,T - Open the Table tab in the ribbon
Alt-X,2 - Open the Add-ins tab in the ribbon
Control-F1 - Expand/collapse the ribbon
Alt-F11 - Switch to/from the VBA editor
Show or hide the MSAccess ribbon toolbar in VBA code. Included here for completeness. This application hides the ribbon bar on application startup.
MSAccess - Minimize the Toolbar Ribbon OnLoad()?
MSAccess 2010 onwards. The acToolbarNo is in the VBA code for this application
DoCmd.ShowToolbar "Ribbon", acToolbarNo 'Hides the full toolbar
DoCmd.ShowToolbar "Ribbon", acToolbarYes 'Show
MSACcess 2010, 2013
CommandBars.ExecuteMso "MinimizeRibbon"
Before MSAccess 2010
SendKeys "^{F1}", False
Special case: You may get an error on the Access startup form if it has a record source which has an error. this is not the case for my application but included here completeness
difficulty tracing microsoft access VBA code
Special case: You get an infinite loop of dialog prompts or errors from the startup form. Hold down the "Control-Break" key while clicking on OK for the error message to break out of the loop of errors. https://bettersolutions.com/vba/debugging/index.htm
It may be possible to break out of the main startup form to the MS Access object explorer by right clicking on the startup form's title bar or right click on the startup form's body.
Right clicking on the startup form's title bar has these menu commands
Save
Close and Close All
Form View
Layout View
Design View
Right clicking on the startup form's body has these menu commands
Form View
Layout View
Design View
Cut, Copy, Past (disabled)
Form Properties (disabled)
Properties (disabled)
Close
the other thing to check? Are you using a shortcut? if it has the /runtime swtich in it, then the shift key will be ignored NO MATTER what you do, and even if no shfit key by-pass code (to disable) shift key means the shift key will STILL be ignored. So, you want to ensure that you not launching/using a shortcut.
you also want to check/ensure/find out/be aware if the application has workgroup security. Again, in 99 out of 100 cases, the shortcut will show this.
next up:
is this a mdb, or mde file? The mde file is a compiled version. No source code exists, and you can't modify the mde. So, again, ensure that you have a mdb file for the front end, not a mde. If you don't have that mdb, then you are in big trouble - you don't have the source code.
You have all this info in your post, but you leave out the most important issues.
So, is this a mde, or mdb? You need to know this.
Is there a worgroup security file (mdw) specifed in the link that is typical used to launch the application. If workgroup secuirty is involed, then the logon id you use might get you past shift key, but then that user might not have been given design rights, so at that point, shify key by-pass will be of zero use to get into the code.
I mean, launch your copy of access 2016 or whatever. Then try to import the objects from that database. This way you don't have to use or ever worry about shfit key, but are doing a simple import of the forms, reports and code into a brand new fresh database.
So, another question:
Don't bother launching the application - create a blank new database, and then import from the existing - can you do this? (doing this does NOT copy the shift key setting of the original database).
MSAccess command line lets you tell it what macro to execute on startup.
I ran the following cmd.exe command line which generates multiple errors and allows you to get into the Access database with the navigator and get into the VBA code. Not the best solution but one possibility.
MSAccess.exe DB /X ADEEERETDEREAR
DB is the full path to the Access database
ADEERETDEREAR is a macro which does not exist
Access 2007?
How to disable Macro and Start-Up values while opening the MS Access DB
Access 2003?
Bypasss shift key. These link to Zip files projects available for download
https://web.archive.org/web/20071214172548/http://www.members.shaw.ca/AlbertKallal/msaccess/msaccess.html
https://web.archive.org/web/20071214172548/http://www.members.shaw.ca/AlbertKallal/msaccess/shiftkey.zip
https://web.archive.org/web/20071214172548/http://www.members.shaw.ca/AlbertKallal/msaccess/shiftkey2000.zip
Access 2007:
remove autoexec macro from MS Access 2007
Create new macro and then rename it in the Access UI to autoexec, say yes to the prompt to overwrite the existing AutoExec macro
Access 2010?
Opening an MS-Access database from the command line without running any of the startup vba code?
Access ?
Disable F11 Key in MS Access to prevent opening the Navigation Pane
Open the Access database, let the main form be shown
Hit F11 to show the navigation pane
A guess that one could modify the autoexec macro and/or the startup form from the navigation pane
Access ?
https://bytes.com/topic/access/answers/211664-programatically-set-startup-form
A guess that you could use VBA in one Access database to open the target database
Get the name of the startup form
Change the startup form's name or maybe blank out the startup form's name
VBA code similar to CurrentDB.Properties("StartupForm") = "MyForm"
Another guess would be to blank out the startup form's name in the database properties
Same may work for the autoexec macro
Access 2010?
Reset startup form to nothing in VBA code
Code from 2012 is here: https://www.tek-tips.com/viewthread.cfm?qid=1673392
First way
Dim strOriginalForm as String
Dim db as Database
Sub RemoveStartup()
Set db = OpenDatabase(yourdatabase)
strOriginalForm = db.Properties("StartUpForm")
db.Properties("StartUpForm") = "(none)"
db.Close
set db = Nothing
End Sub
Sub ResetStartup()
Set db = OpenDatabase(yourdatabase)
db.Properties("StartUpForm") = strOriginalForm
db.Close
Set db = Nothing
End Sub
Second way
Set prp = db.CreateProperty("AllowByPassKey", dbBoolean, True)
db.Properties.Append prp
Third way
Delete the property using - database.properties.delete propertyname
A more complete example from the same page exists.
I have not tried to import the Access objects into a new database. (Thanks Albert Kallal for the information)
This would allow me to look at the VBA code. It may not work as a replacement for the original database with all of the settings internal to the database.
How to import the Access objects from another Access database:
https://support.microsoft.com/en-us/office/import-database-objects-into-the-current-access-database-23aea08b-7487-499d-bdce-0c76bedacfdd
Access 365 steps (likely works for Access 2016)
External Data tab in ribbon
Click New Data Source -> From Database -> Access in the Import & Link ribbon group
Get External Data - Access Database window is shown
Browse for the MSAccess database MDB or ACCDB file in the File Name Field
The Import Objects window is shown
Select the tables, queries, forms, reports macros, modules to import
In the Options button dialog, you can select menus, toolbars, etc. to import
Click on OK
For Names duplicated, Access will append a 1,2,3 to the end of an imported object's name
Access 2010?
Reset startup form to nothing in VBA code
Code from 2012 is here: https://www.tek-tips.com/viewthread.cfm?qid=1673392
Fourth way as mentioned above
A more complete example from the same page.
Code from 2012 is here: https://www.tek-tips.com/viewthread.cfm?qid=1673392
Public Sub GetCBs()
Dim db As DAO.Database
Dim strPath As String
Dim startUpform As String
Dim app As Access.Application
Dim custBars As Collection
Dim custShortCutBars As Collection
Dim custNonShortCutBars As Collection
Dim i As Integer
Dim blnAutoexec As Boolean
strPath = GetOpenFile()
'Get the db without opening in application
Set db = getDb(strPath)
'Get startupform
startUpform = getStartUp(db)
'Turn off the start up form
TurnOffStartUp db
'Check for and auto exec. If exists import and replace
If hasAutoexec(db) Then
blnAutoexec = True
ImportAutoExec (strPath)
End If
Set app = New Access.Application
'Open safely
app.OpenCurrentDatabase (strPath)
'Read command bars
Set custBars = getCustBars(app)
Set custShortCutBars = getCustShortCutBars(app)
Set custNonShortCutBars = getCustNonShortCutBars(app)
app.CloseCurrentDatabase
Set db = app.CurrentDb
Set db = getDb(strPath)
'Return start up form
TurnOnStartUp db, startUpform
db.Close
'Return auto exec
If blnAutoexec Then
ReturnAutoExec (strPath)
End If
Debug.Print "all custom bars:"
'All bars
For i = 1 To custBars.Count
Debug.Print custBars(i)
Next i
'Do something with the command bars
Debug.Print "all shortcut bars:"
'Short cut only
For i = 1 To custShortCutBars.Count
Debug.Print custShortCutBars(i)
Next i
'Not short cut
Debug.Print "Non shortCut"
For i = 1 To custNonShortCutBars.Count
Debug.Print custNonShortCutBars(i)
Next i
End Sub
Public Function getDb(strPath As String) As DAO.Database
Set getDb = DBEngine(0).OpenDatabase(strPath)
End Function
Public Function getCustBars(app As Access.Application) As Collection
' all bars
Dim col As New Collection
Dim cb As Object
For Each cb In app.CommandBars
If cb.BuiltIn = False Then
col.Add (cb.Name)
End If
Next cb
Set getCustBars = col
End Function
Public Function getCustShortCutBars(app As Access.Application) As Collection
' only short cut bars
Dim col As New Collection
Dim cb As commandbar
For Each cb In app.CommandBars
If cb.BuiltIn = False Then
If cb.Type = msoBarTypePopup Then
col.Add (cb.Name)
End If
End If
Next cb
Set getCustShortCutBars = col
End Function
Public Function getCustNonShortCutBars(app As Access.Application) As Collection
' Menu bars that are not shortcut bars
Dim col As New Collection
Dim cb As commandbar
For Each cb In app.CommandBars
If cb.BuiltIn = False Then
If cb.Type <> msoBarTypePopup Then
col.Add (cb.Name)
End If
End If
Next cb
Set getCustNonShortCutBars = col
End Function
Public Function getStartUp(db As DAO.Database) As String
Dim prp As DAO.Property
For Each prp In db.Properties
If prp.Name = "startupform" Then
getStartUp = prp.Value
Exit For
End If
Next
End Function
Public Sub TurnOffStartUp(db As DAO.Database)
Dim prp As DAO.Property
For Each prp In db.Properties
If prp.Name = "startupform" Then
prp.Value = "(None)"
Exit For
End If
Next
End Sub
Public Sub TurnOnStartUp(db As DAO.Database, strFrm As String)
Dim prp As DAO.Property
For Each prp In db.Properties
If prp.Name = "startupform" Then
prp.Value = strFrm
Exit For
End If
Next
End Sub
Public Sub ImportAutoExec(strPath As String)
On Error GoTo errLbl
DoCmd.TransferDatabase acImport, "Microsoft Access", strPath, acMacro, "AutoExec", "AutoExecBackup"
DoCmd.TransferDatabase acExport, "Microsoft Access", strPath, acMacro, "TempAutoExec", "AutoExec"
Exit Sub
errLbl:
If Err.Number = 7874 Then
Debug.Print "Auto Exec macro does not exist"
Else
MsgBox Err.Number & " " & Err.Description
End If
End Sub
Public Sub ReturnAutoExec(strPath As String)
On Error GoTo errLbl
DoCmd.TransferDatabase acExport, "Microsoft Access", strPath, acMacro, "AutoExecBackup", "AutoExec"
DoCmd.DeleteObject acMacro, "AutoExecBackup"
Exit Sub
errLbl:
If Err.Number = 7874 Then
Debug.Print "Auto Exec macro does not exist"
Else
MsgBox Err.Number & " " & Err.Description
End If
End Sub
Public Function hasAutoexec(db As DAO.Database) As Boolean
Dim rs As DAO.Recordset
Dim strSql As String
strSql = "SELECT MSysObjects.Name FROM MSysObjects WHERE MSysObjects.Name = 'AutoExec' AND MSysObjects.Type = -32766"
Set rs = db.OpenRecordset(strSql)
If Not (rs.EOF And rs.BOF) Then
hasAutoexec = True
End If
End Function

how to use environ function to avoid other from using my Access DB

I manage an Access DB (accdb) and it contains some information about my company that I don´t want others to access it out of my company´s server.
I thought to use Environ (5)=computername or Environ (12)=path to retrieve some references such as LEN(environ(path)). With this function, I could, for instance, make sure that the accdb file only works if LEN(environ(path))/2+15=55 (the lenght at my company´s server divided by 2 plus 15 = 80/2+15=55 = algorhytm).
So, on opening the db, it should prompt for a number/code. If the user inserts 55 and the filepath = 80, it will open. If filepath=100 (filepath out of my company´s server), must be prompted 100/2+15=65 to open the db.
Unfortunelly, I don't know how to programe it neither I know how to block the use of SHIFT (that breakes the VBA code on opening) because I'm a rookie.
So, if you please, can you help me to solve these huge problems (1. algorhytm using Environ, 2. avoid using SHIFT on opening).
Thanks in advance.
Bruno
Add this code to your startup form. When the form opens it will check for the username and computername, and if both match the form will open.
Private Sub Form_Open(Cancel As Integer)
If Not (Environ("username") = "santosh" And Environ("computername") = "ABC-CAP1-093") Then
Cancel = True
Application.Quit
End If
End Sub
Avoid using shift key - I have already answered see this link

Access autocad object properties without opening it by VBA

I have been using folder browser for VBA, I could paste the code of it, but bottom line is that I get returned file name as a string.
Is there any way to access drawing properties (i.e number of layouts) without open?
Public Sub TestFileDialog()
dwgname = FileBrowseOpen("C:", "*", ".dwg", 1) 'dwgname is typeof string
End Sub
Its only the first step (use of FileBrowseOpen function is shown, but also i can use FolderBrowse and collect all .dwg inside of folder),actually i had in mind to batch export all layouts of selected .dwgs to currenty open one. Is there any chance for that?
To effectively read a .dwg file you'll need to open AutoCAD, otherwise the information is not accessible. Some properties may be, such as author, but not number of layouts...
But you can use AutoCAD Console (accoreconsole.exe) to run a headless AutoCAD and use APIs to read any information you need. This is really fast for reading lot's of files and the user will not see it running (but it needs to be installed anyway).
http://aucache.autodesk.com/au2012/sessionsFiles/3338/3323/handout_3338_CP3338-Handout.pdf
you could stay in VBA and use ObjectDBX
it leads to a very similar approach as accoreconsole.exe on in .NET does, i.e you won't see any drawing open in UI since it works on the database itself
It requires adding library reference (Tools->References) to "AutoCAD/ObjectDBX Common XX.Y Type Library", where "XX.Y" is "19.0" for AutoCAD 2014
a minimal functioning code is
Sub main()
Dim myAxDbDoc As AxDbDocument
Dim FullFileName As String
FullFileName = "C:\..\mydrawing.dwg" '<== put here the full name of the file to be opened
Set myAxDbDoc = AxDb_SetDrawing(FullFileName)
MsgBox myAxDbDoc.Layers.Count
End Sub
Function AxDb_SetDrawing(FullFileName As String) As AxDbDocument
Dim DBXDoc As AxDbDocument
Set DBXDoc = Application.GetInterfaceObject("ObjectDBX.AxDbDocument.19") '<== place correct AutoCAD version numeber ("19" works for AutoCAD 2014)
On Error Resume Next
DBXDoc.Open FullFileName
If Err <> 0 Then
MsgBox "Couldn't open" & vbCrLf & vbCrLf & FullFileName, vbOKOnly + vbCritical, "AxDB_SetDrawing"
Else
Set AxDb_SetDrawing = DBXDoc
End If
On Error GoTo 0
End Function
Still, you must have one AutoCAD session running from which make this sub run! But you should have it since talked about "currently open" drawing

Capturing spreadsheet usage throughout a company

We have a lot of customized spreadsheet solutions that are being used and we want some programmatic way of keeping track of them. Obviously since they are spreadsheets, people can save them locally, rename them, etc so we need a solution that can account for that.
Some ideas are:
On spreadsheet open, handle the OnOpen event and write a message to a database for tracking
the issues with this are where do we store database details. If the database is down, we dont want the spreadsheet to crash, etc
has anyone come up with a good spreadsheet inventory management solution that handles all the issues above.
I don't understand the problem you're trying to solve here: you don't need spreadsheet usage logging as an end-result, something is causing pain and this is what you've devised to try to fix it.
If you need seriously reliable logging of all spreadsheet usage, then I don't think this is going to work. If you need mostly reliable logging, then just use a database and don't worry about the (rare) occasions that the database is down. On Error Resume Next should be enough to ensure the spreadsheet continues in that event.
That said, I'd be more inclined to go for a web-based solution: that way you don't have to get involved with ensuring everyone has the necessary database drivers, working connection strings and other horridness.
Some more awkward questions that are making me think that you may need another approach:
How are you going to deploy changes to your logging solution?
Do your users have control over their macro security level? Or the ability to write and edit macros? Could they therefore (innocently or otherwise) disable logging?
Can the users operate offline? What happens then?
Have the excel spreadsheet make a request out to a web server.
Add msinet.ocx to your toolbox and create a form with the Inet control. Add the ocx by right clicking somewhere in the toolbox area.
Then you can set the location of the Inet control somewhere you can handle that the spreadsheet was opened.
Although you may need logging in the short term, the long term solution should be to bring your spreadsheets under control. You should gather the "definitive" copy of the spreadsheets, and move them to a file share, where they will all be protected - users will be able to change the data in them, but will be unable to change the formulas.
If you need a more controlled collaboration solution, then you should look into using SharePoint, possibly the MOSS version which has Excel Services on it.
You might also need to explore how the spreadsheets are being used. Perhaps they are being used instead of someone writing a program, and in some cases, it may be time to do that.
Lastly, you don't want to track spreadsheet usage - you don't care if someone creates a spreadsheet to track their kid's soccer team scores. It's particular spreadsheets you're interested in. The logging may help you track that down to start with, but that's all it can help you with.
I like the suggestions being made so far and what you wrote. I personally like to keep things simple so here's my humble suggestion. It sounds like you have a lot of templates you may be managing and with excel things get messy quick and it's hard to know that formulas are not being tampered with. With that in mind I'd forget any database change management solution, instead:
Create a share drive folder that's set to read only and accessible by everyone in the company
You can create a sub folder structure that makes sense by team, department, location, whatever works
Store the latest copies of the excel templates in the folders
I'd also suggest locking the templates that have critical calculations in them
--> Try to leave it as open as you can so they can be customized where they need be but at your discretion
You may also consider setting up a version control repository that manages the changes to this folder structure. Look into version control with a simple interface like tortoiseSVN so you can track what changes were made and when. The standard share drive back ups are a life saver but I'd still supplement with a version control system (just makes things a little easier). Here's a couple of links to help you get started, you can try subversion locally and see what you think:
Instructions to setup Subversion on Windows
Tortoise Client to interact with Subversion
Also note, IF you chose to implement some kind of database connection for a spreadsheet to perform logging on a database server as has already been noted you can use "on error resume next". Here's what you can do:
After resume next attempt to open the connection to the DB
You can choose to handle the error then with an if statement such as:
if err.number = 3024 then
msgbox "Database file not found, check network connection and retry"
exit
end if
Here's a link to look up additional error codes for trapping in similar fashion:
Error Trapping in VBA
I do something very similar to this to check the current version of the Excel application. You could just as easily use this same code to make a web-request to a server that will log 'hits'. Here's my code:
In ThisWorkbook:
Option Explicit
Private Sub Workbook_Open()
Updater.CheckVersion
End Sub
Elsewhere (in a module called Updater)
Option Explicit
Const VersionURL = "http://yourServer/CurrentVersion.txt"
Const ChangesURL = "http://yourServer/Changelog.txt"
Const LatestVersionURL = "http://yourServer/YourTool.xlsm"
#If VBA7 Then
Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
#Else
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
#End If
Public Sub CheckVersion()
On Error GoTo fail
Application.StatusBar = "Checking for newer version..."
Dim ThisVersion As String, LatestVersion As String, VersionChanges As String
ThisVersion = Range("CurrentVersion").Text
If ThisVersion = vbNullString Then GoTo fail
LatestVersion = FetchFile(VersionURL, , True)
VersionChanges = FetchFile(ChangesURL, , True)
If LatestVersion = vbNullString Then
Application.StatusBar = "Version Check Failed!"
Exit Sub
Else
If LatestVersion = ThisVersion Then
Application.StatusBar = "Version Check: You are running the latest version!"
Else
Application.StatusBar = "Version Check: This tool is out of date!"
If (MsgBox("You are not running the latest version of this tool. Your version is " & _
ThisVersion & ", and the latest version is " & LatestVersion & vbNewLine & _
vbNewLine & "Changes: " & VersionChanges & vbNewLine & _
vbNewLine & "Click OK to visit the latest version download link.", vbOKCancel, _
"Tool Out of Date Notification") = vbOK) Then
ShellExecute 0, vbNullString, LatestVersionURL, vbNullString, vbNullString, vbNormalFocus
End If
End If
End If
Exit Sub
fail:
On Error Resume Next
Application.StatusBar = "Version Check Failed (" & Err.Description & ")"
End Sub
As you can see, error handling is in place to make sure that if the URL is unavailable, the app doesn't crash, it just writes a message to the user in the status bar.
Note that if you don't want to set up a web service that does this, you could try to have the spreadsheet write to a database - you could still re-use a lot of this code, but not as much of it.
Your idea is good. Database availability is usually higher than the availability of the users' laptop. And there is a kind of primitive error (exception) handling in VBA, so they won't necessarily see freaking error messages.
Yes, you have a loss. Any uses of the sheet saved offline when the user is not on your network - will be missing from the database. But I don't think that there's a 100% foolproof solution for this.
Try to search for a Financial Times article like "Excel - a tool that is too ad hoc and open for errors". Even the title says it all.
write to the db, if the write fails, catch the error and send an e-mail to someone that can manually increment the count when the database is back up.
You could do a file-based approach with any of several file integrity monitoring solutions. Samhain is one free open source example. That would allow your employees to access their spreadsheets without interference, but would report when new spreadsheets are discovered or when their timestamps or hash values change. It would also detect changes made while the developer was off-line (on their laptops, for example) once they've reconnected to the network.