c# - 将对象从 C# COM 库传递到 C++ 应用程序时如何修复内存泄漏

标签 c# c++ visual-c++ mfc com

我有一个 C++ MFC 应用程序,它使用 C# COM 包装器。问题是每当我调用包装器内的函数时,我都会遇到内存泄漏。谁能解释一下如何清理 C# COM 包装器中进行的分配。

下面的代码块模仿了我想要做的事情,任何人都可以为我提供引用/正确的方法来传递结构对象/清理内存分配

作为 COM 公开的 C# 包装器

using System;
using System.Runtime.InteropServices;


namespace ManagedLib
{
    [ComVisible(true)]
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct comstructure
    {
        
        public string[] m_strName;
         
        public UInt32[] m_nEventCategory;
    }


    [Guid("4BC57FAB-ABB8-4b93-A0BC-2FD3D5312CA8")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    [ComVisible(true)]
    public interface ITest
    {
        
        comstructure  TestBool();

         
    }

    [Guid("A7A5C4C9-F4DA-4CD3-8D01-F7F42512ED04")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComVisible(true)]    
    public class Test : ITest
    {
        public comstructure TestBool( )
        {
            comstructure testvar = new comstructure();

            testvar.m_strName = new string[100000];
            testvar.m_nEventCategory = new UInt32[100000];
            return testvar;
        }
                 
    }
}

C++代码


#include <iostream>
#include <afx.h>
#include <afxwin.h>         
#include <afxext.h>         
#include <afxdtctl.h>   
#include "windows.h"
#include "psapi.h"
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>          
#endif // _AFX_NO_AFXCMN_SUPPORT

#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS  
#include <atlbase.h>
#import "..\comlibrary\bin\Debug\comlibrary.tlb"
comlibrary::ITest* obj;
class mleak
{

public:


   void leakmemory()
   {
       comlibrary::comstructure v2;
       v2 = obj->TestBool();

       
   }
};
   int main()
   {


       CoInitializeEx(nullptr, COINIT_MULTITHREADED);
       CLSID clsid;
       HRESULT hResult = ::CLSIDFromProgID(L"ManagedLib.Test", &clsid);
       hResult = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
           __uuidof(comlibrary::ITest), (void**)&obj);
       std::cout << hResult;
       if (FAILED(hResult))
       {
           std::cout << "COM import failed!\n";
       }
        

       mleak m1;
       for (int i = 0; i < 600; i++)
       {
            
           m1.leakmemory();
           Sleep(100);
       }

       return 0;
   }

最佳答案

显然,如果内存已分配并且没有其他人释放它,您应该释放它。这里,分配的内存是.NET的string[]uint[],表示为SAFEARRAY*在原生世界中。

但是,长话短说:您不能真正使用结构作为 COM 方法的返回类型。这不仅会导致复制语义问题(谁拥有结构体的字段内存等),而且一般来说,它甚至无法根据结构体大小等工作。很麻烦,COM 方法应该返回 32/64 位大小的变量(或无效)。

因此您可以使用 COM 对象而不是结构来解决此问题。例如:

[ComVisible(true)]
public interface IOther
{
    string[] Names { get; set; }
    uint[] EventCategories { get; set; }
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Other : IOther
{
    public string[] Names { get; set; }
    public uint[] EventCategories { get; set; }
}

[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ITest
{
    Other TestOther();
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Test : ITest
{
    public Other TestOther()
    {
        var other = new Other();
        other.Names = new string[100000];
        other.EventCategories = new UInt32[100000];
        return other;
    }
}

在 C++ 方面:

#include "windows.h"
#import "..\ManagedLib\bin\Debug\ManagedLib.tlb"

using namespace ManagedLib;

int main()
{
    CoInitializeEx(nullptr, COINIT_MULTITHREADED);
    {
        ITestPtr test; // see https://stackoverflow.com/a/16382024/403671
        auto hr = test.CreateInstance(__uuidof(Test));
        if (SUCCEEDED(hr))
        {
            IOtherPtr other(test->TestOther());
            auto names = other->Names;

            // do what you want with safe array here
            // but in the end, make sure you destroy it
            SafeArrayDestroy(names);
        }
    }
    CoUninitialize();
    return 0;
}

注意:您还可以使用CComSafeArray简化SAFEARRAY编程。

关于c# - 将对象从 C# COM 库传递到 C++ 应用程序时如何修复内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70362365/

相关文章:

c++ - 本地化在静态控制中不起作用

visual-c++ - 捕获 OpenGL/Direct3D 第 3 方应用程序的屏幕截图

c# - 从结构数组中删除 double

c# - 检测移动浏览器并重定向

c# - 将已发送的 MailMessage 获取到 "Sent Folder"

c++ - 为什么 C++ 链接几乎不使用 CPU?

c++ - 在 CUDA 中高效地初始化共享内存阵列

c# - 书籍索引的序列和 Rangify 列表

c++ - OpenCV C++ 如何使停留点击?

visual-c++ - Visual Studio (2017) 构建工具 150