VBA Excel: not statement & formula - excel

Is there a way of combining a not statement with a function in the following way:
I want it to work like this example
MsgBox not False
which returns True.
But if I add a function instead of the boolean statement
MsgBox not myFunction()
then it returns a mismatch error.
myFunction() is supposed to return True or False
Any suggestions?

You will need to give us more code, as the following works:
Public Sub test()
MsgBox Not myfunction()
End Sub
Function myfunction() As Boolean
myfunction = False
End Function

Simply
MsgBox Not Application.Evaluate(myFunction)

what is myFunction defined as? if its not :
Function myFunction(...) As Boolean
'...
End Function
that would be why, 'not' operator is reserved for Boolean (true/false)
if your function is like this and only recieves 1 and 0:
Function myFunction(...) As Integer
add this to the call :
MsgBox not CBool(myFunction(...))
or if you are actually trying to compare text:
Function myFunction(...) As String
then you will need:
EDIT: not string.compare, (StrComp(Str1, Str2, vbTextCompare) = 0)
hope that helps :)

Related

Set VBA Variable to Result from Function which is String

I've read a bunch about functions today and they all seem to deal with math/numbers. I'm trying to use a function which returns a string and capture that as a variable in the "main sub" but I can't get it to work. Can anybody point out what I'm doing wrong?
Eg:
Function:
Public Function Test(var) As Variant
Bar = var & "World"
MsgBox Bar
End Function
Sub:
Public Bar As Variant
Public Z As Variant
Sub testing()
Call Test("Hello") ' This displays "HelloWorld" from MsgBox in Function
Test ("Hello") ' This displays "HelloWorld" from MsgBox in Function
Z = Test("Hello") ' This displays "HelloWorld" from MsgBox in Function
MsgBox Z ' This displays an empty MsgBox :*(
End Sub
If you want the function to return a value, populate the function variable and return that in the main sub, like so
Public Function Test(var As String) As String
Test = var & " World"
End Function
Sub testing()
returnstr = Test("Hello")
MsgBox returnstr
End Sub
You aren't returning a value from the function. Also, functions should only be used to return values, not to perform actions that change things (other than variables) or display pop-ups. It also gets confusing having global variables and passing variables to a function. You generally pass local variables to a function. Here's a cleaner example (with your main function first, as is normal convention):
Sub Testing()
Dim Z As String
Z = Test("Hello")
MsgBox Z
MsgBox Test("Hello")
End Sub
Public Function Test(ByRef var As String) As String
Test = var & "World"
End Function

Excel VBA module to test if hyperlink string refers to valid file

I am trying to figure out a way to test if a hyperlink string in excel points to a valid file on our network. But my limited VBA knowledge seems to be getting the better of me.
Example:
The hypothetical function "HyperTest" returns TRUE or FALSE depending on Hyperlink validity.
Cell A1 Contains "c:\123.txt"
Cell B1 Contains "=IF(HyperTest(A1),"Yay, the file is real!","Looks like somebody deleted your file.")
I assume the module code should resemble something like:
Public Function HyperTest(hyperpath As String) As Boolean
If [insert test here] Then
return TRUE
Else
return FALSE
End If
End Function
You can use the Dir() function. If the path doesn't exist, the function doesn't return anything. And since the default value of a boolean is False, you don't need an Else statement.
Public Function HyperTest(hyperpath As String) As Boolean
If Dir(hyperpath) <> vbNullString Then HyperTest = True
End Function
you can use this small UDF to get your OP
Function HyperTest(c As Range)
If Dir(c) <> "" Then
HyperTest = "File exists."
Else
HyperTest = "File doesn't exist."
End If
End Function
and call this function in any cell

ByVal vs ByRef VBA

I've tried to attempt something that was answered by JaredPar ByRef vs ByVal Clarification
ByVal in VB.NET means that a copy of the provided value will be sent
to the function. For value types (Integer, Single, etc.) this will
provide a shallow copy of the value. With larger types this can be
inefficient. For reference types though (String, class instances) a
copy of the reference is passed. Because a copy is passed in mutations
to the parameter via = it won't be visible to the calling function.
ByRef in VB.NET means that a reference to the original value will be
sent to the function (1). It's almost like the original value is being
directly used within the function. Operations like = will affect the
original value and be immediately visible in the calling function.
And I've tried to test it with the following code and I can't seem to get it to work use the ByRef to change the value of the cell to 0 if it's 1
Here's my below code that I'm testing with, what am I doing wrong? The value of Range("A1") is still 1
Sub test1()
Dim trythis As Boolean
trythis = False
If (Sheets("TESTING").Range("A1").value = 1) Then
testingRoutine (trythis)
If (trythis) Then
Debug.Print "Value changed to 0"
Sheets("TESTING").Range("A1").value = 0
End If
End If
End Sub
Private Function testingRoutine(ByRef trythis As Boolean)
Debug.Print "Ran Function"
trythis = True
End Function
VB subroutines don't require braces around the argument list. However, if you pass a single argument and you enclose that in braces, you are passing an expression . Expressions cannot be passed by reference. They are evaluated and their result is passed. Therefore you must remove the braces in the call testingRoutine (trythis) and write testingRoutine trythis
Note: if you call a function without using its return value, it must be written as a procedure call (without braces around the argument list). As an example:
myVal = myFunction (trythis) ' trythis will be passed by reference
myFunction (trythis) ' trythis will be seen as an expression
myFunction trythis ' trythis will be passed by reference
myVal = mySub (trythis) ' invalid: mySub is not a function
mySub (trythis) ' trythis will be seen as an expression
mySub trythis ' trythis will be passed by reference
Of course, the problem will be clear immediately when a function or sub has more than one parameter because a comma cannot appear in an expression.
Change this:
testingRoutine (trythis)
to this:
testingRoutine trythis
then try it.
Also, look what happens if I change it to this, where the function is being used as a function (returning something)
Sub test1()
Dim trythis As Boolean
Dim testit As Boolean
trythis = False
If (Sheets("Sheet1").Range("A1").Value = 1) Then
testit = testingRoutine(trythis)
If (trythis) Then
Debug.Print "Value changed to 0"
Sheets("TESTING").Range("A1").Value = 0
End If
End If
End Sub
Private Function testingRoutine(ByRef trythis As Boolean) As Boolean
Debug.Print "Ran Function"
trythis = True
End Function
I would do it this way.
Sub test1()
Dim trythis As Boolean
trythis = False
If (Sheets("TESTING").Range("A1").value = 1) Then
tr = testingRoutine(trythis)
If tr Then
Debug.Print "Value changed to 0"
Sheets("TESTING").Range("A1").value = 0
End If
End If
End Sub
Private Function testingRoutine(ByRef trythis As Boolean)
Debug.Print "Ran Function"
testingRoutine = True
End Function
Because trythis is not a global variable, changing it in the function will do nothing in the sub. It will just define trythis as True in the function and stay in that scope. To get trythis to be affected by the function and read by the sub you have to assign it to a variable within the sub.
i can't remember where i read this, but i know that if you add the bracets () to arguments when calling a sub/function, it is a specific (not an error) way microsoft implented to workaround byref calls (to byval).
example : lets say you call a sub who has ONLY byref, and 2 arguments:
call Sub1 (a), (b)
is a proper way to force Byvalarguments, even if they were initially coded as Byval

excel VBA return result of function

Simple Layup for anyone. I've written a function isMac() which looks at the current operating System, if the first 3 letters are Mac, it is supposed to return True. I then want to assign the return value of the function to a variable in another function. I'm currently running a Mac, so when I run the following code, the MsgBox says True, while the Debug.Print returns False
Function isMac() As Boolean
If Left(Application.OperatingSystem, 3) = "Mac" Then
result = True
Else
result = False
End If
MsgBox result
End Function
Sub test()
Debug.Print isMac()
End Sub
How do I correctly return a Boolean from my IF statement so that I can utilize it in another function?
Try assigning the result to the function.
Function isMac() As Boolean
isMac = CBool(LCase(Left(Application.OperatingSystem, 3)) = "mac")
End Function
Sub test()
Debug.Print isMac()
End Sub
Another approach would be Compiler Directives and Compiler Constants. In a module code sheet's declarations area as,
#If Mac Then
Public Const bMAC as Boolean = True
#Else
Public Const bMAC as Boolean = False
#End If
Use bMAC anywhere in your code to determine whether the OS is a Mac or not.

Type mismatch when trying to assign return value to variable (VBA Excel)

Long time listener, first time caller.
I am having an issue with VBA in Excel 2010. I am trying to compare various fields on a user form to determine if they are empty. I will then highlight red, and set focus on the first one on the list.
To do this, I have created functions for each type that can be blank/not selected. They are all declared AS BOOLEAN. The idea was to do the function call to highlight, pass the function calls with the appropriate sub functions, and use the results of those in the highlight function:
function Blah(DoThis01(Me.Object1), DoThis02(Me.Object2), ...) As Boolean
That gave me nojoy; the values always came back false. So I created three boolean variables to assign the values of those functions, and it started givinng me byRef errors. After declaring each variable rather than all on one line, that solved the byref, but now I get a type mismatch:
Dim foo As Boolean
foo = DoThis01(Me.Object1)
if Blah(foo, bar, ..)
It doesn't like that center line; that is where I am running into the error.
Below is the code snippet I am working with, along with an example of the functions I am trying to pass. I can't figure out why my As Boolean functions aren't compatible with an As Boolean variable. Also, the functions to determine whether or not the fields are filled are giving me some issues as well, not registering the correct values. Google had lots of answers, but none that worked for me so far. I appreciate any insight you can offer.
Thanks,
J
PS I realize some of the logic may be a bit off when triggering the message. That is ok, because I am not getting the right values anyways. I will clean it up if I can get the rest working.
Working Code:
Save Button:
Dim emptyRow As Long
Dim isDuplicate As Boolean, nameSelect As Boolean, comboSelect As Boolean, listSelect As Boolean
Dim listLength As Integer
Dim blah As Integer
' check for empty on form
nameSelect = IsSelectedName(Me.SignalNameTxtBox)
comboSelect = IsSelectedCombo(Me.ComboBox1)
listSelect = IsSelectedList(Me.ListBox1)
If HighlightEmpty(nameSelect, comboSelect, listSelect) Then
blah = MsgBox("Empty fields required!", vbOKOnly)
Exit Sub
End If
...More stuff
To Highlight Empty Form Objects:
Function HighlightEmpty(nameSelect As Boolean, comboSelect As Boolean, listSelect As Boolean) As Boolean
' Highlight empty fields
If Not nameSelect Then Enter_New_Form.SignalNameTxtBox.BackColor = RGB(255, 0, 0)
If Not comboSelect Then Enter_New_Form.ComboBox1.BackColor = RGB(255, 0, 0)
If Not listSelect Then Enter_New_Form.ListBox1.BackColor = RGB(255, 0, 0)
' Set focus to first empty field on form
If Not nameSelect Then
Enter_New_Form.SignalNameTxtBox.SetFocus
ElseIf Not comboSelect Then
Enter_New_Form.ComboBox1.SetFocus
ElseIf Not listSelect Then
Enter_New_Form.ListBox1.SetFocus
End If
' Return boolean to trigger message
HighlightEmpty = nameSelect Or comboSelect Or Not listSelect
End Function
My functions to determine if empty:
Function IsSelectedList(lst As ListBox) As Boolean
Dim I As Integer
For I = 0 To lst.ListCount - 1
IsSelectedList = lst.Selected(I)
If IsSelectedList Then Exit Function
Next I
End Function
Function IsSelectedCombo(cbo As ComboBox) As Boolean
If cbo.Value = "" Then IsSelectedCombo = False
End Function
Function IsSelectedName(nme As TextBox) As Boolean
If nme.Value = "" Then IsSelectedName = False
End Function
Your functions will always return false unless otherwise declared as true. Add an else statement like this:
Function IsSelectedName(nme As TextBox) As Boolean
If nme.Value = "" Then
IsSelectedName = False
Else
IsSelectedName = True
End If
End Function
As #Timwilliams pointed out you can reduce this to one line since nme.Value = "" will evaluate to True or False. You might find however, that you need to test if the cell is empty in other ways such as isBlank() and isEmpty(). In this case use the previous example.
Function IsSelectedName(nme As TextBox) As Boolean
IsSelectedName = Len(nme.Value) > 0
End Function
EDIT
To check the value just pass the text string to the function rather than the textbox object. Try This:
Private Sub CommandButton1_Click()
MsgBox (IsSelectedName(Me.SignalNameTxtBox.Text))
End Sub
Function IsSelectedName(nme As String) As Boolean
IsSelectedName = Len(nme) > 0
End Function

Resources