InterviewSolution
| 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. A couple (a lot of) problems with this: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+dynamicallyI 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). |
|