 |
 | Emit?  mscholz | 22:21 21 Jun '04 |
|
 |
Hi,
if you want to load a dll, you normaly use the DLLImportAttribute. You can emit this attribute at runtime to load a dll. Do something like this:
using System; using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; public class DynamicBeeper { public static void Main() { DynamicPInvoke("user32.dll", "MessageBeep", typeof(bool), new Type[]{ typeof(uint) }, new Object[]{ (uint)0 }); }
public static object DynamicPInvoke(string dll, string entryPoint, Type returnType, Type [] parameterTypes, object [] parameterValues) { // Create a dynamic assembly and a dynamic module AssemblyName asmName = new AssemblyName(); asmName.Name = "tempAssembly"; AssemblyBuilder dynamicAsm = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run); ModuleBuilder dynamicMod = dynamicAsm.DefineDynamicModule("tempModule");
// Dynamically construct a global PInvoke signature // using the input information MethodBuilder dynamicMethod = dynamicMod.DefinePInvokeMethod( entryPoint, dll, MethodAttributes.Static | MethodAttributes.Public | MethodAttributes.PinvokeImpl, CallingConventions.Standard, returnType, parameterTypes, CallingConvention.Winapi, CharSet.Ansi);
// This global method is now complete dynamicMod.CreateGlobalFunctions();
// Get a MethodInfo for the PInvoke method MethodInfo mi = dynamicMod.GetMethod(entryPoint);
// Invoke the static method and return whatever it returns return mi.Invoke(null, parameterValues); } }
|
| Sign In·View Thread·PermaLink | 4.63/5 |
|
|
|
 |
|
 |
Hi,
Great bit of code, however will this work with custom dlls or does it have to be system dlls. If custom ones will work, when you specify the dll name do you have to give the absolute path. Also do you know anything about getting the returning values back out from the call.
Thanks
Jason
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
It works will all DLLs, user and system dlls. The method signature is:
public static object DynamicPInvoke(string dll, string entryPoint, Type returnType , Type [] parameterTypes, object [] parameterValues)
The functions returns the return value, you only have to cast it to returnType.
Of cause you can (or) must enhance these method if you want to use custom marshalling.
The dll will be searched in the normal "windows" way, (current directroy, system directory, PATH ....)
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I've thought about this solution too, but I think it overloads the application with too many "code emittions" (once everytime I call any method in a plug-in).
The solution I came with calls only the GetProcAddress on every call. This could also be reduced if I load every function pointer (using the singleton pattern is a good idea) an only pass it to the auxiliar DLL to call. 
[]'s, Harkos --- .NET Develeloper
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Save the MethodInfo mi after the first time you call the DLL-Method. (for example in a Hashtable)
The code is just an idea, not a complete solution...still room for improvements 
Marco
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
It works too, but I tried to save the overhead of creating a new method dynamically for every method in every DLL. In the end both solutions will work for any DLL, we just have to evaluate their performance.
[]'s, Harkos --- .NET Developer
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
Great code, but I've a problem with the return value.
I've a very basic DLL that's just returning an 'int'. When invoke with mi.Invoke it always returns '0', instead of the expected value (i.e. '10' in my specific case. I instrumented the DLL so I'm pretty sure it does what it should.
I set 'returnType' to "typeof(int)"
Any idea ? Thanks!
Fabrizio
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Some ideas:
- To isolate the problem, try a Win32 Function with the same signature.
- Try to call your dll with a normal static-linked [DllImport] attribut and check the return value.
- Check calling conventions
Good luck.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hello, thanks for your fast reply!
"try a Win32...": I tried with the "atoi" function, with the same result:
object o1 = DynamicPInvoke("NTDLL.dll", // DLL name "atoi", // Entry point typeof(int), // Return type new Type[]{ typeof(string) }, // Parameter types new Object[]{ (string)"123" } // Parameter list );
The static-link mechanism works (I used it as reference), both for my function and for the "atoi" test above,
What do you mean for "check calling conventions ? In my test functions I use only integer (int Somma(int a, int b) )..
Thanks for any idea...
Fabrizio
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
 | Re: Emit?  walker_network_ranger | 0:23 15 Nov '06 |
|
 |
Fabrizio Carrai wrote: "try a Win32...": I tried with the "atoi" function, with the same result:
object o1 = DynamicPInvoke("NTDLL.dll", // DLL name "atoi", // Entry point typeof(int), // Return type new Type[]{ typeof(string) }, // Parameter types new Object[]{ (string)"123" } // Parameter list );
Hello,
I have the same problem as you, Frabritzio (return value is always zero when i expect to be an positive integer value). I tried also your example above (with calling atoi method) and the result is allways zero. If someone find a solution for this problem please post it here. Thanks!
Marius ~~~~~~~~~~~~~~ .NET developer
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I had the same problem, and solved it with this :-
[DllImport( "kernel32.dll", EntryPoint = "LoadLibrary" )] static extern IntPtr LoadLibrary( string lpLibFileName );
[DllImport( "kernel32", EntryPoint = "GetProcAddress", SetLastError = true )] static extern IntPtr GetProcAddress( IntPtr hModule, string lpProcName );
[DllImport( "kernel32", EntryPoint = "FreeLibrary", SetLastError = true )] static extern bool FreeLibrary( IntPtr hModule );
public delegate int fn( char[] str ); private static int DbifCommand( string p_sCommand ) { IntPtr hModule = IntPtr.Zero; IntPtr pfn = IntPtr.Zero;
// Load the library and get a pointer to the function hModule = LoadLibrary( "whatever.dll"); pfn = GetProcAddress( hModule, "fn" );
fn myfunc = (fn) Marshal.GetDelegateForFunctionPointer( pfn, typeof( fn ) ); int rtn = myfunc( p_sCommand.ToCharArray() ); return rtn; }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
 | Re: Emit?  walker_network_ranger | 3:47 19 Nov '06 |
|
 |
I'm sure your solution works but only on Framework 2.0 (because GetDelegateForFunctionPointer method is available only with Framework 2.0). In this moment I need a solution for Framework 1.1.
Thanks anyway for your help!
Marius ~~~~~~~~~~~~~~ .NET developer
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
A PInvokeStackImbalance occures with VS 2005 / NET 2.0 inside "return mi.Invoke(null, parameterValues);"!!
Also with this code:
public sealed class DynamicPInvoke { private static Hashtable libraries = new Hashtable(); private static AssemblyBuilder builder;
private static ModuleBuilder module;
static DynamicPInvoke() { AssemblyName an = new AssemblyName(); an.Name = "DynamicPInvokeAssembly"; builder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run); module = builder.DefineDynamicModule("DynamicPInvokeModule"); }
private DynamicPInvoke() { }
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)] [ReflectionPermission(SecurityAction.Demand, ReflectionEmit = true)] public static object InvokeMethod(string library, string method, Type returnType, object[] args) { MethodInfo meth = GetMethod(library, method, returnType, args); return meth.Invoke(null, args); }
private static MethodInfo GetMethod(string library, string method, Type returnType, object[] args) { if (!libraries.ContainsKey(library)) { libraries[library] = new Hashtable(); } Hashtable methods = (Hashtable) libraries[library]; StringBuilder sb = new StringBuilder(); sb.Append(method); sb.Append('('); for (int i = 0; i < args.Length; i++) { if (i > 0) { sb.Append(','); } sb.Append(args[i].GetType().FullName); } sb.Append(')'); string signature = sb.ToString(); if (!methods.ContainsKey(signature)) { Type[] paramTypes = new Type[args.Length]; for (int i = 0; i < args.Length; i++) { paramTypes[i] = args[i].GetType(); } MethodInfo meth = DefineMethod(library, method, returnType, paramTypes); methods[signature] = meth; return meth; } return (MethodInfo) methods[signature]; }
private static MethodInfo DefineMethod(string library, string method, Type returnType, Type[] paramTypes) { TypeBuilder tb = module.DefineType(Guid.NewGuid().ToString()); tb.DefinePInvokeMethod(method, library, MethodAttributes.PinvokeImpl | MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, returnType, paramTypes, CallingConvention.Cdecl, CharSet.Auto); Type type = tb.CreateType(); return type.GetMethod(method, BindingFlags.Static | BindingFlags.Public, null, paramTypes, null); }
The return-code is wrong, like the statment from Fabrizio, but the functionality will work correct (the extern method will be called correctly), except a PInvokeStackImbalance occures in line "return meth.Invoke(null, args);".
Anyone an idea????
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I found at http://groups.google.de/group/microsoft.public.dotnet.languages.csharp/browse_thread/thread/98de540828e0324e/381d97720718fe91?lnk=st&q=methodinfo+invoke+PInvokeStackImbalance&rnum=1&hl=de#381d97720718fe91 a hint to use:
dynamicMethod.SetImplementationFlags(MethodImplAttributes.PreserveSig);
and voilá it worked...
HTH Didi
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi, you example is excellent mscholz but it can not pass with my code:
FileStream f = File.OpenRead("password"); byte[] buffer = new byte[f.Length]; int buf_size = (int)f.Length; f.Read(buffer, 0, buf_size); fixed (byte* pbuffer = buffer) { Object ok = DynamicPInvoke("my.dll", "Pass", typeof(bool), new Type[] { typeof(string), typeof(string), typeof(byte*), typeof(int) }, new Object[] { "name", "pass", *pbuffer,buf_size});
if ((bool)ok) Console.WriteLine("ok"); else Console.WriteLine("no!"); Console.ReadLine(); the trouble is in type Byte* , i think because my dll have this unsafe parameter...
Plz help me :/ thanks a lot !
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hello,
When i use your code with only natif function beep(uint, uint), i can heard the beep but an exception has throw like this:
PInvokeStackImbalance was detected Message: A call to PInvoke function 'tempModule!::Beep' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
anyone have some response ? thank a lot !
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|