什么是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. Oracle 10g bigfile表空间、smallfile 表空间

    smallfile tablespace设置不同大小的db_block_size时数据文件允许的最大大小 db_block_size=2KB,2KB*4M=8192M      8Gdb_block_ ...

  2. Java文件读写操作指定编码方式。。。。。

    读: File file=new File(this.filePath);BufferedReader br=new BufferedReader(new InputStreamReader(new ...

  3. QQ登入(2)获取用户信息

    private void initView() { mUserInfo = (TextView) findViewById(R.id.user_info); mUserLogo = (ImageVie ...

  4. python--类方法、对象方法、静态方法

    1.我们已经讨论了类/对象可以拥有像函数一样的方法,这些对象方法与函数的区别只是一个额外的self变量 # -*- coding:utf-8 -*- #!/usr/bin/python # Filen ...

  5. 怎么给OCR文字识别软件设置正确的扫描分辨率

    ABBYY FineReader 12是一款专业的OCR文字识别软件,可快速方便地将扫描纸质文档.PDF文件和数码相机的图像转换成可编辑.可搜索的文本,不仅支持对页扫描,还支持多页扫描,扫描分辨率的选 ...

  6. Iaas-cloudstack

    http://cloudstack.apt-get.eu/systemvm/4.6/ 模板地址 http://cloudstack.apt-get.eu/centos7/4.6/ 代理及管理地址 ht ...

  7. OpenJudge计算概论-文字排版

    /*====================================================================== 文字排版 总时间限制: 1000ms 内存限制: 65 ...

  8. 006 [翻译] Haneke(一个Swfit iOS缓存类)

    Github项目地址:https://github.com/Haneke/HanekeSwift Haneke是一个用swift写成的轻量级iOS类,以简单好用著称(design-decisions- ...

  9. 使用注解来构造IoC容器

    用注解来向Spring容器注册Bean.需要在applicationContext.xml中注册<context:component-scan base-package=”pagkage1[,p ...

  10. ASP.NET MVC 出现错误 “The view 'XXX' or its master was not found or no view engine support”

    来自:http://www.dengyukeji.com/archiver/tid-151.html 错误如下:The view 'XXX' or its master was not found o ...