How to load an internal class in end-user compiled code ? (advanced) - vb.net

I have a main program with two classes
1- A winform that contains two elements :
Memo Edit to type some code;
Button named compile.
The end user may type some VB.Net code in the memo edit and then compile it.
2 - A simple test class :
Code :
Public Class ClassTest
Public Sub New()
MsgBox("coucou")
End Sub
End Class
Now I would like to use the class ClassTest in the code that will be typed in the MemoEdit and then compile it :
When hitting compile I recieve the error :
The reason is that, the compiler can't find the namespace ClassTest
So to summarize :
The class ClassTest is created in the main program
The end user should be able to use it and create a new assembly at run time
Does anyone know how to do that please ?
Thank you in advance for your help.
Code of the WinForm :
Public Class Form1
Private Sub SimpleButtonCompile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SimpleButtonCompile.Click
Dim Code As String = Me.MemoEdit1.Text
Dim CompilerResult As CompilerResults
CompilerResult = Compile(Code)
End Sub
Public Function Compile(ByVal Code As String) As CompilerResults
Dim CodeProvider As New VBCodeProvider
Dim CodeCompiler As System.CodeDom.Compiler.CodeDomProvider = CodeDomProvider.CreateProvider("VisualBasic")
Dim Parameters As New System.CodeDom.Compiler.CompilerParameters
Parameters.GenerateExecutable = False
Dim CompilerResult As CompilerResults = CodeCompiler.CompileAssemblyFromSource(Parameters, Code)
If CompilerResult.Errors.HasErrors Then
For i = 0 To CompilerResult.Errors.Count - 1
MsgBox(CompilerResult.Errors(i).ErrorText)
Next
Return Nothing
Else
Return CompilerResult
End If
End Function
End Class

Here is the solution :
If the end user wants to use internal classes he should use the command : Assembly.GetExecutingAssembly
The full code will be :
Code :
Imports System.Reflection
Imports System
Public Class EndUserClass
Public Sub New()
Dim Assembly As Assembly = Assembly.GetExecutingAssembly
Dim ClassType As Type = Assembly.GetType(Assembly.GetName().Name & ".ClassTest")
Dim Instance = Activator.CreateInstance(ClassType)
End Sub
End class

Related

Communicating with a class that's in use in VB.NET

I'm trying to communicate with a class that's already in use, something like this.
Assume "PROJECTNAME" as a namespace or the whole project
Class1:
Public Class Class1
Dim Text1 As String
Sub ChangeString(input as String)
Text1 = String
End Sub
Sub Main()
Do
' Code to prevent the Process stopping (Ignore This)
Loop
End Sub
End Class
Class 2:
Imports PROJECTNAME
Public Class Class2
Dim ForeignClass1 As New Class1
Dim ForeignClass2 As New Class1
Sub Main()
Do
'Code to prevent the Process stopping(Ignore This)
Loop
End Sub
End Class
Class 3:
Imports PROJECTNAME
Public Class Class3
Dim CustomClass As New Class2
Sub Main()
'Code here to interact between "ForeignClass2" and "ForeignClass1"
End Sub
End Class
The codes above is a concept that I'm trying to explain, not the actual code as it's a private code that I'm not suppose to expose. So what I want is to make "ForeignClass2" interact with "ForeignClass1" or make "ForeignClass1" interact with "ForeignClass2" without touching or making a new "Class1" array and just "ForeignClass1" and "ForeignClass2" only. How can I do that?

Event 'Load' cannot be found

Getting the error "Event 'Load' cannot be found" referring to "Handles MyBase.Load" Please see attached code. Any help much appreciated!
I have many other applications set up the same way and they all work. However, these were in an older version of Visual Studio.
Option Explicit On
Option Strict On
Imports System, System.IO
Imports System.Text
Public Class Form1
Private Sub cleanXMLDialog_Load(ByVal eventSender As System.Object, ByVal
eventArgs As System.EventArgs) Handles MyBase.Load
Main()
End
End Sub
Public Sub Main()
Dim directories() As String = Directory.GetDirectories("C:\")
Dim files() As String = Directory.GetFiles("C:\", "*.dll")
DirSearch("c:\")
End Sub
Sub DirSearch(ByVal sDir As String)
Dim d As String
Dim f As String
Try
For Each d In Directory.GetDirectories(sDir)
For Each f In Directory.GetFiles(d, "*.xml")
'Dim Response As String = MsgBox(f)
Debug.Write(f)
Next
DirSearch(d)
Next
Catch excpt As System.Exception
Debug.WriteLine(excpt.Message)
End Try
End Sub
End Class
Load should happen without this error.
This is the class declaration:
Public Class Form1
It looks like you intend this to inherit from a windows Form type, but there's nothing here to make that happen.
You may want this:
Public Class Form1 Inherits System.Windows.Forms.Form
but even this is unlikely to really accomplish anything. It's not enough just to inherit from the Form type if you don't have any controls are properties set and don't ever show the form.
Did you accidentally create a Console or Class Library project when you mean to create a WinForms project?

NSQ vb.net MessageHandler

I am trying to use this package in vb.net NsqSharp
There is a good code for it in C# but i need it in vb.net.
I got it to send a message to my NSQ server, but the problem is to get it.
But i get a error on consumer.AddHandler(New HandleMessage()) and i do not know if i declare the HandleMessage right.
Imports NsqSharp
Imports System.IO
Imports System.Text
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim producer = New Producer("127.0.0.1:4150")
producer.Publish("test-topic-name", Me.txt_tx.Text)
producer.Stop()
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim consumer = New Consumer("test-topic-name", "channel-name")
consumer.AddHandler(New HandleMessage())
consumer.ConnectToNsqLookupd("127.0.0.1:4161")
consumer.Stop()
End Sub
Public Interface IHandler : End Interface
Public Sub HandleMessage(message As Message)
Dim msg As String = Encoding.UTF8.GetString(message.Body)
MsgBox(msg)
End Sub
Public Sub LogFailedMessage(message As Message)
Dim msg As String = Encoding.UTF8.GetString(message.Body)
MsgBox(msg)
End Sub
End Class
But i get a error on Implements IHandler
Lovely description of the problem, you can't get useful answers when you don't describe the exact error message you see. You did write the code wrong, VB.NET requires the Implements keyword on interface method implementations. You'd normally fall in the pit of success by letting the IDE generate these methods for you. As soon as you type "Implements IHandler" and press the Enter key, the IDE automagically adds the methods.
So there's probably something wrong with the library reference as well. Steps one-by-one:
Tools > Nuget Package Manager > Package Manager Console.
Type "Install-Package NsqSharp". Watch it trundle while it downloads and installs the package.
Put Imports NsqSharp at the top of the source file.
You should now end up with:
Public Class MessageHandler
Implements IHandler
Private Sub IHandler_HandleMessage(message As Message) Implements IHandler.HandleMessage
Dim msg As String = Encoding.UTF8.GetString(message.Body)
MessageBox.Show(msg)
End Sub
Private Sub IHandler_LogFailedMessage(message As Message) Implements IHandler.LogFailedMessage
Dim msg As String = Encoding.UTF8.GetString(message.Body)
MessageBox.Show(msg)
End Sub
End Class

Cannot load temporary file in VBCodeProvider

Here's my script code:
Imports System.Diagnostics
Public Class Script
Implements IScript
Public Sub DoWork(w As WebBrowser, f As Form1) Implements IScript.DoWork
w.Navigate("http://www.google.com")
wait("5000")
w.Document.All("input").InvokeMember("click")
w.Document.All("input").SetAttribute("value", "Torrenter is the best!")
wait("2000")
w.Document.All("421").InvokeMember("click")
wait("1000")
End Sub
Public Sub wait(ByVal interval As Integer)
Dim sw As New Stopwatch
sw.Start()
Do While sw.ElapsedMilliseconds < interval
' Allows UI to remain responsive
Application.DoEvents()
Loop
sw.Stop()
End Sub
End Class
In-code:
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
If int1.Text = "1" Then
int1.Text = "0"
Dim script As IScript = GenerateScript(File.ReadAllText(ListBox2.Items.Item(int2).ToString()))
script.DoWork(WebBrowser1, Me) 'Object reference not set to an instance of an object.
int2 = int2 + 1
int1.Text = "1"
End If
End Sub
Why? :(
It's supposed to start the next script after the first was done. I tried 4 methods but I can't understand why.
The problem is that your script code is failing to compile, but then you are trying to instantiate an object from the compiled assembly anyway. Since it failed to compile, the assembly doesn't actually exist, hence the error. If you modify the Return line in the GenerateScript method, so that it shows the compile errors, the actual problem will be more clear:
Dim results As CompilerResults = provider.CompileAssemblyFromSource(parameters, codes)
If results.Errors.HasErrors Then
Dim builder As New StringBuilder()
builder.AppendLine("Script failed to compile due to the following errors:")
For Each i As CompilerError In results.Errors
builder.AppendFormat("Line {0}: {1}", i.Line, i.ErrorText)
builder.AppendLine()
Next
Throw New Exception(builder.ToString())
Else
Return CType(results.CompiledAssembly.CreateInstance("Script"), IScript)
End If
I suspect that one of the reasons it's failing to compile is because the script uses IScript which is undefined. The reason it would complain that it's undefined is for two reasons. First, you declared the IScript interface as nested inside the Form1 class. You should move that outside of the form class so that it's not nested inside of any other type. Second, you are not specifying the full namespace nor importing the namespace in your script. You can automatically add the Imports line to the beginning of the script code before compiling it, like this:
Dim interfaceNamespace As String = GetType(IScript).Namespace
Dim codes As String = "Imports " & interfaceNamespace & Environment.NewLine & code
As I mentioned in the comments above, you really ought to be passing a string array into the CompileAssemblyFromSource method, not a string. I'm not sure how that even compiles, unless that's something having Option Strict Off somehow allows? In any case, it expects an array, so you should really be giving it one, like this:
Dim interfaceNamespace As String = GetType(IScript).Namespace
Dim codeArray() As String = New String() {"Imports " & interfaceNamespace & Environment.NewLine & code}
Dim results As CompilerResults = provider.CompileAssemblyFromSource(parameters, codeArray)
Another obvious reason why the script would fail to compile is because you have it using methods and properties of your Form1 class, as if it were a member of that class. Remember, the Script class defined by the script file source code is a completely separate class in a separate assembly. It will have no reference to the form unless you give it a reference, for instance, you could define the interface like this:
Public Interface IScript
Sub DoWork(f As Form1)
End Interface
Then, in your script, you could do this:
Public Class Script
Implements IScript
Public Sub DoWork(f As Form1) Implements IScript.DoWork
f.WebBrowser1.Navigate("http://www.google.com")
f.wait("5000")
f.wait("4000")
f.WebBrowser1.Document.All("input").InvokeMember("click")
f.WebBrowser1.Document.All("input").SetAttribute("value", "User")
f.wait("2000")
f.WebBrowser1.Document.All("421").InvokeMember("click")
End Sub
End Class
UPDATE
Ok, since you can't get it working, and I don't want this whole conversation to be a total loss, I put together a working project and tested it. Here's what you need to do to get it to work.
Contents of IScript.vb
Public Interface IScript
Sub DoWork(w As WebBrowser)
End Interface
Contents of Form1.vb
Imports Microsoft.VisualBasic
Imports System.CodeDom.Compiler
Imports System.Reflection
Imports System.IO
Imports System.Text
Public Class Form1
Dim int1 As Integer = 0
Dim int2 As Integer = 0
Dim p As Point
Public Function GenerateScript(ByVal code As String) As IScript
Using provider As New VBCodeProvider()
Dim parameters As New CompilerParameters()
parameters.GenerateInMemory = True
parameters.ReferencedAssemblies.Add(GetType(WebBrowser).Assembly.Location)
parameters.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location)
Dim interfaceNamespace As String = GetType(IScript).Namespace
code = "Imports System.Windows.Forms" & Environment.NewLine & "Imports " & interfaceNamespace & Environment.NewLine & code
Dim results As CompilerResults = provider.CompileAssemblyFromSource(parameters, code)
If results.Errors.HasErrors Then
Dim builder As New StringBuilder()
builder.AppendLine("Script failed to compile due to the following errors:")
For Each i As CompilerError In results.Errors
builder.AppendFormat("Line {0}: {1}", i.Line, i.ErrorText)
builder.AppendLine()
Next
Throw New Exception(builder.ToString())
Else
Return CType(results.CompiledAssembly.CreateInstance("Script"), IScript)
End If
End Using
End Function
Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
For Each File As FileInfo In New System.IO.DirectoryInfo(Application.StartupPath & "/scripts").GetFiles
If CheckedListBox1.GetItemCheckState(int2) = CheckState.Checked Then
ListBox1.Items.Add(File.FullName)
End If
int2 = int2 + 1
Next
int2 = 0
Dim script As IScript = GenerateScript(File.ReadAllText(ListBox1.Items.Item(int2).ToString()))
script.DoWork(WebBrowser1)
End Sub
End Class
Contents of script file
Imports System.Diagnostics
Public Class Script
Implements IScript
Public Sub DoWork(w As WebBrowser) Implements IScript.DoWork
w.Navigate("http://www.google.com")
wait("5000")
wait("4000")
w.Document.All("input").InvokeMember("click")
w.Document.All("input").SetAttribute("value", "User")
wait("2000")
w.Document.All("421").InvokeMember("click")
End Sub
Public Sub wait(ByVal interval As Integer)
Dim sw As New Stopwatch
sw.Start()
Do While sw.ElapsedMilliseconds < interval
' Allows UI to remain responsive
Application.DoEvents()
Loop
sw.Stop()
End Sub
End Class

paypal API in VB.net

Hey all, i have converted some C# PayPal API Code over to VB.net. I have added that code to a class within my project but i can not seem to access it:
Imports System
Imports com.paypal.sdk.services
Imports com.paypal.sdk.profiles
Imports com.paypal.sdk.util
Namespace GenerateCodeNVP
Public Class GetTransactionDetails
Public Sub New()
End Sub
Public Function GetTransactionDetailsCode(ByVal transactionID As String) As String
Dim caller As New NVPCallerServices()
Dim profile As IAPIProfile = ProfileFactory.createSignatureAPIProfile()
profile.APIUsername = "xxx"
profile.APIPassword = "xxx"
profile.APISignature = "xxx"
profile.Environment = "sandbox"
caller.APIProfile = profile
Dim encoder As New NVPCodec()
encoder("VERSION") = "51.0"
encoder("METHOD") = "GetTransactionDetails"
encoder("TRANSACTIONID") = transactionID
Dim pStrrequestforNvp As String = encoder.Encode()
Dim pStresponsenvp As String = caller.[Call](pStrrequestforNvp)
Dim decoder As New NVPCodec()
decoder.Decode(pStresponsenvp)
Return decoder("ACK")
End Function
End Class
End Namespace
I am using this to access that class:
Private Sub cmdGetTransDetail_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdGetTransDetail.Click
Dim thereturn As String
thereturn =GetTransactionDetailsCode("test51322")
End Sub
But it keeps telling me:
Error 2 Name 'GetTransactionDetailsCode' is not declared.
I'm new at calling classes in VB.net so any help would be great! :o)
David
Solved
Dim payPalAPI As New GenerateCodeNVP.GetTransactionDetails
Dim theReturn As String
theReturn = payPalAPI.GetTransactionDetailsCode("test51322")
You're probably getting that error because you need to call it like this:
Private Sub cmdGetTransDetail_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdGetTransDetail.Click
Dim thereturn As String
Dim myTransaction as new GetTransactionDetails
thereturn = myTransaction.GetTransactionDetailsCode("test51322")
End Sub
Or you can make the function be a public shared function and access it as if it were a static method
Your GetTransactionDetailsCode method is an instance method of the GetTransactionDetails class, which means that you need an instance of the GetTransactionDetails class in order to call the method.
You can do that like this:
Dim instance As New GetTransactionDetails()
thereturn = instance.GetTransactionDetailsCode("test51322")
However, your method doesn't actually use the class instance, so you should change your GetTransactionDetails class to a Module instead.