2011-12-06 15 views
7

Estoy tratando de encontrar el método de mejor rendimiento para llamar al código administrado .NET desde el código C++ no administrado. Encontré información sobre Hosting .NET dentro de mi aplicación C++ y soy capaz de crear un pRuntimeHost y comenzarlo sin ningún problema.La mejor manera de llamar al código administrado .NET desde el código no administrado

El ExecuteInDefaultAppDomain parece muy limitado, ya que realmente quiero enviarle algunos parámetros y hacer que devuelva una estructura de información. La alternativa más obvia es usar métodos COM, pero el código actual de C# no está realmente configurado como interfaces con métodos.

De cualquier forma quiero devolver enteros, cadenas (char *) s, dobles y otros tipos básicos de C++. Hay demasiado código en ambos lados para convertir el C++ a C# y el uso de C++ administrado no es una solución aceptable, ya que los otros grupos que usan este código C++ no quieren comenzar a usar el código Administrado por razones de rendimiento.

El objetivo es modificar el código C++ y C# existentes lo menos posible pero seguir usando métodos dentro del código C# en puntos específicos dentro de C++ sin afectar en gran medida la velocidad del código C++.

Sobre la base de código que se encuentra en Internet el arranque y apagado de la secuencia de acoger .NET es:

#include "stdafx.h" 
#include <metahost.h> 

#pragma comment(lib, "mscoree.lib") 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    ICLRMetaHost  *pMetaHost  = NULL; 
    ICLRMetaHostPolicy *pMetaHostPolicy = NULL; 
    ICLRDebugging  *pCLRDebugging = NULL; 

    HRESULT hr; 
    hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost); 
    hr = CLRCreateInstance(CLSID_CLRMetaHostPolicy, IID_ICLRMetaHostPolicy, (LPVOID*)&pMetaHostPolicy); 
    hr = CLRCreateInstance(CLSID_CLRDebugging, IID_ICLRDebugging, (LPVOID*)&pCLRDebugging); 

    DWORD dwVersion = 0; 
    DWORD dwImageVersion = 0; 
    ICLRRuntimeInfo *pRuntimeInfo; 
    hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID *)&pRuntimeInfo); 

    ICLRRuntimeHost * pRuntimeHost = NULL; 
    hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID *)&pRuntimeHost); 

    hr = pRuntimeHost->Start(); 

    DWORD dwRetCode = 0; 
    //hr = pRuntimeHost->ExecuteInDefaultAppDomain(argv[1], L"MyNamespace.MyClass", L"Message", L"Hello World!", &dwRetCode); 

    // Stop the CLR runtime and shutdown cleanly. 
    hr = pRuntimeHost->Stop(); 
    hr = pRuntimeHost->Release(); 
    hr = pRuntimeInfo->Release(); 
    hr = pCLRDebugging->Release(); 
    hr = pMetaHostPolicy->Release(); 
    hr = pMetaHost->Release(); 

    return 0; 
} 

Respuesta

5

Sí, estoy de acuerdo con John. Realmente no desea crear una nueva instancia del tiempo de ejecución y hospedarlo explícitamente. Primero, la tubería detrás de esto no está bien documentada y podría cambiar en futuras versiones. En segundo lugar, C++/CLI fue diseñado para hacer exactamente esto de la manera más eficiente y segura.

  1. Escriba las interfaces C++ nativas que representan la funcionalidad .Net requerida.

  2. Configure un dll con soporte CLR que implemente las interfaces nativas utilizando clases umanaged. Dentro de su implementación, puede crear y acceder a tipos CLR y almacenar variables de instancia en los campos gcroot<T>. Use la funcionalidad clr interop para calcular referencias entre códigos administrados/no administrados, google o bing para marshal_as.

  3. Proporcione una función de fábrica (no administrada), que crea una instancia de este componente. Esta + la interfaz C++ no administrada es la API que verá su código nativo. Use el dll exactamente de la misma manera que usaría un dll no administrado.

+0

El motivo para crear un dominio de aplicación adicional es que el código C++ ya está usando el dominio de aplicación predeterminado para algunas cosas y no quiero que mis ensamblajes .NET adicionales interfieran con el código actual y también para evitar que sus elementos interfieran con el mío . Por cierto, me las arreglé para que la capa de la CLI funcionara a la perfección, pero aún estoy tratando de descubrir cómo hacer que toda la capa de la CLI se convierta en un dominio de aplicación separado que no es el dominio de la aplicación predeterminado. –

+0

Aún no he intentado hacerlo yo solo, pero teóricamente esto no debería ser un problema. Entiendo que su escenario es llamar a un componente administrado desde uno nativo, ¿verdad? Hay una función llamada "promoción de subprocesos" (google o bing) que provoca que un subproceso nativo se promueva a uno administrado, siempre que primero intente ejecutar el código administrado. Como el CLR no tiene idea de qué AppDomain debe ejecutar el código administrado que se llama así, lo pone en el predeterminado. Por lo tanto, tendrá que manejar explícitamente esa transición, probablemente utilizando la familia de funciones 'msclr :: call_in_appdomain'. –

+0

He documentado mi solución final en esta ubicación: http://stackoverflow.com/questions/10301727/marshalling-c-pointer-interface-back-though-c-sharp-function-call-in-a-non-def –

3

Si es aceptable, la mejor solución puede ser la de crear una DLL administrada de C++ que se encuentra en el medio . El código administrado de C++ es la forma mejor/más eficiente de puentear el código administrado y no administrado.

Usted Realmente No quiero agregar COM a la mezcla. Eso ralentizará mucho más las cosas.

Además, ¿se deben cuantificar estos "motivos de rendimiento" para evitar el código administrado? Suena como una anécdota arrojada para evitar algo que simplemente no quieren. Además, puede señalar que son ya usando código administrado, ya que C# está en la mezcla.

+0

El rendimiento se cuenta en microsegundos. Entonces, después de todo esto, agregué el almacenamiento en caché de la solicitud/respuesta como C++ std :: map. Esto permite una búsqueda rápida de todo lo solicitado previamente sin volver a la capa C#. He adjuntado información adicional arriba. –

Cuestiones relacionadas