首页 文章

互操作签名不正确导致内存泄漏

提问于
浏览
1

通过interop生成的接口从c#使用的第三方com模块正在泄漏内存

第三方c方法签名是:

somemethod(....., long** param3, long** param4)

生成的互操作方法是:

somemethod(...., IntPtr param3, IntPtr param4)

最后2个参数由umanaged dll分配数组,并从c#Marshal.CoMemFree中释放(不记得确切的sig atm)

使用C通过com接口的相同方法并以相同方式释放不会产生泄漏

从命令行使用tlbimp会产生:

TlbImp : warning TI0000 : At least one of the arguments for
'Sometype.somemethod' cannot be marshaled by the runtime
marshaler. Such arguments will therefore be passed as a pointer and may
require unsafe code to manipulate.

我发现令人惊讶的是长期** params无法自动编组 .

比.net更了解c(不包括Com黑魔法),但实现.net方面...

访问和释放param3和param4中传回的内存的正确方法是什么 . 我怀疑他们应该'出IntPtr'?

2 回答

  • 3

    此声明与COM Automation严重不兼容 . 数组需要作为SAFEARRAY传递,因此很清楚它们有多大以及如何管理它们的内存 . 传递长**通常表示被调用者负责分配数组并返回指向数组的指针 . 究竟应该如何分配是问题,不清楚它是应该使用进程堆,COM堆还是可以使用CRT堆 .

    Tlbimp.exe抛出一个拟合,它不知道如何正确翻译参数类型 . 您必须使用ildasm.exe反编译互操作库,编辑IL以将参数转换为IntPtr或out int []并使用ilasm.exe再次编译它 . 对分配器唯一合理的猜测是Marshal.AllocCoTaskMem() . 可能会工作,可能会严重泄漏 . 您需要组件供应商或作者的帮助,以避免猜测 .

  • 0

    找到'a'方法来获得预期的功能,不确定解决方案的声音 . 以下工作没有泄漏

    long* arr1 = null;
    long* arr2 = null;
    
    IntPtr parr1 = new IntPtr(&arr1);
    IntPtr parr2 = new IntPtr(&arr2);
    
    somemethod(....., parr1, parr2);
    
    Marshal.CoTaskMemFree(new IntPtr(arr1));
    Marshal.CoTaskMemFree(new IntPtr(arr2));
    

    注意事项:

    • 没有尝试访问数组,我实际上并不需要内容,但这样做我想可能需要Marshall.Copy调用 .

    • 直观地,呼叫应该是某种方法(.....,ref parr1,ref parr2);然而看起来IntPtr实际上更像是一个void指针,所以尽管它是通过值传递的,它的值是arr1的地址,所以被调用者能够分配到arr1,闻起来错误但是它有效,可能arr1或parr1应该被分配Marshal.CoTaskMemAlloc(?)

    • 我之前在控制台应用程序中尝试了上述内容并且仍然泄漏,但是在指定[STAThread]时(与未指定/ default相反),泄漏停止 . 公寓的事实改变了代码的含义,所以微妙的臭味

相关问题