catvba, false positive if statement - vba

Unfortunately, sometimes when the if statements are more complex, behavior is quite strange, here is a copy of the line which doesnt work as expected when used like this
If someFunction(arg1, arg2, CreatedFromClass(arg3, arg4, arg5)) Then GoTo err1
someFunction(...) itself has return type long, but in this case is absolutely always evaluated as positive, even though someFunction before return contains 0 as a return value.
so, it can be wrapped as any of the following and result will be always true
If someFunction() = True Then
If someFunction() = False Then
If someFunction() = 0 Then
If someFunction() = 1 Then
If someFunction() <> 0 Then
If someFunction() <> 1 Then
If Not someFunction() = 0 Then
If Not someFunction() = 1 Then
If (someFunction() = 0) = False Then
If (someFunction() = 0) = True Then
If CBool(someFunction() = 0) = True Then
If CBool(someFunction() = 1) = True Then
but when is split into segments, and manually assigned to the variable, then works as expected
Dim rVal As Long
rVal = someFunction(arg1, arg2, CreatedFromClass(arg3, arg4, arg5))
If rVal Then GoTo err1
question is of course why the behavior is not the same? did someone experienced similar?
Additionally, after couple hours, i been able to isolate problematic piece of code!
Class: cls.cls
Option Explicit
Private mCol As Collection
Private Sub Class_Initialize()
Set mCol = New Collection
End Sub
Private Sub Class_Terminate()
Set mCol = Nothing
End Sub
Public Sub Add(iItem)
mCol.Add iItem
End Sub
Public Function DoCopy() As cls
Set DoCopy = New cls
Dim i As Long
For i = 1 To mCol.Count
DoCopy.Add mCol(i)
Next
End Function
and testing module
Option Explicit
Public Function CreateCls(ParamArray params()) As cls
Set CreateCls = New cls
If UBound(params) < 0 Then Exit Function
Dim i As Long
For i = LBound(params) To UBound(params)
CreateCls.Add params(i)
Next
End Function
Private Function doTest(iCls As cls) As Long
doTest = 0
End Function
Private Sub CATStart()
Dim x As cls
Set x = CreateCls("param1", "param2", "param3", "param4")
If doTest(x.DoCopy) = 0 Then Debug.Print "long_0"
If doTest(x.DoCopy) = 1 Then Debug.Print "long_1"
If CBool(doTest(x.DoCopy)) = True Then Debug.Print "bool_True"
If CBool(doTest(x.DoCopy)) = False Then Debug.Print "bool_False"
Set x = Nothing
End Sub
And of course all of them will be evaluated as True valid and result printed!

And yes, i found an answer on my question, in Catia, i have VBA version 7.1.1033, which doesn't work as expected, while the the same piece of code works in Excel, which uses newer VBA version, 7.1.1049...
So answer is, VBA has bug in that release..

Related

How to tell a MS word paragraph from a display-mode equation

I want to use VBA to do something about a normal MS word paragraph. But a display mode equation looks just like a paragraph. Can anybody tell me, please, the difference between them? Or provide a VBA example to distinguish them.
Function IsADisplayModeEquation(ParagraphIndex As Long)
Dim ParagrapLineNum As Long
Dim EquationLineNum As Long
ParagrapLineNum = ActiveDocument.Paragraphs(ParagraphIndex).Range.Information(wdFirstCharacterLineNumber)
n = ActiveDocument.Bookmarks("\page").Range.OMaths.Count
For I = 1 To n
EquationLineNum = ActiveDocument.Bookmarks("\page").Range.OMaths(I).Range.Information(wdFirstCharacterLineNumber)
If (ParagrapLineNum = EquationLineNum) And ActiveDocument.Bookmarks("\page").Range.OMaths(I).Type = wdOMathDisplay Then
IsADisplayModeEquation = True
Exit Function
End If
Next I
IsADisplayModeEquation = False
End Function
A ugly function:
Function IsADisplayModeEquation(ParagraphIndex As Long)
Dim ParagrapLineNum As Long
Dim EquationLineNum As Long
ParagrapLineNum = ActiveDocument.Paragraphs(ParagraphIndex).Range.Information(wdFirstCharacterLineNumber)
n = ActiveDocument.Bookmarks("\page").Range.OMaths.Count
For I = 1 To n
EquationLineNum = ActiveDocument.Bookmarks("\page").Range.OMaths(I).Range.Information(wdFirstCharacterLineNumber)
If (ParagrapLineNum = EquationLineNum) And ActiveDocument.Bookmarks("\page").Range.OMaths(I).Type = wdOMathDisplay Then
IsADisplayModeEquation = True
Exit Function
End If
Next I
IsADisplayModeEquation = False
End Function

Troubles with setting object in VBA

Maybe this question is simple, but I couldn't find an answer by googling.
So, I've got my class WSheet. I initialize array of objects of this class in my program:
ReDim WSheets(twb.Sheets.Count)
For i = 0 To UBound(WSheets)
Set WSheets(i) = New WSheet
Next i
And then, I try to read new values and sort them by insertion sort:
For i = twb.Sheets.Count To 2 Step -1
flag = False
tsName = twb.Sheets(i).Name
twb.Sheets(i).Delete
twb.Save
CurShW = curLen - FileLen(TempFName)
curLen = FileLen(TempFName)
For j = UBound(WSheets) To 2 Step -1
If WSheets(j - 1).Weight < CurShW Then
Set WSheets(j) = WSheets(j - 1)
Else
WSheets(j).SetName (tsName)
WSheets(j).SetWeight (CurShW)
flag = True
Exit For
End If
Next j
If Not flag Then
Set WSheets(1) = New WSheet
WSheets(1).SetName (tsName)
WSheets(1).SetWeight (CurShW)
flag = False
End If
Next i
So, the problem: after I set WSheets(j) = WSheets(j - 1), wsheets(j - 1) starts to contain link to wsheets(j), so, when I change wsheets(j), Wsheets (j - 1) changes too.
Please, share how to make absolute equation in this sample?
Thank you!
PS code in WSheet class
Dim SName As String 'Name of sheet
Dim SWeight As Long 'Weight of sheet in bytes
Dim blocks() As Long 'Weights of blocks in sheet in bytes
Public Function Weight() As Long
Weight = SWeight
End Function
Public Sub SetWeight(ByVal sw As Long)
SWeight = sw
End Sub
Public Function Name() As String
Name = SName
End Function
Public Sub SetName(ByVal nm As String)
SName = nm
End Sub
edited to turn the function into a Class method
You must clone the WSheet object instead of referencing it
For instance you could add a Clone() method to your WSheet class
Function Clone() As WSheet
Dim newWSheet As WSheet
Set newWSheet = New WSheet
newWSheet.SetName SName
newWSheet.SetWeight SWeight
Set Clone = newWSheet
End Function
Then in your main code change:
Set WSheets(j) = WSheets(j - 1)
To:
Set WSheets(j) = WSheets(j - 1).Clone

Getting 424 Runtime error, object required

Please help with the code error 424 below
Public counter As String
Private Sub Workbook_WindowActivate(ByVal Wn As Window)
If ActiveSheet1.Name = Sheet2.Name Then
If counter = 0 Or counter = Null Then
Call LLP_Hide
End If
End If
End Sub
Remove 1 from ActiveSheet1.
If counter is meant to count it should be declared as Integer type instead of String.
Anyway, this part of code will also cause error: counter = 0. Replace it with counter = "0" or change the type of counter.
Public counter As Integer
Private Sub Workbook_WindowActivate(ByVal Wn As Window)
If ActiveSheet.Name = Sheet2.Name Then
If counter = 0 Then
Call LLP_Hide
End If
End If
End Sub

monitor variable value within class object WITHOUT watch windows and WITHOUT OnTime call, in VBA

Hello I am looking to see if there is a way to monitor and execute code when a variable in a class object has changed value during run time.
Here is one way I tried to pull it off....
Create this class:
Option Compare Database
Option Explicit
Private p_bVarToMonitor As Boolean
Public Property Get bVarToMonitor() As Boolean
bVarToMonitor = p_bVarToMonitor
End Property
Public Property Let bVarToMonitor(v As Boolean)
p_bVarToMonitor = v
If v = False Then
GoTo bVarToMonitorFalse
End If
End Property
Then test it in a module (not in the class module):
Sub test()
Dim m As clsVarMonitorBoolean
Set m = New clsVarMonitorBoolean
m.bVarToMonitor = False 'this should make it goto bVarToMonitorFalse:
'Code to skip when bVarToMonitor = False
Exit Sub
bVarToMonitorFalse:
'other alternative code to run when bVarToMonitor = False
End Sub
...however, it doesn't work because the goto label is in a different module. Note, I need to use the class object in a regular code module, not within the same class module.
Update:
If I can't do this I have to do something like this
test()
Dim b As Boolean
b = SomeFunctionCall(input1)
if b = False then
goto altcode
end if
b = SomeFunctionCall(input1)
if b = False then
goto altcode
end if
b = SomeFunctionCall(input2)
if b = False then
goto altcode
end if
b = SomeFunctionCall(input3)
if b = False then
goto altcode
end if
'etc....repeat serveral times
end Sub
I.e. I have to do a ton of if statements throughout the code for each input to SomeFunctionCall.

Passing blank array to a function to and populate it from there

I am trying to pass a blank array to a function that will manipulate the array dependent on certain scenarios. I don't know where I am going wrong with this but I am getting the following error Type mismatch. Below shows how I am creating the blank array:
Dim testArray(0 to 10) as string
Dim ABredu() As String
ABredu = Equipment(testArray)
Below shows the function that I have written to populate the array
Function Equipment(Test() As String)
If standYes = True And .ComboBox2.ListIndex = 0 Then
ReDim ABredu(1 To 3)
ABredu(1) = "Pen"
ABredu(2) = "Ruler"
ABredu(3) = "Monitor"
Else
ReDim ABredu(1 To 3)
ABredu(1) = "17-P2"
ABredu(2) = "17-L73"
ABredu(3) = "16-ENR"
End If
End sub
If someone could help me or give a push in the right direction it would be greatly appreciated!
Pass the array by reference as a variant.
Function Equipment(ByRef Test As Variant)
If standYes = True And .ComboBox2.ListIndex = 0 Then
ReDim Test(1 To 3)
Test(1) = "Pen"
Test(2) = "Ruler"
Test(3) = "Monitor"
Else
ReDim Test(1 To 3)
Test(1) = "17-P2"
Test(2) = "17-L73"
Test(3) = "16-ENR"
End If
End sub
Slightly different approach using variant arrays.
Sub Some_Macro()
Dim ABredu As Variant, i As Long
ABredu = Equipment(True, 0)
For i = LBound(ABredu) To UBound(ABredu)
Debug.Print ABredu(i)
Next i
ABredu = Equipment(False, 0)
For i = LBound(ABredu) To UBound(ABredu)
Debug.Print ABredu(i)
Next i
End Sub
Public Function Equipment(standYes As Boolean, cdLI As Long)
Dim vEQUIP As Variant
If standYes And cdLI = 0 Then
vEQUIP = Array("Pen", "Ruler", "Monitor")
Else
vEQUIP = Array("17-P2", "17-L73", "16-ENR")
End If
Equipment = vEQUIP
End Function
There are several ways to accomplish what you are looking for. Pick the one that makes the most sense to you.
Okay, so I'm going to make a couple of assumptions about your expected logic here, since the code in your question is a bit nonsensical.
You're trying (I think) to:
Create an array of strings called ABredu
Use a function or subroutine to populate that array based on some conditions
With that in mind, you can create the following sub
Sub PopulateEquipment(EquipArr() As String)
ReDim EquipArr(1 To 3)
If <condition> Then '<~~ Insert your own conditions here
EquipArr(1) = "Value 1"
EquipArr(2) = "Value 2"
EquipArr(3) = "Value 3"
Else
EquipArr(1) = "AltVal 1"
EquipArr(2) = "AltVal 2"
EquipArr(3) = "AltVal 3"
End If
End Sub
Then to populate your array using this, you need only Dim it and then call the subroutine, passing the variable as an argument.
Dim ABredu() As String
Call PopulateEquipment(ABredu)
Even simpler, use an ArrayList.
Public arList As Object
Sub PartOne()
Set arList = CreateObject("System.Collections.ArrayList")
Call Equipment
End Sub
Private Sub Equipment() '// No Need to pass argument as arList is of Public scope.
With arList
If standYes And Me.ComboBox2.ListIndex = 0 Then
.Add "Pen"
.Add "Ruler"
.Add "Monitor"
Else
.Add "17-P2"
.Add "17-L73"
.Add "16-ENR"
End If
End With
End Sub