How to use Activator.CreateInstance to instantiate an external class? - vb.net

I have an application where I want to instantiate a class that is completely outside the application, perhaps written at a later date by a third party. So the class cannot be known, but the interfaces in the class are known. So I want to use late binding.
In my code (VB.NET), I have the following:
Dim a As Object
a = Activator.CreateInstance("MyNameSpace.CustomClass", "")
MsgBox(a.Name)
I get an exception at the second line: Could not load file or assembly 'MyNameSpace.CustomClass' or one of its dependencies. The system cannot find the file specified. even though the assembly is in the same folder as the executable. I can't use Type.GetType() because the type is not known to the calling assembly.

You need the CreateInstanceFrom method.
var typeReference = Activator.CreateInstanceFrom(assemblyPath,
fullyQualifiedClassName);
But, for me, MEF would be a better solution as you can bind the Import/Export on the interface.

Related

Permission class in vb.net

creating an assembly named Assembly1. Assembly1 contains a public method.
The global cache contains a second assembly named Assembly2. You must ensure that
the public method is only called from Assembly2. Which permission class should you use?
It is impossible to say "method can be used only by Assembly2". But, if I understood you correctly and your goal is to prevent calls from any other assembly, except for Assembly1 or Assembly2, I have an answer.
In .NET you can do this using some trick. You can make your public method Friend (can be used only by Assembly1). And then use Friendly Assembly mechanism. After that you will have method that could be called only from Assembly1 or Assembly2.

Add path to Current AppDomain

I have two completely different directories. Directory 1 contains my application and Directory 2 having few assemblies. During run-time when application launches, I will load the assemblies. By default, the executing Assembly's AppDomain will discover the assemblies in Directory 1 (application folder) or GAC. If the file is not there, we will get the error. But I have to extend the AppDomain's search directory to search in Directory 2 also. That is, AppDomain will search Directory1 (local bin), then GAC, then other defaults at last search in Directory 2.
I have tried :
1. By setting PrivateBinPath, but it is restricted only within ApplicationBaseDirectory.
2. By AssemblyResolve, but it is not directly referenced. The AssemblyResolve code never hits also.
Using the AssemblyResolve event is generally the correct way. If it is never hit, it is probably bound to too late. For instance, when the CLR encounters a method, it will compile it completely, resolving all its references. If such resolution fails, it will fail always. If you bind the AssemblyResolve event after any or all assemblies failed binding, the event will never hit.
To resolve this, make sure that the AssemblyResolve event is bound as early as possible. In an executable this is easy enough (first thing in the entry point of your application, or any cctor of a type you use there). In a library this can be harder, best practice approach is to use the module initializer, which is run whenever a module is loaded (most assemblies contain one module).
Since the module initializer cannot be set by C# or any other .NET language I know of, you have to resort to method weaving. I personally like Fody and as it turns out, there's a predefined Fody package called Fody Module Init for exactly this thing.
Just place, somewhere publicly in your library, the following code:
public static class ModuleInitializer
{
public static void Initialize()
{
// bind to the CurrentDomain.AssemblyResolve event
}
}
Fody also works with other languages (you don't specify which you use), but then you'll have to create the static ModuleInitializer class by hand.
Using this approach, you can be certain that the AssemblyResolve event will be called for any assembly that CLR's Fusion cannot find by itself.

Automating an Application using COM

I am building an automation interface for an existing application. After implementing a DLL server and an EXE server (mainly for getting familiar with the basics of COM) I am now at the point where I generate a type library from an IDL file and can, for example, basically automate my application from VBScript:
Set oApp = CreateObject("MyApp.1")
oApp.ShowAboutBox()
This simple call to a function that takes no parameters works. The next step I want to take is call a function that takes a parameter.
The signature of the function in the IDL file is
HRESULT CreateSomeChildWindow([out, retval] MyChildWindow** ppChildWindow);
and in VBScript I assume it would be
Dim oWnd As MyChildWindow
oWnd = oApp.CreateSomeChildWindow()
This call already works in C++ although MyChildWindow is not currently registered as a COM object in the registry. The reason MyChildWindow doesn't need to be registered is that CreateSomeChildWindow simply returns the interface pointer to the created MyChildWindow object in a parameter. And the reason it isn't registered is that I want to avoid redundancy, and also I don't want MyChildWindow to be instantiated directly (e.g. by calling CreateObject in VBScript).
Question:
Now I'm trying to find out whether it will be necessary to register MyChildWindow after all. Is my assumption correct that in order to call CreateSomeChildWindow in VBScript
I need to write Dim oWnd As MyChildWindow
For this to work, MyChildWindow must be registered
And if the answer to that is yes, hopefully clients still can't MyChildWindow directly, since I don't implement a class object for it? Or will I have to implement a class object?
Your out/retval is not an object (on the scripting side), it is an interface pointer. And since the method CreateSomeChildWindow is on IDL, in type library, in registered type library - scripting/automation is aware of interface definition, such as methods etc, because the whole type library is already registered. You are already well set, no additional registration required.
When caller receives an interface pointer, it does not care what object the pointer belongs to. Interface pointer alone is good enough, and scripting/automation environment known how to deal with it.
On the callee side however, you need to return an interface pointer, and you are dealing with objects. So you need some class which implements this interface and you return this object's interface.

.NET class as callback object in COM DLL

I am a relative newcomer to Windows programming and VB.net. What we are trying to do is call a function in an existing, 3rd party COM dll. This function requires a callback parameter, whose type is an interface also defined in the dll.
In our VB.net application, we have added the dll as a COM reference, and created a class that implements the interface in the DLL. We then send an object of that type as the callback parameter. This compiles fine. However, when we run the application, we receive an error stating that the program is unable to cast the object from our existing type to the interface type.
I suspect that there is a simple fix, but so far, my efforts to find a solution have come up short. If anyone could point me in the right direction, I'd be very grateful.
Thanks very much.
I suggest you to check whether the COM interface which you are implementing has a registerd proxy/stub or a correspondent typelibrary (tlb). You may check this by searching the interface's IID (this is a guid assossiated with this interface) in the registry:
Proxy/stub case:
HKEY_CLASSES_ROOT
Interface
{iid}
(Default) = ICustomInterfaceName
ProxyStubClsid32 = {clsid}
Typelibrary case:
HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}
HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0 = Automation Hello 2.0 Type Library.
HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0\HELPDIR =
; U.S. English.
HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0\9\win32 = hello.tlb
Replace {F37C8060-4AD5-101B-B826-00DD01103DE1} with a guid assossiated with your typelibrary.
In case if the typelibrary is registered. Check if its file is present on your PC

How to get the executable path from a Managed DLL

I have a managed DLL (written in C++/CLI) that contains a class used by a C# executable. In the constructor of the class, I need to get access to the full path of the executable referencing the DLL. In the actual app I know I can use the Application object to do this, but how can I do it from a managed DLL?
Assembly.GetCallingAssembly()
or
Assembly.GetExecutingAssembly()
or
Assembly.GetEntryAssembly()
Depending on your need.
Then use Location or CodeBase property (I never remember which one).
#leppie: Thanks - that was the pointer I needed.
For future reference, in C++/CLI this is the actual syntax that works:
String^ appPathString = Assembly::GetEntryAssembly()->Location;
GetExecutingAssembly() provided the name of the DLL
GetCallingAssembly() returned something like System.Windows.Forms
GetEntryAssembly returned the full path, similar to GetModulePath() under Win32.