什么是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);

最新文章

  1. H5移动端中必备技能
  2. Web报表页面如何传递中文参数
  3. [转] easyui 获取数据表格中选中行的数据 Get selected row data from...
  4. WPF弹出取消确定框
  5. 【BZOJ】1987: Zju2672 Fibonacci Subsequence
  6. Android 编程下Touch 事件的分发和消费机制
  7. [Js]高级运动
  8. JavaScript 垃圾回收机制分析
  9. Python解释器运行成功,命令运行显示无此属性解决办法
  10. c# datagridview导出到excel【转载】
  11. [BZOJ 1143] [CTSC2008] 祭祀river 【最长反链】
  12. HighCharts 具体使用及API文档说明
  13. hdu 2769 uva 12169 Disgruntled Judge 拓展欧几里德
  14. 【剑指offer】调整数组顺序
  15. linux 备份 文件+sql
  16. Codeforces 791B Bear and Friendship Condition(DFS,有向图)
  17. Linux(CentOs6.3)网络配置
  18. ArcGIS 产品体系结构
  19. C++实现离散数学的关系类,支持传递闭包运算
  20. sql-josn

热门文章

  1. GUI、GUILayout、EditorGUI、EditorGUILayout
  2. Navicat导入数据时发生了报错 --- 1153 - Got a packet bigger than &#39;max_allowed的处理办法
  3. asterisk
  4. openssl数字证书私钥删除私钥密码
  5. 【Reporting Services 报表开发】— 数据表存储格式修改
  6. Box Anemometer
  7. scala之method和function的区别
  8. C++中的Overload、Override和Overwrite
  9. [Hibernate] - Criteria Select
  10. LintCode &quot;Find Peak Element II&quot;