I've made this short function to find whether a name is "given name surname" or "surname, given name", however when this is run by another user (on another PC), the result function In error #NAME? :
Function FindName_Function(NameCell As String) As String
Dim FindComma As Long
Dim FindName As String
FindComma = InStr(1, NameCell, ",")
If FindComma <> 0 Then
FindName = VBA.Right(NameCell, Len(NameCell) - FindComma)
Else
FindName = VBA.Left(NameCell, InStr(1, NameCell, " ") - 1)
End If
FindName_Function = FindName
End Function
This is how the function is called:
This is the formula:
="Hello "&FindName_Function(INDEX(Table_HP_Effective_contact_list;MATCH(SiteID;Table_HP_Effective_contact_list[Site];0);4))&","
I believe you use the function as a UDF (User Defined Function) and the #NAME error indicates that the function can't be found or executed. Make sure you store the UDF on a discoverable location and has permission to run. It is not clear from your question -where- you stored the UDF and what the security settings are on the client machines.
What I did is create a new Workbook, added a new Module to the Workbook, copied the UDF in the Module, used it in a cell on the new Workbook and worked without problems. So my guess from the limited information provided is that you stored the UDF in a different location outside the Workbook, inaccessible for the other users to find.
On a side note:
- the VBA. prefix is not necessarily needed
- test if the name is empty, InStr will fail if the name is empty
If you want a better answer, please elaborate on the location of the UDF (where did you create/store the UDF) and what are the macro security settings currently in place on the machines you see the error on.
if u save the function in the same workbook and saved the workbook in *.xlsm format, then the possible cause is user did not enable macro when opening the file.
if u save the function in the same workbook and saved the workbook in *.xlsx format, then u saved it in the wrong format.
if u save the function in another workbook, then that workbook should be saved in Excel Add-In format (*.xlam) and the Add-in must be loaded in Excel.
hope this helps
+
Try use the insert function window to find the function. Select category = "User Defined".
If the function is listed, then try call it from there.
If the function is not listed, then for sure macro for that workbook is not enabled.
Related
I just discovered that in MS Word it is possible to store a Variable in a MS Word File that can not be accessed through the regular interface when running Microsoft Word.
Sub SetMyVariable()
Dim VARNAME As String
VARNAME = "HiddenVar"
ActiveDocument.Variables.Add VARNAME, "My special info"
End Sub
This gets saved in the XML Schema under word\settings.xml
I have tried using the ThisWorkbook Object in Excel, but it doesn't seem to have a Variable object that can be added like in word.
I want to know if there is something similar in Excel to store information/varialbes that get saved with the file.
PS: the closest thing I can think of (and use in codig) is a hidden named range.
You can try with the CustomXMLParts property of the Workbook which from the link seems a generic feature of Office products and available in Excel. Given you noted that a user would have to manually inspect the XML within the unzipped xlsx files then this seems to map to the Word Variables feature. The code sample just substitutes ThisWorkbook for ActiveDocument:
Option Explicit
Sub TextXMLPart()
Dim objXMLPart As CustomXMLPart
'add
Set objXMLPart = ThisWorkbook.CustomXMLParts.Add("<foo>bar</foo>")
'inspect
For Each objXMLPart In ThisWorkbook.CustomXMLParts
Debug.Print objXMLPart.XML
Next objXMLPart
End Sub
The accepted answer to this question (which focuses on Excel and vsto) states that:
Custom XML parts For an application-level add in, this is my preferred method of storing any application data that needs to be persisted in a saved xls file without ever being visible to the user.
I am trying to make a custom function in Excel VBA using the complex number functions from the Analysis ToolPak VBA add-in. If I assign c = imSum(a, b) I get a popup error "Compile Error: Sub or Function not defined." If I change it to c = WorksheetFunction.imSum(a, b) (as what little I've found on this led me to try) I do not get the popup error but I get a #VALUE error in the cell. Changing the method name to something bogus creates the same result. I have both "Analysis ToolPak" and "Analysis ToolPak - VBA" add-ins checked in Excel but in the VBA add-in manager there are none listed at all. Is this a syntax thing or a missing module thing?
UPDATE...
I got this working using the simple format c = imSum(a, b) after checking "atvbaen.xls" in the references window. I also ran the command AddIns.Add("atvbaen.xls").Installed = True though I have no idea if this helped. Couldn't get [imSum(a, b)] evaluation or Application.WorksheetFunction.ImSum(a, b) to work.
In the worksheet, IMSUM() takes strings as input so in VBA:
Public Function whatever(s1 As String, s2 As String) As String
s3 = Application.WorksheetFunction.ImSum(s1, s2)
whatever = "Hello " & s3 & " World"
End Function
If you can't use IMSUB() in a worksheet cell, then there is little chance that VBA will be able to find it either.
EDIT#1:
Subs allow better debugging than UDFs. Try this sub and tell us what happens:
Sub HelpMePlease()
Dim s1 As String, s2 As String
Dim s3 As String
s1 = "1+1i"
s2 = "2+2i"
s3 = Application.WorksheetFunction.ImSum(s1, s2)
MsgBox s3
End Sub
This is a bit of a long shot, but are you using Excel 2003? If you're not, you don't need to worry about the Analysis ToolPak/VBA ToolPak being installed as these functions are all built in (in fact, I'd uninstall them if you have them there).
If you're using Excel 2003, you need to have the VBA ATP installed and also you need to go into the references for your VBA project and check "atpvbaen.xls".
Another option is to evaluate them :
o = [IMSUM(A1,B1)]
or
a = "12+34i"
b = "67-89i"
c = Evaluate("IMSUM(" & a & "," & b & ")")
I'm trying to automate some report generation where Excel VBA is doing all the work. My employer has a standardized set of templates of which all documents are supposed to be generated from. I need to populate one of these templates from Excel VBA. The Word templates utilize VBA extensively.
This is (some of) my Excel VBA code:
Sub GenerateReport() ' (Tables, InputDataObj)
' code generating the WordApp object (works!)
WordApp.Documents.Add Template:="Brev.dot"
' Getting user information from Utilities.Userinfo macro in Document
Call WordApp.Run("Autoexec") ' generating a public variable
Call WordApp.Run("Utilities.UserInfo")
' more code
End sub
In the Word VBA Autoexec module, a public variable named user is defined and declared. The Userinfo sub from the Utilities module populates user. Both these routines are run without any complaints from VBA. I would then like to be able to access the user variable in my Excel VBA, but I get the following error
Compile Error: Variable not yet created in this context.
How can I access the Word VBA variable in Excel VBA? I thought it more or less was the same?
EDIT: the user variable is a user defined Type with only String attributes. Copying the Word VBA functions that populate the user variable is absolutely doable, just more work than I though was necessary...
In a Word module:
Public Function GetUserVariable() As String '// or whatever data type
GetUserVariable = user
End Function
In an Excel module:
myUser = WordApp.Run("GetUserVariable")
Alternatively, you could be able to replicate the variables value - as it's called user I suspect it is returning some information about a user, or author, of a document. In which case one of the following might be what you're after:
'// Username assigned to the application
MsgBox WordApp.UserName
'// Username defined by the system
MsgBox Environ$("USERNAME")
'// Name of the author of the file specified
MsgBox CreateObject("Shell.Application").Namespace("C:\Users\Documents").GetDetailsOf("MyDocument.doc", 9)
Another option - if you could only add a line of code to the Utilities.UserInfo sub (after setting your public variable):
ActiveDocument.Variables("var_user") = user
Then you could access it easily afterwards in Excel:
Sub GenerateReport() ' (Tables, InputDataObj)
' code generating the WordApp object (works!)
'I am assuming your WordApp object is public, as you don't declare it.
'Capture the new document object
Dim newdoc as Object
set newdoc = WordApp.Documents.Add(Template:="Brev.dot")
' Getting user information from Utilities.Userinfo macro in Document
Call WordApp.Run("Autoexec") ' generating a public variable
Call WordApp.Run("Utilities.UserInfo")
'Get and show the value of "user"
Dim user as String
user = newdoc.Variables("var_user")
msgbox, user
End Sub
This is assuming that useris a string.
EDIT: As it is a requirement to work only on the Excel VBA, I would definely try the approach suggested by Scott and MacroMan - replicating the same functionality of the Word macros in Excel - if possible.
I assume that you've already ruled out the possibility of using an edited copy of the original template, set in a public folder...
For the sake of completness, there is another possibility: actually it is possible to inject VBA code in a Word document without the VBProject Object Model, by "brute force". If you rename a Word document as a .zip file and open it, you will notice a \word\vbaProject.bin file in it. This file contains the VBA project for the document and, in principle, one could add or change VBA code by modifying or replacing it.
I did some tests transplanting code from one document to another by simply copying the vbaProject.bin file, and the concept works. If you are interested in learning more about this file, this topic could be of use.
Notice, however, that to do what you want with such a technique would be somewhat complex (it would involve, for starters, updating zip files from your Excel VBA), and would require a lot of experimentation to mitigate the risk of accidentally corrupting your files. Definetly not recommended if you are looking for an easy and simple solution - but it is possible.
I have an user form which selects a directory path. That path is stored in a variable. The problem is that every time I start the macro, I have to rechoose the path for the directory. How should be the path variable declared in order to keep it's value once the macro is closed, or the excel file is closed ?
Persisting data between calls to a macro is simpler; use a variable at module scope in the .bas module containing the macro.
Persisting data on saving is more difficult. You could write to the registry but that's tricky and you'll need to use various Windows API functions.
The simplest thing to do would be to write the data to somewhere on the workbook.
The registry is simple in VBA. It's is very limited and uses ini file concepts.
There's a few of them such as (from Object Browser [F2] in VBA editor)
Function GetAllSettings(AppName As String, Section As String)
Member of VBA.Interaction
Sub SaveSetting(AppName As String, Section As String, Key As String, Setting As String)
Member of VBA.Interaction
Sub DeleteSetting(AppName As String, [Section], [Key])
Member of VBA.Interaction
Function GetSetting(AppName As String, Section As String, Key As String, [Default]) As String
Member of VBA.Interaction
Also the newer Windows Scripting Host Shell object also makes registry access easy.
object.RegDelete(strName)
object.RegRead(strName)
object.RegWrite(strName, anyValue [,strType])
Also WMI can access registry. Unlike both above methods it can ennumerate, so you can see what is there without have to know in advance.
Dim proglist()
Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
ret = oReg.EnumKey(&H80000002, "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", proglist)
If err.num =0 then
For each prog in proglist
msgbox prog
Next
Else
Msgbox err.num & " " & err.description & " " & err.source
err.clear
End If
It can also check security and monitor changes to keys.
I would use a Name, which can be saved with the workbook.
ThisWorkbook.Names.Add Name:="SavedPath", RefersTo:= someString
Another simple alternative is to put that value in a cell, eventually in a hidden sheet, or a hidden row/column of any suitable sheet.
A third solution is to add it to the file properties.
Registry tricks are complex, don't work if you change machine or if user has not enough rights.
I have solved the problem storing the data on a cell and then on excel file initialization giving the data to corresponding variables. Thank you very much for those who thought to a solution !
I would like to know if there is a way to call a VBA function or method from another specified workbook's module as it is possible for a specific worksheet without using the Application.Run
For the worksheet I can call for example :
ActiveSheet.MyTest()
if MyTest is defined in the sheet module
But I would like to call a function which is defined in a module
I tried :
ActiveWorkbook.MyTestModule()
ActiveWorkbook.VBProject.VBComponents("MyModule").MyTestModule(myArg)
which don't work generating an error Object does not support this method
I could call
Application.Run(ActiveWorkbook.name & "!MyTestModule", myArg)
But I am not sure of the error handling of the Application.Run and I would find cleaner to run directly the method
In the workbook you want to call from (I'll call this A), you could add a reference to the workbook that you want to call to (I'll call this B) as follows:
In workbook A, open the Microsoft Visual Basic for Applications window (for example, by pressing Alt+F11).
Select Tools, References.
In the References dialog that appears, choose Browse.
In the Add Reference dialog that appears, choose Microsoft Excel Files from the Files of type box, select the file that you want to call (B), and choose Open.
Choose OK to close the References dialog.
In file A, you should then be able to call public module-level functions in file B as if they were in file A. To resolve any naming conflicts, you can prefix calls by the "Project Name" for file B as specified in the General tab of the Project Properties dialog (accessible via the Properties command in the Microsoft Visual Basic for Applications Tools menu). For example, if the "Project Name" for file B was "VBAProjectB", you could call function F from file A using the syntax VBAProjectB.F.
By the way, this also works if you want to access a custom data type in another workbook:
' In workbook ABC, project name Library
Public Type Book_Data
Title As String
Pub_Date As Date
Pub_City As String
End Type
' In workbook DEF (after a ref to Library)
Dim Book_Info As Library.Book_Data
Book_Info.Title = "War and Peace"
Debug.Print Book_Info.Title
Note that if you want to call a method in a module of a different workbook without having the annoying behavior of a DLL-style link as mentioned in the other answers, you can use code like the below:
Dim otherWorkBook As Workbook
Set otherWorkBook = Workbooks.Open("myWorkbook.xlsm")
Call otherWorkBook.Sheets("SomeSheet").someMethod(arg1, arg2...)
Where someMethod() is a method which calls the actual method you're interested in within the module of the other sheet