什么是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调用非托管代码数据类型不一致的问题的更多相关文章

  1. C#如何直接调用非托管代码

    C#如何直接调用非托管代码,通常有2种方法: 1.  直接调用从 DLL 导出的函数. 2.  调用 COM 对象上的接口方法 我主要讨论从dll中导出函数,基本步骤如下: 1.使用 C# 关键字 s ...

  2. java.sql.SQLException: ORA-00932: 数据类型不一致: 应为 -, 但却获得 CLOB

    总是报:ORA-00932: 数据类型不一致: 应为 -, 但却获得 CLOB 是由于这个a.progressAndPlan字段clob字段. 第一种解决方法: a.progressAndPlan 改 ...

  3. SQL Server ->> 数据类型不一致比较时的隐式转换

    当使用操作符进行比较的时候,两边数据类型不一致的情况下,数据类型优先级别低的会往优先级别高的发生隐式转换.下面的参考链接是优先级别列表. 参考: Data Type Precedence (Trans ...

  4. C# 直接调用非托管代码的方法

    C# 代码有以下两种可以直接调用非托管代码的方法: 直接调用从 DLL 导出的函数. 调用 COM 对象上的接口方法. 对于这两种技术,都必须向 C# 编译器提供非托管函数的声明,并且还可能需要向 C ...

  5. DB字段顺序与类的属性顺序一致:{Oracle.DataAccess.Client.OracleException ORA-00932: 数据类型不一致: 应为 TIMESTAMP, 但却获得 NUMBER

    {Oracle.DataAccess.Client.OracleException ORA-00932: 数据类型不一致: 应为 TIMESTAMP, 但却获得 NUMBER     应用程序中类型T ...

  6. Oracle关联查询-数据类型不一致问题 ORA-01722: 无效数字

    一.存在表A和表B,都包含字段user_no,但数据类型不一致,如下: create table A ( user_id varchar2(20), user_no number(12,0), xxx ...

  7. Caused by: java.sql.SQLSyntaxErrorException: ORA-00932: 数据类型不一致: 应为 NUMBER, 但却获得 BINARY

    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvo ...

  8. 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 ...

  9. C# 调用c++数据类型对应

    C#调用 非托管C++ dll 传入Stringbuilder.ref string . ref char 等都报错,如mscorlib.dll 异常.其他信息: 尝试读取或写入受保护的内存.这通常指 ...

随机推荐

  1. PostgreSQL and bloat

    The bucardo project has released its nagios plugins for PostgreSQL and we can extract from them this ...

  2. Python学习笔记——文件

    1.文件只是连续的字节序列 open()内建函数是打开文件之门的钥匙 file_obj=open(file_name,access_mode='r/w/a,' buffering=-1) file_n ...

  3. svg中改变class调用的线条颜色

    <style type="text/css"><![CDATA[ .kV220 {stroke:rgb(255,0,0);fill:none} .kV22 {st ...

  4. 009. C#中的WebBrowser控件的属性、方法及操作演示代码(转)

    本文转自 http://www.open-open.com/code/view/1430559996802 0.常用方法 Navigate(string urlString):浏览urlString表 ...

  5. 【转】TYVJ 1695 计算系数(NOIP2011 TG DAY2 1)

    计算系数 题目描述 给定一个多项式(ax + by)k,请求出多项式展开后xn ym项的系数. [数据范围] 对于 30%的数据,有0≤k≤10: 对于 50%的数据,有a = 1,b = 1: 对于 ...

  6. 数据结构线性表(js实现)

    最近在复习数据结构的过程中,发现基本上数据结构都是用C来实现的,自己之前学习的时候也是用C去写的,由于目前对js更为熟悉一些,所以这里选择使用js去实现其中的某些算法和结构.实际上算法和语言关系不大, ...

  7. Google将数十亿行代码储存在单一的源码库

    过去16年,Google使用一个中心化源码控制系统去管理一个日益庞大的单一共享源码库.它的代码库包含了约10亿个文件(有重复文件和分支)和 3500万行注解,86TB数据,900万唯一源文件中含有大约 ...

  8. jQuery validate在没有校验通过的情况下拒绝提交

    下面通过一个简单的例子说明,这个问题,可能是很多人遇到的,验证不通过的时候,依然提交了表单. HTML <form class="survey" id="surve ...

  9. php时间日期处理

    php日期函数: 首先想到的就是date(),time(),strtotime(),mktime() strtotime() strtotime()函数用于将英文文本字符串表示的日期转换为时间戳,为 ...

  10. 关于mysql数据库在输入密码后,滴的一声直接退出界面的解决办法

    转自:http://www.2cto.com/database/201412/361751.html 网上搜索到的解决办法: 1.找到mysql安装目录下的bin目录路径.2.打开cmd,进入到bin ...