首页 > 编程语言 >记一次被非托管代码支配的恐惧「C#对接企微会话存档SDK问题修复」

记一次被非托管代码支配的恐惧「C#对接企微会话存档SDK问题修复」

时间:2022-09-03 00:01:25浏览次数:81  
标签:问题 C# mediaData char GetOutIndexBuf 企微会 SDK

这个问题是我目前在做企微服务商开发以来周期最长、最折磨人的一个问题了;
从3月开始着手排查问题(其实在开发之初就发现了该问题,迫于进度,就暂时搁置了),其中断断续续去尝试解决,并且没有企微对接人,只能社区咨询以及demo调试,加之期间需求不断,也就拖到了当下;
加之企微并没有提供C#对接SDK的demo,我开发起初也仅能根据Java的demo进行开发(此处埋下伏笔);

问题

在使用会话存档SDK(C++开发的SDK)拉取会话媒体文件(视频、文件、语音、图片)时,导致程序崩溃;后排查发现,仅当媒体文件大于512k时,也就是走分片拉取是时才会引发崩溃;且在本地调试时,可能成功,且成功后后续大多都成功;

排查

1、确定崩溃异常信息;崩溃后捕获到的信息为:double free,甚至使用了WinDbg;
2、排查异常点:涉及内存释放的有一下地方FreeSlice()FreeMediaData(),再综合实际情况,是在拉取媒体文件时导致的,故可定位到该方法上;
3、定位具体代码行:经过具体调试,确定只有经过GetOutIndexBuf(),再进行FreeMediaData()才会崩溃;

解决

问题点是定位了,但是,哪里引起问题呢?这是一个最大的问题,当时我就蒙圈了;来来回回尝试了很多次,始终是没有解决:

  1. 从异步方法转为同步方法;
  2. 降级、升级 .NET 版本,甚至使用 Framework 4.8 版本;

最后,还是出动了我司架构师大佬帮忙,在我描述我排错过程以及最终错误定位后,展开了“诊断”;果不其然,架构师就是架构师,三两下给我治得服服帖帖;
话不多说,直接上代码:

// 存在问题代码
[DllImport(DllName)]
public static extern string GetOutIndexBuf(IntPtr mediaData);

// 调用
var outIndexBuf = FinanceAdapter.GetOutIndexBuf(mediaData);
// 调整后代码
[DllImport(DllName, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetOutIndexBuf(IntPtr mediaData);

// 调用
var oibPtr = FinanceAdapter.GetOutIndexBuf(mediaData);
var outIndexBuf = Marshal.PtrToStringAnsi(oibPtr);

想必做 P/Invoke 开发的大佬看到这已经笑出的猪叫,这什么玩意?哈哈哈哈,我也是哭笑不得;

微软文档也说明了这一问题:互操作指南-字符串参数,以及相关文档:Passing Strings Between Managed and Unmanaged Code
也就是在我调用GetOutIndexBuf返回string后,导致了mediaData被销毁了,也就引发了后边进行释放内存的异常,进而导致崩溃;

且回头仔细一看c的案例,不难发现,实际在我们调用GetOutIndexBuf时返回的是char*,是指针变量,而我用string去接收,这哪能没错呀......

typedef struct MediaData {
    char* outindexbuf;
    int out_len;
    char* data;    
    int data_len;
    int is_finish;
} MediaData_t;

char* GetOutIndexBuf(MediaData_t* media_data);

不过,这得怪java (:(手动滑稽)

public native static String GetOutIndexBuf(long mediaData);

总结

至此,这个无从下手的问题得以解决,问题的产生根源还是自己太菜了以及不了解 P/Invoke ;解决该问题的过程也让我涨了不少知识,还简单的使用了WinDbg(这玩意是真的牛,前提得看得懂),收获颇丰;
目前C#版本的会话存档SDK对接也达到了可用的状态(至少目前对于我们的业务来说是没问题了),在此我们也提供了相关源码,相关.NETer也可以参考参考,少走些弯路;

源码地址:
wework-finance-sdk-csharp
相关文章:
1、C#与C++ dll 之间传递字符串string wchar_t* char* IntPtr
2、c#调用c++ dll const char* String类型转换问题。传值,与接收返回值问题

标签:问题,C#,mediaData,char,GetOutIndexBuf,企微会,SDK
From: https://www.cnblogs.com/memoyu/p/16651735.html

相关文章

  • Typescript类型体操 - Deep Readonly
    题目中文实现一个通用的DeepReadonly<T>,它将对象的每个参数及其子对象递归地设为只读。您可以假设在此挑战中我们仅处理对象。数组,函数,类等都无需考虑。但是,您仍然可以......
  • apache访客日志的各个字段含义
    示例:192.168.169.1--[07/Jun/2022:11:42:40+0800]"GET/HTTP/1.1"3040"-""Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGeck......
  • docker 简介
    什么是DockerDocker在容器进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得Docker技术比虚拟机技术更为轻便、快捷。下面......
  • 2.C++实用函数与操作
    1.合并两个无序序列为一个有序序列方法⑴sort(v1.begin(),v1.end());sort(v2.begin(),v2.end());//先将两个序列有序化v3.resize(v1.size()+v2.size());//另开......
  • C#编写折线图控件
    原文:https://blog.csdn.net/bear_csdn/article/details/82918637 C#绘制统计图(柱状图,折线图,扇形图) :https://www.cnblogs.com/ziyiFly/archive/2008/09/24/1297......
  • 【题解】「COCI 2018.10」Teoretičar
    传送门题目大意有一个二分图,构造一种对边的染色方案,使得没有两个颜色相同的边共顶点。假设对于给定二分图的答案是\(C\),记\(X\)是大于等于\(C\)的最小的\(2\)的......
  • 3.计算两个日期的间隔(C++time库)
    一.日期加法题目描述给定一个日期Day和一个正整数n,求日期Day加上n天后的日期。输入描述第一行为给定的日期Day(格式为YYYY-MM-DD,范围为1900-01-01<=Day<=2199-12-31),数据......
  • 4.计算某一天是星期几(C++基姆拉尔森公式)
    题目描述给定一个日期Day,求它是周几。输入描述第一行为给定的日期Day(格式为YYYY-MM-DD,范围为1900-01-01<=Day<=2199-12-31),数据保证一定合法。输出描述输出一个整数,表......
  • docker-compose 启动一个MySQL测试数据库
    services:mysql:image:mysql:5.7ports:-"3306:3306"expose:-"3306"environment:-MYSQL_USER=test-MYSQL_PASSWO......
  • 算法题练习,Solo和koko分糖 ,整数拆分, Cookies 分饼干
    目录1.CandySolo和koko分糖2.整数拆分3=1+1+13=1+23=33.Cookies分饼干1.CandySolo和koko分糖如果可以分给弟弟,必定满足全部异或为0,找出最小的一个给弟弟......