views:

1738

answers:

6

Hi,

I'm new to VBA and have been throwing together a small macro application for the Office. We've got about 80 users on essentially identical PC setups, and it will be accessed by all but a few users.

I've been playing around with some automation of accessing web pages using the Web Services references, and I've also loaded the Microsoft Scripting Runtime references into the project. I attempted to run it on a test PC and it complained that there were missing references.

I don't particularly want to go around 80 PCs and manually load the references.

My question, basically, is how should I manage the distribution of this macro-app to 80 odd users so as to ensure that the references will load every time for every user.

Thanks!

+2  A: 

Instead of having the documents expose the functionality, make it an add-in for Office (the suite, or the individual apps, your choice). This way, you don't have to deal with references.

Then, just distribute an install package with the add-in which registers the components and registers the add-ins with the appropriate Office apps.

VB6 might be a good idea here, given it's similarity to VBA.

casperOne
+3  A: 

If you have references that your application depends on, that you know are not going to be on the target PCs, then I would strongly recommend you investigate some installer technology.

Using the installer you should be able to install your macro, and install and register all appropriate references / libraries.

There are generally two flavours on windows, Windows Installer based technology and Script based technology.

We use InstallShield for all of our deployment, although there are several options for you to use (there are several discussion on Stack Overflow).

Using windows installer technology, you can build MSI install files, which you are then able to deploy automatically using Group Policy.

Jayden
The installer technology will not allow to manage 'external software' references such as references to Office, Excel or Outlook object libraries. Another issue will then be when different machine use different versions of Excel ... I added some words on this specific issues in my answer.
Philippe Grondier
+1  A: 

In addition to this answer, which is the bullet-proof solution to solve this kind of issue, but which is quite complex to implement, you can also write some code to be executed when your VBA application starts, checking the 'references' collection of the 'application' object. You can then check (1) if requested files (dll, ocx, tlb) are available on the computer and (2) if reference can be created (application.references.addFromFile ...).

Be careful: object declarations that might be 'reference dependent', such as:

Dim cat as ADOX.catalog

will raise a compilation bug if the reference is not active when the corresponding module is 'compiled'. I then advise you to isolate your 'reference checking procedure' in a startup module (equivalent to an 'autoexec') which deals only with VBA and basic application objects. Check it with your Help Files (Example: in Access, default references that can be used without external references are VBA, Access and DAO).

EDIT:

in case external references depend on other software package and (1) cannot be distributed with a MSI file or (2) can have multiple versions, I think the 'references.addFromFile' is the only solution that can apply. Example:

  • You have an VBA/Access runtime client app that needs to refer to Word (msword.olb file).
  • For licensing issues, you cannot freely distribute this file with your msi pack
  • the olb file can be either the 'XP version or a newer one

Our solution is to have 2 tables on the client Access file. One lists all the references that have to be checked or added at startup time (Word will be one of them), and the other one lists all the possible locations of the file (depending if the user has the 'office11' version or a newer one), with a one to many relations between the 2 tables.

So, the best strategy could be a mix between msi packs and management through code:

  • msi is great for distributing independant dll's or other files that are totally 'embedded' in your app, such as activeX controls (like scanners controls, report or file viewers, etc)
  • code is the best solution where your app will have to communicate with other applications (word, excel, outlook, etc) that can exist in different versions on your user's machines.
Philippe Grondier
+1  A: 

For the most part, late binding will solve problems with references in VBA, unless you have some unusual references. Most problems are caused by differences in library versions that can be overcome with late binding. With VBA, it is often recommended that you develop with early binding but release with late binding. The main disadvantage of late binding is changing built-in constants to values (speed is no longer the issue it used to be.)

So:

Dim fs As Object 'Instead of FileSystemObject '
Dim xl As Object 'Instead of Excel.Application '

Set fs=CreateObject("Scripting.FileSystemObject")
Set xl=CreateObject("Excel.Application")

'Value instead of built-in constant '
ForReading=2
Set f = fs.OpenTextFile("c:\testfile.txt", ForReading)
Remou
A: 

Can you give me VBA code examples of 1) how to check if references exist, and 2) how to add a reference (AddFromFile) if one or more do not exist? Also, if I have a digitally signed document, will adding references programatically remove the signature?

This 'answer' should be copied to a new question.
Kenny Evitt
A: 

This is in response to Remou's post, above. I'm using VBA with Excel 2003. I have the following code which references the Outlook 2003 object library. The code opens a new Email message, sets the subject and recipient fields, and adds an attachment.

I would like to remove the reference so that it works equally well for Outlook 2007 users, without having to change the references.

' Create new Email.
With New Outlook.Application
    With .CreateItem(olMailItem)

        ' Set subject and recipients.
        .Subject = "Weekly Status Report: " & [ProjectName] & ", Week Ending " _
            & Format([DateEnd].Range("A1"), "mm/dd/yyyy")
        .To = [Email_To]
        .CC = [Email_CC]

        ' Add attachment. Display Email.
        .Attachments.Add strAttachment, olByValue, 1
        .Display
    End With
End With

How can I use generic object variables (which do not require a reference to the Outlook object library) in place of the "New Outlook.Application" and .CreateItem(olMailItem) object variables?

This 'answer' should be copied to a new question.
Kenny Evitt