如何调用com组件中包含IntPtr类型参数的函数
背景
公司的支付平台最近对接了西安移动的支付接口,接口中签名的方法是对方提供了一个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类型参数的函数的更多相关文章
- 微信小程序自定义组件的使用以及调用自定义组件中的方法
在写小程序的时候,有时候页面的内容过多,逻辑比较复杂,如果全部都写在一个页面的话,会比较繁杂,代码可读性比较差,也不易于后期代码维护,这时候可以把里面某部分功能抽出来,单独封装为一个组件,也就是通常说 ...
- Angular 4 父组件调用子组件中的方法
1. 创建工程 ng new demo3 2. 创建子组件 ng g component child 3. 在子组件中定义方法greeting 4. 父组件html(第三行是模板中调用子组件的方法) ...
- 父组件调用子组件中的方法- this.$refs.xxx.子组件方法();
子组件中有一个说的方法 在父组件中去调用当你点击的时候 去调用子组件中的方法 fu.vue 在父组件的方法中调用子组件的方法,很重要 this.$refs.mychild.parentHandlecl ...
- Vue3 SFC 和 TSX 方式调用子组件中的函数
在开发中会遇到这样的需求:获取子组件的引用,并调用子组件中定义的方法.如封装了一个表单组件,在父组件中需要调用这个表单组件的引用,并调用这个表单组件的校验表单函数或重置表单函数.要实现这个功能,首先要 ...
- 深入理解--VUE组件中数据的存放以及为什么组件中的data必需是函数
1.组件中数据的存放 ***(重点)组件是一个单独模块的封装:这个模块有自己的HTML模板,也有data属性. 只是这个data属性必需是一个函数,而这个函数返回一个对象,这个对象里面存放着组件的数据 ...
- vue组件中的data为什么是函数?
一.vue组件中的data为什么是函数 为了保证组件的独立性 和 可 复用性,data 是一个函数,组件实例化的时候这个函数将会被调用,返回一个对象,计算机会给这个对象分配一个内存地址,你实例化几次, ...
- Vue 组件中 data 为什么必须是函数
原文地址 vue组件中的data必须是函数 类比引用数据类型 Object是引用数据类型,如果不用function 返回,每个组件的data 都是内存的同一个地址,一个数据改变了其他也改变了; jav ...
- time.h文件中包含的几个函数使用时须注意事项
time.h头文件中包含以下函数 char* asctime(const struct tm *tm); char* asctime_r(const struct tm *tm,char *buf); ...
- vue组件中—bus总线事件回调函数多次执行的问题
在利用vue组件进行事件监听时发现,如果对N个vue组件实例的bus总线绑定同一事件的回调函数,触发任意组件的对应事件,回调函数至少会被执行N次,这是为什么呢? 为此,调研了普通对象的事件绑定和触发实 ...
随机推荐
- Spring MVC学习总结(8)——Swagger入门详解
前言 Swagger 是一款RESTFUL接口的文档在线自动生成+功能测试功能软件.本文简单介绍了在项目中集成swagger的方法和一些常见问题.如果想深入分析项目源码,了解更多内容,见参考资料. S ...
- python写第一个网页
1>安装django见别的博客http://djangobook.py3k.cn/2.0/chapter03/ 2>运行开发服务器 在命令提示符里进入目录mytest:cd: mytest ...
- noip模拟赛 捡金币
问题描小空正在玩一个叫做捡金币的游戏.游戏在一个被划分成 n行 n列的网格状场地中进行.每一个格子中都放着若干金币,并且金币的数量会随着时间而不断变化. 小空的任务就是在网格中移动,拾取尽量多的金币. ...
- A + B Problem Too
Problem Description This problem is also a A + B problem,but it has a little difference,you should d ...
- 今天開始慢下脚步,開始ios技术知识的查漏补缺。
从2014.6.30 開始工作算起. 如今已经是第416天了.不止不觉.时间过的真快. 通过对之前工作的总结.发现,你的知识面.会决定你面对问题时的态度.过程和结果. 简单来讲.知识面拓展了,你才干有 ...
- 使用SwipeRefreshLayout和RecyclerView实现仿“简书”下拉刷新和上拉载入很多其它
一.概述 本篇博客介绍的是怎样使用SwipeRefreshLayout和RecyclerView实现高仿简书Android端的下拉刷新和上拉载入很多其它的效果. 依据效果图能够发现,本案例实现了例如以 ...
- duilib中加入自己定义控件之后怎么可以在xml文件里配置使用
加入自己定义控件可能有两种不同的情况: 1. 在duilib库中加入的自己定义控件. 2. 在我们的应用程序中自己重写了一个控件. 以下開始解说不同的情况下怎么才干支持在xml文件配置控件: 1. ...
- Python&MySQL
环境:windows8+Python2.7+MySQL5.6 尝试过在C/C++中嵌入SQL语言,最终在其复杂"繁琐"环境配置中败下阵来,后来发现Python和MySQL比較eas ...
- LeetCode 824. Goat Latin (山羊拉丁文)
题目标签:String 首先把vowel letters 保存入 HashSet. 然后把S 拆分成 各个 word,遍历每一个 word: 当 word 第一个 字母不是 vowel 的时候,把第一 ...
- Error处理: 重提No Launcher activity found!
Error处理: 重提No Launcher activity found! 重提No Launcher activity found!错误提示,及解决的方法 Android应用开发中No Launc ...