Debugging VB.Net Service, but getting Source Not Available - vb.net

I've been googling and trying different things, but I can't seem to figure out a way to debug my service :(
Typically I just use NLog to debug, but the service doesn't seem to want to create log files :( So - I need to debug step-by-step, if possible.
I have used VS to attach to the process (can only do that with no program/solution loaded into VS)... but it says 'Source Not Available'.
Any help would be greatly appreciated.

One way to debug a service is to run it as a non-service. In the following example, use System.ServiceProcess.ServiceBase.Run(New serviceclassname) to run as a service, or the dim and runConsole lines to run as a normal process. Do While True is ugly, but it works for debugging.
Shared Sub main()
System.ServiceProcess.ServiceBase.Run(New serviceclassname)
' use these two lines to debug (instead of the one above)
'Dim ps As New serviceclassname
'ps.runConsole(Nothing)
End Sub
Sub runConsole(ByVal args() As String)
' This is only used for console debugging (even though nothing goes to the console)
Call OnStart(args) ' onStart Override -- if you need it.
Console.ReadLine()
Do While True
Loop
Call OnStop()
End Sub

Related

VB.net Process.Start starts process but leaves variable as nothing

To start I would only rate myself as a novice programmer as I only know the concepts I've needed to learn to accomplish specific tasks at my work. That being said I'm using Process.Start to open the built-in Windows to camera program but when I do it leaves the process variable empty (nothing). Because of this I can't use Process.WaitForExit() as the code causes an error during execution.
Imports System.Diagnostics
Sub Main()
Dim camTimeout as integer = 5 * 60000
Dim camProcess as new System.Diagnostics.Process
camProcess = System.Diagnostics.Process.Start("microsoft.windows.camera:")
If Not camProcess.WaitforExit(camTimeout) then
MsgBox("timeout")
Else
MsgBox("picture")
End if
End Sub
During execution the camera app opens but I get a "NullReferenceException" at camProcess.WaitForExit. This is because camProcess is Nothing and I don't understand why that is. Can someone explain why camProcess isn't set properly when the camera app starts or point me to some novice-level reference material. Thanks!
Edit: This code is in a Windows Form Application.

NullArgumentException when Passing Arguments through Cmd

I've created a Windows Application using VB.Net that uses Sub Main to determine if the application should run a specific process or just open as a form for user interaction. Everything works great except for when I try to schedule my application via Windows Task Scheduler. I kept getting the result code of 0xFF. I then tried running my application directly through the command prompt. When doing this, I received a System.ArgumentNullException error. The other information provided is very lacking so I'm struggling to determine where my issue actually lies. I can run my application from the form using a System.Diagnostics.Process command and passing the arguments to it that way. I can also successfully run it by entering command line arguments in the Debug tab of the application Properties. Below is a general outline of what my code looks like. I'm using the Command Line Parser Library to decipher the arguments. Any help or guidance would be greatly appreciated
Imports CommandLine
Imports CommandLine.Text
Module Startup
Public Sub Main()
Dim Args() As String = Environment.GetCommandLineArgs
Dim Options As New Arguments
Dim Parser As New Parser
If Parser.ParseArguments(Args, Options) Then
' Run application
Else
' Open windows form
End If
End Sub
Public Class Arguments
<[Option]("p", "process", Required:=True)> Public Property ProcessOption As String
<[Option]("r", "run", Required:=True)> Public Property RunOption As String
<[Option]("d", "date", Required:=False, DefaultValue:=Nothing)> Public Property DateOption As Date
<[Option]("u", "user", Required:=False, DefaultValue:="")> Public Property UserOption As String
End Class
End Module
I was able to run this on my testing machine with a debugger and found where my issue is. It actually has nothing to do with the arguments being passed by the command prompt. It's with another sub call I make. I will have to play with it and if I can't figure it out I will open another question. Thank you for your help.

How to make SendKeys act Synchronously in IBM Host Access Library

I use the IBM Host Access Class Library for COM Automation as a way to communicate with an IBM AS400 (aka iSeries, IBM i, green screen, 5250) through a terminal emulator. I notice that when you issue a "SendKeys" instruction, control returns to your application before the IBM emulator finishes with the command. This can lead to timing problems because you might then send another "SendKeys" instruction before the system is ready to accept it.
For example:
Imports AutPSTypeLibrary
Imports AutConnListTypeLibrary
Imports AutSessTypeLibrary
Sub Example
Dim connections As New AutConnList
connections.Refresh()
If connections.Count < 1 Then Throw New InvalidOperationException("No AS400 screen can currently be found.")
Dim connection As IAutConnInfo = DirectCast(connections(1), IAutConnInfo)
_Session = New AutSess2
_Session.SetConnectionByHandle(connection.Handle)
Dim _Presentation As AutPS = DirectCast(_Session.autECLPS, AutPS)
_Presentation.SendKeys("PM70[enter]", 22, 8)
_Presentation.SendKeys("ND71221AD[enter]", 22, 20)
End Sub
would work correctly when stepping through code in a debugger, but would fail when running normally because the second instruction was sent too soon.
One way to work with this is to put a timer or loop after each command to slow the calling program down. I consider this less than ideal because the length of time is not always predictable, you will often be waiting longer than necessary to accommodate an occasional hiccup. This slows down the run time of the entire process.
Another way to work around this is to wait until there is a testable condition on the screen as a result of your sent command. This will work sometimes, but some commands do not cause a screen change to test and if you are looking to abstract your command calling into a class or subroutine, you would have to pass in what screen condition to be watching for.
What I would like to find is one of the "Wait" methods that will work in the general case. Options like the autECLScreenDesc class seem like they have to be tailored to very specific conditions.
The autECLPS (aka AutPS) class has a number of Wait methods (Wait, WaitForCursor, WaitWhileCursor, WaitForString, WaitWhileString, WaitForStringInRect, WaitWhileStringInRect, WaitForAttrib, WaitWhileAttrib, WaitForScreen, WaitWhileScreen) but they also seem to be waiting for specific conditions and do not work for the general case. The general case it important to me because I am actually trying to write a general purpose field update subroutine that can be called from many places inside and outside of my .dll.
This example is written in VB.NET, but I would expect the same behavior from C#, C++, VB6, Java; really anything that uses IBM's Personal Communications for Windows, Version 6.0
Host Access Class Library.
The "Operator Information Area" class seems to provide a solution for this problem.
My general case seems to be working correctly with this implementation:
Friend Sub PutTextWithEnter(ByVal field As FieldDefinition, ByVal value As String)
If IsNothing(field) Then Throw New ArgumentNullException("field")
If IsNothing(value) Then Throw New ArgumentNullException("value")
_Presentation.SendKeys(Mid(value.Trim, 1, field.Length).PadRight(field.Length) & "[enter]", field.Row, field.Column)
WaitForEmulator(_Session.Handle)
End Sub
Private Sub WaitForEmulator(ByVal EmulatorHandle As Integer)
Dim Oia As New AutOIATypeLibrary.AutOIA
Oia.SetConnectionByHandle(EmulatorHandle)
Oia.WaitForInputReady()
Oia.WaitForAppAvailable()
End Sub
I give thanks to a user named "khieyzer" on this message board for pointing our this clean and general-purpose solution.
Edit:
After a few weeks debugging and working through timing and resource release issues, this method now reads like:
Private Sub WaitForEmulator(ByRef NeededReset As Boolean)
Dim Oia As New AutOIA
Oia.SetConnectionByHandle(_Presentation.Handle)
Dim inhibit As InhibitReason = Oia.InputInhibited
If inhibit = InhibitReason.pcOtherInhibit Then
_Presentation.SendKeys("[reset]")
NeededReset = True
WaitForEmulator(NeededReset)
Marshal.ReleaseComObject(Oia)
Exit Sub
End If
If Not Oia.WaitForInputReady(6000) Then
If Oia.InputInhibited = InhibitReason.pcOtherInhibit Then
_Presentation.SendKeys("[reset]")
NeededReset = True
WaitForEmulator(NeededReset)
Marshal.ReleaseComObject(Oia)
Exit Sub
Else
Marshal.ReleaseComObject(Oia)
Throw New InvalidOperationException("The system has stopped responding.")
End If
End If
Oia.WaitForInputReady()
Oia.WaitForAppAvailable()
Marshal.ReleaseComObject(Oia)
End Sub

VB.NET Service Skipping Over Sub Procedure

I'm writing a Windows Service in VB using Visual Studio 2010. The service is going to check for changes to a table in a database every minute or so. I have experience with VB6 but am new to both VB.NET and creating services, so I might be overlooking something obvious here. When the service is stopped, paused, started, or resumed, a sub procedure is supposed to be called. The problem is that the program skips right over the call to the sub procedure. I set break points at OnPause() and OnContinue() and stepped through the code, to confirm that the program is skipping right over the calls to AgentStopped() and AgentStarted(). What am I doing wrong?
Protected Overrides Sub OnPause()
Log.WriteEntry("Agent paused.") 'This is written to the log
AgentStopped() 'This line is skipped
End Sub
Protected Overrides Sub OnContinue()
Log.WriteEntry("Agent restarted.") 'This is written to the log
AgentStarted() 'This line is skipped
End Sub
Private Sub AgentStarted()
Log.WriteEntry("AgentStarted called.") 'This never written to the log
End Sub
Private Sub AgentStopped()
Log.WriteEntry("AgentStopped called.") 'This never written to the log
End Sub
As you understand, there is no way for the lines you imply to be skipped since the containing method is called. Something else is happening. I suppose the code you are showing is simplified. Right?
I would bet that either you are running a wrong version of your code by mistake, or on your real code an exception occurs inside the called methods (AgentStarted and AgentStopped).
In order to debug this, I would follow these steps:
Change the current log messages and add messages after the call to the functions
Protected Overrides Sub OnPause()
Log.WriteEntry("Agent pause beginning.")
AgentStopped()
Log.WriteEntry("Agent pause ending.")
End Sub
Protected Overrides Sub OnContinue()
Log.WriteEntry("Agent restart beginning.")
AgentStarted()
Log.WriteEntry("Agent restart ending.")
End Sub
If you see the new messages, you will be able to verify that you are actually running the right version of the code and not an older version deployed by mistake.
You should use exception handling with try - catch. I am not really sure (I have never used it), but perhaps using the UnhandledException event to get info for possible uncaught exceptions could be helpful. Another option would be to check the windows event log for errors occuring while executing a web service.
Hope I helped!

Profiling VBA code for microsoft word

I have some legacy code that uses VBA to parse a word document and build some XML output;
Needless to say it runs like a dog but I was interested in profiling it to see where it's breaking down and maybe if there are some options to make it faster.
I don't want to try anything until I can start measuring my results so profiling is a must - I've done a little searching around but can't find anything that would do this job easily. There was one tool by brentwood? that requires modifying your code but it didn't work and I ran outa time.
Anyone know anything simple that works?
Update: The code base is about 20 or so files, each with at least 100 methods - manually adding in start/end calls for each method just isn't appropriate - especially removing them all afterwards - I was actually thinking about doing some form of REGEX to solve this issue and another to remove them all after but its just a little too intrusive but may be the only solution. I've found some nice timing code on here earlier so the timing part of it isn't an issue.
Using a class and #if would make that "adding code to each method" a little easier...
Profiler Class Module::
#If PROFILE = 1 Then
Private m_locationName As String
Private Sub Class_Initialize()
m_locationName = "unknown"
End Sub
Public Sub Start(locationName As String)
m_locationName = locationName
MsgBox m_locationName
End Sub
Private Sub Class_Terminate()
MsgBox m_locationName & " end"
End Sub
#Else
Public Sub Start(locationName As String)
'no op
End Sub
#End If
some other code module:
' helper "factory" since VBA classes don't have ctor params (or do they?)
Private Function start_profile(location As String) As Profiler
Set start_profile = New Profiler
start_profile.Start location
End Function
Private Sub test()
Set p = start_profile("test")
MsgBox "do work"
subroutine
End Sub
Private Sub subroutine()
Set p = start_profile("subroutine")
End Sub
In Project Properties set Conditional Compilation Arguments to:
PROFILE = 1
Remove the line for normal, non-profiled versions.
Adding the lines is a pain, I don't know of any way to automatically get the current method name which would make adding the profiling line to each function easy. You could use the VBE object model to inject the code for you - but I wonder is doing this manually would be ultimately faster.
It may be possible to use a template to add a line to each procedure:
http://msdn.microsoft.com/en-us/library/aa191135(office.10).aspx
Error handler templates usually include an ExitHere label of some description.. The first line after the label could be the timer print.
It is also possible to modify code through code: "Example: Add some lines required for DAO" is an Access example, but something similar could be done with Word.
This would, hopefully, narrow down the area to search for problems. The line could then be commented out, or you could revert to back-ups.
Insert a bunch of
Debug.Print "before/after foo", Now
before and after snippets that you think might run for long terms, then just compare them and voila there you are.
My suggestion would be to divide and conquer, by inserting some timing lines in a few key places to try to isolate the problem, and then drill down on that area.
If the problem is more diffused and not obvious, I'd suggest simplifying by progressively disabling whole chunks of code one at a time, as far as is possible without breaking the process. This is the analogy of finding speed bumps in an Excel workbook by progressively hard coding sheets or parts of sheets until the speed problem disappears.
About that "Now" function (above, svinto) ...
I've used the "Timer" function (in Excel VBA), which returns a Single.
It seems to work just fine. Larry