带有 gcServer = true 和 gcAllowVeryLargeObjects = true 的 C# COM DLL [英] C# COM DLL with gcServer = true and gcAllowVeryLargeObjects = true

查看:27
本文介绍了带有 gcServer = true 和 gcAllowVeryLargeObjects = true 的 C# COM DLL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我已经

  • 一个名为 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 在这种情况下.
  • a C# DLL called managed.dll which is COM visible.
  • a C# EXE called magaged.exe which uses the managed.dll and which has an app.config called managed.exe.config.
  • a C++ EXE called unmanaged.exe which calls the managed.dll over COM and which has the same app.config as the C# EXE but called unmanaged.exe.config in this case.

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

The managed.dll has the following two test properties:

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 看起来都是这样:

The app.config looks like that for both EXEs:

<?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"/> 设置被忽略.我不明白为什么?

For the managed.exe everything works as expected. But for the unmanaged.exe the <gcServer enabled="true"/> setting is ignored. I cannot understand why?

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

I can see that the unmanaged.exe.config is loaded when the first instance of a COM object is created. It's as well used, tested by changing for example the <gcAllowVeryLargeObjects enabled="true" /> setting.

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

I'm using Visual Studio 2013, Windows 7 (64-bit) and .NET 4.6.1. Everything is compiled for x64.

在 COM 上使用 managed.dll 时,为什么会忽略 <gcServer enabled="true"/> 设置?

Any ideas why the <gcServer enabled="true"/> setting is ignored when the managed.dll is used over COM?

问候沃尔米希

推荐答案

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

I was able to find two different workarounds:

解决方法 1(COM 互操作之前的主机 CLR)

Workaround 1 (Host CLR before COM Interop)

我必须更改以下内容:

  • 名为 unmanaged.exe 的 C++ EXE 必须先托管 CLR 并设置启动标志,然后才能通过 COM 调用 managed.dll.
  • the C++ EXE called unmanaged.exe has to host the CLR first and set the startup flags before calling the managed.dll over COM.

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.

This is my personal preferred workaround, because no additional helper.dll is needed.

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

Workaround 2 (Use C++/CLI DLL before COM Interop)

我必须更改以下内容:

  • 添加一个名为 helper.dll 的 C++/CLI DLL,它有一个名为 helper.dll.config 的 app.config.app.config 与 C++ EXE 相同.
  • 名为unmanaged.exe 的C++ EXE 必须先从C++/CLI helper.dll 调用一个函数,然后再调用managed.dll> 通过 COM.
  • add a C++/CLI DLL called helper.dll which has an app.config called helper.dll.config. The app.config is the same as for the C++ EXE.
  • the C++ EXE called unmanaged.exe has to call first a function from the C++/CLI helper.dll before calling the managed.dll over COM.

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 文件中定义.

If the helper.dll.config file is missing the <gcServer enabled="true"/> setting is ignored again. The other settings, for example the <gcAllowVeryLargeObjects enabled="true" /> setting, are defined in the unmanaged.exe.config file.

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

For me it's still not clear why the <gcServer enabled="true"/> setting is ignored when I'm not using the CLR hosting or the workaround helper.dll first?

问候沃尔米希

这篇关于带有 gcServer = true 和 gcAllowVeryLargeObjects = true 的 C# COM DLL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆