zoukankan      html  css  js  c++  java
  • (转)C#调用DLL时参数问题的一点心得

    C#导入DLL时,参数怎么定义是一个比较头痛的问题。特别是指针类型的参数,关于此问题本人有点不成熟的经验。

          以 GetComputerName这个函数为例。

         函数原型如下

    BOOL GetComputerName(
      LPTSTR lpBuffer,
      LPDWORD lpnSize
    );
    

    这个lpBuffer就是下个string型的指针,其实无论是什么类型的指针,对于Windows来说都是一个32位的无符号的整数,也就是一个内在地址,函数之所以使用指针就是要向指针所指向的内存空间写入数据。

    我们用C#调用时也要给它传递一个指针,还要对应一块分配的空间 。

    下面是代码:

    Code

    其实和C++在调用的本质是一样的,都要分配空间并将空间的地址传给函数

    。只是C#是运行在托管环境,所以对空间的分配的数据的读取都要特殊处理。

    还是更简单的方法,就是用StringBuilder。本质上还是和上面一样的,只不过是C#替你做了得多工作。

    Code

    对于结构体也是一样,以

    BOOL GetVersionEx(
      LPOSVERSIONINFO lpVersionInformation
    );

    typedef struct _OSVERSIONINFO{
      DWORD dwOSVersionInfoSize;
      DWORD dwMajorVersion;
      DWORD dwMinorVersion;
      DWORD dwBuildNumber;
      DWORD dwPlatformId;
      TCHAR szCSDVersion[128];
    } OSVERSIONINFO;

    为例说明一下。

    参数是一个结构体的指针,函数会填充结构体的各个字段,其实就是向这块内存空间的不同位置写入不同的数据。

    Code

    根据结构体的定义有5个DWORD和一个128位的CHAR数组,所以要给这个结构体分配148位空间。结构体的第一个字段这是个结构体的大小,我们用 Marshal.WriteInt32(pv, 148);写入结构体的大小(这也是Windows API在使用结构体的一个特点,就是大部分结构体在传给函数填充前要指定其大小。),然后执行函数。

    如果函数正常返回,就可以根据结构体的定义从相应的位置读出数据。

    Marshal.ReadInt32(pv, 4);读取第二个整数也就是MajorVersion,Marshal.ReadInt32(pv, 12);第四个是BuildNumber,Marshal.PtrToStringAnsi((IntPtr)(pv.ToInt32() + 20));五个整数之后是CSDVersion。

    写上面的内容只是想分析一下机理,如果学习过汇编就很好理解了。

    下面是通常的做法:

    Code
  • 相关阅读:
    String类型作为方法的形参
    [转] 为什么说 Java 程序员必须掌握 Spring Boot ?
    Centos打开、关闭、结束tomcat,及查看tomcat运行日志
    centos中iptables和firewall防火墙开启、关闭、查看状态、基本设置等
    防火墙没有关导致外部访问虚拟机的tomcat遇到的问题和解决方法
    可以ping通ip地址,但是访问80,或者8080报错
    JAVA的非对称加密算法RSA——加密和解密
    CA双向认证的时候,如果一开始下载的证书就有问题的,怎么保证以后的交易没有问题?
    图解HTTPS协议加密解密全过程
    https单向认证服务端发送到客户端到底会不会加密?
  • 原文地址:https://www.cnblogs.com/fjchenqian/p/1445258.html
Copyright © 2011-2022 走看看