Check if .dll file exists and load it - vb.net

What is the easiest want to check if a .dll file exists, then to load it ? ( i don't need to use modules from that dll file, i just want to run it ).
I'd like to have simple example of code.

To check if a file exists use system.io.file.exists(path).
To load the assembly look at Assembly.Load, you can execute code from it by loading it, then calling Activator.CreateInstance on a type from that assembly. Once you have an instance of the type you can call methods on it.
If you don't have an interface defined on the type from the assembly for easy calling you will have to use Reflection to inspect the types and methods on those types. That starts getting more complicated and without a specific example of what you are trying to do I can't give you an example of how to actually do it in code.
updated example
The simplest way to just execute code from a dynamically loaded assembly involves knowing a few things about it in advance.
You should know in advance the name of the Type that contains the code you want to execute, the name of the Method that contains the code, and the parameters it takes. For this example lets say that you always have a class in the assembly called "MyClass", and the code you want to run is in a sub called "Execute" that take no parameters. You can load and execute it like this.
You should Import System.Reflection
Dim asm as Assembly = Assembly.LoadFrom("TheDll.dll") 'Load the assembly
dim t as type = asm.GetType("MyClass") 'Get a reference to the type that contains the code
dim info as MethodInfo = t.GetMethod("Execute") 'Get a reference to the method on the type that we want to call
dim instance as object = Activator.CreateInstance(t) 'Create an instance of the type to call the method on
info.Invoke(obj,nothing) 'Invoke the method with no parameters

Related

How can I pass a callable object to another function/subroutine without calling/invoking it?

I'm using VBA 7.1 in MS Office 2013. I'm trying to interact with a function in JavaScript (or an interface of it created using as close as possible in shortened code CreateObject("HtmlFile").ParentWindow.close - similar to window.close in JavaScript). The problem is, I'm trying to pass it to another function, but it keeps calling the actual window.close function in JavaScript as I pass it. This is where it gets weird: it doesn't get invoked in a few specific built-in functions.
CStr(obj) ' Invokes the interface; window close dialog appears
VarType(obj) ' Invokes the interface; window close dialog appears
IsEmpty(obj) ' Invokes the interface; window close dialog appears
TypeName(obj) ' Doesn't invoke the interface; returns "Object"
IsObject(obj) ' Doesn't invoke the interface; returns True
Is there a way to pass it around without invoking it?
EDIT: You can replicate the setup using this:
With CreateObject("HtmlFile")
.ParentWindow.ExecScript "obj = window.close"
Set obj = .ParentWindow.obj
End With
To answer your question is you pass the name of the object.
Objects are CODE. There is an object factory that makes your object.
The data structures for an object is 4x32 bit integers (Longs in VB talk). One is the reference count (and if 0 the object terminates), one is the address of the VTable (the address of each property get/set and method calls), two are reserved and are unused and always will be.
Due to the magic of COM your object appears as a data structure and a loaded function library in your program (even if it's an executable rather than a dll).
To pass objects that don't yet exist pass the name. JScript/VBScript can write code at runtime. In VBScript see execute, executeglobal, and eval. All take a string of VBScript code that becomes part of your program in various ways.

GetType() Shows non-existent type?

As I am trying to figure out how to work with the Siemens Tia Portal Openness framework, I try to find an item in my Tia Portal project with the ControllerTarget type.
I try to find the items like this:
Imports Siemens.Engineering
Imports Siemens.Engineering.HW
Module Module1
Sub Main()
Dim myTiaPortal
myTiaPortal = New TiaPortal(TiaPortalMode.WithoutUserInterface)
'The portal is open, now create a project.
Dim tiaProject As Project
'Open the sample project:
Dim fileName As String
fileName = "C:\Path\To\Project\Sample_Project.ap13"
tiaProject = myTiaPortal.Projects.Open(fileName)
'Get the frist device from the project:
Dim tiaDevice As Device
tiaDevice = tiaProject.Devices.First
For Each item As IDeviceItem In tiaDevice.DeviceItems
Console.WriteLine(item.GetType())
Next
Console.ReadKey()
End Sub
End Module
This shows two items in the project:
Siemens.Engineering.HW.DeviceItemImplementation
Siemens.Engineering.HW.ControllerTargetImplementation
When I try to define an object of the type ControllerTargetImplementation I get the message that this datatype does not exist.
When I try to convert the item of type ControllerTargetImplementation to an object of type ControllerTarget, this seems to work perfectly.
Does this mean that the type returned by GetType() does not have to be the same as the actual type of the object? Is this normal? Or is this a strange thing in the openness platform?
When I try to define an object of the type ControllerTargetImplementation I get the message that this datatype does not exist.
Types can be internal to an assembly, which means that while they exist and things like GetType will show them to be there, you can't use them directly.
When I try to convert the item of type ControllerTargetImplementation to an object of type ControllerTarget, this seems to work perfectly.
Given the names involved here, it certainly sounds like ControllerTarget is the type being exposed to you, the consumer of the library, while the implementation of that type, perhaps a subclass or an implementation of an interface (ie is ControllerTarget a class or interface?) is hidden from you as you don't need to know about how it does it's job, nor interfere with it.
Does this mean that the type returned by GetType() does not have to be the same as the actual type of the object?
The actual type of the object is what is reported by GetType, but that doesn't mean that it's necessarily what you refer to it as. For instance, consider the following:
Class A
End Class
Class B
Inherits A
End Class
Sub Main
Dim obj as A = new B()
Console.WriteLine(obj.GetType())
End Sub
This will report obj as having a type of B (because that's the actual type we instantiated with new B()), even though it's stored against a variable of type A.

Reference to a non-shared member requires an object reference in VB.net

I have a VB.net program that I got from someone else. It is comprised of a main form and 6 other modules (all .vb files). These files all have a "VB" icon next to them in the Explorer pane. I am trying to make a call to a sub-routine in one of the modules from the main form. My line of code is:
QuoteMgr.StartGettingQuotesLevel2(sSym)
where QuoteMgr is the name of the module and StartGettingQuotesLevel2(sSym) is the name of the sub-routine. When I enter this, I get the error message:
Reference to a non-shared member requires an object reference.
The sub-routine is defined in the QuoteMgr Module as follows:
Public Sub StartGettingQuotesLevel2(ByVal oSymbol As String)
What is strange is when I enter:
QuoteMgr.
(the name of the module with a period), it does not show me all the sub-routines and functions in the module. It only shows:
Update_Level1
Update_Level12
Update_Level2
These are Public Const in the module.
Can you tell me what I need to do?
What the compiler is trying to tell you with this error message
Reference to a non-shared member requires an object reference
is that the StartGettingQuotesLevel2 subroutine is an instance method not a shared or class method, see a more detailed explanation here
To call an instance method, you need to have an object instance to call it on. In your case, an object instance of the class type QuoteMgr. Like in the example below:
' create a new QuoteMgr object instance
Dim myQuoteMgr As QuoteMgr = New QuoteMgr()
' call its instance method with "abc" as its oSymbol argument.
myQuoteMgr.StartGettingQuotesLevel2("abc")
It is possible that you only want a single QuoteMgr object instance to be created and used by your main form. In that case, you can make it a member variable of your main form and create it once.
Public Partial Class MainForm
' Create it as a private member variable of the main form
Private m_QuoteMgr As QuoteMgr = New QuoteMgr()
' Use it when "some" button is pressed
Private Sub btnSome_Click(sender As Object, e As EventArgs) Handles btnSome.Click
m_QuoteMgr.StartGettingQuotesLevel2(txtSymbol.Text)
' And possibly do something with the results.
End Sub
End Class
Also, if instances of your QuoteMgr class depend on other object instances for their tasks, you will have to supply these to the constructor method of the QuoteMgr class as the arguments for its constructor's method parameters. Constructors (Sub New(...)) look like this:
Public Class QuoteMgr
' This is a constructor that takes two arguments
' - oMainSymbol: a string value
' - oKernel: an instance of the type Kernel
Public Sub New(oMainSymbol As String, ByRef oKernel As Kernel)
' ....
End Sub
End Class
That means, that when you create a QuoteMgr instance, you have to call its constructor method with the things it need, for example
' There must be an instance of Kernel created somewhere.
Dim myKernel As Kernel = ....
' create a new QuoteMgr object instance with these arguments:
' - oMainSymbol = "SYMABC"
' - oKernel = myKernel
Dim myQuoteMgr As QuoteMgr = New QuoteMgr("SYMABC", myKernel)
Some other recommendations
The explanations I have provided, are about basic VB.NET language features (e.g. the terms highlighted in bold). I suggest that before you make any changes to the code you have, you (1) make a backup of it, and (2) try to read a tutorial and practice on something smaller.
The compiler is (virtually) always right. When it gives you an error message, read it carefully, it will indicate the line where something is wrong and a message that tells you what it needs or is missing.
It is not the purpose of Stack Overflow to provide tutorials or code. It is a Q&A site where the best questions and answers deal with specific, delineated programming problems, for which succinct answers are possible.
Right click your application and go to Properties.
Make sure your application type is "Windows Forms Application".
It means that the routine you are trying to call needs to reference an instance of the form to access the routine. You can either reference an instance as Alex says, or you can make the routine 'Shared', so it doesn't need an instance. To do this, change the definition in QuoteMgr.vb to
Friend Shared Sub StartGettingQuotesLevel2(ByVal oSymbol As String)
Switching it to `Shared' may start showing compiler errors, if the routine accesses form controls or module-level variables. These will need to be added to the parameter list.

What is a public object module in VBA?

I'm trying to get as close to function pointers / abstract classes as I can in VBA.
I have a class called VerificationManager and verifies a bunch of cells in a couple of spreadsheets match up. This will be done in different ways depending on the information and spreadsheets being used with it.
I'd like to be able to make the code reusable by specifying a method to be called in a string using the Application.Run function. So I can rewrite the function that changes.
Now if I was using Java or C# I would be able to extend an abstract class and rewrite the internals to the function. If I was using JavaScript I could store a function in a variable and pass the variable to the class and call it from there.
Inside my class I have a public property called "verificationModule" which I set to the name of the function I want it to call.
Sub VerifyWorkLocations(empLoc As EmployerLocation)
...
For i = 0 To empLoc.numOfEmp
Application.Run verificationModule, empLoc.taxdescmatch, empLoc.employees(i)
Next i
...
End Sub
However, when I try to call Application.Run I receive the following error:
Compile Error:
"Only user-defined types defined in public object modules can be
coerced to or from a variant or passed to late-bound functions"
I already tried placing my User Defined Types in a Class Module but it basically said that a class module was the wrong place for a type.
The error comes from full-fledged VB, where you can create an ActiveX dll project, create a public class there and put a UDT into that class.
In VBA, you use classes instead of UDTs when you need to coerce to or from a variant.
So just declare a class with all the fields you have in your UDT, and delete the UDT.
Alternatively, create a DLL in VB6 that would only contain the declaration of the type, and reference that dll from VBA. Or, if you're comfortable with IDL, just create a TLB file directly.
To add a module to a VBA application, try the following steps (assuming you've already entered the VBA IDE):
From the Project Explorer, right-click on your project.
Click on "Insert..."
Select "Module."
If no modules exist, a new folder within the VBA/Excel project will be created, named "Modules," and a module with a default name of "Module1" will be created.
Double-click the module to open it in the source editor.
This is where you have to place UDT's. I believe this is because of the difference in the way such types are stored internally by VBA relative to the COM-style structure of elements/objects declared/manipulated as Classes...

How to specify a code module as the "Object Ref" parameter in VB.Net CallByName?

I am trying to call a public subroutine from a Windows form based on a string variable containing the name of the subroutine. The subroutine is a procedure in a code module and works fine when called by using the procedure name directly.
The VB.net function CallByName should work, but I don't know how to specify the module name as the "Object Ref" parameter.
In the code shown, "ReportLibrary" is a module containing the public sub with the name contained in the string strReportProcedure. This results in the following error helper:
The Help says this about the ObjectRef parameter:
ObjectRef
Type: System.Object
Required. Object. A pointer to the object exposing the property or method.
What am I missing or is it just not possible to call a routine from a module using CallByName?
CallByName will not work for code in VB.Net modules since the first parameter requires an object. You need to move the methods into a class, then create an instance of the class in order to make CallByName work.
Hmmm, I think the problem is somewhere else.
I think you haven't declared a variable like this:
Dim RL as NEW Reportlibrary
And after declaring it, use this:
CallByName(RL, strReportProcedure , CallType.Method , blnPreview)
Probably the problem was in declaration, because (in your case) your class doesn't let you access to your library's subroutines. That's why you need to declare "as New ReportLibrary".
Good Luck !
Dim object As NEW Reportlibrary and then just use that Object.