1.

Solve : Trying to make a remote app that you can change code anytime, need help. VB?

Answer»

So I'm kind of interested to experiment with this, what I'm trying to do is make the program read the code off an uploaded text file that I'm able to change anytime. Well I'm kind of stuck, here is what i got.



Code: [Select]Imports System.Net
Imports System.IO

Public Class Form1

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim request As System.Net.HttpWebRequest = System.Net.HttpWebRequest.Create("the link to the text file with all the code")
Dim response As System.Net.HttpWebResponse = request.GetResponse()
Dim stream As System.IO.StreamReader = New System.IO.StreamReader(response.GetResponseStream())
stream.ReadToEnd()
End Sub
End Class

Uploaded text file can be any code for example:
Code: [Select] Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
messagebox.show ("Hello")
End Sub
End Class


It will end up being a sub within a sub or something like that, i haven't gotten that far in the programming language. Anything to help would be great, Thanks.A couple (a lot of) problems with this:
1. This isn't exactly a good idea -- someone can just watch the network requests and download all your source code -- do you really want that?
2. Are you really going to download the source code at every program run? You'll have a LOT of downloading to do when your program gets to be bigger (and trust me, it eventually will)
3. What about other files you need? 3rd party libraries? Images? How will it download or know to download those?
4. How on earth are you going to execute this? You'll basically have to either re-compile the program every run (takes time to do, requires every PC the program is run on to have the proper SDKs/tools, and will frustrate users) OR interpret it (.NET is not optimized for direct interpretation).
5. Your 'sample' won't work in any case because types are immutable -- you can't add part of a class at runtime; about the closest you can get is a class in an external library that implements some common interface.
6. What if the internet is down?
7. There are many ways to deliver and check for updates (assuming that's what you're doing) that are better than this.

If I may ask, what are you trying to accomplish by being able to edit the code in this way? It's a really good way to frustrate users when you make changes to the user interface without warning.Quote from: TechnoGeek on November 09, 2012, 10:18:58 PM

A couple (a lot of) problems with this:
1. This isn't exactly a good idea -- someone can just watch the network requests and download all your source code -- do you really want that?
2. Are you really going to download the source code at every program run? You'll have a LOT of downloading to do when your program gets to be bigger (and trust me, it eventually will)
3. What about other files you need? 3rd party libraries? Images? How will it download or know to download those?
4. How on earth are you going to execute this? You'll basically have to either re-compile the program every run (takes time to do, requires every PC the program is run on to have the proper SDKs/tools, and will frustrate users) OR interpret it (.NET is not optimized for direct interpretation).
5. Your 'sample' won't work in any case because types are immutable -- you can't add part of a class at runtime; about the closest you can get is a class in an external library that implements some common interface.
6. What if the internet is down?
7. There are many ways to deliver and check for updates (assuming that's what you're doing) that are better than this.

If I may ask, what are you trying to accomplish by being able to edit the code in this way? It's a really good way to frustrate users when you make changes to the user interface without warning.
It's just something to simply try out, there is really no point to the program I'm making other then running code from an uploaded file. It's just for fun and not for a serious program.here's some stuff that may help: https://duckduckgo.com/?q=compile+vb.net+dynamically
The thing about re-compiling in #4 and #5 isn't quite accurate, I didn't know about the dynamic compilation libraries available .NET before. But the performance considerations still stand, I think.Quote from: TechnoGeek on November 09, 2012, 11:02:57 PM
here's some stuff that may help: https://duckduckgo.com/?q=compile+vb.net+dynamically
The thing about re-compiling in #4 and #5 isn't quite accurate, I didn't know about the dynamic compilation libraries available .NET before. But the performance considerations still stand, I think.
I am using visual studio if that helps at all, I'm not using any old VB 6.0 or anything.Quote from: DaftHacker on November 09, 2012, 11:14:37 PM
I am using visual studio if that helps at all, I'm not using any old VB 6.0 or anything.

VB6.0 was part of visual studio. I can see from your screenshot that you're using VS2012 (running as admin for whatever reason), and maybe not the express version either given some of the menus you have available (unless those are VB specific). I think you'll find if you look that ONE of the first results in that link I posted has a zip file of sample code you can look at, which should work on any recent version of VB.NET.Not having a GOAL on what to specifcially achieve with such a program, and to achieve anything within the limitations of VB itself or any other language you chose to use, with the dynamic creation remotely, I would think that you would want to create a web interface by which to authenticate against, and create your code with, then have a routine on the web server side process and compile your code, and then offer you up a dynamic hyperlink pointing to your finished compiled product for download to the workstation etc that your on.

Only catch in this and VB is that I am not aware of any command line compilers for VB where there are numerous ones available for C++ which I work with. On the server side you would need to have a routine that takes your program and compiles it and then references to the compiled product and to do this, you would need to be able to execute a command via command line to compile from within say the Perl script which can interface with the command prompt on the fly and run an external process to that of the Perl CGI etc.

Personally this is A LOT OF WORK to create a program through a remote web interface, when its easiest to create the code locally. And would be even more involved if you made a WYSIWYG type interface that makes it so that a person who doesnt even know VB could assemble objects and create VB programs similar to WYSIWYG HTML creation tools.

The only programs I have ever created that were changed remotely, where controlled in a way that the code itself did not change. I had a program with a purpose, and within my program I had all the bells and whistles I needed. The program would read in a config file and that config file gave the program the variable inputs to process the correct routines based on simple IF,THEN,ELSE and loops in the functionality. So I wouldnt have to send a new EXE to a workstation or server to perform different tasks, the tasks could be changed by changing the config file and sending that config file over the private network to the systems/servers, and upon scheduled task, trigger and run the way I wanted it to following DIRECTIONS from the Config.TXT file that was in the root of the EXE.VB.NET,C#, and even FSharp expose their compilers as part of the .NET Framework, as part of the System.CodeDom.Compiler namespace. the C# Compiler is the CSharpCodeProvider class; the VB.NET compiler is the VBCodeProvider. These can both be used to compile files or strings into full Assemblies.

The compilation unit of .NET is the assembly. The best way to work with an assembly is with either concrete classes or interfaces. Create a class definition that implements that known interface or derives from a known concrete class, and then use the CodeDOM to compile that file into an assembly, using one of the language code providers.

The compilation is the same as that performed by Visual Studio. The resulting Assembly is not interpreted anymore than something compiled from Within Visual Studio. The only catch is that you cannot unload dynamically compiled Assemblies unless you load them in a separate AppDomain, but that should only be an issue if your program runs for very long periods and loads a lot of separate assemblies. This can usually be mitigated by simply doing all the compilation needed during application startup.

One important piece is that you need a consistent interface. That is, Something that the main program knows to look for in the resulting compiled assembly.
Thankfully, you can implement a simple interface in your external file, and use that.


Eg. ICodeRunner interface:

Code: [Select]Public Interface ICodeRunner


Sub Run()

End Interface



and a program that reads .cs and .vb files and compiles them into Assemblies, which it stores in a List. It then iterates through each assembly and then each Type in each Assembly and looks for classes that Implement the ICodeRunner interface defined in the project, and when it does it instantiates them and runs the interface method.


Code: [Select]Imports System.Reflection
Imports System.IO
Imports System.CodeDom.Compiler
Imports Microsoft.CSharp

Module Module1

Sub Main()

Dim PathUse As String = Assembly.GetExecutingAssembly().Location
PathUse = PathUse.Substring(0, PathUse.LastIndexOf(Path.DirectorySeparatorChar))
Dim di As New DirectoryInfo(PathUse)
Dim AssemblyResults As New List(Of Assembly)()

Dim fi As FileInfo
For Each fi In di.GetFiles()
Dim result As Assembly = CompileScriptToAssembly(fi.FullName)
If Not result Is Nothing Then AssemblyResults.Add(result)

Next
Dim Runthese As New List(Of ICodeRunner)()
For Each iterate As Assembly In AssemblyResults

For Each looptype As Type In iterate.GetTypes()
If looptype.GetInterfaces().Contains(GetType(ICodeRunner)) Then

Runthese.Add(Activator.CreateInstance(looptype))

End If



Next


Next


'now run them...
For Each looprun As ICodeRunner In Runthese
looprun.Run()
Next

Console.ReadKey()

End Sub

Public Function GetTempPath() As String
Dim tpath As String = Path.GetTempPath()
tpath = Path.Combine(tpath, Assembly.GetExecutingAssembly().GetName().Name)
If Not Directory.Exists(tpath) Then Directory.CreateDirectory(tpath)
Return tpath
End Function
Public Function CompileScriptToAssembly(ByVal ScriptFile As String) As Assembly
Try
Dim readfilein As New FileStream(ScriptFile, FileMode.Open)
Dim sr As New StreamReader(readfilein)
Dim allcode As String = sr.ReadToEnd()
sr.Close()
Dim ExtensionTest As String = Path.GetExtension(ScriptFile).ToLower()
Dim AssemblyNames As String() = New String() {"system.dll", "system.Design.dll", "System.Xml.dll", "system.data.dll", "system.windows.forms.dll", "system.drawing.dll", Assembly.GetExecutingAssembly().Location}
Dim cp As New CompilerParameters(AssemblyNames)
cp.GenerateExecutable = False
cp.GenerateInMemory = TRUE
Dim outfile As String = Path.Combine(GetTempPath(), "script_" + Path.GetFileNameWithoutExtension(ScriptFile))
If File.Exists(outfile) Then File.Delete(outfile)
cp.OutputAssembly = outfile
Dim result As Assembly
Dim cr As CompilerResults = Nothing
Select Case ExtensionTest
Case ".cs"
Dim Prov As New CSharpCodeProvider()
cr = Prov.CompileAssemblyFromFile(cp, New String() {ScriptFile})
Case ".vb"
Dim Prov As New VBCodeProvider()
cr = Prov.CompileAssemblyFromFile(cp, New String() {ScriptFile})
Case Else
Return Nothing
End Select

If cr.Errors.HasErrors OrElse cr.Errors.HasWarnings Then
'Errors occured during compilation...



Else
Return cr.CompiledAssembly
End If
Catch
Return Nothing


End Try

End Function

End Module


As a console project- then put the following in the Bin/Debug folder, in a file called "RunExample.vb":

Code: [Select]imports System
imports dynamicrunner

Public Class RunExample
Implements ICodeRunner
Public Sub Run() Implements ICodeRunner.Run
Console.WriteLine("Executing from outside the program!")


End Sub



End Class

The End result is the output "Executing from outside the program" indicating that the "text file" was compiled and run.


This example uses files as the main source, but the requisite functions (CompileToAssembly) Can also accept plain strings. You could always use a WebClient to download a file to a local path before compiling, as well.

This simple implementation doesn't do anything special in the case of errors. (The C# Code that I derived it from uses a special Exception class to represent the aggregation of compiler errors, but I've removed it for brevity in this VB.NET implementation).





Discussion

No Comment Found