Extracting Method Names from an unmanaged DLL(VB Dll) through c# Code - c#

I am writing an application in which user has to browse for a dll to be used. Then if that dll does not contain the required method definition an error message is to be shown. I used following code :
private void CheckDll()
{
string dllName;
string methodName;
bool isMethodFound = false;
OpenFileDialog browseFile = new OpenFileDialog();
browseFile.Filter = "DLL : |*.dll;*.DLL |OCX Files| *.ocx|All File|*.*";
try
{
if (browseFile.ShowDialog() != DialogResult.Cancel)
{
methodName = CommonMod.GetMethodName(1);
dllName = browseFile.FileName;
Assembly loadedDll = Assembly.LoadFile(dllName);
foreach (Type memberType in loadedDll.GetTypes())
{
if (memberType.IsClass)
{
MethodInfo method = memberType.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public);
if (method != null)
{
isMethodFound = true;
}
}
}
if (!isMethodFound)
{
MessageBox.Show(methodName + " method not found in DLL.", "Script Generator", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
Debug.Print(e.Message);
}
}
}
}
This works fine with .net DLLs but with VB dll it fails, is there a way to do it for vb DLLs.
thanks in advance.

Com components comes with type library which is like an interface for that perticular component.
You could use TypeLibConverter.ConvertTypeLibToAssembly to create a interop and then use reflection in normal way.
See example here on msdn
You will have to check whether the dll is com component or .net assembly though.
An example is at following link
How to determine whether a DLL is a managed assembly or native (prevent loading a native dll)?

You are using reflection, which will only work on .NET dll's. For regular DLL's I think you are looking for the Win32 calls LoadLibrary and GetProcAddress

Related

Get methods and attributes from dll assembly

I'm trying to get a small plugin mechanism running by reflecting an dll file providing my class Plugin (implementing my Plugin-Interface shared among dll and main project / sorry for naming both the same) offering an attribute of type string and a main-method activate:
Interface:
public interface Plugin
{
string pluginName{get;set;}
void activate(System.Windows.Forms.Form main);
}
dll class:
public class Plugin : WhiteA.Plugin
{
public string pluginName{get;set;}
public void activate(System.Windows.Forms.Form main){
//find the right form to modify it
IEnumerable<System.Windows.Forms.ComboBox> ie= GetControlsOfType<System.Windows.Forms.ComboBox>(main);
System.Windows.Forms.ComboBox cb=GetControlsOfType<System.Windows.Forms.ComboBox>(main).FirstOrDefault();
cb.Items.Add("Modification");
System.Windows.Forms.MessageBox.Show(cb.SelectedItem.ToString());
}
public static IEnumerable<T> GetControlsOfType<T>(System.Windows.Forms.Control root)
where T : System.Windows.Forms.Control
{
var t = root as T;
if (t != null)
yield return t;
var container = root as System.Windows.Forms.ContainerControl;
if (container != null)
foreach (System.Windows.Forms.Control c in container.Controls)
foreach (var i in GetControlsOfType<T>(c))
yield return i;
}
}
So here comes the problem, there is no type named "Plugin" to be found in the assembly. Tried to get all types from all assemblies in the directory, get all methods/members/custom attributes from them, have them logged etc, but there is nothing of my class Plugin to be found, while the dll definitely is being found, as it doesn't return the MessageBox.
string[] files=new string[]{};
string path="Error retrieving path";
try{
path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
files = System.IO.Directory.GetFiles(path, "*.dll");
}catch(Exception exF){
}
if(files.Length>0){
foreach (string dll in files){
try{
System.Reflection.Assembly sampleAssembly = System.Reflection.Assembly.LoadFrom(dll);
Type myType = sampleAssembly.GetType("Plugin");
System.Reflection.MethodInfo method = myType.GetMethod("activate");
object myInstance = Activator.CreateInstance(myType);
method.Invoke(myInstance, new object[]{this});
}catch(Exception exL){
}
}
}else{
MessageBox.Show("No working plugins detected in " + path.ToString(), "Nothing to activate", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
}
I know my code probably looks really messy to you all - I think the last try-block is the only thing relevant here, wanted to put in the class itself and the interface for a little bit transparency though - and my english isn't perfect, but I hope someone can help me out finding my attribute+method in the assembly.
EDIT:
try{
System.Reflection.Assembly sampleAssembly = System.Reflection.Assembly.LoadFrom(dll);
List<Type> list= sampleAssembly.GetTypes().Where(p =>
p.Namespace == dll &&
p.Name.Contains("Plugin")
).ToList();
Type myType=list.FirstOrDefault();
//Type myType = sampleAssembly.GetType("Plugin");
System.Reflection.MethodInfo method = myType.GetMethod("activate");
object myInstance = Activator.CreateInstance(myType);
method.Invoke(myInstance, new object[]{this});
}
I did change it according to Getting all types in a namespace via reflection
Still the same result, what did I do wrong?
As pointed out by #stuartd:
Type myType = sampleAssembly.GetType("WhiteA_Plugin_PausedVideo.Plugin");
is the solution, missed the namespace
cb.Items.Add("Modification");
doesn't work though...any suggestions?
Got it to work getting the form's children by Controls["nameOfChild"] directly, that help method to fetch all objects by class seems to be wrong here.
Plugin works now, thanks!

UWP - How to use Resources.resw in class library

in library
public string GetName()
{
ResourceLoader rl = ResourceLoader.GetForCurrentView("ClassLibrary1/Resources");
return rl.GetString("Name");
}
at "ResourceLoader rl = ResourceLoader.GetForCurrentView("ClassLibrary1/Resources");"
An exception of type 'System.Runtime.InteropServices.COMException' occurred in ClassLibrary1.dll but was not handled in user code
WinRT information: 未找到 ResourceMap。
Additional information: 未找到 ResourceMap。
未找到 ResourceMap。
If there is a handler for this exception, the program may be safely continued.
if i add reference this library , it is working well.
but i Dynamic reference this library ,it is failure.
Assembly assembly = Assembly.Load(new AssemblyName("ClassLibrary1"));
if (assembly == null)
{
return;
}
Type type = assembly.GetType("ClassLibrary1.Class1");
ICore core = Activator.CreateInstance(type) as ICore;
textBlock1.Text = core.GetName();
//ClassLibrary1.Class1 c1 = new ClassLibrary1.Class1();
//textBlock1.Text = c1.GetName(); //it is working well
how to use resources for Dynamic reference in the library?
if i add reference this library , it is working well. but i Dynamic reference this library ,it is failure.
Most of your code is right, you didn't mention what exactly the exception is. Here is my demo:
Portable class library, class1:
public class Class1
{
public Class1()
{
Debug.WriteLine("ClassLib Loaded!");
}
public void Output()
{
Debug.WriteLine("ClassLib method!");
}
}
In UWP app:
Assembly assembly = Assembly.Load(new AssemblyName("ClassLibrary1"));
if (assembly == null)
{
return;
}
Type type = assembly.GetType("ClassLibrary1.Class1");
object obj = Activator.CreateInstance(type);
var method = type.GetMethod("Output");
method.Invoke(obj, null);
The output in the immediate window is like this:
To do this, you will need to:
build your class library.
right click your class lib, choose "Open folder in File Explorer", in the folder find the "bin" folder => "Debug", copy the ClassLibrary1.dll into your UWP project like this:
Although doing this can solve the problem, but in my personal opinion, it seems not easier than directly adding reference of this library.

Dynamically load DLL files in C# project - how?

In my project I need to use plugins. But to use these in my project I need to import an reference of the plugin. Since I can't know how many or which plugins the project uses beforehand I would like to import them dynamically in my project.
String path = Application.StartupPath;
string[] pluginFiles = Directory.GetFiles(path, "*.dll");
ipi = new IPlugin[pluginFiles.Length];
Assembly asm;
for (int i = 0; i < pluginFiles.Length; i++)
{
string args = pluginFiles[i].Substring(
pluginFiles[i].LastIndexOf("\\") + 1,
pluginFiles[i].IndexOf(".dll") -
pluginFiles[i].LastIndexOf("\\") - 1);
asm = Assembly.LoadFile(pluginFiles[i]);
Type[] types = asm.GetTypes();
In this code example I searched all the .dll files and put them into a string list.
But how can I now load all these .dll files? Or is there a way to use these .dll files without really importing them?
The MEF (Managed Extensibility Framework) Method:
You'll want to add references to System.ComponentModel.Composition to your projects that utilize the import/export functionality of MEF.
First, the bootstrapper/loader (in my case, I just added it to the Main class).
Program.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using MEFContract;
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
var prgm = new Program();
// Search the "Plugins" subdirectory for assemblies that match the imports.
var catalog = new DirectoryCatalog("Plugins");
using (var container = new CompositionContainer(catalog))
{
// Match Imports in "prgm" object with corresponding exports in all catalogs in the container
container.ComposeParts(prgm);
}
prgm.DoStuff();
Console.Read();
}
private void DoStuff()
{
foreach (var plugin in Plugins)
plugin.DoPluginStuff();
}
[ImportMany] // This is a signal to the MEF framework to load all matching exported assemblies.
private IEnumerable<IPlugin> Plugins { get; set; }
}
}
The IPlugin interface is the contract between the imports & exports. All plugins will implement this interface. The contract is pretty simple:
IPlugin.cs:
namespace MEFContract
{
public interface IPlugin
{
void DoPluginStuff();
}
}
Finally, you can create as many plugins as you like in different assemblies. They must implement the contract interface and also be decorated with the "Export" attribute to indicate to MEF that they should be matched up with any corresponding imports. Then drop the dlls in a "Plugins" folder (this folder should reside in the same location as the executable). Here's a sample plugin:
Plugin.cs:
using System;
using System.ComponentModel.Composition;
using MEFContract;
namespace Plugin
{
[Export(typeof(IPlugin))]
public class Plugin : IPlugin
{
public void DoPluginStuff()
{
Console.WriteLine("Doing my thing!");
}
}
}
Let's assume for the sake of simplicity that all of the implementations of IPlugin have default constructors (public and no parameters).
That said, you really want to find all types that implement this interface and create an instance of them. You're on the right track somewhat, but you can simplify this tremendously with a little LINQ:
String path = Application.StartupPath;
string[] pluginFiles = Directory.GetFiles(path, "*.dll");
ipi = (
// From each file in the files.
from file in pluginFiles
// Load the assembly.
let asm = Assembly.LoadFile(file)
// For every type in the assembly that is visible outside of
// the assembly.
from type in asm.GetExportedTypes()
// Where the type implements the interface.
where typeof(IPlugin).IsAssignableFrom(type)
// Create the instance.
select (IPlugin) Activator.CreateInstance(type)
// Materialize to an array.
).ToArray();
That said, you might be better off using a dependency injection framework; they usually allow for dynamic loading and binding to interface implementations in assemblies not referenced at compile time.
Also, while a bit convoluted (in my opinion), you might want to look at the System.AddIn namespaces, as they are built specifically for this purpose. However, the dependency injection route is usually much easier if you don't have to worry about version control of contracts and the like.
I have an application which can not only load plugin at runtime, but also hot-load and unload them as user drop them in the folder, take them out or erase them. So, when I need to recompile my plugin, I don't need to re-launch my application. In my case, all plugin derive from the Plugin abstract, so they are easy to find in .DLL.
Here's my loading method:
private static void LoadPlugins(FileInfo file)
{
try
{
Assembly assembly = Assembly.LoadFrom(file.FullName);
foreach (Type type in assembly.GetTypes())
{
if (type.IsSubclassOf(typeof(Plugin)) && type.IsAbstract == false)
{
Plugin b = type.InvokeMember(null,
BindingFlags.CreateInstance,
null, null, null) as Plugin;
plugins.Add(new PluginWrapper(b, file));
b.Register();
}
}
}
catch (ReflectionTypeLoadException ex)
{
StringBuilder sb = new StringBuilder();
foreach (Exception exSub in ex.LoaderExceptions)
{
sb.AppendLine(exSub.Message);
if (exSub is FileNotFoundException)
{
FileNotFoundException exFileNotFound = exSub as FileNotFoundException;
if (!string.IsNullOrEmpty(exFileNotFound.FusionLog))
{
sb.AppendLine("Fusion Log:");
sb.AppendLine(exFileNotFound.FusionLog);
}
}
sb.AppendLine();
}
string errorMessage = sb.ToString();
Log.Error("Plugins Manager", errorMessage);
}
}

How can I check if dll is .net library "The module was expected to contain an assembly manifest."

How can I verify if dll was wrote in .net? I'm using code as below:
Assembly assembly = null;
try
{
foreach (string fileName in Directory.GetFiles(Environment.CurrentDirectory.ToString(), "*.dll", SearchOption.TopDirectoryOnly))
{
try
{
assembly = Assembly.LoadFrom(fileName);
Console.WriteLine(fileName);
}
catch (Exception ex)
{
...
}
finally
{
...
}
}
}
catch (ReflectionTypeLoadException ex)
{
..
}
When I want to load assembly = Assembly.LoadFrom(fileName) non-.net dll, an exception will appear:
Could not load file or assembly 'file:///...' or one of its dependencies.
The module was expected to contain an assembly manifest.
I want to use verify in if-else clause.
Can you help me?
There's a helper function in the .NET bootstrapper DLL that you can use. Mscoree.dll exports GetFileVersion(), a helper that returns the CLR version that an assembly needs. That function is going to fail when the file isn't an assembly and does so without raising an exception.
It should look like this:
using System;
using System.Text;
using System.Runtime.InteropServices;
public class Utils {
public static bool IsNetAssembly(string path) {
var sb = new StringBuilder(256);
int written;
var hr = GetFileVersion(path, sb, sb.Capacity, out written);
return hr == 0;
}
[DllImport("mscoree.dll", CharSet = CharSet.Unicode)]
private static extern int GetFileVersion(string path, StringBuilder buffer, int buflen, out int written);
}
You can do the following trick :
try {
Assembly assem = Assembly.LoadFile(filePath);
}
catch (BadImageFormatException e) {
//NOT .NET ASSEMBLY
}
In practice if on assembly load you recieve BadImageFormatException , that means that assembly is not formatted in CLR assembly way.
Hine form MSDN link:
The exception that is thrown when the file image of a dynamic link
library (DLL) or an executable program is invalid.
If you do not need to load the assembly in the current domain, I suggest to use:
using System.Reflection;
public class AssemblyName_GetAssemblyName
{
public static void Main()
{
// Replace the string "MyAssembly.exe" with the name of an assembly,
// including a path if necessary. If you do not have another assembly
// to use, you can use whatever name you give to this assembly.
//
try
{
AssemblyName myAssemblyName = AssemblyName.GetAssemblyName("MyAssembly.exe");
}
catch (BadImageFormatException ex)
{
...
}
}
}
The best way to know it, without to throw an exception, is to parse the OptionalImageFileHeader of the PE and look at the DataDirectory for CLR Header.
Currently I working on it, because I had the same issue..

How to get Names of DLLs used by application

I'm looking the way to read all assemblies (.dlls) used by my app.
In a standard C# project there is "References" folder, when it is expanded I can read all libraries used.
My goal is programatically read all assemblies which are used by each project in my solution.
Finally I'd like to see what libraries are used by my compiled *.exe application.
Have you looked at Assembly.GetReferencedAssemblies?
Note that any references you don't use won't end up being emitted into the metadata, so you won't see them at execution time.
I've used GetReferencedAssemblies recursively before now to find a named type without having to specify the assembly.
To do this properly, you need to walk the assemblies, picking up the dependencies... if your exe needs Dll_A, and Dll_A needs Dll_B (even if the exe doesn't reference it), then your exe also needs Dll_B.
You can query this (on any assembly) via reflection; it takes a little work (especially to guard against circular references, which do happen; here's an example that starts at the "entry assembly", but this could just as easily be any assembly:
List<string> refs = new List<string>();
Queue<AssemblyName> pending = new Queue<AssemblyName>();
pending.Enqueue(Assembly.GetEntryAssembly().GetName());
while(pending.Count > 0)
{
AssemblyName an = pending.Dequeue();
string s = an.ToString();
if(refs.Contains(s)) continue; // done already
refs.Add(s);
try
{
Assembly asm = Assembly.Load(an);
if(asm != null)
{
foreach(AssemblyName sub in asm.GetReferencedAssemblies())
{
pending.Enqueue(sub);
}
foreach (Type type in asm.GetTypes())
{
foreach (MethodInfo method in type.GetMethods(
BindingFlags.Static | BindingFlags.Public |
BindingFlags.NonPublic))
{
DllImportAttribute attrib = (DllImportAttribute)
Attribute.GetCustomAttribute(method,
typeof(DllImportAttribute));
if (attrib != null && !refs.Contains(attrib.Value))
{
refs.Add(attrib.Value);
}
}
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
}
refs.Sort();
foreach (string name in refs)
{
Console.WriteLine(name);
}
System.Reflection.Assembly []ar=AppDomain.CurrentDomain.GetAssemblies();
foreach (System.Reflection.Assembly a in ar)
{
Console.WriteLine("{0}", a.FullName);
}
You can use AppDomain.GetAssemblies.
But this will give ALL assemblies used explicitly or implicitly in your application.
If you have an Assembly object, you can call GetReferencedAssemblies() on it to get any references that assembly uses. To get a list of assemblies the currently running project uses, you can use:
System.Reflection.Assembly.GetExecutingAssembly().GetReferencedAssemblies()
I guess you can use:
AssemblyName[] assemblies = this.GetType().Assembly.GetReferencedAssemblies();

Categories