VB.NET Automatically include DLLs in specific folder - vb.net

I have a project where I have a directory called plugins/ which will contain multiple DLLs.
As an example, I will have two (2) DLLs in my plugins/ directory: Visual.dll and Momen.dll
Each of those will be a Class, Visual.dll will have the Class name Visual and Momen.dll will have the Class name Momen.
I need to make a loop that will loop through all DLL files in my plugins/ directory; once in that loop, it will obviously know the file is Visual.dll or Momen.dll. First, it will need to include the DLLs (just as if I added them as References to my Project) so that I can use them. If the loop is at Visual.dll, I will then need it to create an instance of the Visual Class, and then execute a method called Run()
I'm a PHP developer, and relatively new to VB.NET, in PHP I'd be able to do something like, which would create a new instance of my Visual Class (while passing a few arguments), then execute the Run() method:
$className = "Visual";
$instance = new $className("arg1", "arg2");
$instance->Run();
I appreciate any help.
Thank you

If the DLLs are .NET assemblies, then you can load them with Assembly.LoadFile. That will give you a reference to an Assembly object.
You can use the assembly's GetExportedTypes method to view public types in the assembly, or the GetType overload that takes a string parameter to get a type from the assembly based on its name.
From there, you should be able to use an appropriate overload of Activator.CreateInstance to create an instance of the class. From there, you should also be able to find and run its Run method through reflection.
Edit This is untested, but something like this might work (or be close to working):
Dim plugin As Assembly = Assembly.LoadFile("test.dll")
Dim pluginType As Type = plugin.GetType("Test")
Dim instance As Object = Activator.CreateInstance(pluginType)
Dim runMethod As MethodInfo = pluginType.GetMethod("Run")
Dim param1 As String = "Hello"
Dim param2 As String = "World"
runMethod.Invoke(instance, New Object() {param1, param2})
If you're going to do much with plugins other than just load and run a method, then it might be worthwhile to look for a plugin framework to use.

Related

TypeScript API for SourceFile creation: how to get syntactic errors information

TypeScript API Program has method getSyntacticDiagnostics to get syntactic errors. But if there is no Program, just SourceFile how can I get the same kind of information?
I created SourceFile through
function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes?: boolean, scriptKind?: ScriptKind): SourceFile;
Remember that fileName (string) parameter in createSourceFile is virtual file name. This fileName (string) is used globaly while using TypeScript library.
The most important thing what you need is what doc comment on createProgam method says. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions' that represent a compilation unit. createProgam method as first parameter requires list of strings which are virtual names of files used in this program.
If you don't understand previous 2 theoretical paragraphs I think that comments in sample will help you.
// this is the real code of file. Use fs.readFile, fs.readFileSync or something other to load file real source code.
var code = "class 1X {}";
// I will use this virtual name to reference SourceFile while working with TypeScript API.
var virtualFileName = "aaa.ts";
// initialize SourceFile instance
var sf = ts.createSourceFile(virtualFileName, code, ts.ScriptTarget.ES5);
// Make program as collection of my one virtual file
var prog = ts.createProgram([virtualFileName], {});
// process response as you need.
console.log(prog.getSyntacticDiagnostics(sf));

How to convert a type, loaded from one project, to an interface

Prerequisites
.NET environment
A Common assembly with an interface IModule
Main project, referencing Common
Implementor project, referencing Common, but not referenced from Main
When everything is built, the Common.dll is present in both Main and Implementor.
Now the Main project tries to load the class implementing IModule at runtime. What I could achieve so far:
Dim asm = Assembly.LoadFrom(asmFile)
For Each asmType in asm.GetExportedTypes()
If asmType.IsClass AndAlso
asmType.GetInterfaces().Any(Function(i) i.Name = GetType(IModule).Name) Then
Dim handle = AppDomain.CurrentDomain.CreateInstanceFrom(asmFile, asmType.FullName)
Dim inst = CType(handle.Unwrap(), IModule) ' EXCEPTION
End If
Next
So I can load the Implementor assembly and find the type implementing IModule. But I can't create an instance of it such that I can cast it to my local IModule. Is this at all possible?
Workaround
I found a workaround - in Implementor project, click on reference to Common and clear "Copy Local" flag. Then I can even use simpler code, like IsAssignableFrom(). But is this the only way? What if I get a DLL from third party, where the IModule is compiled into it?
EDIT:
Assembly.LoadFrom loads the first found matching assembly in a directory tree (via the so called Probing Path). So if you have your Common DLLin folder A and the updated Common DLL is in folder A\B then the one in folder A is taken (if both dlls have the same name).
From MSDN:
The load-from context allows an assembly to be loaded from a path not
included in probing, and yet allows dependencies on that path to be
found and loaded because the path information is maintained by the
context.
The LoadFrom method has the following disadvantages.Consider using
Load instead.
If an assembly with the same identity is already loaded, LoadFrom returns the loaded assembly even if a different path was specified.
If an assembly is loaded with LoadFrom, and later an assembly in the load context attempts to load the same assembly by display name,
the load attempt fails.This can occur when an assembly is
de-serialized.
If an assembly is loaded with LoadFrom, and the probing path includes an assembly with the same identity but a different location,
an InvalidCastException, MissingMethodException, or other unexpected
behavior can occur.
Original Answer:
Use Activator.CreateInstance to create the object and typeof to check if it implements the Interface :
Dim a As assembly = Assembly.LoadFrom(asmFile)
Dim concreteModule As IModule = Nothing
For each type In a.GetExportedTypes().Where(Function(x) x.IsClass)
Dim o = Activator.CreateInstance(type)
If TypeOf o Is IModule
concreteModule = DirectCast(o, IModule)
Exit For
End If
Next
Remark:
You wrote: But I can't create an instance of it such that I can cast it to my local IModule.
The concrete object must implement the Interface you cast to. I donĀ“t know if I understood you correctly but casting from a Interface IModule in a 3rd party dll to a different Interface IModule* in your local dll will not work (unless your local interface implements the other).

How to load DLL file from Jscript file?

So I'm writing a standalone JScript file to be executed by Windows Script Host (this file is not going to be used as a web application).
My goal is to load a dll file. Just like using LoadLibrary function in a C++ application.
I tried researching the subject but I didn't come up with anything useful. I'm so lost I don't have any piece of code to share. I understand using ActiveXObject may come to my rescue. if so, any idea how to use it?
Update:
If we all agree that loading is impossible, I'll settle for validity check. Meaning, don't try to load but check if it is loaded and functional.
You can export a specific function for this purpose.
Then, from your JScript, execute rundll32.exe and check that the function ran as expected.
You might also give Gilles Laurent's DynaWrap
ocx a chance.
This kind of dll needs to be registered on the target system like regsvr32 /s DynaWrap.dll.
It is restricted to 32-bit DLLs, and this might be inconvenient for you to use, but it works on a 64bit Windows. You can't access function exported by ordinal number and you can't directly handle 64bit or greater values/pointers.
Here's a sample to call MessageBoxA from JScript:
var oDynaWrap = new ActiveXObject( "DynamicWrapper" )
// to call MessageBoxA(), first register the API function
oDynaWrap.Register( "USER32.DLL", "MessageBoxA", "I=HsSu", "f=s", "R=l" )
// now call the function
oDynaWrap.MessageBoxA( null, "MessageBoxA()", "A messagebox from JScript...", 3 )
And here from VBScript:
Option Explicit
Dim oDynaWrap
Set oDynaWrap = CreateObject( "DynamicWrapper" )
' to call MessageBoxA(), first register the API function
UserWrap.Register "USER32.DLL", "MessageBoxA", "I=HsSu", "f=s", "R=l"
' now call the function
UserWrap.MessageBoxA Null, "MessageBoxA()", "A messagebox from VBScript...", 3
To use a function you need to "register" the exported function of your DLL.
To do this you need to call the register method with a first parameter containing a string object to the complete path of the DLL, a second parameter for the exported name of the function to use, and following three paremeters describing the functions declartion in a somehow obscure syntax.
i= describes the number and data type of the functions parameters.
f= describes the type of call: _stdcall or _cdecl. Default to _stdcall.
r= describes the return values data type.
The supported data types are:
Code Variant Description
a VT_DISPATCH IDispatch*
b VT_BOOL BOOL
c VT_I4 unsigned char
d VT_R8 8 byte real
f VT_R4 4 byte real
h VT_I4 HANDLE
k VT_UNKNOWN IUnknown*
l VT_I4 LONG
p VT_PTR pointer
r VT_LPSTR string by reference
s VT_LPSTR string
t VT_I2 SHORT
u VT_UINT UINT
w VT_LPWSTR wide string
Thus the Register method call used in the examples describes MessageBoxA like this:
_stdcall LONG MessageBoxA( HANDLE, LPSTR, LPSTR, UINT );
For a explanation of MessageBoxA look at the docs on MSDN.
Please read the DynaWrap docs for more sophisticated examples... But you might need Google translate, 'cos they are written in french ;-)
To be able to use a dll as ActiveXObject, it needs to be registered as COM object. There are some restrictions on this but if you have a code for this dll, it is certainly doable.
When you register your dll as COM object, it is assigned a name. You use this name to create an object. This example from MSDN uses excel since it is already registered if you installed office.
var ExcelApp = new ActiveXObject("Excel.Application");
var ExcelSheet = new ActiveXObject("Excel.Sheet");
// Make Excel visible through the Application object.
ExcelSheet.Application.Visible = true;
// Place some text in the first cell of the sheet.
ExcelSheet.ActiveSheet.Cells(1,1).Value = "This is column A, row 1";
// Save the sheet.
ExcelSheet.SaveAs("C:\\TEST.XLS");
// Close Excel with the Quit method on the Application object.
ExcelSheet.Application.Quit();
Apart from restriction of registering dll, using dll is no different from using it as c++ or c# dll. Note that, C# (or other .NET dlls) should be ComVisible to be used from javascript this way.
EDIT: The only other way of using C/C++ dll from javascript is swig interfaces. I have not used it, therefore I can only point you in that direction.
SWIG is a software development tool that connects programs written in
C and C++ with a variety of high-level programming languages. SWIG is
used with different types of target languages including common
scripting languages such as Javascript, Perl, PHP, Python, Tcl and
Ruby.

Getting current file

I know in vb.net you can use System.Reflection.MethodInfo.GetCurrentMethod.ToString to get the name of the current method you are in. However, is there a way to use System.Reflection... to get the name of the current file you are in?
So if you had a file in the project named blah.vb I would want System.Reflection... to return blah.vb
Is this possible?
You can use System.Reflection.Assembly to find the file name of the current assembly. There are several applicable methods to choose from:
GetEntryAssembly - Returns the assembly that started the process (the executable)
GetCallingAssembly - Returns the assembly that called the current method
GetExecutingAssembly - Returns the assembly in which the current method resides
I suspect that what you want is GetExecutingAssembly. All of those methods return an Assembly object through which you can get the file path, like this:
Dim myFilePath As String = System.Reflection.Assembly.GetExecutingAssembly().Location
For what it's worth, if you need get the file name of the executable, but it's not a .NET assembly (because you're in a .NET library invoked via COM), then the above method won't work. For that, the best option would be to grab the first argument from the command line, like this:
Dim myComExeFile As String = Environment.GetCommandLineArgs()(0)

Load DLL with parameters

I need to delete every single function from my project (VB.Net) and place them in separate DLLs. For example, i have a function that creates a text file and appends text to it. I need a solution that will load my AppendToTextFile.DLL with params just like a function works.
At this time my function accepts two parameters like
AppendToTextFile("C:\test\textFile.txt", "text to be appended")
Does anyone know how to load a custom DLL with params like the function above?
Create your custom DLL.
Then add it as reference to your project.
Call you function and use it like this :
Dim mydll As New MyCustomeDll
mydll.AppendToTextFile("C:\test\textFile.txt", "text to be appended")
That's all.