VB.net Hour(Now()) Not Working - vb.net

I am trying to make a vb.net program which at a specific time that the user has chosen, the code will excecute. To do this, I need to check every minute to check every minute if the hour and minute the user has entered are matching to the current time (unless there is a better way to do this). I tried to use
Dim CurrentHour As Integer = Hour(Now())
But the program gives me an error message saying,
Expression is not an array or method, and cannot have an argument list
I am going to use a Do Loop to check, but of course to see if the two are matching, I need the current Hour and Minute

Your code is correct. What you need to watch our for is stuff like this:
Dim Now As Date
Dim CurrentHour = Hour(Now())
Which produces error BC30471: Expression is not an array or a method, and cannot have an argument list.
You see the problem by now perhaps, the Now variable hides the Now function. The compiler now gets confuzzled, it doesn't understand why the parentheses are present. And correctly complains that Now is not an array and not a method. It isn't, not anymore.
Other than renaming the variable, you can also solve it by giving a more complete name:
Dim CurrentHour = Hour(DateAndTime.Now())
Although that gets to be fairly obscure, using DateTime.Now instead is the .NET way instead of the Basic way.

You should use the native DateTime properties:
Dim CurrentHour As Integer = Now().Hour
If you want to use the Hour method, you may need to fully qualify it to be:
Microsoft.VisualBasic.Hour(Now())
because Hour is most likely a property or method elsewhere in your application.

Dim Inputtime As DateTime
if Inputtime = Date.Now.Hour Then
MsgBox("Success!")
End If
I wouldn't use a do loop as it will consume all of the memory for the program. I would go with a timer that ticks once every miunute. and have it fire this sub routine.

Task Scheduler is an option. I rather use Marshal.FinalReleaseComObject then the loop in the bottom of the code, and GC.Collect needs to be called again after GC.WaitForPendingFinalizers()

Related

Do While with Multiple Conditions

Simple Question, I must just be missing something obvious.
I am trying to create a subroutine that polls for a window to be open and I am aiming to accomplish this by a loop that will run while two conditions are met. I keep getting an error:
Run time error 13: Type Mismatch
On the Do while loop, and after searching through the similar issues on SO I still am not quite sure what I am doing wrong.
Here is the line that keeps erroring out:
Sub FindHWND()
Dim HWNDOut as string
Dim Timer as Date
Timer = Now()
'This following line is the one erroring out.
Do While ((Now() < Timer + TimeValue("00:00:10")) And (HWNDOut = 0))
HWNDOut = CStr(Hex(FindWindowEx(0&, 0, "SunAwtFrame", "Graph.graphml - yEd")))
Debug.Print HWNDOut
Sleep (100)
Loop
'Other, following sub and code that is not relevant
End Sub
Where Timer is the Now() at moment before the loop starts, and HWNDOut is the handle for the window I am looking for, which will be found in the loop.
All this loop does is look every 100 MS to see if the window to a third party program has opened, in order to prevent the loss of commands in the next subroutines.
Post Script: If anyone has any suggestions how to do this better, I'm all ears. This is my first time using UI Automation so I'm still learning.
Edit: Added more code to the block for context.
With:
And (HWNDOut = 0))
you are comparing a String to a numeric value..............this will fail.
Try changing variable name Timer to something else e.g. StartTime (think there is a Timer function in VBA which returns a value of a different type; so best not to use words which are reserved or semantically significant).
Might help, might not, good luck.

VBA assigns incorrect value to variable

I have a function in VBA, which is a part of a bigger setup. The function resides inside a Class Module, and is basically just a glorified subtraction. I wondered why I got some weird results, so I (over-)simplified the function for debugging purposes. It turns out, that one of the variables isn't assigned the value that it should, but rather some seemingly random value. How can a simple assign go so wrong?
And even weirder, why does it not always it assigns the incorrect value? It only happens sometimes. Other times it is correct. And occationally it seems like nothing is evaluated at all, and the function just returns 0 (zero).
From all I can see it cannot be an issue with my code, but rahter with the way VBA works (behind the scenes). But as long as I do not understand it, it is quite difficult to mitigate.
Code:
Public Property Get MySubtractionFunction() As Double
Dim tmpValue1 As Double
Dim tmpValue2 As Double
Dim tmpOutput As Double
'When debugging, sometimes CDbl(Me.Value2) evaluates to approximately 18.000
'However tmpValue2 evaluates to approximately 10.000
tmpValue1 = CDbl(Me.Value1)
tmpValue2 = CDbl(Me.Value2)
tmpOutput = tmpValue1 - tmpValue2 'Breakpoint is set at this line
tmpOutput = Application.WorksheetFunction.Min(tmpOutput , tmpValue1)
'Return output
MySubtractionFunction= tmpOutput
End Property
Update 1
When I hover the mouse over Me.Value2 before reaching the breakpoint, it actually shows the value that is assigned to tmpValue2. If I then remove the mouse, and hover back over Me.Value2 again, then it shows a different value. How can a property value just change like that, without any code being executed?
Update 2
Maybe I should mention that the problem only arises when I use the Class Object inside a loop. It is called like this:
For i = 1 To 1000
Dim myObject As myClass
Set myObject = New myClass
'Some initialization
result = myObject.MySubtractionFunction
'A bunch of other stuff
Set myObject = Nothing
Next i
All computer languages have a huge problem, when they are dealing with doubles (floating points). Thus, in C#, you should use decimal to avoid this problem. In Excel, you should round.
Take a look at what Microsoft says about it:
https://support.microsoft.com/en-us/help/78113/floating-point-arithmetic-may-give-inaccurate-results-in-excel
Solution
As I mentioned, the property I had an issue with, was the last in a chain of many. All calling other properties of the class module (except the first in the chain). The problem originated quite early, and chained through all the steps.
The reason it was so difficult to identify, was that the property value which was initially incorrect, was updated when I hovered the mouse over the variable to inspect the variable, in debugging mode.
The solution was to expand all the steps in the chain, in a manner similar to that in the original post. This is not always required, since the problem only showed when I ran a multiple of calculations rapidly. But if anyone expeirence similar problems, I would suggest you try this fix.
This did not work:
Public Property Get myProperty() As Double
myProperty = Me.someOtherProperty + Me.aThirdProperty
End Property
This did:
Public Property Get myProperty() As Double
Dim tempSomeOtherProperty As Double
Dim tempAThirdProperty As Double
Dim tempResult As Double
tempSomeOtherProperty = Me.someOtherProperty
tempAThirdProperty = Me.aThirdProperty
tempResult = tempSomeOtherProperty + tempAThirdProperty
myProperty = tempResult
End Property

VB.NET DateTime from seconds only

I would like to get a time (for example 03:00:03) feeding only the seconds, but nothing else.
Using the Microsoft.VisualBasic runtime, I could say
Dim sTimeRemaining As String = DateAndTime.TimeSerial(0, 0, iSecondsRemaining)
I would use this to show the user how long a download is still going to take.
Can somebody tell me how to do this without the Microsoft.VisualBasic runtime?
Thank you!
You could use
Dim sTimeRemaining As Date = New Date().AddSeconds(iSecondsRemaining)
Note that you should set Option Strict to On. Then your code wouldn't compile since DateAndTime.TimeSerial returns a Date and not a String. But it's a good thing because you are forced to build more robust and type safe code.
Perhaps it would also be better to use a TimeSpan instead of a Date in this case.
Dim seconds = TimeSpan.FromSeconds(iSecondsRemaining)

How to use the same class accross multiple threads and return a variable

My apologies in advance if this has already been answered, but every search I have done does not come close to what I need. Also, this is all pseudo code.
Here is the situation: I created a form (targeting DOT NET 3.5) that does a loop on a gridview recreating a class and runs the code. After the code runs, there is a local variable on the class that gets updated and allows me to use it and the process repeats. Something like this:
For x as Integer = 0 to Me.txtTextBox.Lines.Count - 1 'Can be in the hundreds
Dim objMyClass as MyClass = New MyClass(Me.DatagridView1.Rows(x).Cells(0).Value)
if objMyClass.Start() = True then
'Do my thing with objMyClass.LocalLongVariable
End If
Next
This works just fine, but takes literally days to complete. The last time I ran this it took like 6 days, 7 hours and 40 something minutes to complete and barely bumped the CPU usage.
So, now I want to use MulitThreading to run several of these instances at the same time. I have not been able to get this to work. Everything I try returns different values every time I run it (and it should not). I believe that the threads are accessing the local variable across other threads and are incrementing at will. And SyncLock locks up the entire program. I have also tried adding a custom event that fires when the process is completed and executes a delegate on the Main form, but that has not worked either.
Now, my question is simple: How can I run multiple threads using the same base class (passing a unique string variable) and have the local class variable produce the correct results back to the UI? (And, from what I have been reading, the BackgroundWorker class in not suitable for this many threads (like hundreds); correct me if I read it incorrectly please)
I am looking for something like:
Dim thrd(Me.txtTextBox.Lines.Count) as Thread
Dim objMyClass(Me.txtTextBox.Lines.Count) as MyClass
For x as Integer = 0 to Me.txtTextBox.Lines.Count - 1
thrd(x) = new Thread (Sub()
objMyClass(x) = New MyClass(Me.GridView1.Rows(x).Cells(0).Value
If objMyClass.Start() = True Then
'Do my stuff here (maybe call a delegate??)
End If
End)
thrd(x).IsBackground = True
thrd(x).Start()
Next
Any help/advice on how to proceed will be greatly appreciated. And, if you know of any examples of your suggestion, please post the code/link.
The solution was, in fact, Synclock. My issue was that I was locking the wrong object, objMyClass, instead of the current Me AND I was failing to use Monitor.PulseAll(). Also, I switched to using the ThreadPool.QueueUserWorkItem(AddressOf objMyClass, args) and also used SyncLock on my custom event raised when the thread completes. It's a whole lot easier!! Thanks!!

How does the VBA immediate window differ from the application runtime?

I've encountered a very strange bug in VBA and wondered if anyone could shed some light?
I'm calling a worksheet function like this:
Dim lMyRow As Long
lMyRow = WorksheetFunction.Match(vItemID, rngMyRange.Columns(1), 0)
This is intended to get the row of the item I pass in. Under certain circumstances (although I can't pin down exactly when), odd things happen to the call to the Match function.
If I execute that line in the immediate window, I get the following:
lMyRow = WorksheetFunction.Match(vItemID, rngMyRange.Columns(1), 0)
?lMyRow
10
i.e. the lookup works, and lMyRow gets a value assigned to it. If I let that statement execute in the actual code, I lMyRow gets a value of 0.
This seems very odd! I don't understand how executing something in the immediate window can succeed in assigning a value, where the same call, at the same point in program execution can give a value of 0 when it runs normally in code!
The only thing I can think of is that it's some odd casting thing, but I get the same behaviour taking if the variable to which I'm assigning is an int, a double, or even a string.
I don't even know where to begin with this - help!!
The only difference between the immediate window and normal code run is the scope.
Code in the immediate window runs in the current application scope.
If nothing is currently running this means a global scope.
The code when put in a VBA function is restricted to the function scope.
So my guess is that one of your variables is out of scope.
I would put a breakpoint in your function on that line and add watches to find out which variable is not set.
And if you don't have Option Explicit at the top of your vba code module, you should add it.
You're not assigning the function name so that function will always return zero (if you're expecting a Long). It seems you should have
makeTheLookup = lMyRow
at the end of your function.
I don't know if you are still looking at this or not but I would have written it this way:
Function makeTheLookup(vItemID As Variant, rngMyRange as Range)as Long
makeTheLookUp = WorksheetFunction.Match(vItemID, rngMyRange.Columns(1), 0)
End Function
I cannot reproduce the problem with Excel 2007.
This was the code I used:
Sub test()
Dim vItemID As Variant
Dim lMyRow As Long
Dim rngMyRange As Range
Set rngMyRange = ActiveWorkbook.Sheets(1).Range("A1:Z256")
vItemID = 8
lMyRow = WorksheetFunction.Match(vItemID, rngMyRange.Columns(1), 0)
Debug.Print lMyRow
End Sub
It may sound stupid but are you sure that all parameters of the Match function are the same in your macro and in the immediate window? Maybe the range object has changed?
Thanks for the answers guys - I should have been slightly more specific in the way I'm making the call below:
Function makeTheLookup(vItemID As Variant, rngMyRange as Range)
Dim lMyRow As Long
lMyRow = WorksheetFunction.Match(vItemID, rngMyRange.Columns(1), 0)
End Function
The odd thing is, I'm passing the two parameters into the function so I can't see any way they could be different inside and outside of the function. That said, I'm still entirely clueless as to what's causing this, particularly since it's a really intermittent problem
Is there any easy way of comparing the range object in the function context to the range object in the Immediate window context and telling if they're different? Given that range is a reference type, it feels like I should just be able to compare two pointers, but I've got no idea how to do that in VBA!
I'm using Excel 2007 by the way, although I'm not sure if that makes any difference.
As will has mentioned above, It most definitely seems like a problem of scope. Or an Obscure Bug.
I would try to use Debug.print statements, as well as Watch, and see if they match up, and take it from there.