Access TempVars Don't Compile - vba

I've used TempVars for some time, but am having some issues with one set in an Access 2010 database.
Whenever I try to compile, an error dialog stating "Method or data member not found" appears and the term TempVars is highlighted.
Here's the code snippet in question:
If TempVars("Connected") And TempVars("HasAccessBE") And Me.chkBackupOnExit Then MakeBackup
While I've successfully used TempVars("xx") previously where "xx" is the variable which has been defined elsewhere with TempVars.Add "xx", "yy"
In this instance the compiler somehow thinks TempVars isn't viable code.
These have been checked as well:
Application.TempVars("xx")
TempVars.Item("xx")
Search for user defined variables named TempVars (none found)
Desired variable has been defined via TempVars.Add "xx", "yy" (it was)
In case this is a corruption thing, the following tasks have also been completed:
Database Compact & Repair
Database Decompile
I'm trying to resolve this so I can compile and move forward. The code functions fine for users, however it still needs to be compiled.
Any ideas on how to resolve the issue?

Very interesting behavior.
This compiles for me:
If TempVars("Connected") And TempVars("HasAccessBE") Then Debug.Print "Yay!"
If the TempVars don't exist, I will get a runtime error, not a compile error.
Actually not even this, they just return Null.
This does not compile:
If TempVars("Connected") And TempVars("HasAccessBE") Then WrongFunction
but: The compiler selects the first TempVars and says "Sub or Function not defined". Instead of selecting WrongFunction where the problem is.
=> The error is not in TempVars, but in the rest of the statement.
Judging from the error message, I'd say that Me.chkBackupOnExit does not exist / is spelled wrong.
Edit: To see what's going on, change your code line to
If Me.chkBackupOnExit Then MakeBackup
and try to compile this.

When adding to TempVars collection, you need to define the name and value. Then you can retrieve the value by name.
TempVars.Add(name As String, value)
Working example:
Sub Test()
Dim b As Boolean
b = True
TempVars.Add "bool", b
Debug.Print TempVars("bool")
End Sub
'True

Related

Variable in a form won't keep its value after being used in the call to another form

I have a form with a variable in it called "VigilTable." This variable gets its value from the calling string OpenArgs property.
Among other things, I use this variable in the call string when opening other forms.
But it only works the first call.
MsgBox VigilTable before the call will always show "Spring2022" or whatever on the first call but always comes up blank on succeeding calls (and I get "invalid use of NULL" when the called form attempts to extract the value from OpenArgs). The variable is dimmed as String in the General section of the form's VBA code.
So what's happening here? And can I fix it?
Thanks.
Ok, so you delcared a variable at the form level (code module) for that given form.
and we assume that say on form load, you set this varible to the OpenArgs of the form on form load.
So, say like this:
Option Compare Database
Option Explicit
Public MyTest As String
Private Sub Form_Load()
MyTest = Me.OpenArgs
End Sub
Well, I can't say having a variable helps all that much, since any and all code in that form can use me.OpenArgs.
but, do keep in mind the following:
ONLY VBA code in the form can freely use that variable. It is NOT global to the applcation, but only code in the given form.
However, other VBA code outside of the form can in fact use this variable. But ONLY as long as the form is open.
So, in the forms code, you can go;
MsgBox MyTest
But, for VBA outside of the form, then you can get use of the value like this:
Msgbox forms!cityTest.MyTest
However, do keep in mind that any un-handled error will (and does) blow out all global and local variables. So, maybe you have a un-handled error.
Of course if you compile (and deploy) a compiled accDB->accDE, then any errors does NOT re-set these local and global variables.
but, for the most part, that "value" should persist ONLY as long as the form is open, and if you close that form, then of course the values and variables for that form will go out of scope (not exist).
Now, you could consider moving the variable declare to a standard code module, and then it would be really global in nature, but for the most part, such code is not recommended, since it hard to debug, and such code is not very modular, or even easy to maintain over time.
So, this suggests that some error in VBA code is occurring, and when that does occur, then all such variables are re-set (but, the noted exception is if you compile down to an accDE - and any and all variables will thus persist - and even persist their values when VBA errors are encountered.
For a string variable, a more robust solution not influenced by any error, should be writing/reading in/from Registry. You can use the, let as say, variable (the string from Registry) from any workbook/application able to read Registry.
Declare some Public constants on top of a standard module (in the declarations area):
Public Const MyApp As String = "ExcelVar"
Public Const Sett As String = "Settings"
Public Const VigilTable As String = "VT"
Then, save the variable value from any module/form:
SaveSetting MyApp, Sett, VigilTable , "Spring2022" 'Save the string in Regisgtry
It can be read in the next way:
Dim myVal as String
myVal = GetSetting(MyApp, Sett, VigilTable , "No value") 'read the Registry
If myVal = "No value" Then MsgBox "Nothing recorded in Registry, yet": Exit Sub
Debug.print myVal
Actually, this proved not to be the the answer at all.
It was suggested that I declare my variables as constants in the Standard module but I declared them as variables. It appeared at first to work, at least through one entire session, then it ceased to work and I don't know why.
If I declare as constants instead, will I still be able to change them at-will? That matters because I re-use them with different values at different times.
I didn't do constants but declaring VigilName in the Standard module and deleting all other declarations of it fixed both problems.
While I was at it I declared several other variables that are as generally used and deleted all other declarations of them as well so that at least they'll be consistently used throughout (probably save me some troubleshooting later.
Thanks to all!

Input box getting a compile error in VBA

I am learning how to create input boxes and I keep getting the same error. I have tried two different computers and have received the same error. The error I get is a "Compile Error: Wrong number of arguments or invalid property assignment"
Here is my code:
Option Explicit
Sub InputBox()
Dim ss As Worksheet
Dim Link As String
Set ss = Worksheets("ss")
Link = InputBox("give me some input")
ss.Range("A1").Value = Link
With ss
If Link <> "" Then
MsgBox Link
End If
End With
End Sub
When I run the code, it highlights the word "inputbox"
And help would be greatly appreciated.
Thanks,
G
Three things
1) Call your sub something other than the reserved word InputBox as this may confuse things. *Edit... and this alone will resolve your error. See quote from #Mat's Mug.
2) A̶p̶p̶l̶i̶c̶a̶t̶i̶o̶n̶.̶I̶n̶p̶u̶t̶B̶o̶x̶(̶"̶g̶i̶v̶e̶ ̶m̶e̶ ̶s̶o̶m̶e̶ ̶i̶n̶p̶u̶t̶"̶)̶ Use VBA.Interaction.InputBox("give me some input"). You can do this in addition to the first point. Documentation here.
3) Compare with vbNullString rather than "" . See here. Essentially, you will generally want to do this as vbNullString is, as described in that link, faster to assign and process and it takes less memory.
Sub GetInput()
Dim ss As Worksheet
Dim Link As String
Set ss = Worksheets("ss")
Link = VBA.Interaction.InputBox("give me some input")
ss.Range("A1").Value = Link
' With ss ''commented out as not sure how this was being used. It currently serves no purpose.
If Link <> vbNullString Then
MsgBox Link
End If
' End With
End Sub
EDIT: To quote #Mat's Mug:
[In the OP's code, what is actually being called is] VBA.Interaction.InputBox, but the call is shadowed by the procedure's identifier "InputBox", which is causing the error. Changing it to Application.InputBox "fixes" the problem, but doesn't invoke the same function at all. The solution is to either fully-qualify the call (i.e. VBA.Interaction.InputBox), or to rename the procedure (e.g. Sub DoSomething(), or both.
Sub InputBox()
That procedure is implicitly Public. Presumably being written in a standard module, that makes it globally scoped.
Link = InputBox("give me some input")
This means to invoke the VBA.Interaction.InputBox function, and would normally succeed. Except by naming your procedure InputBox, you've changed how VBA resolves this identifier: it no longer resolves to the global-scope VBA.Interaction.InputBox function; it resolves to your InputBox procedure, because VBAProject1.Module1.InputBox (assuming your VBA project and module name are respectively VBAProject1 and Module1) are always going to have priority over any other function defined in any other referenced type library - including the VBA standard library.
When VBA resolves member calls, it only looks at the identifier. If the parameters mismatch, it's not going to say "hmm ok then, not that one" and continue searching the global scope for more matches with a different signature - instead it blows up and says "I've found the procedure you're looking for, but I don't know what to do with these parameters".
If you change your signature to accept a String parameter, you get a recursive call:
Sub InputBox(ByVal msg As String)
That would compile and run... and soon blow up the call stack, because there's a hard limit on how deep the runtime call stack can go.
So one solution could be to properly qualify the InputBox call, so that the compiler knows exactly where to look for that member:
Link = VBA.Interaction.InputBox("give me some input")
Another solution could be to properly name your procedure so that its name starts with a verb, roughly describes what's going on, and doesn't collide with anything else in global scope:
Sub TestInputBox()
Another solution/work-around could be to use a similar function that happens to be available in the Excel object model, as QHarr suggested:
Link = Application.InputBox("give me some input")
This isn't the function you were calling before though, and that will only work in a VBA host that has an InputBox member on its Application class, whereas the VBA.Interaction.InputBox global function is defined in the VBA standard library and works in any VBA host.
A note about this:
If Link <> "" Then
This condition will be False, regardless of whether the user clicked OK or cancelled the dialog by "X-ing out". The InputBox function returns a null string pointer when it's cancelled, and an actual empty string when it's okayed with, well, an empty string input.
So if an empty string needs to be considered a valid input and you need to be able to tell it apart from a cancelled inputbox, you need to compare the string pointers:
If StrPtr(Link) <> 0 Then
This condition will only be False when the user explicitly cancelled, and will still evaluate to True if the user provided a legit empty string.

VBA error in saving file using Format (date) function

I'm trying to save an activeworkbook but when I use the following code, I keep getting the error "compile error: expected function or variable" with the word "format" highlighted.
It boggles my mind because I used the exact same function and format in another macro and it saved the file perfectly. I also made sure they had the same types of variables defined already...
Here's the one line code
ActiveWorkbook.SaveAs Filename:=SavedPath & format(Date, "mmddyyyy") & " 4512 GLUpload.xlsm"
The variable savedpath is fine because when I run this line without the format part, it saves the file, but not sure why this screw it up. Also noticed in my other code, format is capitalized but it's not here.
The compiler error you are getting indicates that VBA is expecting an assignable value (either a literal, a variable, or the return value of a function). This means that one of the identifiers in the statement to the right of the equals sign doesn't fall into those categories. So, either SavedPath is defined somewhere as Sub SavedPath(), or there is a Sub Format(arg1, arg2) defined somewhere (if it had a different number of arguments you would get a "Wrong number of arguments or invalid property assignment" error). The second clue (in the comments) is that changing format to the strongly typed Format$ gave a "Type-declaration character does not match declared data type" error. This points to the compiler not treating the symbol format as a function call (Format$() is the strongly typed version of Format()). The solution is to track down the errant use of the VBA function name and re-name it.
A perfect example of why avoiding VBA keywords and function names is good practice.

VBA: Run-time error '5825' Object has been deleted

I was putting this code ActiveDocument.Variables("time1").Delete before End Sub and I get that error "Object has been deleted" so that if a variable "time1" exist, it will be deleted at the end of the procedure. I understand why I get that code because "time1" has already deleted on the first run but I want to skip and end the sub if it encounter errors. I tried to do this
On Error Goto here
ActiveDocument.Variables("time1").Delete
here:
End sub
but I still get that Error. Why is it that the error handler did not work?
You should be able to avoid this if you are not interested in whether the Variable existed or not.
ActiveDocument.Variables("time1") = ""
should remove a Variable called "time" if there is one, and execute without errors if there is not.
In a similar way,
ActiveDocument.Variables("time1") = "something"
will create the Variable if it does not exist.
This is one of the things that makes Variables slightly easier to work with than Custom Document Properties, although it does mean that empty variables are not allowed.

VBA User form with ThemeColorScheme and late binding

I'd like to run a user form with status bar.
I show my form with code bolow.
How should I declare variables and assigning new values to those variables?
Very important: I have to use late binding in my project.
Sub RunMyUserForm()
With MyUserForm
.LabelProgress.Width = 0
.TextBox1 = 1
'to make the progress bar color match the workbook's current theme:
.LabelProgress.BackColor = ActiveWorkbook.Theme.ThemeColorScheme.Colors(msoThemeAccent1)
.Show vbModeless
End With
End Sub
Thank you in advance for your help!
Updated information:
When I try to run my macro with "Option Explicit", it doesn't work (Compile error: Variable not defined - part of code msoThemeAccent1 is marked as yellow color). That's why I asked for help in defining the variables.
When I try to run my macro without "Option Explicit", it dosen't work (Err.Description: "Value is out of range", Err.Number: -2147024809)
When I try to run my macro with early binding (reference to "MS Office Object Library" via Tools/References in VBE) everything works perfect with (and without) "Option Explicit".
Your compiler is seeing msoThemeAccent1 as a variable, and it is undeclared. This is why your code won't run with Option Explicit and also why your code raises an error when you disable Option Explicit. .Colors is a 1-based collection (?) so when you call:
ActiveWorkbook.Theme.ThemeColorScheme.Colors(msoThemeAccent1)
It is compiling to:
ActiveWorkbook.Theme.ThemeColorScheme.Colors(0)
Which raises an expected, albeit cryptic error.
I used some code to check the value of this constant, but in hindsight I should have just referred to the documentation:
http://office.microsoft.com/en-us/excel-help/HV080559557.aspx
This should fix it for you
ActiveWorkbook.Theme.ThemeColorScheme.Colors(5)
Alternatively, if you need to rely on this value in several places in your code, you could declare a variable (public or private, scope depends on what you need it for).
Public Const myAccentColor1 as Long = 5
And then, in your code you could:
ActiveWorkbook.Theme.ThemeColorScheme.Colors(myAccentColor1)
Revised
I understand now, without reference to MS Office Object Library this makes sense. This is one of the few libraries that I maintain a reference to in my XLSB file, so my confusion was a result of the fact that I thought I was using an appropriate late-binding, but I was really using early-binding.