4

I have an Excel spreadsheet template with VBA code (an 'xltm' file).

I want to find the path of the template in the spreadsheet that is opened by the template.

Example of the problem:

  • A user opens a new spreadsheet from the template file in 'C:\My Stuff' by double clicking it.
  • They fill in the cells, then click a button that creates a text file after asking them what to call it.
  • The code then uses Application.ActiveWorkbook.path to save the text file in the same place as the spreadsheet is open.
  • This causes a permission error, as the spreadsheet hasn't yet been saved, and as such, doesn't have a path.

Is there a way to find the original template's file path? In the example C:\My Stuff.

I could make the user save the file before the text file is created, or I could just use an xlsm file but a template will minimise the chance of messing up the formatting of the file. I don't want to ask them to save the file each time. They'll probably copy and paste most data in, then just want the text file, not a different spreadsheet each time.

Community
  • 1
  • 1
James R
  • 141
  • 2
  • 14

4 Answers4

4

So my question is: Is there a way to find the original template's file path? In the example this would be C:\My Stuff.

You can't.

I am sure this is not the answer you were looking for but unfortunately this is the answer.

If you double clicked the template in explorer to create a file then AFAIK you cannot find that path or template name like you can do in MS Word using oDoc.AttachedTemplate

Alternative

In your template, put this code in ThisWorkbook

Private Sub Workbook_Open()
    ChDir "C:\Blah Blah" '<~~ Change this to the templates path
End Sub

And then from the new workbook that you created by double clicking the template you can use CurDir to get that path.

Drawbacks of the above method

  1. The Workbook_Open() code gets carried over to the new file
  2. If the user changes the location of the template then you will not get the right path
Siddharth Rout
  • 147,039
  • 17
  • 206
  • 250
  • Thanks, you're right, that's not the answer I was looking for, but at least I know it can't be done now. I'll try your suggested solution. – James R Nov 06 '14 at 11:28
  • @JamesR alternatively instead of hardcoding the file path into a macro with side effects you can hardcode the path in the template files as simple string in a cell in a hidden sheet before deploying them.. – xmojmr Nov 06 '14 at 15:23
1

There's a way to do what you want...sort of. The name or path of the original template can't be known, because Excel makes an instant copy of it to create the new workbook, and it doesn't expose any properties with that information. But, the template can be identified by a unique tag which can then be accessed in the new workbook. And the tag doesn't have to be anything funky like a secret cell, hidden worksheet, or hidden textbox. It uses a rarely mentioned built-in feature of Excel called CustomDocumentProperties.

To do this requires a bit of extra VBA code that you may not be familiar with. Specifically, a VBA project reference to MSO.DLL, aka the Microsoft Office X Object Library, where "X" is the version of office. In my case, it's Office 2007, which is version 12, so it's Microsoft Office 12.0 Object Library.

To give the template a tag, simply add a custom document property to it. This can be done right from the main Excel window while you have the workbook open, as follows:

Click the Office Button > Prepare > Properties as shown below:

enter image description here

This opens the yellow Document Properties bar with various textboxes such as Author, Title, etc:

enter image description here

Then click Document Properties > Advanced Properties...

enter image description here

This opens the Workbook Properties window:

  • Click the Custom tab.
  • Type a property name.
  • Type a property value.
  • Click the Add button.

enter image description here

The new custom property will appear in the Properties list. Click the OK button:

enter image description here

Now for that bit of extra VBA I mentioned...

Open the VBA editor window, click Tools > References, and add a reference for Microsoft Office X Object Library (assuming you don't already have it), where X is your version of Office. If it doesn't appear in the list, you'll have to browse for it, and it could be in a variety of places depending on your version of Windows and Office.

This is how it appears IF you already have it. In my case it's already there and the box is checked:

enter image description here

If you scroll way down to the Microsoft items in the middle of the list, and you don't find it, poke the browse button. Note that if it is in the list, but you miss it, adding it again won't hurt anything. Plus sometimes it's just easier to do that instead of staring at the list for five minutes.

On my 32-bit dev-beater box, the path is as follows. I think this should also be the same for 64-bit Windows with 64-bit office, but I'm not sure.

C:\Program Files\Common Files\Microsoft Shared\OFFICE12\MSO.DLL

On my 64-bit Windows desktop machine with 32-bit Office, it's:

C:\Program Files (x86)\Common Files\Microsoft Shared\OFFICE12\MSO.DLL

Remember to change the OFFICE12 to the version of Office you have if that's not it. Once you have it, click the OK button.

Now for the code...

In the VBAProject Explorer, double-click ThisWorkbook and add the following code. If you already have a Sub Workbook_Open, you'll have to integrate this into that as you see fit. Then once you see how it works, you can use it however necessary:

Private Sub Workbook_Open()
    Dim xl      As Excel.Application
    Dim wb      As Excel.Workbook
    Dim dcps    As Office.DocumentProperties
    Dim dcp     As Office.DocumentProperty
    Dim tname   As String
    Const dq As String = """"
    Set xl = Excel.Application
    Set wb = xl.ActiveWorkbook
    Set dcps = wb.CustomDocumentProperties
    Set dcp = dcps.Item("ThisTemplateName")
    tname = dcp.Value
    MsgBox "This workbook was created from the template named " & dq & tname & dq & "..!"
End Sub
spinjector
  • 3,121
  • 3
  • 26
  • 56
0

The issue is that, in an unsaved workbook, Application.ActiveWorkbook.path is undefined. Here is a method that exposes the template path to the unsaved workbook. It requires two batch (command) files to be in the same folder as the Excel Template.

The first batch file, SetVariable.cmd, creates an environment variable.

@echo off

rem Create an environment variable That Excel macro can read
setx TTxyPATHzz "%cd%"

Because of the way Windows handles environment variables, the value is not immediately available to the current console session. (Source)

Therefore, the second command file, OpenInstance.cmd is needed.

@echo off
:: This boot-strap script enables the use of an environment variable which can be read by an Excel macro
:: Because of the way user environment variables are created, run SetVariable the first time you use template.

rem Create an environment variable That Excel macro can read
rem Setting the variable again will allow the location to change.
setx TTxyPATHzz "%cd%"

rem Invoke cmd.exe to open instance of Excel template
FOR /F "usebackq delims==" %%i IN (`dir *.xltm /B`) DO start excel /n "%%i"

In the template's Workbook.Activate event handler for ThisWorkbook, include the following:

Private Sub Workbook_Activate()

   Dim CurrentLocation As String

   CurrentLocation = Environ("TTxyPATHzz")

   ' Your workbook now knows where the template is located.
   
End Sub

Instruct the users to double-click SetVariable.cmd one time. Thereafter, users just have to double-click OpenInstance.

The choice of name for the environment variable is arbitrary and is intended to avoid accidentally overwriting an existing variable.

-1

I am working on a similar task. I am using the following as my starting point:

MsgBox Application.TemplatesPath

https://learn.microsoft.com/en-us/office/vba/api/excel.application.templatespath

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 08 '22 at 02:50