我们假设我已经
- 一个名为
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
答案 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 ++ / CLIhelper.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本身。因此,请记住这一点并做出对您的环境有意义的决定。