.Net调用非托管代码数据类型不一致的问题
什么是Net互操作?.Net不能直接操作非托管代码,这时就需要互操作了。
c#中调用非托管c++函数,此函数又包含指向某个结构的指针,譬如指向c#中的byte数组。对于这样的参数,考虑到非托管变量不能直接在托管代码中使用,那么应该如何去处理呢?
上例子:
private string getSelText(int start,int Scount)
{
try
{
StringBuilder a = new StringBuilder(Scount); IntPtr pdf_pag = FPDFView.FPDF_LoadPage(pdf_doc, currentPage);
IntPtr cur_textpag = FPDFText.FPDFText_LoadPage(pdf_pag);
int count=Scount/;
for (int i = ; i <= count; i++)
{
byte[] copyText = new byte[];//托管数组
IntPtr pdata = Marshal.AllocHGlobal();//申请内存
Marshal.Copy(copyText, , pdata, );//再向里copy数据
if (i != Scount / )
{
FPDFText_GetText(cur_textpag, start + i * , , copyText);//非托管c++函数,参数copyText是带有返回数据的非托管数组
}
else
{
FPDFText_GetText(cur_textpag, start + i * , Scount % , copyText);
}
Marshal.FreeHGlobal(pdata);//以及释放内存
a.Append( UnicodeEncoding.Unicode.GetString(copyText)); } DeleteObject(pdf_pag);
DeleteObject(cur_textpag);
return a.ToString();
}
catch (Exception ex)
{ MessageBox.Show(ex.Message);
return null;
} }
(此处需注意的是:需要非托管指针byte[]参数的内存要先申请,再向里copy数据;还有最后要记得释放申请的内存. )
细心的读者可能会发现方法中有总的数据长度,为什么要分n个固定长度去读取呢?这是因为要操作的数据过大时,程序就会报内存不够用的错误,所以使用小数组循环读取,避免此问题的出现。可为什么数组长度是1024,而每次读取的长度是512呢?假如我们使用长度为512的数组 结果会怎样呢?
答案是只会返回一部分字符串数据,那缺少的部分哪去了呢,问题出在哪呢?
很容易也很关键的就想到,byte[]长度不够,字符数据被截取了,问题很可能就出在c++非托管代码返回的数据类型与c#托管代码数据类型不一致造成的偏差(定义函数的人真坑)。我们转到定义查看FPDFText_GetText的声明。
c#代码:
[DllImport("fpdfsdk.dll", CharSet = CharSet.Unicode)]
public static extern int FPDFText_GetText(IntPtr text_page, int start_index, int count, byte[] result);
没错啊,byte[] 类型的,让我们再来看下关于此非托管函数的c++文档说明:
| DLLEXPORT int STDCALL FPDFText_GetText | ( | FPDF_TEXTPAGE | text_page, |
| int | start_index, | ||
| int | count, | ||
| unsigned short * | result | ||
| ) |
答案出现了, c++的unsigned short类型的指针能不能用c#中byte[]类型承接?查资料 ,非托管c++unsigned short与c#中的 System.UInt16是等价的,均是 16 位的,而c#的byte是8位的,难怪总是出现数据丢失的现象。
该怎么解决呢?由于c#中没有现成的UInt16转字符串的方法,唯有抛弃UInt16,改用原来的byte,只要每次读入固定的长度,而承接的byte[]的长度是该长度的两倍即可。
另一种解决办法是使用Marshal.PtrToStringUni(ptr)转化,代码如下:
int BufferLength = ;
BufferLength = FPDFText.FPDFText_PageToText(pdf_doc, CurrentPage, IntPtr.Zero, , );
IntPtr ptr = Marshal.AllocCoTaskMem(BufferLength * sizeof(UInt16));//申请内存大小,Uint16,16位等价于c/c++中wchar_t,unsigned short
FPDFText.FPDFText_PageToText(pdf_doc, CurrentPage, ptr, BufferLength, );
string str = Marshal.PtrToStringUni(ptr);
.Net调用非托管代码数据类型不一致的问题的更多相关文章
- C#如何直接调用非托管代码
C#如何直接调用非托管代码,通常有2种方法: 1. 直接调用从 DLL 导出的函数. 2. 调用 COM 对象上的接口方法 我主要讨论从dll中导出函数,基本步骤如下: 1.使用 C# 关键字 s ...
- java.sql.SQLException: ORA-00932: 数据类型不一致: 应为 -, 但却获得 CLOB
总是报:ORA-00932: 数据类型不一致: 应为 -, 但却获得 CLOB 是由于这个a.progressAndPlan字段clob字段. 第一种解决方法: a.progressAndPlan 改 ...
- SQL Server ->> 数据类型不一致比较时的隐式转换
当使用操作符进行比较的时候,两边数据类型不一致的情况下,数据类型优先级别低的会往优先级别高的发生隐式转换.下面的参考链接是优先级别列表. 参考: Data Type Precedence (Trans ...
- C# 直接调用非托管代码的方法
C# 代码有以下两种可以直接调用非托管代码的方法: 直接调用从 DLL 导出的函数. 调用 COM 对象上的接口方法. 对于这两种技术,都必须向 C# 编译器提供非托管函数的声明,并且还可能需要向 C ...
- DB字段顺序与类的属性顺序一致:{Oracle.DataAccess.Client.OracleException ORA-00932: 数据类型不一致: 应为 TIMESTAMP, 但却获得 NUMBER
{Oracle.DataAccess.Client.OracleException ORA-00932: 数据类型不一致: 应为 TIMESTAMP, 但却获得 NUMBER 应用程序中类型T ...
- Oracle关联查询-数据类型不一致问题 ORA-01722: 无效数字
一.存在表A和表B,都包含字段user_no,但数据类型不一致,如下: create table A ( user_id varchar2(20), user_no number(12,0), xxx ...
- Caused by: java.sql.SQLSyntaxErrorException: ORA-00932: 数据类型不一致: 应为 NUMBER, 但却获得 BINARY
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvo ...
- java.sql.SQLSyntaxErrorException: ORA-00932: 数据类型不一致: 应为 NUMBER, 但却获得 BINARY
2019-07-24 17:24:35 下午 [Thread: http-8080-4][ Class:net.sf.ehcache.store.disk.Segment Method: net.sf ...
- C# 调用c++数据类型对应
C#调用 非托管C++ dll 传入Stringbuilder.ref string . ref char 等都报错,如mscorlib.dll 异常.其他信息: 尝试读取或写入受保护的内存.这通常指 ...
随机推荐
- EDIUS如何实现抠图
有时候我们把素材图片导入到EDIUS中会发现图片的背景有点不合适,这时候就会想替换掉这个背景.那么EDIUS也可以像PS一样替换掉背景吗?答案当然是肯定的,现在小编就带领你们一起来学习EDIUS抠图吧 ...
- 用CorelDRAW勾画对象轮廓图的方法
轮廓图效果是利用渐变的步数来使图形产生渐变效果,与调和效果相似.两者的区别在于图形数不同,调和效果作用于两个或两个以上的图形,轮廓图只作用于一个图形.本教程将详解CorelDRAW中如何勾画对象轮廓图 ...
- FrameBuffer
http://blog.csdn.net/luxiaoxun/article/details/7622988 http://blog.csdn.net/godspirits/article/detai ...
- linux包之iproute之ip命令
[root@localhost ~]# rpm -qf /sbin/ipiproute-2.6.32-31.el6.x86_64ip 是个命令, ip 命令的功能很多!基本上它整合了 ifconfig ...
- python子类分配
原问题是将左边样式变成右边样式: 即有父类和子类,父类包括多个子类,怎样将子类匹配到父类下面的问题 代码如下 #!/usr/bin/python3.4 # -*- coding: utf-8 -*- ...
- VB的if和elseif
VB中if和elseif的用法是: if...then...elseif...then...else...endif 切记在then的后面不要加冒号,加了冒号出现else没有if的错误,因为加了冒号表 ...
- asp.net中virtual和abstract的区别分析
这篇文章主要介绍了asp.net中virtual和abstract的区别,较为详细的分析了virtual与abstract的概念与具体用法,并以实例的形式予以总结归纳,需要的朋友可以参考下 本文实例分 ...
- Zabbix的安装与部署---问题处理(php65.6.28 mysqli 报错误 处理)
1)php65.6.28 mysqli 报错误 处理 http://www.xiaochengfu.com/index.php/index/detail/aid/92.html 2)linux下p ...
- [Spring] IOC - study
Spring IOC简单注入例子,本例子使用JUnit进行测试.Spring版本:3.2 项目结构: Spring所需引用的JAR包: Spring XML配置: springContext.xml ...
- 【linux】grub详解
参数解释 1. default=0 # default后加一个数字n,表示n+1个“title”操作系统,0表示第一个“title” 的操作系统,以此类推. 2. timeout=0 # timeou ...