Is it possible to create a DLL which contains another DLL? - c#

I am working on a project. The task is to create a DLL Project. In that project, I am having an existing DLL with set of methods. With the use of existing DLL I can call some methods and create some methods in the new DLL.
Is that Possible in C#? What are the possibilities and methods to create such a project?

If you want to hide that DLL in the contents of your own DLL, you can simply put it into resources. From the standpoint of resources, a DLL is just a file like any other and you can simply add it to program resources and simply drop the file where you need it.
However this will prohibit you from using implicit linking and you will have to link the DLL explicitly. MSDN already offers a quite reasonable tutorial already and here.
using System;
using System.Reflection;
public class Asmload0
{
public static void Main()
{
// Use the file name to load the assembly into the current
// application domain.
Assembly a = Assembly.Load("example");
// Get the type to use.
Type myType = a.GetType("Example");
// Get the method to call.
MethodInfo myMethod = myType.GetMethod("MethodA");
// Create an instance.
object obj = Activator.CreateInstance(myType);
// Execute the method.
myMethod.Invoke(obj, null);
}
}
If you want to create your own DLL that just uses the old one you may just Add Reference. Then you can set up "Use Copy Local", but you will have to distribute two files:
And if you want to make "static link" simply by compiler/linker (build in to visual studio) you need to use a statically linked library (LIB) and not a dynamically linkws library (DLL)...
Or you can try reading "How to link a .DLL statically?" which seems to provide some guidance (proprietary software) on how to do this.

Related

How to update dll while using it in Visual Studio

I want to replace dll "a" to their new version while the application is running, but when I trying to make it, I getting error: IOException that this file already using by process.
How can I replace it without getting this error?
Even if you were able to do what you're describing, and you're not, but even if you were, the code that's already executed, along with a large portion of the code physically around it has already been loaded in memory by the pre-loader and JIT. A large part of that was probably also already JITed. So you replacing the file would only affect new page faults, leading to internal corruption when they resolve against your new library.
Instead .Net provides AppDomain instances to let you load and unload libraries into for a moderate performance cost when using them, allowing you to unload your libraries when you want to do your update magic.
However I cannot stress enough how unviable your solution is. The standard update process is, and always has been:
download your new files in a separate folder
start a second, smaller, preferably C++ application (less prerequisites) that:
waits for the main application to close (you can use a named mutex)
copies the files from the temp folder over to the main folder
handles any errors, and deletes the temp folder if everything went alright
starts the main application again
as soon as the second application is started, exit out of the main application
One of possible solutions.
Note: in this solution constructor must be parameterless. Logic with input parameters must be separated to Initialize() method.
Separate all models/interfaces/enums etc. from
project "a" to another project (let's call it "Models").
Make reference from Models to both project a and your executable project.
Remove reference from a to your executable project (but make sure that your a.dll will be placed in same folder as executable).
In your executable project add next Helper:
using System;
using System.Linq;
using System.Reflection;
...
public static class DynamicLoader
{
public const string MyLibName = "a.dll";
public static T Create<T>(this T type)
{
Assembly asm = Assembly.LoadFrom(MyLibName);
Type assemblyType;
assemblyType = typeof(T).IsInterface ? asm.GetTypes().First(p => typeof(T).IsAssignableFrom(p)) : typeof(T);
return (T)asm.CreateInstance(assemblyType.FullName);
}
}
...
//Usage example:
Models.SomeType instance = typeof(Models.SomeType).Create();
instance.Initialize(15);
With this you can replace your "a.dll" and next call of Create() returns instance from new file.

How to call a COM object from C#

First, I realize that there are many posts here that discuss this topic. I must have read 20+ of them, easily. But none of them give the answer that I seek.
I have written a tiny C# test COM DLL with a single method in it that prints "I am alive!" in a message box. Using VStudio as admin, I can build and register the COM object. I have successfully called the object from VBA and run the method. And I can see the name of the COM Interface in the VStudio Add Reference / COM dialog box. This all makes me think the object is properly constructed, registered, and usable.
Now I'm trying to call it from a console C# app. Like many others, I'm trying to figure out the equivalent of the VBA "CreateObject("DLLName.ClassName")" code to get hold of the object in C#.
One way is to just add a reference to the DLL to my console app project. I point to the assembly through the Projects section of the Add Reference dialog, not through the COM section of the dialog. Then I can simply say var o = new MyComImplementationClass(); and treat it like any other class. That works, but it means my console app is cheating and not using the COM object through the usual COM GAC interface.
Another way (that doesn't work, but I wish it did), is to add the reference through the COM tab on the Add Reference dialog. I can see it but VS protests that "the XXX.tlb file was exported from a .NET assembly. Add a reference to the assembly instead." Which brings me back to the solution above, which I think means that my app is cheating. (I didn't have to add references to my VBA test app, for example.)
Another way is to use Type.GetTypeFromProgId as shown by this code fragment below. But I can't get that to work either. I must be passing in the incorrect ProgID string - I get the sense it has something to do with registry info and is not the same "DLLName.ClassName" string that I feed CreateObject() in VBA.
public static dynamic ComObjectGet () {
const string progID = "ComExampleDLLName.ComImplementationClassName";
Type foo = Type.GetTypeFromProgID (progID);
dynamic COMobject = Activator.CreateInstance (foo);
return COMobject;
}
Worse yet, on this MSDN example page it says "This method is provided for COM support. Program IDs are not used in Microsoft .NET Framework because they have been superseded by the concept of namespace." So probably I should not be using the GetTypeFromProgID at all.
If it helps any, I can use VSTO in C# to call the MSOffice primary interop assemblies. But they load from the COM tab of the add reference dialogs (which is where I want my COM library to load from).
For clarity, my COM DLL name is ComExampleLibrary.dll. The default namespace is ComExampleNamespace. The interface name is IComInterface, and the implementation classname is ComImplementation. The internal method name is Run.
Could someone give me instructions or a code snippet that does the "right, approved" thing for calling COM objects (not just the ones I write) from C#? Thank you.
Thanks to the people who helped me out, here is the answer. Both GetTypeFromProgID and GetTypeFromCLSID work as shown below. My problem was that I was using "AssemblyName.ClassName" instead of "Namespace.ClassName" in the call to GetTypeFromProgID.
public static dynamic ComObjectGet () {
const string progID = "ComExampleNamespace.ComImplementation";
Type foo = Type.GetTypeFromProgID (progID);
//var bar = Guid.Parse ("99929AA7-0334-4B2D-AC74-5E282A12D06C");
//Type foo = Type.GetTypeFromCLSID (bar);
dynamic COMobject = Activator.CreateInstance (foo);
return COMobject;
}
So my original code was correct, but I was passing in the wrong argument. This snippet is the equivalent of the VBA CreateObject("Namespace.ClassName") call.
I still don't know why I cannot add a reference to the COM item in the COM tab of the Add Reference dialog like I would for any other COM object. I suppose that's a different question.

Get properties of the application referencing a C# class library from the library

What I'm trying to accomplish is this; I have a class library I've made, but I want to be able to detect which application is using it since I have several applications using one library, but I want to be able to make certain functions available to one application and not have them available to any other applications, all while only having a single standalone class library. The information I'd like to be able to retrieve when the class library is referenced or called upon by an application is; the application name, version, and if it is signed.
Is this possible at all?
You can use reflection System.Reflection.Assembly.GetEntryAssembly() to find the entry point for an application (eg. the executable assembly that was originally run).
Assembly caller = Assembly.GetEntryAssembly();
var name = caller.GetName();
var version = name.Version;
// etc.

Loading multiple versions of DLLs

I have a C# application which interfaces with some hardware (USB device) as follows:
C# application -> intermediate DLL -> hardware DLL -> hardware. The intermediate DLL and hardware DLL are supplied with the USB device so I have no control over these.
The intermediate DLL is the only which which I need to include in the VS project as this is what I call. The hardware DLL is then in the same directory so must be found automatically.
A new version of hardware device is now released with a different hardware DLL. The old DLL is not compatible with the new hardware and the new DLL is not compatible with the old hardware.
How can I make my application work with both pieces of hardware? I guess that I need to load and unload each DLL as required?
Here's what I do for a similar problem. I have a chunk of code that I want to work with, but I have to load the dll at runtime. So I refer to it in my project, but I don't put it in the same directory as the rest of my assemblies. Instead, in the consuming code, I have some code that looks like this:
// constructor called from a static constructor elsewhere
MyDllLoader(string hardwareFolder) {
_hardwareFolder = hardwareFolder;
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
SeeIfAlreadyLoaded();
}
private void SeeIfAlreadyLoaded() {
// if the assembly is still in the current app domain then the AssemblyResolve event will
// never fire.
// Since we need to know where the assembly is, we have to look for it
// here.
Assembly[] assems = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly am in assems)
{
// if it matches, just mark the local _loaded as true and get as much
// other information as you need
}
}
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
string name = args.Name;
if (name.StartsWith("Intermediate.dll,"))
{
string candidatePath = Path.Combine(_hardwareFolder, "Intermediate.dll");
try {
Assembly assem = Assembly.LoadFrom(candidatePath);
if (assem != null) {
_location = candidateFolder;
_fullPath = candidatePath;
_loaded = true;
return assem;
}
}
catch (Exception err) {
sb.Append(err.Message);
}
}
return null;
}
There's another solution too - it's complicated, but I've done it and done the work for you. You declare an abstract class, say MyHardwareAbstraction, that has the signatures of the methods that you want and you code against that interface. Then you write some code which given a path to an assembly, loads it and dynamically defines a new class that matches MyHardwareAbstraction and makes it map onto an instance of the actual object that you want. I wrote a blog several years ago on how to do this.
The nice thing about doing this is that you use the abstract type in your code and work against that and then the adapter compiler will, at run time, compile a new class that will complete that abstract type using some other type as the target type. It's fairly efficient too.
I you want both dll to coexist in the program, you'll have to use AppDomains, as explained here.
Else, you can simply use LoadLibrary after the user has made a clear choice about what version he needs ?
Edit:
If the intermediate DLL is a .Net Assembly, you can use the method mentioned here to specify where to look for your intermediate DLL before you call any method that uses the intermediate DLL, without having to change your existing code.
then you must not directly reference the DLL in your C# project, because .Net Assemblies are discovered and loaded before your Main method is even called. Instead, you must dynamically load the intermediate DLL using AppDomain or other methods, then use the library via reflection, or by using dynamic objects.
Apparently, this would make programming very cumbersome. However, there is an alternative method. You can write a launcher program, that loads your original application (you can load .exe files as libraries), and invokes the Main method of your original program reflectively. To make sure that the correct intermediate DLL is loaded, you can use the method mentioned here, while your launcher program is loading your original application.
The following discussion still applies to the hardware DLL.
The following is valid if:
You need only one version of the dll at a time (during the entire period your application runs), and
The two versions of the intermediate DLLs have exactly the same API.
According to MSDN, the DLL Search Path includes directories specified under the PATH environment variable. (http://msdn.microsoft.com/en-us/library/7d83bc18%28v=vs.80%29.aspx). Hence, you may put the two versions of the intermediate DLLs under seperate sub-directories under your application directory, but with exactly the same name under each directory, for example:
bin\
hardware-intermediate-v1\
intermediate.dll
hardware-intermediate-v2\
intermediate.dll
Then, at start up, after your application has determined which version to use, you may add one of the above directories to your PATH environment variable,
using System;
using System.Reflection;
using System.IO;
...
Environment.SetEnvironmentVariable(
"PATH",
Environment.GetEnvironmentVariable("PATH") + ";" +
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) +
"\\hardware-intermediate-v1"
);
Then, calls to P-Invoke methods (DLLImport) will result in the corresponding version of the DLL to be loaded. To immediately load all DLLs, you may refer to DllImport, how to check if the DLL is loaded?.
However, if you wish to use the two version of the DLLs together without restarting your application, or if there are any API difference between the two DLLs on the level of method name and/or parameter count/type, you must create two seperate sets of P-Invoke methods, each binding to its corresponding version of the intermediate DLL.

How can I pass a reference type between Assemblies referencing a common DLL?

High level: I am trying to build a console app (e.g. ConsoleApp.exe) which can perform some processing on any given DLL which references a certain type defined in ConsoleApp.exe.
I decided, maybe mistakenly, that I would need a companion DLL for ConsoleApp which contained the type or types (e.g. ConsoleClass) which were intended to be referenced by arbirary DLLs. To pull this off, as I don't know of a better way, I have two projects in the ConsoleApp solution, one is a class library (Proving ConsoleApp.dll) and the other is a console application which references the class library project.
At this point, I now am able to copy my ConsoleApp.dll to another relatively unrelated project in a separate solution (e.g. OtherApp.dll), reference it, and write a method which consumes a ConsoleClass instance as a parameter.
Now, in order to arbitrarily process this OtherApp.dll, the ConsoleApp.exe loads that Assembly, instantiates the proper class in that Assembly, and then calls the proper method on that instance. Pertinent lines below hopefully provide context to how I am doing this:
Assembly.LoadFrom(path_to_OtherApp_dll);
...
var x = (dynamic)Activator.CreateInstance(type_inside_OtherApp_dll);
...
var instance = new ConsoleClass();
x.some_method_call(instance);
Ultimately this fails. It seems to be because even though the two projects (ConsoleApp.exe and OtherApp.dll) are referencing the same DLL to define ConsoleClass, the runtime still considers them to be different types.
Any thoughts?
Define the public interface. Put it to its own interface.dll.
Reference interface.dll in your plugin. Let the main class in your plugin.dll implements your interface.
Reference interface.dll in your exe.
Use Assembly.Load() or Assembly.LoadFrom() to load plugin into your exe.
Use CreateInstance() to create instance of your plugin class.
Simply cast created plugin to your interface type.
So you don't need "dynamic" or other complicated things. Just easy, go step by step as I wrote and it will work. Good luck.
Yes, this will happen when ConsoleApp.dll gets loaded twice. Once by the main app, again by a plugin, using its local copy. A type's identity is determined by the assembly it was loaded from.
It isn't that clear to me how that happened. Your first weapon of choice is Fuslogvw.exe, set it up to log all the binds. First thing to do is to doctor the plugin project and set the Copy Local property of the ConsoleApp.dll reference to False so that extra copy isn't there to get accidentally used.
Copying the plugin DLLs to the main app build folder is the never-have-trouble solution, you can load them with Assembly.Load(). Or a subdirectory with a .config file that uses the <probing> element to allow the CLR to find them.
What do you by "runtime is considering them to be of differnt type"? does setup ends with some exception of error? does method in x variable receives something it does not recognize or what?

Categories