2006-10-10 17:14:00 ltolll 阅读数 1506
  • Unity热更新之ILRuntime

    ILRuntime项目为基于C#的平台(例如Unity)提供了一个纯C#实现,快速、方便且可靠的IL运行时,使得能够在不支持JIT的硬件环境(如iOS)能够实现代码的热更新 ILRuntime的优势 同市面上的其他热更方案相比,ILRuntime主要有以下优点: * 无缝访问C#工程的现成代码,无需额外抽象脚本API * 直接使用VS2015进行开发,ILRuntime的解译引擎支持.Net 4.6编译的DLL * 执行效率是L#的10-20倍 * 选择性的CLR绑定使跨域调用更快速,绑定后跨域调用的性能能达到slua的2倍左右(从脚本调用GameObject之类的接口) * 支持跨域继承 * 完整的泛型支持 * 拥有Visual Studio的调试插件,可以实现真机源码级调试。支持Visual Studio 2015 Update3 以及Visual Studio 2017 _____________________________________________________________________________________________________________ 本课程带领大家极速的上手ILRuntime中,让大家学会在Unity如何快速集成ILRuntime热更新技术~

    488 人正在学习 去看看 官剑铭

C#中调用DLL

1.先把调用的DLL文件复制到执行文件的目录(调试时为DEBUG目录)
2.在需调用DLL的*.CS文件中using System.Runtime.InteropServices;
3.在类定义中用DllImport关键字进行声明函数接口
public class FrmQuickSearch : System.Windows.Forms.Form
 {
        [DllImport("JINCARD7.DLL")]
        public extern static int Rcard(StringBuilder rdata,int track);
......

4.引用:
            StringBuilder rdata = new StringBuilder(32);            
            int re = Rcard(rdata,1);

这里要注意如果函数参数为PChar型,如(Rcard(rdata:pchar;track:integer):integer;)则可在C#中将其声明为StringBuilder而不用String.

相关文章:http://support.microsoft.com/default.aspx?scid=kb;zh-cn;815065

 
2017-09-08 17:44:28 qq_22562763 阅读数 1176
  • Unity热更新之ILRuntime

    ILRuntime项目为基于C#的平台(例如Unity)提供了一个纯C#实现,快速、方便且可靠的IL运行时,使得能够在不支持JIT的硬件环境(如iOS)能够实现代码的热更新 ILRuntime的优势 同市面上的其他热更方案相比,ILRuntime主要有以下优点: * 无缝访问C#工程的现成代码,无需额外抽象脚本API * 直接使用VS2015进行开发,ILRuntime的解译引擎支持.Net 4.6编译的DLL * 执行效率是L#的10-20倍 * 选择性的CLR绑定使跨域调用更快速,绑定后跨域调用的性能能达到slua的2倍左右(从脚本调用GameObject之类的接口) * 支持跨域继承 * 完整的泛型支持 * 拥有Visual Studio的调试插件,可以实现真机源码级调试。支持Visual Studio 2015 Update3 以及Visual Studio 2017 _____________________________________________________________________________________________________________ 本课程带领大家极速的上手ILRuntime中,让大家学会在Unity如何快速集成ILRuntime热更新技术~

    488 人正在学习 去看看 官剑铭

   最近碰到有关C#调用MFC dll的问题,查了很多资料,参考了不少的网上博客,做了如下总结,C#动静态调用C++ dll,C++调用C#dll。也算一个简单的自我整理,有问题也请提出来,共同进步。

C# 静态调非托管C++ dll

 1)C++ dll中含代码

    extern "C" __declspec(dllexport) int Add(int a,int b)

{return a+b;}

 2)C#调用dll  dll放在C#生成的文件中  C#代码中

引用加上:using System.Runtime.InteropServices;

class Program
    {
        [DllImport("CppDemo.dll", EntryPoint = "Add", ExactSpelling = false          CallingConvention = CallingConvention.Cdecl)]
        public static extern int Add(int a, int b); //DllImport请参照MSDN
        static void Main(string[] args)
        {
            Console.WriteLine(Add(12));
            Console.Read();
        }
    }

DllImport参数说明

说明:

1DllImport只能放置在方法声明上。

2DllImport具有单个定位参数:指定包含被导入方法的 dll 名称的 dllName 参数。

3DllImport具有五个命名参数:

   aCallingConvention 参数指示入口点的调用约定。如果未指定CallingConvention,则使用默认值CallingConvention.WinapiCalling Convention是指程序在函数调用时传递参数和获取返回值所采用的方法:通过寄存器、或通过栈、或者是两者的混合。

注释:_stdcall _cdecl是两种不同的函数调用约定,区别在函数参数入栈的顺序,由调用函数还是被调用函数将参数弹出栈,以及产生函数修饰名的方法。对于参数可变的函数如printf,使用的是_cdecl调用约定,Win32API函数都遵循_stdcall调用约定。在VC++开发环境中,默认的编译选项是_cdecl,对于那些需要_stdcall调用约定的函数,必须显式的加上_stdcall

 

 

名称

参数传递

栈的清空

其它

 

__cdecl

参数按从右到左的顺序传递,放于栈中

栈的清空由主调函数完成

  在生成的汇编代码中,函数名以下划线 _ 开头

编译选项:/Gd

对于变参函数,如printf,只能用这种方式

 

__stdcall

参数按从右到左的顺序传递,放于栈中

 

 

栈的清空由被调函数完成

在生成的汇编代码中,函数名以下划线 _ 开头,以@和所有参数所占用的字节数结尾。如call     _sumExample@8

编译选项:/Gz

Win32程序中的WINAPI即是__stdcall#define WINAPI __stdcall

由于栈是由被调函数自己清空,其产生的执行代码要小于__cdecl方式所产生的代码

 

__fastcall

前两个参数要求不超过32bits,分别放入ECXEDX,其余参数按从右到左的顺序传递,放于栈中

 

参数由被调函数弹出栈

在生成的汇编代码中,函数名以@开头,以@和所有参数所占用的字节数结尾

M$有可能将前两个参数放在不同的寄存器中

编译选项:/Gr

 

Thiscall

this指针存放于CX寄存器,参数从右到左压。

栈的清空有被调函数完成

thiscall仅仅应用于“C++”成员函数。

 

Winapi

 

 

 此成员实际上不是调用约定,而是使用了默认平台调用约定。例如,在 Windows上默认为 System.Runtime.InteropServices.CallingConvention.StdCall,在 Windows CE.NET 上默认为 System.Runtime.InteropServices.CallingConvention.Cdecl

 

   bCharSet参数指定用在入口点的字符集。如果未指定CharSet,则使用默认值CharSet.AutoC++一般使用asni格式。

   cEntryPoint参数给出dll中入口点的名称。如果未指定EntryPoint,则使用方法本身的名称。

   dExactSpelling参数指示EntryPoint是否必须与指示的入口点的拼写完全匹配。如果未指定ExactSpelling,则使用默认值false

   ePreserveSig参数指示方法的签名被保留还是被转换。当签名被转换时,它被转换为一个具有HRESULT返回值和该返回值的一个名为retval的附加输出参数的签名。如果未指定PreserveSig,则使用默认值true

   fSetLastError参数指示方法是否保留Win32“上一错误”。如果未指定SetLastError,则使用默认值false

4、它是一次性属性类。

5、用DllImport属性修饰的方法必须具有extern修饰符。

DllImport的用法示例(是用来写入ini文件的一个win32api):

 DllImport("kernel32")

 private static extern long WritePrivateProfileString(string section,string key,string val,string filePath);

用此方法调用WinAPI的数据类型对应:DWORD=intuint,BOOL=bool,预定义常量=enum,结构=struct

DllImport路径问题:DllImport会按照顺序自动去寻找的地方:

1exe所在目录 2System32目录 3、环境变量目录

 

C# 动态调非托管dll

静态调用C++动态链接,由于Dll路径的限制,使用的不是很方便,C#中我们经常通过配置动态的调用托管Dll,例如常用的一些设计模式:Abstract FactoryProviderStrategy模式等等,通过LoadLibrary, GetProcess, FreeLibrary这几个函数是可以动态调用动态链接的(它们包含在kernel32.dll中)

1)C++ dll中含代码

    extern "C" __declspec(dllexport) int Add(int a,int b)

{return a+b;}

2)kernel32中的几个方法封装成本地调用类NativeMethod

    public static class NativeMethod
    {
        [DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
        public static extern int LoadLibrary(
            [MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);

        [DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
        public static extern IntPtr GetProcAddress(int hModule,
            [MarshalAs(UnmanagedType.LPStr)] string lpProcName);

        [DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
        public static extern bool FreeLibrary(int hModule);
    }

 

3)使用NativeMethod类动态读取C++Dll,获得函数指针,并且将指针封装成C#中的委托。 C#中已经不能使用指针了.

  static void Main(string[] args)
        {
            //1. 动态加载C++ Dll
            int hModule = NativeMethod.LoadLibrary(@"c:\CppDemo.dll");
            if (hModule == 0return;

            //2. 读取函数指针
            IntPtr intPtr = NativeMethod.GetProcAddress(hModule, "Add");

            //3. 将函数指针封装成委托
            Add addFunction = (Add)Marshal.GetDelegateForFunctionPointer(intPtr, typeof(Add));

            //4. 测试
            Console.WriteLine(addFunction(12));
            Console.Read();
        }

        /// <summary>
        /// 函数指针
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        delegate int Add(int a, int b);

 

C++ C#托管 dll

1)有一个可供调用的C# dll文件

2)C++项目属性的配置: 添加公共语言运行时支持 /clr

3)C++ 中要引用此类库

 #using "..\ClassLibrary1\bin\Debug\ClassLibrary1.dll"           //引用C#类库

4)创建C#对象时要用gcnew ;托管对象需要使用^来进行声明。

1)ClassLibrary1::Class1 ^c = gcnew ClassLibrary1::Class1();   //注意一定要用 ^  , 一定要用gcnew  

5)自身的C++类要用 ref class 定义。

 

 

 

 

 

 

 

 

 

 

2017-02-21 11:16:24 xumengmeng_xu 阅读数 2001
  • Unity热更新之ILRuntime

    ILRuntime项目为基于C#的平台(例如Unity)提供了一个纯C#实现,快速、方便且可靠的IL运行时,使得能够在不支持JIT的硬件环境(如iOS)能够实现代码的热更新 ILRuntime的优势 同市面上的其他热更方案相比,ILRuntime主要有以下优点: * 无缝访问C#工程的现成代码,无需额外抽象脚本API * 直接使用VS2015进行开发,ILRuntime的解译引擎支持.Net 4.6编译的DLL * 执行效率是L#的10-20倍 * 选择性的CLR绑定使跨域调用更快速,绑定后跨域调用的性能能达到slua的2倍左右(从脚本调用GameObject之类的接口) * 支持跨域继承 * 完整的泛型支持 * 拥有Visual Studio的调试插件,可以实现真机源码级调试。支持Visual Studio 2015 Update3 以及Visual Studio 2017 _____________________________________________________________________________________________________________ 本课程带领大家极速的上手ILRuntime中,让大家学会在Unity如何快速集成ILRuntime热更新技术~

    488 人正在学习 去看看 官剑铭

一般使用方法

[System.Runtime.InteropServices.DllImport("E:\\Project\\DLL\\XXX.dll", EntryPoint = "OpenComm", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern int  OpenComm(int port);

注意里面的E:\\Project\\DLL\\XXX.dll,这个路径测试不能用变量代替,也就是说必须直接这样写才可以,那每次网站换个路径这里就要改一遍,我是遇到了这种情况,方法可以用。


方法二:C#动态调用DLL中的函数

参考:http://www.cnblogs.com/kingmoon/archive/2011/04/26/2028833.html

namespace DllOperation
{
    #region 使用方法例子
      //public static int  Open()  
      //  {
      //      int DID = 0;
      //      Dynamicloadingdll ddl = new Dynamicloadingdll();
      //      String DllPath = "E:\\Project\\ElectricitySellingSystem\\ElectricitySellings\\DLL\\HCard32.dll";
      //      ddl.LoadDll(DllPath);
      //      ddl.LoadFun("UC_OpenComm");
      //      object[] Parameters = new object[] { (int)100 }; // 实参为 100 
      //      Type[] ParameterTypes = new Type[] { typeof(int) }; // 实参类型为 int 
      //      DllOperation.Dynamicloadingdll.ModePass[] themode = new DllOperation.Dynamicloadingdll.ModePass[] { DllOperation.Dynamicloadingdll.ModePass.ByValue }; // 传送方式为值传 
      //      Type Type_Return = typeof(int); // 返回类型为 int 
      //      object DeviceID= ddl.Invoke(Parameters, ParameterTypes, themode,Type_Return).ToString();
      //      DID = int.Parse(DeviceID.ToString());
            
      //      Parameters = new object[] { DID }; // 实参为 0 
      //      ddl.LoadFun("UC_CloseComm");
      //      ddl.Invoke(Parameters, ParameterTypes, themode, Type_Return).ToString();
      //      ddl.UnLoadDll();
      //      return DID;
      //  }
    #endregion
    /// 
    /// Dynamicloadingdll 的摘要说明
    /// 
    public class Dynamicloadingdll
    {
        public Dynamicloadingdll()
        {
            //
            // TODO: 在此处添加构造函数逻辑
            //
        }
        /// 
        /// 参数传递方式枚举 ,ByValue 表示值传递 ,ByRef 表示址传递
        /// 
        public enum ModePass
        {
            ByValue = 0x0001,
            ByRef = 0x0002
        }
        #region 声明LoadLibrary、GetProcAddress、FreeLibrary及私有变量hModule和farProc:
        /// 
        /// 原型是 :HMODULE LoadLibrary(LPCTSTR lpFileName);
        /// 
        /// DLL 文件名 
        ///  函数库模块的句柄 
        [DllImport("kernel32.dll")]
        static extern IntPtr LoadLibrary(string lpFileName);

        /// 
        /// 原型是 : FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);
        /// 
        ///  包含需调用函数的函数库模块的句柄 
        ///  调用函数的名称 
        ///  函数指针 
        [DllImport("kernel32.dll")]
        static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

        /// 
        /// 原型是 : BOOL FreeLibrary(HMODULE hModule);
        /// 
        ///  需释放的函数库模块的句柄 
        ///  是否已释放指定的 Dll
        [DllImport("kernel32", EntryPoint = "FreeLibrary", SetLastError = true)]
        static extern bool FreeLibrary(IntPtr hModule);
        /// 
        /// Loadlibrary 返回的函数库模块的句柄
        /// 
        private IntPtr hModule = IntPtr.Zero;
        /// 
        /// GetProcAddress 返回的函数指针
        /// 
        private IntPtr farProc = IntPtr.Zero;

        #endregion
        #region  添加LoadDll方法,并为了调用时方便,重载了这个方法:
        /// 
        /// 装载 Dll
        /// 
        /// DLL 文件名 
        public void LoadDll(string lpFileName)
        {
            hModule = LoadLibrary(lpFileName);
            if (hModule == IntPtr.Zero)
                throw (new Exception(" 没有找到 :" + lpFileName + "."));
        }
        //若已有已装载Dll的句柄,可以使用LoadDll方法的第二个版本:
        public void LoadDll(IntPtr HMODULE)
        {
            if (HMODULE == IntPtr.Zero)
                throw (new Exception(" 所传入的函数库模块的句柄 HMODULE 为空 ."));
            hModule = HMODULE;
        }
        #endregion
        #region 添加LoadFun方法,并为了调用时方便,也重载了这个方法,方法的具体代码及注释如下:
        /// 
        /// 获得函数指针
        /// 
        ///  调用函数的名称 
        public void LoadFun(string lpProcName)
        { // 若函数库模块的句柄为空,则抛出异常
            if (hModule == IntPtr.Zero)
                throw (new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !"));
            // 取得函数指针
            farProc = GetProcAddress(hModule, lpProcName);
            // 若函数指针,则抛出异常
            if (farProc == IntPtr.Zero)
                throw (new Exception(" 没有找到 :" + lpProcName + " 这个函数的入口点 "));
        }

        /// 
        /// 获得函数指针
        /// 
        ///  包含需调用函数的 DLL 文件名 
        ///  调用函数的名称 
        public void LoadFun(string lpFileName, string lpProcName)
        { // 取得函数库模块的句柄
            hModule = LoadLibrary(lpFileName);
            // 若函数库模块的句柄为空,则抛出异常
            if (hModule == IntPtr.Zero)
                throw (new Exception(" 没有找到 :" + lpFileName + "."));
            // 取得函数指针
            farProc = GetProcAddress(hModule, lpProcName);
            // 若函数指针,则抛出异常
            if (farProc == IntPtr.Zero)
                throw (new Exception(" 没有找到 :" + lpProcName + " 这个函数的入口点 "));
        }
        #endregion
        #region  添加UnLoadDll及Invoke方法,Invoke方法也进行了重载:
        /// 
        /// 卸载 Dll
        /// 
        public void UnLoadDll()
        {
            FreeLibrary(hModule);
            hModule = IntPtr.Zero;
            farProc = IntPtr.Zero;
        }

        //Invoke方法的第一个版本:
        ///  
        /// 调用所设定的函数 
        ///  
        ///  实参  
        ///  实参类型  
        ///  实参传送方式  
        ///  返回类型  
        ///  返回所调用函数的 object 
        public object Invoke(object[] ObjArray_Parameter, Type[] TypeArray_ParameterType,ModePass[] ModePassArray_Parameter, Type Type_Return)
        {
            // 下面 3 个 if 是进行安全检查 , 若不能通过 , 则抛出异常 
            if (hModule == IntPtr.Zero)
                throw (new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !"));
            if (farProc == IntPtr.Zero)
               throw (new Exception(" 函数指针为空 , 请确保已进行 LoadFun 操作 !"));
            if(ObjArray_Parameter.Length!=ModePassArray_Parameter.Length) 
            throw(new Exception(" 参数个数及其传递方式的个数不匹配 ." ) ); 

            // 下面是创建 MyAssemblyName 对象并设置其 Name 属性 
            AssemblyName MyAssemblyName = new AssemblyName();
            MyAssemblyName.Name = "InvokeFun";

            // 生成单模块配件 
            AssemblyBuilder MyAssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(MyAssemblyName, AssemblyBuilderAccess.Run);
            ModuleBuilder MyModuleBuilder = MyAssemblyBuilder.DefineDynamicModule("InvokeDll");
            // 定义要调用的方法 , 方法名为“ MyFun ”,返回类型是“ Type_Return ”参数类型是“ TypeArray_ParameterType ” 
            MethodBuilder MyMethodBuilder = MyModuleBuilder.DefineGlobalMethod("MyFun", MethodAttributes.Public | MethodAttributes.Static, Type_Return, TypeArray_ParameterType);
            // 获取一个 ILGenerator ,用于发送所需的 IL 
            ILGenerator IL = MyMethodBuilder.GetILGenerator();
            int i;
            for (i = 0; i < ObjArray_Parameter.Length; i++)
            {// 用循环将参数依次压入堆栈 

                switch (ModePassArray_Parameter[i])
                {

                    case ModePass.ByValue:
                        IL.Emit(OpCodes.Ldarg, i);
                        break;

                    case ModePass.ByRef:
                        IL.Emit(OpCodes.Ldarga, i);
                        break;

                    default:
                        throw (new Exception(" 第 " + (i + 1).ToString() + " 个参数没有给定正确的传递方式 ."));

                }
            }
            if (IntPtr.Size == 4)
            {// 判断处理器类型 
                IL.Emit(OpCodes.Ldc_I4, farProc.ToInt32());
            }
            else if (IntPtr.Size == 8)
            {
                IL.Emit(OpCodes.Ldc_I8, farProc.ToInt64());
            }
            else
            {
                throw new PlatformNotSupportedException();
            }
            IL.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, Type_Return, TypeArray_ParameterType);
            IL.Emit(OpCodes.Ret); // 返回值 
            MyModuleBuilder.CreateGlobalFunctions();

            // 取得方法信息 
            MethodInfo MyMethodInfo = MyModuleBuilder.GetMethod("MyFun");
            return MyMethodInfo.Invoke(null, ObjArray_Parameter);// 调用方法,并返回其值 

        }

        //Invoke方法的第二个版本,它是调用了第一个版本的:
        ///  
        /// 调用所设定的函数 
        ///  
        ///  函数指针  
        ///  实参  
        ///  实参类型  
        ///  实参传送方式  
        ///  返回类型  
        ///  返回所调用函数的 object 
        public object Invoke(IntPtr IntPtr_Function, object[] ObjArray_Parameter, Type[] TypeArray_ParameterType, ModePass[] ModePassArray_Parameter,Type Type_Return)
        {
            // 下面 2 个 if 是进行安全检查 , 若不能通过 , 则抛出异常 
            if (hModule == IntPtr.Zero)
                throw (new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !"));
            if (IntPtr_Function == IntPtr.Zero)
                throw (new Exception(" 函数指针 IntPtr_Function 为空 !"));
            farProc = IntPtr_Function;
            return Invoke(ObjArray_Parameter,
                          TypeArray_ParameterType,
                          ModePassArray_Parameter, Type_Return);
        }
        #endregion
    }
}

这样做路径就可以从配置文件中读取,或者通过Server.MapPath获得物理路径。


在使用C++编写的Dll时候,不是直引用用就可以了,中间需要转化方法。


2017-05-03 17:34:00 diwuci123 阅读数 137
  • Unity热更新之ILRuntime

    ILRuntime项目为基于C#的平台(例如Unity)提供了一个纯C#实现,快速、方便且可靠的IL运行时,使得能够在不支持JIT的硬件环境(如iOS)能够实现代码的热更新 ILRuntime的优势 同市面上的其他热更方案相比,ILRuntime主要有以下优点: * 无缝访问C#工程的现成代码,无需额外抽象脚本API * 直接使用VS2015进行开发,ILRuntime的解译引擎支持.Net 4.6编译的DLL * 执行效率是L#的10-20倍 * 选择性的CLR绑定使跨域调用更快速,绑定后跨域调用的性能能达到slua的2倍左右(从脚本调用GameObject之类的接口) * 支持跨域继承 * 完整的泛型支持 * 拥有Visual Studio的调试插件,可以实现真机源码级调试。支持Visual Studio 2015 Update3 以及Visual Studio 2017 _____________________________________________________________________________________________________________ 本课程带领大家极速的上手ILRuntime中,让大家学会在Unity如何快速集成ILRuntime热更新技术~

    488 人正在学习 去看看 官剑铭
C++中的方法int MyFun(int a,int b);
生成dll文件:MyDll.dll

在C#中调用dll文件一般需要声明:
[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int MyFun( int a, int b);
这样想动态来加载dll没办法操作。

后来在网上查了下,有两种方式能够动态的加载dll,不用声明:

先准备好DllInvoke类

public class DllInvoke
{
#region Win API
[DllImport("kernel32.dll")]
private extern static IntPtr LoadLibrary(string path);

[DllImport("kernel32.dll")]
private extern static IntPtr GetProcAddress(IntPtr lib, string funcName);

[DllImport("kernel32.dll")]
private extern static bool FreeLibrary(IntPtr lib);
#endregion

private IntPtr hLib;
public DllInvoke(String DLLPath)
{
hLib = LoadLibrary(DLLPath);
if (hLib == IntPtr.Zero)
{
throw (new Exception("没有找到:" + DLLPath + "。"));
}
}

~DllInvoke()
{
FreeLibrary(hLib);
}
public IntPtr GetIntPtr(string APIName)
{
IntPtr api = GetProcAddress(hLib, APIName);
if (api == IntPtr.Zero)
{
throw (new Exception(" 没有找到 :" + APIName + " 这个函数的入口点 "));
}
return api;
}
//将要执行的函数转换为委托
public Delegate GetDelegate(string APIName, Type t)
{
IntPtr api =GetIntPtr(APIName);
return (Delegate)Marshal.GetDelegateForFunctionPointer(api, t);
}
}



方法一:

delegate int Add(IntPtr[] X, int r, int c);


DllInvoke dk = new DllInvoke("MyDll.dll");
Add addFunction = (Add)dk.GetDelegate("MyFun", typeof(Add));
int sum=addFunction(2,3);



方法二:

object[] par = new object[] {2,3 };//输入参数
Type[] parType = par.Select(s=>s.GetType()).ToArray();//输入参数的类型
//Type[] parType =new Type[]{typeof(int),typeof(int)};
Type Type_Return = typeof(int); // 返回类型

AssemblyName assemblyName = new AssemblyName("InvokeName");//名称随便写
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("InvokeModule");
MethodBuilder methodBuilder = moduleBuilder.DefineGlobalMethod("InvokeMethod", MethodAttributes.Public | MethodAttributes.Static, Type_Return, parType);
ILGenerator IL = methodBuilder.GetILGenerator();
for (int i = 0; i < par.Length; i++)
{// 依次压入堆栈
IL.Emit(OpCodes.Ldarg, i); //实参传送方式,byValue
// IL.Emit(OpCodes.Ldarga, i);//实参传送方式,byRef
}
//要调用的dll
DllInvoke dk = new DllInvoke("MyDll.dll");
//调用的方法
IntPtr farProc = dk.GetIntPtr("MyFun");
if (IntPtr.Size == 4)
{// 判断处理器类型
IL.Emit(OpCodes.Ldc_I4, farProc.ToInt32());
}
else if (IntPtr.Size == 8)
{
IL.Emit(OpCodes.Ldc_I8, farProc.ToInt64());
}
else
{
throw new PlatformNotSupportedException();
}
IL.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, Type_Return, parType);
IL.Emit(OpCodes.Ret);
moduleBuilder.CreateGlobalFunctions();
//方法名和上面的一致
MethodInfo MyMethodInfo = moduleBuilder.GetMethod("InvokeMethod");
object sum = MyMethodInfo.Invoke(null, par);// 调用方法,并返回其值

2019-05-22 13:25:18 qq_41324483 阅读数 420
  • Unity热更新之ILRuntime

    ILRuntime项目为基于C#的平台(例如Unity)提供了一个纯C#实现,快速、方便且可靠的IL运行时,使得能够在不支持JIT的硬件环境(如iOS)能够实现代码的热更新 ILRuntime的优势 同市面上的其他热更方案相比,ILRuntime主要有以下优点: * 无缝访问C#工程的现成代码,无需额外抽象脚本API * 直接使用VS2015进行开发,ILRuntime的解译引擎支持.Net 4.6编译的DLL * 执行效率是L#的10-20倍 * 选择性的CLR绑定使跨域调用更快速,绑定后跨域调用的性能能达到slua的2倍左右(从脚本调用GameObject之类的接口) * 支持跨域继承 * 完整的泛型支持 * 拥有Visual Studio的调试插件,可以实现真机源码级调试。支持Visual Studio 2015 Update3 以及Visual Studio 2017 _____________________________________________________________________________________________________________ 本课程带领大家极速的上手ILRuntime中,让大家学会在Unity如何快速集成ILRuntime热更新技术~

    488 人正在学习 去看看 官剑铭

C#调用C语言生成的dll

using System;
using System.Runtime.InteropServices;	//与导入dll有关的命名空间
using System.Windows.Forms;
class Example
{
	//[导入dll,dll与exe在同一个文件夹下]导入dll中getCpuID1函数
    [DllImport("CPUID32DLL.dll", CharSet = CharSet.Auto)] public static extern IntPtr getCpuID1(); 
    static void Main()
    {
    	string CPU_ID1 = "";
        int s1 = (int)getCpuID1();					//执行dll中getCpuID1函数
        CPU_ID1 = String.Format("{0:X8}", s1);   	//整形转化为十六进制字符串...
        MessageBox.Show(CPU_ID1);					//弹出提示框,显示CPU_ID1内容
    }
}

Java 调用 C# DLL

阅读数 193

PB7调用C# dll

阅读数 2855

C#调用外部DLL

阅读数 2306

没有更多推荐了,返回首页