背景

  公司的支付平台最近对接了西安移动的支付接口,接口中签名的方法是对方提供了一个com组件,组件中包含了一个签名的方法和一个验签的方法,注册了签名之后,在vs中进行了引用,引用之后,查看组件的定义如下:

using System;
using System.Runtime.InteropServices; namespace UMPAYLib
{
[ClassInterface()]
[Guid("E92EB0AA-00CC-4F93-A76D-632BEA94E980")]
[TypeLibType()]
[ComConversionLoss]
public class SignClass : ISign, Sign
{
public SignClass(); [DispId()]
public virtual string Sign(string str, string certfile, string keyfile);
[DispId()]
public virtual int Verify(string str, string sig, IntPtr certfile);
}
}

  首先先看一下签名的方法:Sign(string str,string certfile,string keyfile);

  三个参数分别是用于签名的串、公钥证书的路径和私钥证书的路径。

  再看验签的方法:Verify(string str,string sig,IntPtr certfile);

  三个参数分别是用于签名的串,要验证的签名值和公钥证书的路径。

  那么问题来了,验签方法的第三个参数,证书的路径怎么是IntPtr类型呢?IntPtr到底是个什么类型呢?我该怎么调用这个方法呢?

解决过程

  首先我问题了接口方,接口放的对接人员倒是挺负责任,帮我看文档,问同事,可接口方看过他们自己的文档之后,也郁闷了,他们也不清楚文档咋和组件里的方法定义不一样,他们说要请示总部,而请示总部要用邮件,而且半天也不见回复,可接口后天就要上线测试了,等回复看来不靠谱,还得靠自己,于是就开始了求助度娘。

  首先我们来看看IntPtr到底是个什么类型?

  MSDN的解释:

用于表示指针或句柄的平台特定类型。
备注:
IntPtr 类型被设计成整数,其大小适用于特定平台。 即是说,此类型的实例在 32 位硬件和操作系统中将是 32 位,在 64 位硬件和操作系统上将是 64 位。
IntPtr 类型可以由支持指针的语言使用,并可作为在支持与不支持指针的语言间引用数据的一种通用方式。
IntPtr 对象也可用于保持句柄。 例如,IntPtr 的实例广泛地用在 System.IO.FileStream 类中来保持文件句柄。
IntPtr 类型符合 CLS,而 UIntPtr 类型却不符合。 只有 IntPtr 类型可用在公共语言运行时中。 UIntPtr 类型大多数是提供来维护与 IntPtr 类型之间的体系结构上的对称性。
此类型实现 ISerializable 接口。

  其中一行是这样说的:

  IntPtr类型可以由支持指针的语言使用,并可作为在支持与不支持指针的语言间引用数据的一种通用方式。

引用数据的通用方式?指针?看到这个之后,我就在度娘里输入了“IntPtr传字符串“几个字,搜索结果中看到了一篇园子里一个仁兄写的博客,http://www.cnblogs.com/jxsoft/archive/2011/07/06/2099061.html,正式这篇博客,让我豁然开朗,找到了问题最终的解决办法,虽然解决的方法不是用的这位仁兄的方法,但思路是从这儿而来,所以还是要谢谢”许明吉博客“了。

  我先是用了这篇博客中的如下这个方法进行测试:

/// <summary>
/// 根据数据的长度申请非托管空间
/// </summary>
/// <param name="strData">要申请非托管空间的数据</param>
/// <returns>指向非拖管空间的指针</returns>
private static IntPtr mallocIntptr( string strData )
{
//先将字符串转化成字节方式
Byte[] btData = System.Text.Encoding.Default.GetBytes(strData); //申请非拖管空间
IntPtr m_ptr = Marshal.AllocHGlobal(btData.Length); //给非拖管空间清0
Byte[] btZero = new Byte[btData .Length+ ]; //一定要加1,否则后面是乱码,原因未找到
Marshal.Copy(btZero, , m_ptr, btZero.Length); //给指针指向的空间赋值
Marshal.Copy(btData, , m_ptr, btData.Length); return m_ptr;
}

  测试的代码如下:

UMPAYLib.SignClass signClass = new UMPAYLib.SignClass();
IntPtr ptrCertFile = mallocIntptr(certFile);
int b = signClass.Verify(prestr, SIGN, ptrCertFile);

运行测试的页面,当执行到signClass.Verify这个com组件验签的方法的时候,报了一个”没有足够的内存来继续运行程序“的异常,组件内部的代码也看不到,所以也不知道里面怎么处理导致了这个内存溢出的异常,好不容易找到了思路,却有出现了这个问题,该怎么办呢?于是我又看了看ptrCertFile的属性和方法,我输出了ptrCertFile的.ToString(),发现得到了一个很大的数字,可还是不知道为什么会内存溢出,我又仔细看了看,mallocIntptr这个方法,方法里有一个分配内存的类引起了我的兴趣,它就是Marshal,我们再来看看Mashal这个类具体是干啥的?有啥方法?

MSDN的解释:

提供了一个方法集,这些方法用于分配非托管内存、复制非托管内存块、将托管类型转换为非托管类型,此外还提供了在与非托管代码交互时使用的其他杂项方法。

从解释中可以看出,该类主要是用于分配非托管内存和在托管类型和非托管类型之间进行转换。

于是我就浏览了一下Mashal类的成员,发现了一个方法:

而这个方法也本身就能实现上面mallocIntptr这个方法的功能,于是我就把代码修改为如下:

UMPAYLib.SignClass signClass = new SignClass();
string certPath = MobileWapPayConfig.CertFile;
IntPtr ptrCertFile = Marshal.StringToBSTR(certPath);
int result = signClass.Verify(prestr, sign, ptrCertFile);
Marshal.FreeBSTR(ptrCertFile);
return result == ;

重新运行测试页面,一切正常。

至此,最初遇到的IntPtr不知如何调用的问题已经解决了,但遗留了一个小问题,那就是为什么mallocIntptr这个方法会导致内存溢出,望了解的朋友不吝赐教!

总结

对于一些com组件的方法参数IntPtr类型的,可以使用Marshal类的相关方法来处理。

如何调用com组件中包含IntPtr类型参数的函数的更多相关文章

  1. 微信小程序自定义组件的使用以及调用自定义组件中的方法

    在写小程序的时候,有时候页面的内容过多,逻辑比较复杂,如果全部都写在一个页面的话,会比较繁杂,代码可读性比较差,也不易于后期代码维护,这时候可以把里面某部分功能抽出来,单独封装为一个组件,也就是通常说 ...

  2. Angular 4 父组件调用子组件中的方法

    1. 创建工程 ng new demo3 2. 创建子组件 ng g component child 3. 在子组件中定义方法greeting 4. 父组件html(第三行是模板中调用子组件的方法) ...

  3. 父组件调用子组件中的方法- this.$refs.xxx.子组件方法();

    子组件中有一个说的方法 在父组件中去调用当你点击的时候 去调用子组件中的方法 fu.vue 在父组件的方法中调用子组件的方法,很重要 this.$refs.mychild.parentHandlecl ...

  4. Vue3 SFC 和 TSX 方式调用子组件中的函数

    在开发中会遇到这样的需求:获取子组件的引用,并调用子组件中定义的方法.如封装了一个表单组件,在父组件中需要调用这个表单组件的引用,并调用这个表单组件的校验表单函数或重置表单函数.要实现这个功能,首先要 ...

  5. 深入理解--VUE组件中数据的存放以及为什么组件中的data必需是函数

    1.组件中数据的存放 ***(重点)组件是一个单独模块的封装:这个模块有自己的HTML模板,也有data属性. 只是这个data属性必需是一个函数,而这个函数返回一个对象,这个对象里面存放着组件的数据 ...

  6. vue组件中的data为什么是函数?

    一.vue组件中的data为什么是函数 为了保证组件的独立性 和 可 复用性,data 是一个函数,组件实例化的时候这个函数将会被调用,返回一个对象,计算机会给这个对象分配一个内存地址,你实例化几次, ...

  7. Vue 组件中 data 为什么必须是函数

    原文地址 vue组件中的data必须是函数 类比引用数据类型 Object是引用数据类型,如果不用function 返回,每个组件的data 都是内存的同一个地址,一个数据改变了其他也改变了; jav ...

  8. time.h文件中包含的几个函数使用时须注意事项

    time.h头文件中包含以下函数 char* asctime(const struct tm *tm); char* asctime_r(const struct tm *tm,char *buf); ...

  9. vue组件中—bus总线事件回调函数多次执行的问题

    在利用vue组件进行事件监听时发现,如果对N个vue组件实例的bus总线绑定同一事件的回调函数,触发任意组件的对应事件,回调函数至少会被执行N次,这是为什么呢? 为此,调研了普通对象的事件绑定和触发实 ...

随机推荐

  1. 个人常用git命令

    最近开始使用git,将自己常用git命令做一个简单归纳,便于记忆. 初始化及配置 git init:初始化资料库 git config --global user.name 'xxx':配置用户名 g ...

  2. 2.1 shuffle sort(洗牌)

    1.目的:将数组以随机的顺序重新排序,类似洗牌的过程 2.用途用于快速排序或者任何以划分为基础的排序中,目的是减少最坏可能性发生的概率. 3.想法1:给数组的每一个元素产生一个随机的数字作为键,然后使 ...

  3. java 远程调用

    1.webservice (soap+http) -aixs -axis2 -xfire—>cxf 2.webservice问题 -基于xml,xml效率,(数据传输效率,xml序列化效率) - ...

  4. 通过代码学习python之@property,@staticmethod,@classmethod

    URL: https://www.the5fire.com/python-property-staticmethod-classmethod.html #coding=utf-8 class MyCl ...

  5. 5、Java并发性和多线程-相同线程

    以下内容转自http://tutorials.jenkov.com/java-concurrency/same-threading.html(使用谷歌翻译): 相同线程(同一线程)是一种并发模型,其中 ...

  6. Java中原始数据类型存放位置理解

    原始数据类型的变量存放在栈还是堆,应该由上下文去决定. 如下所示的局部方法中,定义了本地变量a,且为原始数据类型,所以存放在栈中. public void func(){ int a = 3; } 再 ...

  7. Qos management

    本文基于oracle 11.0.2.3. 主要介绍什么叫Qos management.本文包括以下内容: 什么是 Oracle Database QoS Management? 使用QoS Manag ...

  8. 怎样在Linux下使用Markdown进行文档工作

    怎样在Linux下使用Markdown进行文档工作 在Linux系统中,编辑markdown能够用retext工具: sudo apt-get install retext retext Releas ...

  9. [Vue-rx] Switch to a Function which Creates Observables with Vue.js and Rxjs

    Wrapping the creation of an Observable inside of a Function allows you delay the creation of the Obs ...

  10. VB Socket编程 框架

    [转载]VB Socket编程 框架 (2014-07-15 20:06:28) 转载▼ 标签: 转载   原文地址:VB Socket编程 框架作者:安静的浪花 VB Socket编程(Winsoc ...