怎么动态调用DLL并传递参数

怎么动态调用DLL并传递参数,第1张

子程序 _按钮1_被单击

局部变量 Parameters, , , "4", '有多少参数就填多少数组,不然报错。

Parameters [1] = 到数值 (&Thread)

Parameters [2] = lstrcpyn (“赋予了一个参数进去!”, 0, 0)'取变量数据地址 ()

汇编动态调用Api函数 (“shlwapidll”, “SHCreateThread”, Parameters)

子程序 Thread

参数 Text

信息框 (指针到文本 (Text), 0, )

调用及结果 并没有区别

区别在于,直接调用需要在工程中加入so的引用

而用dlopen可以直接使用动态库,更灵活

另外,如果直接调用方式,so文件不存在会导致整个程序无法运行

而用dlopen动态加载,可以运行后再判断是否加载成功,即使失败,还可以保留程序其它功能。

在编译代码中指定DYN参数:

//COBOL EXEC PGM=IGYCRCTL,REGION=640K,COND=(12,LE),

// PARM=(NOTERM,LIB,XREF,DYN,'')

//LINK EXEC PGM=HEWLF064,REGION=2048K,COND=(12,LE),PARM=(DYN)

其实只要在COBOL程序中是CALL一个变量,它就是表示一个动态调用。

  C语言具有简洁紧凑,灵活方便,运算符丰富,数据类型丰富,表达方式灵活实用等特点,所以C语言程序设计更主动、灵活。很多人从C语言入门编程,下面整理了一些C语言基础知识,希望对大家有所帮助!

 1C语言中,变量必须先声明后使用,即一个程序块(花括号对)中所有临时变量必须在第一条可执行语句之前全部声明,而不能像C++那样随用随声明;

 2C语言中参数传值传递形参,即为参数的拷贝,此与C++/JAVA相同,同时值得注意,ANSI C不支持引用,此与C++/JAVA有区别,那么要对参数进行修改只能使用指针方式(指针传值指针本身仍是形参,要修改指针本身那必须使用双重指针);

 3C语言默认类型为int,即参数无类型或函数无返回值类型声明,则认为是int(貌似一些编译器不支持),同时不建议使用该特性;

 4无参数的函数声明应当使用void表明,否则C语言按照老式声明方法忽略参数类型检查;

 5全局变量建议全大写,局部变量建议全小写,内部变量31个字符有效,外部变量不区分大小写,仅6个字符有效,所以必须保持唯一性;

 6ANSI C是按照多字节实现的,UNICODE是后来发展的,所以有char/WCHAR,与NET中char直接是双字节有区别,在C#中导入dll时值得注意;

 7C语言支持枚举,并且枚举和int直接强制类型转换即可,比NET方便;

 8#define声明宏定义直接在编译时替换,不进行类型检查,const声明常量则可以进行类型检查;

 9运算符的优先级记忆比较麻烦,还是()可靠;

 10goto并不是一无是处,在不考虑程序可读性的情况下可能获得更高的效率;

 11函数实际也可以与特殊的类型相对应,那样对于理解函数指针比较方便,函数为外部类型;

 12static用于全局变量和函数则限定该变量和函数的使用范围仅为该源文件(从而无需考虑与其他源文件不得重名),用于函数内部变量则该变量的内存分配和回收不再同于普通临时变量(调用函数生成,函数返回销毁),而是一直存在于静态变量区,从而可以保存一些状态;

 13头文件的作用体现在调用其他源文件时不需要再次写函数定义,所以实现函数是不需要头文件的,调用时才需要,可以采用富头文件定义一大组接口,然后使用多个源文件分别实现;

 14寄存器变量使用register声明,仅适用于使用频率高的局部变量(含形参)(受限于底层硬件,不一定会被分配到寄存器,但是这么写不影响效率);

 15全局变量和静态变量默认初始化为全零且仅初始化一次,局部变量默认初始化为未定义且每次都会重新初始化;

 16递归调用的方法一般比较紧凑,但是每次调用会单独维护调用的`堆栈,所以效率不是最高;

 17#include的作用体现于将一些内容避免重新写一遍(主要是类型、函数和外部变量定义),所以实际上不一定为h文件;

 18表示一行尚未结束,对于定义长的字符串和define比较有用;

 19函数调用的执行顺序不确定,所以对于a()+b()这样函数中使用相同变量并且改变其值的需要借助临时变量处理,防止不同实现的调用顺序不一致;

 20##用于宏定义中连接前后两个部分,如cat(a, b) a ## b;

 21指针是C/C++的重要内容,当然也是双面刃,用好了很方便而且高效,用不好那就造成程序不稳定;

 22使用va_list, va_start, va_arg, va_end来定义可变参数的函数,通过va_start函数中的第一个不变参数将va_list指向参数列表(函数调用的栈中),然后通过va_arg获取每个参数并将va_list移动指定类型的长度,最后则通过va_end完成必要的回收工作,需要指出的是va_arg没有结束边界,所以比较有效的方式有两种,一种对于参数类型一致,则可以第一个参数指出后续参数的总数,然后依次获取,另一种对于不同类型的参数混用,则可以通过类型标识+参数配对的方式进行使用(第一个参数依然可以指定数量,当然也可以检查标识),从而避免最后读取无效的参数,对于可变参数仅支持int和double两种类型(参数未限定类型,故按照旧式声明理解)以及指针类型;

 23函数指针是用来在C语言中实现动态调用的比较有效的方式

 24结构体用作参数依然是拷贝为形参传递,这点与JAVA中全部对象都是类有区别(类的对象通过引用传值,C#支持struct),所以对于大的结构体事宜使用指针传递,而对于小的结构体拷贝传值效率并不低;

 25代码中字符数组为静态常量,对其 *** 作无效,程序块中数组的声明是可以自动回收的,通过malloc/calloc分配的内存为堆内存,需要自行通过free回收;

 部分代码来自于网络 废话不多说 上代码

 调用方法

 object obj = WinDllInvoke( Kernel dll Beep new object[] { } typeof(void));函数代码

  [System Runtime InteropServices DllImport( kernel )]           private static extern IntPtr LoadLibrary(string lpLibFileName);             [System Runtime InteropServices DllImport( kernel )]           private static extern IntPtr GetProcAddress(IntPtr hModule string lpProcName);             [System Runtime InteropServices DllImport( kernel )]           private static extern IntPtr FreeLibrary(IntPtr hLibModule);           ///          /// 动态调用Windows DLL          ///          /// Dll文件名          /// 待调用的函数名          /// 函数参数          /// 返回值          /// 调用结果          private static object WinDllInvoke(string fileName string funName object[] objParams Type returnType)          {              IntPtr libHandle = IntPtr Zero;              try              {                  //获取函数地址                  libHandle = LoadLibrary(fileName);                  if (libHandle == IntPtr Zero) return null;                  IntPtr procAddres = GetProcAddress(libHandle funName);                  if (procAddres == IntPtr Zero) return null;                                   //获取参数类型                  Type[] paramTypes = new Type[objParams Length];                  for (int i = ; i < objParams Length; ++i)                  {                      paramTypes[i] = objParams[i] GetType();                  }                  //构建调用方法模型                  AssemblyName asembyName = new AssemblyName();                  asembyName Name = WinDllInvoke_Assembly ;                  AssemblyBuilder asembyBuilder = AppDomain CurrentDomain DefineDynamicAssembly(asembyName AssemblyBuilderAccess Run);                  ModuleBuilder moduleBuilder = asembyBuilder DefineDynamicModule( WinDllInvoke );                  MethodBuilder methodBuilder = moduleBuilder DefineGlobalMethod( InvokeFun MethodAttributes Public | MethodAttributes Static returnType paramTypes);                  //获取一个 ILGenerator 用于发送所需的 IL                  ILGenerator IL = methodBuilder GetILGenerator();                  for (int j = ; j < paramTypes Length; ++j)                  {                      //将参数压入堆栈                      if (paramTypes[j] IsValueType)                      {                          IL Emit(OpCodes Ldarg j); //By Value                      }                      else                      {                          IL Emit(OpCodes Ldarga j); //By Addrsss                      }                  }                  // 判断处理器类型                  if (IntPtr Size == )                  {                      IL Emit(OpCodes Ldc_I procAddres ToInt ());                  }                  else if (IntPtr Size == )                  {                      IL Emit(OpCodes Ldc_I procAddres ToInt ());                  }                  else                  {                      throw new PlatformNotSupportedException( 不好意思

lishixinzhi/Article/program/net/201311/12149

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/12462946.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-23
下一篇2023-05-23

发表评论

登录后才能评论

评论列表(0条)

    保存