Error. .. Main not accessible by program - vb.net

I wrote a module and into which a Public Sub Main method. But, when I run the program. It gives " No accessible 'Main' method with an appropriate signature was found in 'abc'."
Could you please suggest possible solutions to the error.
Public Sub Main(ByVal cmdArgs As String)
Dim returnValue As Integer
If cmdArgs.Length > 0 Then
returnValue = Import_Start(cmdArgs, "f9880")
Console.WriteLine("Import end with an error " & returnValue)
Else
Console.WriteLine("parameter failure")
End If
End Sub
End Module

If you want to start your app from a Sub Main, the correct signature is:
Public Sub Main(args As String())
' or
Public Sub Main()
The command line args will be passed as a string array. Yours just declares it as String resulting in the compiler error. You also need to set the StartUp object to Sub Main in Project Properties, but that already seems to have been done.
If you do not want/need to use a module you can add it to a form (it is not clear if this is even a WinForms app) using:
Public Shared Sub Main(args As String())
' or
Public Shared Sub Main()

Related

Expression in With statement becomes Nothing in lambda expression in Task

I have discovered that referencing a member variable in a lambda expression executed in a Task throws a NullReferenceException when accessing it using the With statement.
For example I expect the following code to print two lines on the console. The first one accesses the SomeString member via obj.SomeString while the second one uses the With statement and accesses the member via .SomeString. I expected both options to be equivalent but the second one throws an exception.
Class Foo
Public SomeString As String
End Class
Module Module1
Sub Main()
Dim obj As New Foo With {.SomeString = "Hello World"}
With obj
Task.Factory.StartNew(
Sub()
Console.WriteLine("1:" + obj.SomeString) ' works
Console.WriteLine("2:" + .SomeString) ' NullReferenceException here
End Sub)
End With
Console.ReadKey()
End Sub
End Module
When I move the Console.ReadKey() statement into the With statement, the code works.
I fixed the actual code by not using the With statement but I still don't know what concept I'm missing here. Why can I access members of the obj variable in the lambda expression but not the members of the With expression? It has not been garbage collected because I can still see it in the debugger when the exception is thrown. The expression seems to go out of scope (or something like that) but why doesn't the compiler just do what I expect and treats it the same as obj?
It is because of the voodoo that the VB compiler does to support the With block and lambda expressions. If you look at your code through a decompiler like Redgate's Reflector, your code gets converted into something like the code below except that I renamed the variables to ones supported by VB; they can be quite long and include characters that are invalid for VB variable names
<STAThread> _
Public Shared Sub Main()
Dim var1 As New GeneratedClass1
Dim foo As New Foo With {.SomeString = "Hello World"}
var1.objVar = foo
Dim var2 As New GeneratedClass1.GeneratedClass2 With {.var2 = var1, .theWithVariable = var1.objVar}
Task.Factory.StartNew(New Action(AddressOf var2._Lambda___1))
var2.theWithVariable = Nothing
Console.ReadKey()
End Sub
<CompilerGenerated> _
Friend Class GeneratedClass1
' Methods
<DebuggerNonUserCode> _
Public Sub New()
End Sub
<DebuggerNonUserCode> _
Public Sub New(ByVal other As GeneratedClass1)
If (Not other Is Nothing) Then
Me.objVar = other.objVar
End If
End Sub
' Fields
Public objVar As Foo
' Nested Types
<CompilerGenerated> _
Friend Class GeneratedClass2
' Methods
<DebuggerNonUserCode> _
Public Sub New()
End Sub
<DebuggerNonUserCode> _
Public Sub New(ByVal other As GeneratedClass2)
If (Not other Is Nothing) Then
Me.theWithVariable = other.theWithVariable
End If
End Sub
<CompilerGenerated> _
Public Sub _Lambda___1()
Console.WriteLine(("1:" & Me.var2.objVar.SomeString))
Console.WriteLine(("2:" & Me.theWithVariable.SomeString))
End Sub
' Fields
Public theWithVariable As Foo
Public var2 As GeneratedClass1
End Class
End Class
You can see that the compiler creates a class that holds a reference to the With variable and the method of the lambda expression. As soon as the With variable is out of scope it is set to Nothing and hence the null reference expression when task executes.

Bootstrapper class not found in Nito.AsyncEx

Please see the answer to the following question: Can't specify the 'async' modifier on the 'Main' method of a console app
I am trying to do this with a VB.NET program. I have added the package using NUGET and I have ensured that the Reference is added. Please see the code below:
Imports Nito.AsyncEx
Public Class ScheduledTasks
Private Shared Async Sub MainAsync(args As String())
Dim bs As New Bootstrapper()
Dim list As VariantType = Await bs.GetList()
End Sub
End Class
The error is: Type BootStrapper is not found. I have used Intellisense to look at the types contained in Nito.AsyncEx and Bootstapper is not there? How do I create an asynchronous main method using VB.NET?
Bootstrapper is not a part of AsyncEx. AsyncContext is:
Imports Nito.AsyncEx
Public Class Program
Private Shared Sub Main(args As String())
AsyncContext.Run(Function() MainAsync(args))
End Sub
Private Shared Function MainAsync(args As String()) As Task
...
End Function
End Class

'Sub Main' was not found. Service management console application error?

There is possibly a few things wrong with the below. Haven't had a chance to test/debug the code yet as can't run it. It stating that no main method has been found. But there is? i've even changed it to shared etc. It's probably something obvious?
It's flagging - 'Sub Main' was not found in 'ConsoleApplication1.Module1' error.
Also the main method wasn't always a separate class, I was just trying stuff. I'm importing a reference - system.processes. Was initially created as a vb.form but realised i didn't want the form part and recreated as a console app (which is very possibly where the problem lies as it's one of the first console apps i've done).
Code is basically planned to act on a service dying. Report and try and manage the restart (not finished, ideas welcome).
Imports System
Imports System.Management
Imports System.ServiceProcess
Imports System.Diagnostics
Imports System.Threading
Imports System.IO
Module Module1
Public Class Control
Public Sub Main() 'Public Sub Main(ByVal sArgs() As String)
Dim restart As New Rest
restart.startTime = DateTime.Now()
restart.cr20Services()
restart.Report()
End Sub
End Class
Public Class Rest
public startTime As String
Dim logPath As String = "C:\cr20\restart.txt"
'Dim fileExists As Boolean = File.Exists(strFile)
Dim arrcr20ServicesInitialStatus As New ArrayList
Dim failedServices As New ArrayList
Dim arrcr20Services As New ArrayList
Public Sub cr20Services()
'cr20 Services
arrcr20Services.Add("cr20 service")
arrcr20Services.Add("cr20 router")
For Each cr20Service In arrcr20Services
arrcr20ServicesInitialStatus.Add(cr20Service & " - " & cr20Status(cr20Service))
cr20Restore(cr20Service)
Next
End Sub
Private Function cr20Status(ByVal cr20Service As String)
Dim service As ServiceController = New ServiceController(cr20Service)
Return service.Status.ToString
End Function
Private Sub cr20Restore(ByVal cr20Service As String)
Dim service As ServiceController = New ServiceController(cr20Service)
'Dim p() As System.Diagnostics.Process = System.Diagnostics.Process.GetProcessesByName("calc")
If (service.Status.Equals(ServiceControllerStatus.Stopped)) Or (service.Status.Equals(ServiceControllerStatus.StopPending)) Then
failedServices.Add(service)
service.Stop()
Thread.Sleep(10000) 'give service 10 seconds to stop
service.Start()
End If
End Sub

VB.NET Plugin Architecture

Hello I'm working on using the interface class in vb.net to make a plugin architecture. So far I've not found a step by step tutorial for a beginner. But I've gotten as far as this:
Main App
Public Class PluginHandler
Interface IApplications
Sub ChangeForms()
End Interface
Public Shared Sub GetDLLFromDir(ByVal TheDir)
For Each dll As String In System.IO.Directory.GetFiles(TheDir, "*.dll")
LoadPlugin(dll)
Next
End Sub
Public Shared Sub LoadPlugin(ByVal ThePlugin)
Dim Asm = Assembly.LoadFile(ThePlugin)
Dim type As Type = Asm.GetType("TestPlugin.Class_TestPlugin")
Dim method As MethodInfo = type.GetMethod("ChangeForms")
method.Invoke(Nothing, Nothing)
End Sub
End Class
TestPlugin.vb
Public Class Class_TestPlugin
Implements Plugin_Application.PluginHandler.IApplications
Sub ChangeForms() Implements Plugin_Application. _
PluginHandler.IApplications.ChangeForms
Dim NewForm As New Form_Test
NewForm.Show()
End Sub
End Class
My issue is it says for the method to invoke --> Non-static method requires a target.
I seen on another forum that the method may not be found. I found it says the methods name and void. But I'm not sure what to do. If somebody can mod my code to work or give me some ideas to make my code work. Thanks :)
Here is a link to my test project folder: Link
You have to create an object the method should be called on:
Dim ctor = type.GetConstructor({}) 'no parameters for constructor
Dim obj = ctor.Invoke({})
method.Invoke(obj, {})

Calling Subroutines from lambda in vb.net

I find myself calling functions from lambdas frequently as the provided delegate does not match or does not have sufficient parameters. It is irritating that I cannot do lambda on subroutines. Each time I want to do this I have to wrap my subroutine in a function which returns nothing. Not pretty, but it works.
Is there another way of doing this that makes this smoother/prettier?
I have read that this whole lambda inadequacy will probably be fixed in VS2010/VB10 so my question is more out of curiosity.
A simple Example:
Public Class ProcessingClass
Public Delegate Sub ProcessData(ByVal index As Integer)
Public Function ProcessList(ByVal processData As ProcessData)
' for each in some list processData(index) or whatever'
End Function
End Class
Public Class Main
Private Sub ProcessingSub(ByVal index As Integer, _
ByRef result As Integer)
' (...) My custom processing '
End Sub
Private Function ProcessingFunction(ByVal index As Integer, _
ByRef result As Integer) As Object
ProcessingSub(index, result)
Return Nothing
End Function
Public Sub Main()
Dim processingClass As New ProcessingClass
Dim result As Integer
' The following throws a compiler error as '
' ProcessingSub does not produce a value'
processingClass.ProcessList( _
Function(index As Integer) ProcessingSub(index, result))
' The following is the workaround that'
' I find myself using too frequently.'
processingClass.ProcessList( _
Function(index As Integer) ProcessingFunction(index, result))
End Sub
End Class
If you find that you are doing it too often and generally with the same type of data, you can wrap the delegate in a class.
Create a base class that converts to the delegate:
Public MustInherit Class ProcessDataBase
Public Shared Widening Operator CType(operand As ProcessDataBase) as ProcessingClass.ProcessData
Return AddressOf operand.Process
End Sub
Protected MustOverride Sub Process(index As Integer)
End Class
Inherit from the class:
Public Class ProcessResult
Inherits ProcessDataBase
Public Result As Integer
Protected Overrides Sub Process(index as Integer)
' Your processing, result is modified.
End SUb
End Class
Use it:
Public Class Main()
Public Sub Main()
Dim processingClass As New ProcessingClass
Dim processor As New ProcessResult
processingClass.ProcessList(processor)
Dim result as integer=processor.Result
End Sub
End Class
It IS fixed in VB10, the VS10 Beta is available, if it's an option for you to use it. In VB10 you have lambdas without a return value, and inline subs/functions.
For now, maybe you could just forget lambdas and work with delegates instead? Something like:
processingClass.ProcessList(AddressOf ProcessingSub)