I have a DLL written in C#. In this DLL there is a class that is defined.
Let's assume that the code of this DLL is :
namespace unloadableDLL
{
public class DivisionClass
{
public /*static*/ long Division(long x, long y)
{
// We deliberately do not use a try catch to catch divide by 0 exceptions
return (x / y);
}
}
}
Now, I want to load dynamically this DLL in a test program. I need to see what happens if I divide by zero in the two following cases :
1) DLL is loaded directly (without using an AppDomain)
2) DLL is not loaded directly, an AppDomain is created first and then it loads the DLL.
I'm completely new in C#, by new I mean I've started less than 4 hours ago but I have a C++ background.
My problem is that in my test program, I need to instanciate a DivisionClass Object but this one is declared only in the DLL.
=> Resolved
My test program is
class Program
{
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
static void Main(string[] args)
{
// Load the DLL
Console.WriteLine("Attempting to load unloadableDLL");
Assembly a = Assembly.LoadFrom("./unloadableDLL.dll");
unloadableDLL.DivisionClass divisionObject = (unloadableDLL.DivisionClass)a.CreateInstance("unloadableDLL.DivisionClass");
long number = divisionObject.Division(8, 2);
Console.WriteLine(number);
}
}
I don't know what but the compilers keeps telling me that Static member unloadableDLL.DivisionClass.Division(lon, long) cannot be accessed with an instance reference; qualify it with a typename instead.
Thank you all
To load into a separate AppDomain an execute the method from there - use reflection as in the following StackOverflow question. It does get involved as is typically a more advanced C# topic but the code is fairly boilerplate and for a man with C++ knowledge it shouldn't present problems.
For a direct call then follow the methods outlined above - i.e. reference the dll in your project and instantiate through code as per Oded (who has deleted his answer unfortunately so reproducing below)
DivisionClass.Division(1, 2)
EDIT
If the methods are not static
Invoking a method via reflection
Assembly myAssembly1 = Assembly.LoadFrom("myPath\\Assembly1.dll");
Type myType = myAssembly1.GetType("MyClass");
object myObject = Activator.CreateInstance(myType);
myType.Invoke("myMethodName", BindingFlags.InvokeMethod, null, myObject, null);
In a separate App Domain adds to the complexity - see link.
Also I don't think your Division class will work as is. To call across app domains you need to employ some kind of serialisation for your classes or inherit the class from MarshalByRefObject - see this SO question. Given that this looks like a proof of concept type of thing/a ground up implementation of your class then MarshalByRefObject would be you best bet - easiest i think. That said executing across AppDomains can get fiddly.
Invoking a method via instaniation in code
DivisionClass divisor = new DivisionClass()
divisor.Division(1,2)
Related
I have a class (TabControlH60) that both inherits from a base class (UserControl) and implements an interface (IFrameworkClient). I instantiate the object using the .NET Activator class. With the returned instance, I can cast to the UserControl base class, but not to the interface. The exception I get is below the code snipet. How do I cast to the interface?
object obj = Activator.CreateInstance(objType);
Type[] interfaces = obj.GetType().GetInterfaces(); // contains IFrameworkClient
m_Client = (UserControl)obj; // base class cast works
IFrameworkClient fc = (IFrameworkClient)obj; // interface cast fails
// Note: The (IFrameworkClient)obj cast works fine in the debugger Watch window.
{"Unable to cast object of type 'FPG.H60.AFF.TabControlH60' to type
'FPG.AFF.Interfaces.IFrameworkClient'."}
I hat the same problems with a library of mine providing "plugin"-functionality... I got it finally working...
Here was my problem: I had one main assembly using plugins, one assembly with the plugin (Plugin.dll) AND (important) another assembly providing the plugin-functionality (Library.dll).
The Plugin.dll referenced the main assembly (in order to be able to extend it) and the Library.dll with the plugin-func. - it's binaries got to a directory "./Plugins" relative to the main assembly.
The main assembly also referenced the plugin-func. assembly in order to use the "PluginManager" is wrote. This "PluginManager" gets a path and loads all *.dll files via reflection in order to analyze if there is a "IPlugin"-interface (which comes from Library.dll too).
Everytime I called the PluginManager to load the plugins it could not cast them to "IPlugin" although they implemented it.
I nearly got mad - but then I found out the whole problem. By compiling the plugin there was not only the "Plugin.dll" but the "Library.dll" written to the "./Plugins" directory. By accidentally loading the "Library.dll" every time with my PluginManager I now had two types of "IPlugin" - one in the actual "Library.dll" that is used from the main assembly and one that was loaded through my PluginManager - and those were incompatible!
Attention - if you just do not load "./Plugins/Library.dll" you nevertheless encounter the problem - because if you load "Plugin.dll" which references "Library.dll" then it just uses the one in the same directory... TILT...!! My PluginManager now just deletes "Library.dll" where it find it.
The clue is: Be sure that you do not access two assemblies in different contexts!
The most likely cause here is that IFrameworkClient is from a different assembly in the two cases, and is thus a different .NET type. Even if it is the same code, it can be a different type.
Check the AssemblyQualifiedName. Note also that if you are loading this assembly with reflection you can get a different type even with the same AssemblyQualifiedName, thanks to the load-context.
Define IFrameworkClient Interface in independent namespace (must be have namespace) of independent project (class library).Then add refrence of the class library to Control project and main project
When the Interface is in a different assembly and i get my class dynamically at run-time in a different assembly, interface casting will be failed like your sample (C# knows our interface as a different type than which one the class inherited from that).
This is my simple and useful technique in this cases:
When I'm sure my Class has inherited from the mentioned Interface (eq. IFrameworkClient), so i write one magic line of code like this:
dynamic fc = obj as IFrameworkClient ?? (dynamic) obj;
By this technique you can:
Write your codes after this line of code for fc at design time base on Interface members info and vs editor intelligences system.
Prevent any interface casting error at run-time
Notes:
You need C# v4 to use dynamic type
Usually i don't like to use dynamic types in my codes but it can help us in some cases like this
Something tells me your sample code is leaving some stuff out...
class Program
{
static void Main(string[] args)
{
var type = typeof(MyClass);
object obj = Activator.CreateInstance(type);
Type[] interfaces = obj.GetType().GetInterfaces();
var m_Client = (UserControl)obj;
IFrameworkClient fc = (IFrameworkClient)obj;
}
}
public interface IFrameworkClient { }
public class UserControl { }
public class MyClass : UserControl, IFrameworkClient { }
This compiles and runs.
I'm betting that the DLL containing the definition of IFrameworkClient hasn't yet been loaded before you try to cast. This can happen when you're using Activator.CreateInstance.
Try inserting var forceLoad = typeof(IFrameworkClient); before the cast.
If the class FPG.H60.AFF.TabControlH60 actually does implement IFrameworkClient there should be no reason this would fail. The only thing I can think of that causes this exception is if the assembly that contains IFrameworkClient is strongly named and the Tab Control object happens to reference a different version of the containing assembly or your are using a different interface with the name IFrameworkClient.
In my case I had to add a build event to copy the needed DLL since I was creating instances and assigning to interface types at run time. Otherwise the DLL loaded might not be the most up-to-date DLL, and therefore may not cast to the interface.
The reason I used build events in this case (instead of adding the DLL as a reference) is that the architecture is such that the main application should only reference the interface types, and everything else should be loaded dynamically.
TLDR;
In the case of loading types dynamically from another DLL, make sure you copy the most recent version of that DLL to the bin directory using build events, otherwise casting may not work when it appears that it should.
I ran into same issue and I just added the following code
private void LoadAssemblyPlugins(string dll)
Assembly ass = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => new Uri(a.CodeBase).Equals(new Uri(dll)));
if (ass == null)
// Load it here
// use activator here
Although, in production it will never be a problem, in unit test it was but now I don't need to load it again and create a "different type"
The cast isn't working because you're trying to cast from type object to the interface. If you replace the interface cast line with:
IFrameworkClient fc = (IFrameworkClient)m_Client;
It will work.
Alternately, I'm mildly certain that you could do the cast from the object to the interface with the as operator.
See this article for more information:
http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx
One more piece of the puzzle. Interfaces do not derive from object:
http://blogs.msdn.com/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx
I want to use c# code app in tcl using COM > twapi > tcl path.
By studying "call c# code from tcl" wiki page I understood two things.
We need to compile c# code with com interface register VS option. Then use that namespacename.classname to create object instance. But it is not clear how twapi (or tcom) will use that com (or link). Can you please explain in more details. Thanking you in advance.
C# code
using System;
namespace MyClassLib
{
public class Class1
{
public Class1() {}
public int Double (int val) { return val * 2 ; }
}
}
When the project is registered for COM Interop and built, the class is registered in the system's Registry as a provider for that class name. The tcom package knows how to use that information. When you do:
set myCom [tcom::ref createobject "ClassLibrary1.Class1"]
It goes away and asks the COM service that's built into Windows to make an instance of that object and give a reference to it back to you. That reference is what is stored in the variable. You can then invoke methods of the object; the syntax for that is Tcl-ish rather than C#-ish, but the models line up.
$myCom Double 6
Yes, there's a lot of complexity going on behind the scenes, mostly centred on IDispatch and its related interfaces.
I'm trying to make an expansion setup for this game I'm developing, (not going to go into detail about), but all a single expansion will need is the 1 .dll file added into the Expansions folder I have added.
I have figured out how to access these .dll added into this folder as seen below:
Assembly ExpAssembly = Assembly.LoadFrom("Expansions/Intrique.dll");
Type myType = ExpAssembly.GetTypes()[0];
Here is an example of the class I'm trying to load:
public class Expansion: MyGame.Expansion {
public Expansion() {
//Stuff
}
public string SomeMethod()
{
return "Test";
}
}
Calling the following code runs SomeMethod() just fine
MethodInfo Method = myType.GetMethod("SomeMethod");
object myInstance = Activator.CreateInstance(myType);
MessageBox.Show(Method.Invoke(myInstance, null).ToString());
But what I want to do is be able to write Expansion expObj; and assign it by calling new Expansion() from this not-referenced .dll, but not in the library itself.
(For the purposes of this answer, I'm going to assume that your Expansion subclass is has a fully qualified name of Intrique.Expansion. I.e. the namespace is the same as the name of the DLL).
Because your main program does not reference Intrique.dll, the code in your main program cannot use the types in that DLL directly. That is, Intrique.Expansion is not a usable type in the context of the written code of your main program, though it can be used at run-time.
Taking your code example literally, the only approach likely to work given the code you have now would be to use dynamic:
dynamic myInstance = Activator.CreateInstance(myType);
myInstance.SomeMethod();
This is because SomeMethod() is declared only in Intrique.Expansion. There's not any other type you could use statically in your main program where that method is known.
If that method was instead an implementation of a member of some interface that Intrique.Expansion implements and which your main program references, or was an override of some virtual member of MyGame.Expansion (which presumably your main program references, if not actually declares), then you could cast the instance to the interface type or MyGame.Expansion respectively and call the method that way:
ISomeInterface myInstance = (ISomeInterface)Activator.CreateInstance(myType);
myInstance.SomeMethod();
or:
MyGame.Expansion myInstance = (MyGame.Expansion)Activator.CreateInstance(myType);
myInstance.SomeMethod();
Finally, given that you are trying to implement some kind of extensibility architecture, you might consider using the Managed Extensibility Framework, which is designed specifically to handle a lot of the messy parts of exactly this kind of thing.
I lately have had to change a piece of code to allow compatibility with an older version DLL. The DLLs have the same name and are not signed. The difference also is in some additional methods added to the new DLL.
One way to go about this which doesn't seem right to me is to reference the new DLL in the project, build and run. If you want to use the other DLL, you just replace it in the bin folder. You can avoid errors by just checking the existence of a method in a constructor somewhere using Reflection, and set a flag so that later on you can avoid calling the new functions if you are using the older version.
The strange thing to me is that the following piece of code doesn't work when using the old version:
int[] someVariable = (DLLIsNewFormat) ? DLL.CallNewMethod() : new int[5];
Basically what is happening is that the DLLIsNewFormat is False but for some reason I get the error:
Method not found: 'Int32[] [NameSpace].[Class].CallNewMethod()'.
I understand that the best way to go about this is to probably check if each function exists and then calling them using reflection. But I just don't know why the code is behaving this way. Is this just undefined behavior?
This is happening at the time that the method containing your snippet is JIT-compiled. In order for JIT-compilation to happen, the method needs to be available at the time the method is invoked. Since the method is not available, the JIT-compiler throws this exception when the method containing this code is called, before the method is even executed.
One way around this would be to define a new method:
int[] HideCall()
{
return DLL.CallNewMethod();
}
Then call this method instead of DLL.CallNewMethod() directly.
A better solution would be to define an interface in an assembly that is referenced by both your "conditional DLL" and the assembly you are conditionally using this DLL from. Have a default implementation of this interface available in the main assembly, and an alternate implementation in the conditionally-used DLL.
Then, at runtime, you can simply see if the DLL is available, use reflection to construct an instance of the class that implements this interface, and then substitute out a the reference to your default implementation with this one.
Example code:
// Interface, in an assembly visible to both of the other assemblies.
public interface IDLLInterface
{
int[] CallNewMethod();
}
// Implementation in the main program.
class DefaultDLLImplementation : IDLLInterface
{
public int[] CallNewMethod()
{
return new int[5];
}
}
static class DLLImplementation
{
public readonly IDLLInterface Instance;
static DLLImplementation()
{
// Pseudo-code
if (DllIsAvailable) {
Instance = ConstructInstanceFromDllUsingReflection();
} else {
Instance = new DefaultDLLImplementation();
}
}
}
Then you can use DLLImplementation.Instance.CallNewMethod() instead, and the right method will be called automatically.
Of course, I would suggest naming your interface with a more descriptive name so that it's apparent what it means.
What you want is to hide calls to non-existing methods from JIT.
To do so you need to make sure each of non-existent calls made in inside a function and call to such function is controlled by version condition:
private int[] WrappedNewMethod()
{
return DLL.CallNewMethod();
}
...SomeOtherMethod()
{
int[] someVariable = (DLLIsNewFormat) ? WrappedNewMethod(): new int[5];
}
I know the title sounds a bit strange, but this has been boggling my mind for a little bit. So Intel offers this TurboBoost sidebar gadget with calls using JavaScript, and I want to write a program from scratch in C# that does the same thing. The calls stem from what I believe is an ActiveX DLL which I easily imported. The problem is, whenever I try to call a function, it gives me the error "an object reference is required for the non-static field..." I've found all of the functions e.g. the one I used return a dynamic data structure. I've tried splitting up the functions and made them both static but still no luck. Here's the code(ITurboBoostClient is the interface portion):
namespace TurboBoostMon_CLI
{
class Program
{
public static object GetCPUFreq()
{
object n = ITurboBoostClient.GetCurBaseFrequency(); //<---- error
//return Convert.ToDouble(n);
return n;
}
public static void Main(string[] args)
{
object cpubasefreq = GetCPUFreq();
Console.WriteLine(cpubasefreq); // neglect the output for now
}
}
}
If typical naming conventions are being used, ITurboBoostClient is an interface, and you do not have an instance of an object that implements the interface. Hence, the error.
Without knowing more about the ActiveX DLL, its hard to say exactly what to do, but it would be along the lines of:
{
ITurboBoostClient myClient = TurboBoostFactory.GetInstance();
object n = myClient.GetCurBaseFrequencey();
return n;
}
Note that in the first line, you call a static method that can product the class (with the interface) that is required. Then you can actually use that interface.
Look again through the ActiveX library you imported, and see if you can find a factory method, a CreateInstance method, or some other instantiator that will create the initial object.
If you're getting that error, then you need to declare something as a new object. Assuming your error marker is correct, you need to change that to create a new instance of some object that inherits the ITurboBoostClient, then use that to call the GetCurBaseFrequenct() method.
Something like:
ITurboBoostClient myTurboBoost = new TurboBoostClientObject(); // Making names up here, not familiar with the framework you're working with.
object n = myTurboBoost.GetCurBaseFrequency();
Sorry I don't know what class you need to instantiate there, but a short dig on google will most surely be revealing.