如题,
[DllImport("dllfile.dll")]//这里"dllfile.dll"只能用常量表示
public static extern void ShowMessage(string Msg); 
有没有其它方法可以动态调用Dll啊?

解决方案 »

  1.   

    直接用loadlibrary恐怕不行,C#还支持函数指针类型的。
      

  2.   

    sorry ,上面写错了:直接用loadlibrary恐怕不行,C#不支持函数指针类型的。
      

  3.   

    可以考虑自己用c++之类东东先编写一个非托管的dll,在里面使用根据来自
    托管代码的参数用loadlibrary找到函数入口点,再用从托管代码传来的参数
    调用dll中的函数。
    虽然绕了个弯,但应该可行
      

  4.   

    loadlibrary 可以用
    C# 支持调用C 的函数指针
    不过要用 委托代替。loadlibrary C#里没用过 ,不过给你一个 类似的调用函数指针的列子。
    //声明一个委托          public  delegate  IntPtr  NewWndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);           //把最后一个参数生命为 委托
              [DllImport("user32.dll", CharSet=CharSet.Auto)]
              public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, NewWndProc wndproc);//实列化委托(这里就是回调函数)               wpr= new NewWndProc(this.TextBoxWndProc);               //替换控件的默认处理函数(并且返回原始的 默认处理函数,是一个函数指针的地质)               oldWndProc=SetWindowLong(textBox1.Handle,GWL_WNDPROC,wpr);------------------------------------------------------------
    http://blog.csdn.net/flashelf/archive/2004/10/31/161024.aspx
    SetWindowLong ,GWL_WNDPROC 不就是需要一个函数指针吗?子不过C# 生明 api 的时候要有些变化。
      

  5.   

    .Net Framework 1.0和1.1没有直接的办法动态P/Invoke,只能通过Reflection实现。如果知道PInvoke函数的Signature,用Reflection生成一个动态的Assembly,然后注入函数的声明和DllImport属性,再用Reflection动态调用。
      这里是一个例子:http://www.msjogren.net/dotnet/eng/samples/dotnet_dynpinvoke.asp
      

  6.   

    loadlibrary 可以用
    C# 支持调用C 的函数指针
    不过要用 委托代替。loadlibrary C#里没用过 ,不过给你一个 类似的调用函数指针的列子。
    //声明一个委托          public  delegate  IntPtr  NewWndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);           //把最后一个参数生命为 委托
              [DllImport("user32.dll", CharSet=CharSet.Auto)]
              public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, NewWndProc wndproc);//实列化委托(这里就是回调函数)               wpr= new NewWndProc(this.TextBoxWndProc);               //替换控件的默认处理函数(并且返回原始的 默认处理函数,是一个函数指针的地质)               oldWndProc=SetWindowLong(textBox1.Handle,GWL_WNDPROC,wpr);------------------------------------------------------------
    http://blog.csdn.net/flashelf/archive/2004/10/31/161024.aspx
    SetWindowLong ,GWL_WNDPROC 不就是需要一个函数指针吗?子不过C# 生明 api 的时候要有些变化。
      

  7.   

    问题是,loadlibrary 之后,你还要 GetProcAddress,这个GetProcAddress返回的是一个函数指针,没法赋值给 delegate 对象,说什么类型不兼容。
      

  8.   

    关键问题是在获得函数指针后怎么将之转换为委托? msdn里面有将委托转换为函数指针的例子,但没有发现有将函数指针转换为委托的例子。 qqchen79(Phantom Of Autumn) 的意见好像还比较可行。
    俺的想法也是可行的,我试过了。
      

  9.   

    动态生成Assebbly应该用CodeDom...
      

  10.   

    那么试一下那些脚本语言(JScript.NET、Python.NET之类),说不定可以做到 (-:
    我没有试过。
      

  11.   

    string AssemblyName = sServiceID.Substring(0,sServiceID.IndexOf("."));
    Assembly MyAssembly = Assembly.Load(AssemblyName);//AssemblyName DLL的名字
    ISDServer.IRetrieval Rx = (ISDServer.IRetrieval)(MyAssembly.CreateInstanceAssemblyName+".Retrieval"));
    return Rx.Execute((ISDServer.IProcess)this,sServiceID,sParam);
      

  12.   

    这是一个例子.
    里面只是根据UnmanagedType来决定生成的delegate的参数类型.所以没有针对 void** 这样的参数进行处理.其实帮定非托管函数的重点是参数类型的封送处理.给个提示,void*可以影射为object或IntPtr,而void**则影射为ref object或ref IntPtrusing System;
    using System.Collections;
    using System.Reflection;
    using System.Reflection.Emit;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;namespace LostinetSample.InvokeDll
    {
    /// <summary>
    /// Class1 的摘要说明。
    /// </summary>
    class Class1
    {
    /// <summary>
    /// 应用程序的主入口点。
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
    DllService ds=new DllService("user32.dll","MessageBoxW"
    ,CharSet.Unicode
    ,new UnmanagedType[]
    {
    UnmanagedType.U4
    ,UnmanagedType.LPTStr
    ,UnmanagedType.LPTStr
    ,UnmanagedType.U4
    }
    ); ds.Invoke((UInt32)0,"Hello","World",(UInt32)0);
    }
    }
    }
    namespace LostinetSample.InvokeDll
    {
    public class DllService
    {
    static Hashtable cachedAssemblies=new Hashtable();
    static object creationlock=new object(); Delegate func;
    Type[] argTypes; public DllService(string dllfile,string funcname,CharSet charset
    ,UnmanagedType[] umtypes) 
    : this(dllfile,funcname,charset,umtypes,UnmanagedType.AsAny,true)
    {
    }
    public DllService(string dllfile,string funcname,CharSet charset
    ,UnmanagedType[] umtypes,UnmanagedType retumtype) 
    : this(dllfile,funcname,charset,umtypes,retumtype,false)
    {
    }
    public DllService(string dllfile,string funcname,CharSet charset
    ,UnmanagedType[] umtypes,UnmanagedType retumtype,bool retVoid)
    {
    if(dllfile==null)throw(new ArgumentNullException("dllfile"));
    if(funcname==null)throw(new ArgumentNullException("funcname"));
    if(umtypes==null)umtypes=new UnmanagedType[0]; Type retType;
    if(retVoid)
    retType=typeof(void);
    else
    retType=GetUnmanagedType(retumtype); argTypes=GetUnmanagedTypes(umtypes); string key=dllfile+":"+funcname; lock(cachedAssemblies.SyncRoot)
    {
    func=(Delegate)cachedAssemblies[key];
    }
    if(func!=null)return; lock(creationlock)
    {
    lock(cachedAssemblies.SyncRoot)
    {
    func=(Delegate)cachedAssemblies[key];
    }
    if(func!=null)return; AssemblyName asmname=new AssemblyName();
    asmname.Name="assemblyfor"+func+"_"+key.GetHashCode();
    AssemblyBuilder asmbulder=AppDomain.CurrentDomain.DefineDynamicAssembly(asmname
    ,AssemblyBuilderAccess.Run
    ); ModuleBuilder mdlbuilder=asmbulder.DefineDynamicModule(asmname.Name); TypeBuilder typeBuilder=mdlbuilder.DefineType("ClassFor"+func
    ,TypeAttributes.Class|TypeAttributes.Public); MethodBuilder mthbuilder=typeBuilder.DefinePInvokeMethod(funcname,dllfile,funcname
    ,MethodAttributes.Public|MethodAttributes.Static|MethodAttributes.PinvokeImpl
    ,CallingConventions.Standard
    ,retType
    ,argTypes
    ,CallingConvention.StdCall
    ,charset
    ); if(!retVoid)
    {
    mthbuilder.SetMarshal(UnmanagedMarshal.DefineUnmanagedMarshal(retumtype));
    }
    for(int i=0;i<umtypes.Length;i++)
    {
    mthbuilder.DefineParameter(i+1
    ,ParameterAttributes.In,"param"+i);
    }
    TypeBuilder dgTypeBuilder=mdlbuilder.DefineType("DelegateOf"+funcname
    ,TypeAttributes.Class|TypeAttributes.Public|TypeAttributes.Sealed,typeof(MulticastDelegate)); ConstructorBuilder ctorBuilder=dgTypeBuilder.DefineConstructor(MethodAttributes.Public,CallingConventions.Standard,new Type[]{typeof(object),typeof(IntPtr)});
    ctorBuilder.SetImplementationFlags(MethodImplAttributes.Managed|MethodImplAttributes.Runtime); MethodBuilder invokeBuilder=dgTypeBuilder.DefineMethod("Invoke",MethodAttributes.Public,CallingConventions.Standard,retType,argTypes);
    invokeBuilder.SetImplementationFlags(MethodImplAttributes.Managed|MethodImplAttributes.Runtime); for(int i=0;i<umtypes.Length;i++)
    {
    invokeBuilder.DefineParameter(i+1
    ,ParameterAttributes.In,"param"+i);
    }

    Type resultType=typeBuilder.CreateType();
    MethodInfo method=resultType.GetMethod(funcname,BindingFlags.Static|BindingFlags.Public); Type dgType=dgTypeBuilder.CreateType();
    func=Delegate.CreateDelegate(dgType,method); lock(cachedAssemblies.SyncRoot)
    {
    cachedAssemblies[key]=func;
    }
    }
    } Type GetUnmanagedType(UnmanagedType umtype)
    {
    switch(umtype)
    {
    case UnmanagedType.Bool:
    return typeof(bool);
    case UnmanagedType.BStr:
    return typeof(string);
    case UnmanagedType.Currency:
    return typeof(decimal);
    case UnmanagedType.Error:
    return typeof(UInt32);
    case UnmanagedType.FunctionPtr:
    return typeof(IntPtr);
    case UnmanagedType.I1:
    return typeof(byte);
    case UnmanagedType.I2:
    return typeof(short);
    case UnmanagedType.I4:
    return typeof(int);
    case UnmanagedType.I8:
    return typeof(long);
    case UnmanagedType.IDispatch:
    case UnmanagedType.Interface:
    case UnmanagedType.IUnknown:
    return typeof(object);
    case UnmanagedType.LPArray:
    return typeof(object[]);
    case UnmanagedType.LPStruct:
    return typeof(object);
    case UnmanagedType.LPStr:
    case UnmanagedType.LPTStr:
    case UnmanagedType.LPWStr:
    return typeof(string);
    case UnmanagedType.R4:
    return typeof(float);
    case UnmanagedType.R8:
    return typeof(double);
    case UnmanagedType.SafeArray:
    return typeof(object[]);
    case UnmanagedType.Struct:
    return typeof(object);
    case UnmanagedType.SysInt:
    return typeof(long);
    case UnmanagedType.SysUInt:
    return typeof(UInt64);
    case UnmanagedType.TBStr:
    return typeof(string);
    case UnmanagedType.U1:
    return typeof(byte);
    case UnmanagedType.U2:
    return typeof(UInt16);
    case UnmanagedType.U4:
    return typeof(UInt32);
    case UnmanagedType.U8:
    return typeof(UInt64);
    case UnmanagedType.VariantBool:
    return typeof(bool);
    case UnmanagedType.VBByRefStr:
    case UnmanagedType.CustomMarshaler:
    default:
    throw(new NotSupportedException(umtype.ToString()));
    }
    }
    Type[] GetUnmanagedTypes(UnmanagedType[] umtypes)
    {
    int len=umtypes.Length;
    Type[] types=new Type[len];
    for(int i=0;i<len;i++)
    {
    types[i]=GetUnmanagedType(umtypes[i]);
    }
    return types;
    }
    public object Invoke(params object[] args)
    {
    return func.DynamicInvoke(args);
    }
    }
    }
      

  13.   

    哦..其实例子里的新delegate有点多余....前面提问到怎样变为delegate才做一个.
    其实只要使用method.Invoke就可以了。
      

  14.   

    请问,如何把void * 影射object或intptr啊?似乎不行哎。
      

  15.   

    谢谢大家。我最后还是采取了 pgfun(高档菜鸟) 的方法(比较简单)。Lostinet(每晚 8:00 见)的方法和qqchen79(Phantom Of Autumn) 的方法差不多。不过当传入一个char * 时会产生某些问题。