zoukankan      html  css  js  c++  java
  • C#使用Win32函数的一些类型转换

    C#在访问Win 32 Api时需要处理C 结构与C#结构的映射,这在MSDN以及许多Blog上都可以找到参考的资料。Win 32 中有一些定义复杂的Struct,这些结构体拥有长度固定的数组或者一些特殊的结构,比如定义拥有有char Name[ULEN]、GUID、HANDLE等。在Mprapi中有一个名为RAS_CONNECTION_2这样的结构体,它描述了远程连接到服务器【远程与路由访问服务】的连接信息,是一个级联的、复杂的结构体定义。其Win 32的定义如下:

    typedef struct _RAS_CONNECTION_2 {
      HANDLE                hConnection;
      WCHAR                 wszUserName[UNLEN + 1];
      ROUTER_INTERFACE_TYPE dwInterfaceType;
      GUID                  guid;
      PPP_INFO_2            PppInfo2;
    } RAS_CONNECTION_2, *PRAS_CONNECTION_2;
    
    typedef struct _PPP_INFO_2 {
      PPP_NBFCP_INFO nbf;
      PPP_IPCP_INFO2 ip;
      PPP_IPXCP_INFO ipx;
      PPP_ATCP_INFO  at;
      PPP_CCP_INFO   ccp;
      PPP_LCP_INFO   lcp;
    } PPP_INFO_2;
    
    typedef struct _PPP_IPCP_INFO2 {
      DWORD dwError;
      WCHAR wszAddress[IPADDRESSLEN + 1];
      WCHAR wszRemoteAddress[IPADDRESSLEN + 1];
      DWORD dwOptions;
      DWORD dwRemoteOptions;
    } PPP_IPCP_INFO2;

    上面只只列出了一项层级定义,即RAS_CONNECTION_2 -> PPP_FINO_2 ->PPP_IPCP_INFO2,其他层级类似。在这样一个结构封装定义中,需要涉及到固定长度数组的封送(C++到.Net)、特殊类型定义(HANDLE & GUID)以及结构体包含。在MSDN上[2],找到了以下这些.Net已经封装好的用于交互的特殊类型。

    特殊值类型
    系统值类类型 IDL类型
    System.DateTime DATE
    System.Deimal DECIMAL
    System.Guid GUID
    System.Drawing.Color OLE_COLOR

    GUID对应System.Guid。HANDLE不能对应System.Activities.Handle,该类与互调无关。HANDLE一般对应System.IntPtr,见下列代码第一行。固定长度char数组(而不是字符串指针)的定义见第5、6行。第7行的结构体同样需要在C#中进行自行定义,除了命名其他无需特别注意。

     1 [StructLayout(LayoutKind.Sequential,CharSet = CharSet.Unicode)]
     2 public struct RAS_CONNECTION_2
     3 {            
     4         public IntPtr hConnection;
     5         [MarshalAs(UnmanagedType.ByValTStr, SizeConst = UNLEN)]
     6         public string wszUserName;
     7         public ROUTER_INTERFACE_TYPE dwInterfaceType;
     8         public Guid guid;
     9         public PPP_INFO_2 PppInfo2;
    10 };

     对于Win 32结构体中的固定长度的char[]定义,不能使用[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_PORT_NAME)]。字符串数组只能使用UnmanagedType.ByValArray,并指定数组长度大小,即类似这样定义UnmanagedType.ByValArray, SizeConst = MAX_PORT_NAME。如果使用ByBalArray,将会在运行时报错。

    “System.TypeLoadException”类型的异常在 mscorlib.dll 中发生,但未在用户代码中进行处理
    
    其他信息: 无法封送处理类型为“****”的字段“wszPortName”: 无效的托管/非托管类型组合(String 类型的字段必须与 LPStr、LPWStr、LPTStr、BStr 或 ByValTStr 成对出现)。

    在处理字符串数组时,需要明确指定字符的编码方式。需要明确指明为CharSet = CharSet.Unicode,否则会出现字符串的截取不正确。比如出现VPN被解析为V情况,这是因为默认的编码可能为ASCII,而将正常的空解析为了结束符。

    另外还以下一些特殊的类型:

    Win32 类型 .Net 类型
    PBYTE  IntPtr
       
       

    参考:

    [1]默认封送处理行为, https://msdn.microsoft.com/zh-cn/library/zah6xy75.aspx

    [2]可直复制和不可直接复制类型, https://msdn.microsoft.com/zh-cn/library/75dwhxf7.aspx

    [2]数组的默认封送处理——结构内的数组, https://msdn.microsoft.com/zh-cn/library/z6cfh6e6.aspx

  • 相关阅读:
    学习笔记之jq
    学习笔记之pytest
    本月学习小结(01/10
    本月学习小结(01/09
    学习笔记之Poetry
    学习笔记之Dynaconf
    学习笔记之asyncio — Asynchronous I/O
    Redis 根据key获取所有 HashKey
    Java ffmpeg 合成音视频文件
    Redis 存储中文方式
  • 原文地址:https://www.cnblogs.com/jjseen/p/5928792.html
Copyright © 2011-2022 走看看