Unable to create simple VBA function in Excel Macro and call it - excel

I'm trying to create a macro that can collect data from an excel spreadsheet in the local active workbook and then create header file which I would later incorporate into my project. But for the life of me I must be missing something so DUMB that I can't create a working function that returns a string (which would construct a C++ structure) to the calling function. I've simplified the example code to is absolute bare minimum to isolate the problem but I still cannot figure out what I'm doing wrong. I'm not an expert at VBA but I know how to create code and I can't narrow down what VBA is unhappy about. I keep getting "compile error, syntax error." Please copy the following code into your module and see if compiles properly for you. If you know where I went wrong please let me know. Much Appreciated!!!
Sub CREATE_FACTORY_SETTING_HEADER()
Dim FS, TSsource
Set FS = CreateObject("Scripting.FileSystemObject")
Dim TSout
Set TSout = FS.Createtextfile("HeaderFile.h", True)
Dim fileHeading As String
fileHeading = "File Heading for Header file"
Dim fileBody As String
fileBody = "Some initial file body lines"
fileBody = fileBody & createStructBody
TSout.Write fileHeading & fileBody
TSout.Close
End Sub
Public Function createStructBody() As String
Dim structBody As String
structBody = "Hey I'm a struct body, but I can't be returned for some reason"
Return structBody
End Function

Both VBA and VBScript use 'assignment to function' (instead of 'return' or 'result of last statement') to return results from functions. So
Public Function createStructBody() As String
createStructBody = "Hey I'm a string and can be returned."
End Function

Related

How to save Dictionary object to bin file in VBA?

This is VBA case. I want to save Dictionary object to bin file and put it again back to Dictionary later. This object should be the only content of bin file. In general I am stuck on:
Compile error: Can not Get or Put an object reference variable or a
variable of user-defined type containing an object reference
Relevant part of code looks like this:
Public generalListOfAddIns As Object
Public Type BinaryCapsuleType
forObject As Object
End Type
Public Sub CreateGeneralListOfAddIns()
Set generalListOfAddIns = CreateObject("Scripting.Dictionary")
End Sub
Public Sub SaveDictAsBin()
Dim Capsule As BinaryCapsuleType
Set Capsule.forObject = generalListOfAddIns
Dim filePath As String
Dim fileNo As Integer
Dim loadedGeneralListOfAddIns As Object
filePath = "C:\TestFolder\ListOfAddIns.bin"
fileNo = FreeFile
Open filePath For Binary Lock Read Write As #fileNo
Put #fileNo, , Capsule
Close #fileNo
End Sub
I tried and didnt helped:
Both early binding and late binding
Save Dictionary direcly
Encapsulate Dictionary using the Type statement (as in code example)
I would like to avoid:
Saving Dictionary content into text files
Transforming Dictionary into Array for saving purpose
Adding more references into VBA Project
Which sources didnt helped me (or I dont understand them):
https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/can-t-get-or-put-user-defined-type-containing-object-reference
https://analystcave.com/excel-saving-your-vba-data/
Thank you very much for any help or ideas, RosMane

Create Revit Sheets from Excel with multiple project parameters

Hi I have a macro that creates multiple sheets and has Name, Number, Sheet Category. The last being my own project parameter.
I can successfully create the sheets with name and number but I am having difficulty adding the value from CSV file to the project parameter "SD_Sheet Category". Below are some code grabs to help explain.
Public Module mSheetCreator
Public Structure structSheet
Public sheetNum As String
Public sheetName As String
Public sortCategory As String
End Structure
Then I have a function that reads the CSV file and does the following:
Try
currentRow = MyReader.ReadFields()
'create temp sheet
Dim curSheet As New structSheet
curSheet.sheetNum = currentRow(0)
cursheet.sheetName = currentRow(1)
curSheet.sortCategory = currentRow(4)
'add sheet to list
sheetList.Add(curSheet)
Then I have a transaction that does the following:
For Each curSheet As structSheet In sheetList
Try
If sheetType = "Placeholder Sheet" Then
m_vs = ViewSheet.CreatePlaceholder(curDoc)
Else
m_vs = ViewSheet.Create(curDoc, tblock.Id)
m_vs.Parameter("SD_Sheet Category").Set(CStr(curSheet.sortCategory))
End If
m_vs.Name = curSheet.sheetName
m_vs.SheetNumber = curSheet.sheetNum
The problem is this code:
m_vs.Parameter("SD_Sheet Category").Set(CStr(curSheet.sortCategory))
I am getting a warning that says it's an "implicit conversion from 'String' to 'Autodesk.Revit.DB.BuiltInParameter'"
once I build solution
When I run the code in Revit it produces an error saying
"Conversion from string 'SD_Sheet Category" to type 'Integer' is not valid"
It creates the sheets but disregards all the info in the CSV file. I know the rest of the code works as I have removed this particular line of code so I know it isn't the problem
Any suggestions??
I believe that as of a particular version of Revit API you cannot use .Parameter(“name”)
Because there might be two parameters with the same name.
So you need to do something more like
Dim cat as Parameter
Cat = m_vs.GetParameters(“sd_sheet category”).First()
Cat.Set(CSTR(cursht.sortCategory))
Good luck!

Evaluate statement (#DbLookUp) doesn't work with Lotusscript

The last week I asked how to solve an error in an evaluate statement (Error in Evaluate statement macro).
Once fix it, I have other error with the same evaluate statement, it doesn't give me any value.
I will describe what I have and what I try.
#DbLookup in Calculate Text
I have this code into in an calculate Text and it works fine.
suc := #Trim(#Left(LlcPoliza;2));
_lkp := _lkp := #DbLookup("":"NoCache";"C1256EAD:00478951";"People2"; "D"+suc; "FullName");
#If( #IsError( _lkp ) ; " " ; _lkp );
#Name([CN];_lkp)
LlcPoliza is a document field (doc.LlcPoliza) and in a document it has for example the value C2H2H2.
The formula give first the value C2 and then look up into People2 who is D+C2 and give me a person.
It works fine.
Evaluate Statement (#DbLookup) in a Class
I have a class DirectorSucursal.
Class DirectorSucursal
Private m_branch As String
'Constructor class
Public Sub New (branch)
Dim subString As String
subString = Left(branch, 2)
me.m_branch = subString
End Sub
'Deleter Class
Public Sub Delete
End Sub
'Sub show the code about Suc
Public Sub GetCodSuc
MsgBox m_branch
End Sub
'Function get the name director
Public Function getNameDirector As String
Dim varResult As Variant
varResult = Evaluate({#DbLookup("":"NoCache";"C1256EAD:00478951";"People2"; "D} & m_branch & {"; "FullName)"})
getNameDirector = CStr( varResult(0) )
End Function
End Class
Then, in a button I instantiate the new object DirectorSucursal with the parameter of the field doc.LlcPoliza(0) like this.
Sub Click(Source As Button)
Dim director As New DirectorSucursal(doc.LlcPoliza(0))
director.GetCodSuc
director.getNameDirector
end Sub
The field doc.LlcPoliza(0) has the value C2H2H2. GetCodSuc show the value C2, but the function getNameDirector doesn't work.
It shows the error:
Operation failed
Evaluate Statement (#DbLookup) in click button
I have tried the same but into a click sub.
Sub Click(Source As Button)
Dim subString As String
subString = Left(doc.LlcPoliza(0), 2)
Dim eval As String
eval = Evaluate({#DbLookup("":"NoCache";"C1256EAD:00478951";"People2"; "D} & subString & {"; "FullName)"})
Msgbox eval
End Sub
The field doc.LlcPoliza(0) has the value C2H2H2. But it doesn't work
It shows the error:
Operation failed
My question is: what am i doing wrong? Why the code works fine in a calculate text with #Formula but with Lotusscript not?
Thanks.
EDIT 1:
I have added and Error Goto, modified the class code, modified #dblookup in calculate text and I have this error:
Error in EVALUATE macro
Please read documentation and use help! evaluate always returns an ARRAY, as stated in the help:
Return value
variant
The result of the evaluation. A scalar result is returned.
To make your code return a STRING you need to change it like this:
Public Function getNameDirector As String
Dim varResult as Variant
varResult = Evaluate({#DbLookup("":"NoCache";"C1256EAD:00478951";"People2"; "D} & m_branch & {"; "FullName")})
getNameDirector = Cstr( varResult(0) )
End Function
The CStr is just there for the case where the #DBLookup returns an error or a number (both possible)
Just a few things in general:
NEVER write even one line of LotusScript- code without error handler. It will cause you trouble FOR SURE. If you had error handling in place, then it would have told you in which line the error occured...
NEVER use the result of #DBLookup without checking for #IsError... It will cause lot of troubles when the lookup fails.
IF you use #Iserror, then don't do the Lookup twice, assign the lookup to a variable and check that one for #Iserror, like this. Otherwise performance will go down in big forms:
Example:
_lkp := #DbLookup("":"NoCache";"C1256EAD:00478951";"People2"; "D"+suc; "FullName");
#If( #IsError( _lkp ) ; " " ; _lkp )
EDIT: As Knut correctly stated in his answer the real cause for the error was a typo in the formula ( Fullname)" instead of Fullname") that I fixed in my example as well.
1) My suggestion is to never (or at least very seldom) use Evaluate() in Lotusscript. You have proper Lotusscript functionality to do almost everything.
One of the major reasons is that the code is very hard to debug (which is what you are now experiencing).
2) Don't use extended notation when you work with fields. The best practice is to use the GetItemValue and ReplaceItemValue methods of the NotesDocument class for performance reasons as well as compatibility reasons.
3) In the examples with buttons you have a reference to doc, but it is never declared or initialized in the code. If you would use Option Declare at the top of your code you would catch these kinds of errors.
4) I also reccomend against using replica ID to reference databases, that makes it very hard to maintain in the future. Unless you have a very good and convincing reason, reference them by server and filename instead.
I would suggest you refactor your code to something like this:
'Function get the name director
Public Function getNameDirector() As String
Dim db as NotesDatabase
Dim view as NotesView
Dim doc as NotesDocument
Dim key as String
Dim fullname As String
Dim varResult As Variant
Set db = New NotesDatabase("Server/Domain","path/database.nsf")
If db Is Nothing Then
MsgBox "Unable to open 'path/database.nsf'"
Exit Function
End if
Set view = db.GetView("People2")
If view Is Nothing Then
MsgBox "Unable to access the view 'People2'"
Exit Function
End if
key = "D" & m_branch
Set doc = view.GetDocumentByKey(key)
If doc Is Nothing Then
MsgBox "Could not locate document '" & key & "'"
Exit Function
End if
fullname = doc.GetItemValue("FullName")(0)
End Function
Ando of course update the button actions in the same way.
Yes, it is a few lines longer, but it is much more readable and easier to maintain and debug. And you have error handling as well.
Change your last part in #DbLoookup code line to:
"FullName")})

pass variable from excel to access

I have a VBA code in Excel that ask the user where an .xls file is a make something with that file.
What I'd like to do now is to pass the name of the file (myFile) to VBA code that I have in Access, in order to update a table with that file and other fields.
In VBA Excel, the name of the Sub is: Sub UpdateSupplier(myFile As String)
What is the code that I should use in VBA Access in order to use myFile?
Try this: Declare your variable myFile as public, that means not write:
Dim myFile in your Excel Sub,
but write instead
Public myFile in the Declare Section of the module.
Then create a new Function in this module, which only gives back this public variable myFile:
function GiveMemyFile() as string
GiveMemyFile = myFile
end function
Now you can call this function from Access to get the value of myFile.
think I found the solution now, it's so simple if you found it:
Your 'Makro' in Excel should look like this:
function Test (ByRef strFilename)
strFilename = yourFilename
end function
The first 'trick' is, to use a ByRef Parameter 'strFilename' to give back your Filename.
Now in Access you can use:
strNewFilename = ""
xl.Run "Test", strNewFilename
Debug.Print strNewFilename
and you will see the filename the Excel Macro wrote in the variable.
I have tested this and it worked fine for me. Good luck!

Use string variable to set object variable in VBA? (Excel 2013)

I have a number of ActiveX controls/buttons on a page, and I would like to modify several of the parameters of the buttons (in a loop function).
I am fine with writing the loop function to achieve this, but cannot find a way to refer to the object using a string variable. I have set up an object variable (as per below), and a string variable to be used to change the reference for the object variable - but can't find a way to get it to work.
This is the code that does NOT work:
Private Sub TrialCode_Click()
Dim ButtonObj As Object
Dim ButtonCaption As String
Dim ButtonString As String
ButtonString = "CommandButton1"
Set ButtonObj = ButtonString
ButtonCaption = "Something"
ButtonObj.Caption = ButtonCaption 'example of the kind of parameters I want to change
End Sub
The Set ButtonObj = ButtonString is the command that fails, reporting a Type Mismatch error.
I'm working in Excel 2013.
I really hope there is some way to do this. Any help will be really appreciated!!!
The CommandButton belongs to an OLEObject
try
ButtonString = "CommandButton1"
Set ButtonObj = ActiveSheet.OLEObjects(ButtonString)
ButtonCaption = "Something"
ButtonObj.Object.Caption = ButtonCaption 'example of the kind of parameters I want to change
Note that some properties occur directly under ButtonObj, others such as Caption sit below Object

Resources