2009-10-28 2 views
7

[esto se está poniendo TLDR ... perdón ...]Determinar cuándo .NET está a punto de ser cargada en (no administrado) C++

Yo trabajo en una enorme C aplicación (en su mayoría) ++/MFC con cientos de archivos DLL ; es compatible con un mecanismo "add in" cargado dinámicamente a través de COM, por lo que los complementos se pueden desarrollar en .NET utilizando la interoperabilidad COM. Algunas funcionalidades nuevas y limitadas se desarrollan en .NET sin usar este mecanismo de "complemento" (aunque todavía está cargado dinámicamente); sin embargo, el usuario final puede decidir no usar esta característica. Por lo tanto, es posible que .NET no se cargue al inicio.

Pero, cuando .NET es cargado, necesito hacer algo de initialzation-NET específica (ajuste específicamente CurrentUICulture para que coincida con la interfaz de usuario nativa/no administrado).

Una solución es simplemente despejar y hacer esta inicialización de .NET cuando el código se las arregla para cargar ya sea la nueva funcionalidad de .NET o los complementos COM. Dada la naturaleza de esta aplicación, probablemente sea una solución al 95% (la mayoría de los usuarios utilizarán la nueva funcionalidad).

Pero no es infalible. Alguien podría "agregar" rápidamente la nueva funcionalidad .NET en cualquier momento construyendo un módulo con el indicador /clr (recuerde, esta es una gran aplicación).

Una solución más robusta (y obvia) es simplemente hacer que .NET se cargue al inicio a través de C++/CLI. Pero algunos de los desarrolladores de C++ acérrimos a los que todo el ciclo de byte y reloj importa no quieren hacer esto; algo comprensible ya que no es necesario configurar CurrentUICulture a menos que/hasta que se cargue .NET.

Otra posibilidad que pensé en enganchar LoadLibrary y buscar mscorlib. Ahora sé que .NET está a punto de ser cargado por algún motivo, cárguelo de la forma habitual y realice la inicialización antes de que el otro código haga algo. Pero conectar LoadLibrary (o cualquier otra cosa, para el caso) realmente no es algo que quiera hacer.

Entonces, ¿hay una manera fácil (mejor)/mejor de saber si .NET está a punto de cargarse?

Editar: Respuesta de LockClrVersion de Reed es bastante maldito cerca. El único inconveniente es que no funcionará si enlaza en una DLL/ensamblado de modo mixto.

// ClrAboutToLoad.cpp : Defines the entry point for the console application. 
// 

#include "stdafx.h" 

#include <MSCorEE.h> 

// http://community.bartdesmet.net/blogs/bart/archive/2005/07/22/2882.aspx 
FLockClrVersionCallback begin_init, end_init; 
STDAPI hostCallback() 
{ 
    printf("hostCallback()\n"); 

    // we're in control; notify the shim to grant us the exclusive initialization right 
    begin_init(); 

    ICLRRuntimeHost *pHost = NULL; 
    HRESULT hr = CorBindToRuntimeEx(NULL, L"wks", STARTUP_SERVER_GC, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (PVOID*) &pHost); 
    hr = pHost->Start(); 

    // mission completed; tell the shim we're ready 
    end_init(); 

    return S_OK; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    LockClrVersion(&hostCallback, &begin_init, &end_init); 

    //fnTheDLL(); 
    HMODULE hModule = LoadLibrary(L"TheDLL"); 
    FARPROC fp = GetProcAddress(hModule, "fnTheDLL"); 
    typedef void (*fnTheDLL_t)(); 
    fnTheDLL_t fnTheDLL = reinterpret_cast<fnTheDLL_t>(fp); 
    fnTheDLL(); 
    FreeLibrary(hModule); 

    return 0; 
} 

Respuesta

6

Creo que puede hacer que su proceso llame a la función no administrada LockClrVersion antes de usar cualquier API administrada. Esta función le permite especificar dos métodos FLockClrVersion callback.

El primer método (pBeginHostSetup) se llama antes de que CLR se inicialice la primera vez para el proceso de alojamiento. Se llama al segundo método (pEndHostSetup) cuando se completa la inicialización del CLR.

Esto debería permitirle especificar un código no administrado que se ejecuta justo antes y justo después de la inicialización de CLR. En su caso, probablemente necesite conectarse a pEndHostSetup para llamar a las rutinas de configuración de API administradas (deberá esperar hasta que CLR se haya alojado correctamente).

+0

¡Esto parece prometedor! –

+0

Debería hacer exactamente lo que está buscando. No lo he implementado nunca, pero revisé toda la API de alojamiento de CLR para rastrearlo. –

+0

Esto es casi perfecto; el único inconveniente es que debe asegurarse de que nada causa que el CLR se cargue antes de llamar a * LockClrVersion *. El "problema" es que el enlace en un ensamblaje de modo mixto carga el CLR, tiene que cargar dinámicamente el ensamblaje. –

-1

Probablemente debería inicializar .NET Framework al iniciar la aplicación. Trabajé en la aplicación con un fondo similar y de vez en cuando se estancaba porque 2 dlls intentaban inicializar el framework .net al mismo tiempo accediendo indirectamente a .net dlls. Para solucionarlo, realizamos una llamada al CorBindToRuntimeEx en las primeras líneas del punto de entrada del ejecutable.

No creo que haya una forma en que el sistema operativo le dirá si está a punto de cargar .NET.

+0

No hay argumento mío; pero los contadores de bytes no tienen sentido para inicializar .NET si no se va a usar. Recuerde, este es un proyecto (muy) grande; no solo hay problemas de ingeniería para trabajar, sino también políticos. –

1

Puede run your own CLR host to load assemblies. Luego, puede tomar decisiones más específicas sobre qué versión del motor de ejecución (1.1? 2.0? 4.0?) Cargar y separar el código administrado de su código para when a plugin crash, your code won't go down with it.

+0

Pensé en eso ... pero los contadores de bytes no están adoptando exactamente .NET para empezar. Gracias a la interoperabilidad COM, pueden permanecer (mayormente) felizmente inconscientes de que .NET incluso exista (la "nueva funcionalidad" escrita en .NET que mencioné se vio forzada). –

1

Hay dos cosas que pueden ayudarlo: Contadores de rendimiento y WMI. .NET CLR se integra con ambos, y usted debería poder interactuar con cualquiera de ellos (probablemente WMI sería el mejor) para observar el inicio de AppDomain.Sin embargo, ninguna de estas herramientas es particularmente ideal, y en términos de sobrecarga, hacer lo que sugirió Sheng Jiang, hospedar el CLR por su cuenta probablemente sería más eficiente (y por lo tanto más agradable para sus "contadores de bytes").

En una nota ligeramente diferente ... si tiene alguna medida de influencia y control sobre el equipo de desarrollo, reinaría un poco en los "contadores de bytes". Una de las ideas erróneas más grandes sobre .NET es que es menos eficiente que C++. Esa vieja falacia necesita ser enterrada, ya que .NET puede ser increíblemente eficiente, y cuando se usa correctamente, a veces es más eficiente que C++. Más allá de la eficiencia de referencia de cualquiera de las plataformas, debes hacerte la pregunta: ¿cuánta eficacia obtendré realmente gastando volúmenes desconocidos de horas optimizando el grano más fino, cuando estadísticamente, son cosas de mayor escala que generalmente matan el rendimiento: llamadas de proceso cruzado (es decir, llamar objetos COM desde C++ vs. llamar objetos .NET desde .NET), invocar procesos remotos (es decir, servicios web, RPC, etc.), llamar a una base de datos, etc.

Puede intentar resolver su .NET Problema de inicio de AppDomain para apaciguar los malentendidos de los contadores de bytes, o puede implementar un sistema .NET correctamente, y evitar la recopilación de referencias y el interoperabilidad que será enormemente más agotador que cualquier cantidad de ajuste de rendimiento de nivel de bytes podría contrarrestar.

+0

No hay argumento mío; pero viejos conceptos erróneos mueren duro. –

+0

Je, demasiado cierto. Triste, pero definitivamente cierto. – jrista

0

En lugar de intentar enganchar cuando se carga el ensamblaje, ¿puede conectar cuando se carga el Dominio de la aplicación? Busque en System.AppDomainManager para hacer esto.

Después de cargar su System.AppDomainManager subclasificado en el GAC, solo tiene que establecer algunas variables de entorno (APPDOMAIN_MANAGER_TYPE, APPDOMAIN_MANAGER_ASM) antes de ejecutar su programa C++.

+0

Quiero saber cuándo se va a cargar .NET (el CLR), no un ensamblado o AppDomain. En otras palabras, quiero saber cuándo mi proceso no administrado (correcto, mixto) está listo para ejecutar el código administrado por primera vez. –

Cuestiones relacionadas