2009-12-14 10 views
6

No estoy hablando de llamar a un VBA COM de C# ... ¡al revés!COM-Interop lado a lado con C# y VBA

Lo que me gustaría hacer es llamar a una biblioteca de C# utilizando VBA en MS Access sin registrar la DLL. He estado jugando con la interoperacion side-by-side por un tiempo sin éxito y finalmente se me ha ocurrido que un mdb.manifest probablemente no es un reemplazo aceptable para un exe.manifest (probablemente obvio, lo sé, pero yo estaba tratando de ser optimista).

Mi pregunta: ¿Es posible hacer que VBA cargue un componente COM de lado a lado?

O, ¿hay alguna otra forma de utilizar una biblioteca C# no registrada en Access?

(Antes de que lo pregunte, mis razones son: no hay absolutamente ninguna manera de que se me otorgue acceso al registro de Windows de mi cliente, por eso fue escrito en Access en primer lugar. Y tendré que implementar misma funcionalidad en una aplicación C# pronto y más bien no hacerlo dos veces).

Respuesta

3

No necesita tener el exe para usar SxS, SxS es otra palabra para Activation Context. Si puede importar las llamadas de win32 relevantes a vba (y puede), puede usar el activation context api para cargar su archivo de manifiesto.

Más sobre el tema y algunos ejemplos se pueden encontrar here.

+0

Intenté usar esa API. Irónicamente, sin embargo, Microsoft creó un paquete para evitar el registro que requiere registro y deja la misma pregunta que tenía antes: ¿cómo obtenerla en la máquina de mi cliente? Aunque Microsoft.Windows.Actctx está disponible para Windows 2K3 +, solo se incluye en las instalaciones del servidor. Hay otra pregunta de SO quejándose de eso aquí: http://stackoverflow.com/questions/979567/microsoft-windows-actctx-on-windows-xp. Y MSDN lo respalda aquí: http://msdn.microsoft.com/en-us/library/aa375644(VS.85).aspx. – Jelly

+0

Según lo que sé, la API de contexto de activación es parte de Kernel32.lib, lo que significa que no tiene que tener nada instalado, y está incluido en cualquier sistema operativo que tenga soporte para SxS, que es WinXP SP2 y superior. Lo he hecho solo en WinXP SP3 y funcionó sin instalaciones especiales. No sé sobre Microsoft.Windows.Actctx, pero estoy 100% seguro de que puede invocar la API directamente importando las funciones relevantes de Kernel32.lib e invocandolas directamente. Al igual que se presenta en este código de ejemplo http://www.mazecomputer.com/sxs/help/sxsapi3.htm –

+0

Oh, ya veo. Todos los ejemplos en la web que había visto de hacer esto en VBA usan el objeto Actctx en lugar de la API, que es la única razón por la que originalmente concluí que no se podía hacer en código. Aparentemente, está implementado en ambos sentidos (y llamado lo mismo) solo para confundirme. No debería tener demasiados problemas para ponerlo en funcionamiento, y debería ser una solución más estable que piratear la IL, así que moveré la bandera de solución aceptada cuando llegue allí. ¡Gracias por la ayuda! – Jelly

0

Las bibliotecas de C# no son DLL regulares. Son más similares a las bibliotecas COM que deben registrarse (al igual que los controles ActiveX) antes de ser utilizadas; especialmente cuando se llama desde un código que no es .NET.

(A menos que, por supuesto, las cosas han cambiado ...)

+0

Mi impresión de que C# DLL podrían utilizarse sin registrar vino de aquí: http://msdn.microsoft.com/en-us/library/ms973915.aspx donde hay un servidor .NET C# y un cliente non-.NET. Creo que eso es básicamente equivalente a lo que quiero hacer, aparte del hecho de que el cliente es un ejecutable VB6 en lugar de una aplicación VBA. ¿Hay algo más de lo que me estoy perdiendo? Gracias! – Jelly

+0

Es posible que se quede atascado en la parte donde necesita crear un archivo de manifiesto para el cliente, ya que VBA no es un programa independiente para el que podría generar uno. El manifiesto parece bastante simple, pero no puedo decir con certeza cómo asociarlo correctamente. ¿Tal vez podría obtener el VBA para ejecutar un cliente independiente que hace lo que necesita? – Ioan

1

El problema es que para utilizar SxS, se necesita poseer el exe para establecer la configuración para cargar el ensamblado SxS. Usted no es "propietario" de Access, y aunque podría soltar la configuración correcta para que cargue su material .NET COM sin registro, no sería un movimiento de "buen ciudadano".

Si se pone complicado con shimming, puede configurar una DLL no administrada (o una biblioteca de clase C# pirateada con un dllexport, consulte this, por ejemplo) con una exportación que cargará .NET framework, crear una instancia de un tipo gestionable DispInterface COMVisible y lo devuelve (el método debe devolver IDispatch). A continuación, escriba un VBA declare a su función de exportación DLL (declarada como Objeto que retorna). Si esto no tiene sentido, probablemente no deberías intentarlo ... :) He hecho esto antes en una situación similar, y funciona, pero no tengo una muestra para señalarlo.

+0

Eso es muy inteligente y realmente tiene sentido. No había encontrado nada cuando estaba buscando antes sobre piratear el IL para obligar a C# a exportar un método. Conseguí que esa parte funcionara y no creo que debería ser demasiado difícil lograr que sea un punto de entrada para devolver un objeto también. ¡Gracias por la sugerencia! – Jelly

8

Para añadir a las respuestas ya existentes: con .NET 4.0 , de hecho es bastante fácil de consumir una DLL de C# en su proyecto de VBA sin registrar el COM.

EDITAR: Acabo de intentar esto con el mscorlib.tlb y mscoree.tlb que están en C:\windows\Microsoft.NET\Framework\v2.0.50727 - cargar un ensamblado compilado en 3.5-- y funcionó muy bien. Entonces aparentemente no necesitas .NET 4.0.

El siguiente es un ejemplo de cómo usar un dll C# en su proyecto de VBA. Se modifica ligeramente desde la respuesta this.

1) Añadir referencias a las siguientes bibliotecas de tipo de su proyecto de VBA (Herramientas> Referencias):

C:\windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb 
C:\windows\Microsoft.NET\Framework\v4.0.30319\mscoree.tlb 

(use carpeta Framework64 si está ejecutando 64 bits de Office)

2) En el proyecto de C#, asegúrese de añadir el atributo [ComVisible(true)] a su clase:

using System.Windows.Forms; 
using System.Runtime.InteropServices; 
namespace VB6FuncLib 
{ 
    [ComVisible(true)] 
    public class VB6FuncLib 
    { 
     public VB6FuncLib() 
     { } 
     public void test() 
     { 
      MessageBox.Show("Test Successful"); 
     } 
    } 
} 

usted no necesidad de CHEC k la opción "Registrarse para la interoperabilidad COM". Eso es solo para construir un objeto COM estándar. No es necesario que marque "Hacer visible el ensamblaje COM", a menos que desee que todo el conjunto sea visible (lo que también eliminaría la necesidad del atributo COMVisible).

3) En su código VBA, añadir un nuevo módulo con este código:

Sub Test() 
    Dim Host As mscoree.CorRuntimeHost 
    Set Host = New CorRuntimeHost 
    Host.Start 
    Dim Unk As IUnknown 
    Host.GetDefaultDomain Unk 
    Dim AppDomain As AppDomain 
    Set AppDomain = Unk 
    Dim ObjHandle As ObjectHandle 
    Set FS = CreateObject("Scripting.FileSystemObject") 
    Path = FS.GetParentFolderName(CurrentDb().Name) 
    Set ObjHandle = AppDomain.CreateInstanceFrom(Path & "\VB6 Function Library.dll", "VB6FuncLib.VB6FuncLib") 
    Dim ObjInstance As Object 
    Set ObjInstance = ObjHandle.Unwrap 
    ObjInstance.test 
    Host.Stop 
End Sub 

4) Copiar el archivo DLL en la misma carpeta que el proyecto de Office y ejecute la prueba() sub en VBA.

Notas:

Cabe señalar que una de las limitaciones de esta técnica es que no va a funcionar si el DLL se almacena en un recurso compartido de red remoto. Una solución simple sería copiarlo en la misma carpeta local en cada PC donde se usa. Otra solución sería incluir los archivos binarios en su aplicación de Access/proyecto de VBA y exportarlos a MS-Access. Una forma de lograrlo sería almacenarlos en Base64 en una tabla u hoja de cálculo, y luego convertirlos y exportarlos como binarios.

Pude conseguir el enlace anticipado (y, por lo tanto, Microsoft IntelliSense) para trabajar creando una biblioteca de tipos para ir con el DLL (usando tlbexp), y agregando una referencia al TLB en mi proyecto de VBA, pero lo hace complicar las cosas un poco porque requiere que su aplicación VBA sepa dónde están los archivos DLL y TLB (y también requiere que alguien se asegure de que estén allí).

Cuestiones relacionadas