背景

  公司的支付平台最近对接了西安移动的支付接口,接口中签名的方法是对方提供了一个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. 使用HTML5 Canvas API

    一.检测浏览器支持情况 HTML5 Canvas的确是一个好东西,但是并不是所有浏览器都支持HTML5 Canvas的,这就要求我们在使用HTML5 Canvas前要检查浏览器是否支持这玩意儿. 在创 ...

  2. 码云私人代码 SSH 设置----https://blog.csdn.net/kkaazz/article/details/78667573

    码云私人代码 SSH 设置 https://blog.csdn.net/kkaazz/article/details/78667573

  3. rm -rf & node

    rm -rf & node rm -rf $ rm -rf mydir https://www.computerhope.com/issues/ch000798.htm https://sta ...

  4. noip模拟赛 业务办理

    [问题描述]在银行柜台前,有 n 个顾客排队办理业务. 队伍中从前往后,第 i 位顾客办理业务需要ti 分钟时间. 一位顾客的等待时间定义为:队伍中在他之前的所有顾客和他自己的办理业务时间的总和.第 ...

  5. 你的ExcelUtil简单、高效、易扩展吗

    你的ExcelUtil简单.高效.易扩展吗 Author: Dorae Date: 2018年10月23日12:30:15 转载请注明出处 一.背景 最近接到了和Excel导出相关的需求,但是: 项目 ...

  6. Ubuntu安装vnc 解决乱码

    https://blog.csdn.net/dddxxxx/article/details/53580789 https://www.centos.bz/2017/12/%E8%A7%A3%E5%86 ...

  7. SiteMesh2-sitemesh.xml的ConfigDecoratorMapper映射器的用法

    继上一次的示例工程http://www.cnblogs.com/EasonJim/p/7083165.html,使用的就是ConfigDecoratorMapper映射器,通过指定目录下的页面,都同一 ...

  8. 1.3-动态路由协议EIGRP②

    LAB3:Wildcard Mask in EIGRP (通过反掩码,控制运行EIGRP的接口的范围             作用:控制有哪些接口在运行EIGRP) ~~~~~~~~~~~~~~~~~ ...

  9. C++学习之extern "C"

    我们知道,extern关键字可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.这里起到的是声明作用范围的用处.另外,extern还可以与 ...

  10. LeetCode 819. Most Common Word (最常见的单词)

    Given a paragraph and a list of banned words, return the most frequent word that is not in the list ...