2010-10-17 19 views
5

tengo un Excel plug-in (escrito en C#) con una variable estática que está en el corazón de un caché de datos Singleton:¿Excel invoca al servidor de automatización .NET desde dos AppDomains diferentes?

static DataCache _instance; 

Esto se accede a través de tres diferentes rutas de código:

  1. Controladores de eventos en una barra de cinta VSTO inicializan la instancia y también la leen en los cuadros de diálogo auxiliares
  2. Un servidor RTD (una clase declarada [ComVisible] e implementa la interfaz IRtdServer) utiliza los datos para las fórmulas RTD
  3. Un conjunto de llamadas de automatización (implementadas en otra clase que se declara [ComVisible]) también operan en los datos. Se llaman a través de un código VBA que se invoca cuando se hace clic en los botones de la hoja de cálculo de Excel.

EDITAR (# 3):

En función del orden en que estas rutas de código se invocan en primer lugar, me parece que mi código se ejecuta en dos dominios de aplicación separados.

Todos los accesos desde los controladores de eventos de barra de cinta se producen en un dominio de aplicación llamado "MyPlugIn.vsto". Si este es el PRIMER acceso a mi objeto COM, todas las llamadas posteriores (incluidas las llamadas RTD) se producen en el mismo dominio de la aplicación.

Sin embargo, si el acceso FIRST es a través de la interfaz RTD, entonces esa llamada y todas las llamadas posteriores de RTD se producen en un dominio de aplicación llamado "DefaultDomain". (Esto ocurre cuando se carga un documento guardado con fórmulas RTD incorporadas). Las llamadas posteriores para inicializar y manipular el DataCache a través de la barra de herramientas todavía ocurren en el Dominio de aplicación "MyPlugIn.vsto". Esto significa que las fórmulas de RTD siempre se ejecutan como si DataCache no se hubiera inicializado (dado que la variable estática establecida en un AppDomain permanece sin inicializar en el otro).

Parece que Excel o VSTO está creando un dominio de aplicación cuando se inicializa VSTO. Los objetos creados a través de interoperabilidad COM antes de aterrizar esta inicialización en el AppDomain predeterminado, mientras que los objetos creados posteriormente aterrizan en el AppDomain de VSTO.

¿Cómo puedo asegurarme de que se utiliza la misma instancia de DataCache, sin importar en qué dominio de aplicación se crea mi objeto de servidor RTD?

+0

¿Qué quiere decir 'mi objeto singleton no se comparte correctamente'? ¿Es solo la inicialización del objeto, como lo sugiere @mhttk, o está afirmando que diferentes hilos ven diferente estado en esa variable (lo que parece muy extraño), o algo más? – Rory

+0

@Rory - en un hilo, _instance se inicializa. En llamadas posteriores de ese mismo hilo, todavía se inicializa como se esperaba. Sin embargo, cuando otro hilo intenta acceder a él (varios minutos más tarde, esto no es un problema de tiempo) es nulo y debe ser reinicializado para que lo use ese hilo. – Eric

+0

Eso es bastante raro ¿no? En mi experiencia de.NET COM interopera (con Internet Explorer que es similar pero obviamente diferente), eso no sucede. ¿Es eso algo normal con los apartamentos COM? ¿Estás seguro de que las llamadas están dentro del mismo proceso? – Rory

Respuesta

1

Su variable estática ciertamente no se comparte entre AppDomains, por lo que lo que está viendo es lo esperado, dados los diferentes AppDomains.

creo que funciona de esta manera:

El VSTO complemento se ejecuta en su propio dominio de aplicación. Si la fábrica de clase COM para su objeto de caché (o servidor de RTD) se crea desde ese AppDomain, se cargará en el AppDomain llamante. El acceso posterior a esa clase COM lo encontrará ya cargado en el proceso y usará la instancia existente.

Sin embargo, si la primera activación se desencadena por Excel, p. mediante una llamada RTD, el objeto COM implementado .NET se cargará en el dominio de aplicación predeterminado del proceso. No tiene control sobre esta parte del proceso de carga, a menos que haga una corrección no administrada, ya que 'su código' no se está ejecutando cuando ocurre la carga.

Algunas sugerencias de la parte superior de mi cabeza:

  1. hacen que algunas funciones de contenedor para el RTD llama a que están expuestas desde su .NET complemento. De esta manera, puede asegurarse de que la clase RTD esté cargada antes de llamar a la aplicación.RTD de Excel para realizar la configuración real de RTD.

  2. Realice el acceso desde el servidor RTD al caché real a través de funciones definidas por el usuario; de este modo, Excel llamará al dominio de aplicación que tenga el caché real, incluso si no es el dominio de aplicación actual donde vive el servidor RTD.

  3. Intente obtener el objeto de complemento a través de Application.AddIns .... hay una manera de obtener el objeto COM complemento real, y utilizar alguna interfaz en él para llegar al caché.

  4. Crea un shim no administrado (busca en la web el "asistente de corrección de COM") para tu servidor RTD. De alguna manera averigüe cómo cargar su dominio de aplicación VSTO y luego cargue el servidor RTD en ese dominio de aplicación.

  5. Vea si hay una manera de obtener el complemento VSTO cargado en el AppDomain predeterminado. No sé, pero tal vez haya un indicador o interruptor que le dice al "cargador de Microsoft Office Systems" (o lo que sea que se llame ahora esa parte) que no cree el AppDomain aislado.

  6. La respuesta correcta: use Excel-Dna (descargo de responsabilidad: soy el desarrollador). Es compatible con Ribbons, RTD y UDF en su complemento administrado, sin necesidad de registrarse, y todo se pone en su AppDomain de complementos. Es gratis, pero llevará algo de tiempo y esfuerzo portar tus cosas: la RTD es trivial, pero si usas muchos de los objetos auxiliares de VSTO para el acceso a la cinta y a la hoja (tablas, etc.), tendrás que pensar en es un poco

Espero que esto te dé algunas ideas.

--Govert--

-2

en primer lugar, es posible que desee declarar su ejemplo como:

static DataCache _instance = new DataCache(); 

esta manera (no el único seguro), ya sabes _instance se genera seguro para subprocesos. Hay mucha cobertura sobre el tema para singletons seguros para hilos, pero esta parece ser una de las soluciones más simples.

La segunda cosa que puede ser que desee intentar usar es una estructura como

Lock (_lockObject) 
{ 
... 
} 

tanto para lectura y escritura. Esto hará que sus lecturas y escrituras sean seguras desde diferentes subprocesos.

Finalmente, pero esto es pura especulación, puede probar creando un objeto separado para sus llamadas COM que reside en una STA y accede a su biblioteca.

¡Buena suerte!

+0

Lo siento, esto no soluciona mi problema. He editado la pregunta para aclarar que pasan varios minutos entre que un hilo inicializa la instancia y otro hilo intenta usarlo. No se trata de un problema de sincronización de subprocesos, sino de cómo funciona la implementación de .NET/COM. – Eric

Cuestiones relacionadas