.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 异常.其他信息: 尝试读取或写入受保护的内存.这通常指 ...
随机推荐
- Mydumper & Myloader Documentation
Mydumper.org web site has been missing in action for a while now. I've uploaded a copy of the Mydump ...
- JavaScript 全选函数的实现
Html代码: <table id="purchase-info" class="table table-bordered table-hover table-st ...
- 一个关于正整数x的约数个数的结论
分析理解:x的每一个约数都是由x的若干个质因数的积构成. 再根据乘法原理,每个质因数Pi的选择可以是0~Ni个,所以上述结论成立.
- 将n阶方阵左下半三角中的元素值置0.
/*===================================== 将n阶方阵左下半三角中的元素值置0. 0<n<10. =========================== ...
- OpenJudge计算概论-细菌的战争
/*====================================================================== 细菌的战争 总时间限制: 1000ms 内存限制: 6 ...
- xshell 5连接linux服务器的技巧
1.用sttp 方式连接服务器,命令识别不了,用ssh方式才能有效
- ORACLE 常用数值函数
1 ABS(n)返回数值弄参数的绝对值.它接受一个数值型值作为输入参数,或者任何可以隐式地转换为数值型值的值.并且返回数值型值的绝对值. Select abs(-1) from dual ABS(-1 ...
- windows 系统中打开一个数字证书所经历的过程
今天在使用Outlook express调试CSP程序时,发现数字证书总是加载不上(提示该数字证书已经被破坏),使用断点进去跟踪一下,发现在CSP程序中调用CPVerifySignature ...
- HackerRank "Poisonous Plants"
I had the same BFS idea as one of the AC code this: because dying pattern is spead from the initial ...
- <新手必读>Eclipse中,Add Jars与Add Library的区别
Eclipse中,工程属性的Java Build Path的Library标签页下,有如下几个按钮:Add Jars...添加JAR包,是指本Eclipse当前包含的工程中的,在工程列表下选取即可Ad ...