C#COM DLL,gcServer = true,gcAllowVeryLargeObjects = true

时间:2017-02-13 09:02:26

标签: c# .net visual-studio garbage-collection com-interop

我们假设我已经

  
      
  • 一个名为managed.dll的C#DLL,它是COM可见的。
  •   
  • 一个名为magaged.exe的C#EXE,它使用managed.dll并且有一个名为managed.exe.config的app.config。
  •   
  • 一个名为unmanaged.exe的C ++ EXE,它通过COM调用managed.dll,它与C#EXE具有相同的app.config,但在这种情况下调用unmanaged.exe.config
  •   

managed.dll具有以下两个测试属性:

public bool IsServerGC
{
    get { return System.Runtime.GCSettings.IsServerGC; }
}

public bool AreVeryLargeObjectsAllowed
{
    get
    {
        try
        {
            long l = 20000;
            double[,] d = new double[l, l];
            return l * l == d.LongLength;
        }
        catch { return false; }
    }
}

对于两个EXE,app.config看起来都是这样:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <gcAllowVeryLargeObjects enabled="true" />
    <!--<gcConcurrent enabled="false"/>-->
    <gcServer enabled="true"/>
  </runtime>
</configuration>

对于managed.exe,一切都按预期工作。但是对于unmanaged.exe<gcServer enabled="true"/>设置会被忽略。我不明白为什么?

我可以看到在创建COM对象的第一个实例时加载了unmanaged.exe.config。它也是如此使用,通过更改<gcAllowVeryLargeObjects enabled="true" />设置进​​行测试。

我使用的是Visual Studio 2013,Windows 7(64位)和.NET 4.6.1。一切都是为x64编译的。

<gcServer enabled="true"/>上使用COM时忽略managed.dll设置的任何想法?

此致 Wollmich

2 个答案:

答案 0 :(得分:1)

我能找到两种不同的解决方法:

解决方法1 (COM Interop之前的主机CLR)

我不得不改变以下事项:

  
      
  • 名为unmanaged.exe的C ++ EXE必须首先托管CLR并在通过COM调用managed.dll之前设置启动标志。
  •   

unmanaged.exe的源文件如下:

#include "stdafx.h"
#include <metahost.h>
#include <mscoree.h>
#pragma comment(lib, "mscoree.lib")
#import "..\managed\bin\Release\managed.tlb"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
    // Init .NET
    ICLRMetaHost    *pMetaHost = nullptr;
    ICLRRuntimeInfo *pRuntimeInfo = nullptr;
    HRESULT hr;
    hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost);
    hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo));
    hr = pRuntimeInfo->SetDefaultStartupFlags(STARTUP_SERVER_GC, NULL);
    // Init COM
    hr = CoInitialize(NULL);
    IManagedTestClassPtr pManagedTestClass(__uuidof(ManagedTestClass));
    // and so on ...

    // End COM
    CoUninitialize();
    // END .NET
    if (pMetaHost)
    {
        pMetaHost->Release();
        pMetaHost = NULL;
    }
    if (pRuntimeInfo)
    {
        pRuntimeInfo->Release();
        pRuntimeInfo = NULL;
    }
    return 0;
}

这是我个人首选的解决方法,因为不需要额外的helper.dll。

解决方法2 (在COM Interop之前使用C ++ / CLI DLL)

我不得不改变以下事项:

  
      
  • 添加名为helper.dll的C ++ / CLI DLL,其中有一个名为helper.dll.config的app.config。 app.config与C ++ EXE相同。
  •   
  • 名为unmanaged.exe的C ++ EXE必须先调用C ++ / CLI helper.dll中的函数,然后才能通过COM调用managed.dll
  •   

helper.dll包含以下头文件:

#pragma once
#ifdef TEST_HELPER_EXPORTS
#define DLLAPI  __declspec(dllexport)
#else
#define DLLAPI  __declspec(dllimport)
#pragma comment (lib, "..\\x64\\Release\\helper.lib") // if importing, link also
#endif
DLLAPI int IsServerGC();

和以下源文件:

#include "stdafx.h"
#define TEST_HELPER_EXPORTS
#include "helper.h"
int IsServerGC()
{
    return System::Runtime::GCSettings::IsServerGC ? 1 : 0;
}

unmanaged.exe的源文件如下:

#include "stdafx.h"
#include "..\helper\helper.h"
#import "..\managed\bin\Release\managed.tlb"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
    int isServerGC = IsServerGC(); // Init .NET with the C++/CLI helper.dll
    HRESULT hr = CoInitialize(NULL); // Init COM
    IManagedTestClassPtr pManagedTestClass(__uuidof(ManagedTestClass));
    // and so on ...
}

如果缺少helper.dll.config文件,则会再次忽略<gcServer enabled="true"/>设置。其他设置(例如<gcAllowVeryLargeObjects enabled="true" />设置)在unmanaged.exe.config文件中定义。

对于我来说,当我不首先使用CLR托管或解决方法<gcServer enabled="true"/>时,仍然不清楚为什么会忽略helper.dll设置?

此致 Wollmich

答案 1 :(得分:1)

这确实是一个错误,很可能是在.NET Framework 4.0中引入的。虽然我们无法提交时间表,但我们计划在即将发布的.NET Framework版本中修复此问题。

同时,您可以通过设置以下环境变量来解决此问题:

COMPlus_BuildFlavor=SVR

请注意,所有COMPlus_*环境变量都不受支持,仅用于调试/开发CLR本身。因此,请记住这一点并做出对您的环境有意义的决定。