2009-12-14 10 views
6

Je ne parle pas d'appeler un VBA COM de C# ... l'inverse!Side-by-Side COM Interop avec C# et VBA

Ce que je voudrais faire est d'appeler une bibliothèque C# en utilisant VBA dans MS Access sans enregistrer la DLL. J'ai joué avec l'interop côte à côte pendant un moment sans succès et il m'est finalement apparu qu'un mdb.manifest n'est probablement pas un remplacement acceptable pour un exe.manifest (probablement évident, je sais, mais je essayait d'être optimiste).

Ma question: Est-il possible que VBA charge un composant COM côte à côte?

Ou, existe-t-il une autre façon d'utiliser une bibliothèque C# non enregistrée dans Access? (Avant de vous le demander, mes raisons sont les suivantes: il est absolument impossible d'accéder au registre Windows de mon client - c'est pourquoi il a été écrit dans Access en premier lieu. même fonctionnalité dans une application C# bientôt et ne pas le faire deux fois).

Répondre

3

Vous n'avez pas à posséder l'exe pour utiliser SxS, SxS est un autre mot pour Activation Context. Si vous pouvez importer les appels win32 pertinents dans vba (et vous le pouvez), vous pouvez utiliser le activation context api pour charger votre fichier manifeste.

Plus sur le sujet et quelques exemples peuvent être trouvés here.

+0

J'ai regardé en utilisant cette API. Ironiquement cependant, Microsoft a créé un paquet pour éviter l'enregistrement qui nécessite l'enregistrement lui-même et laisse la même question que j'avais auparavant - comment l'obtenir sur la machine de mon client? Bien que Microsoft.Windows.Actctx soit disponible pour Windows 2K3 +, il est uniquement inclus dans les installations du serveur. Il ya une autre question SO se plaindre à ce sujet ici: http://stackoverflow.com/questions/979567/microsoft-windows-actctx-on-windows-xp. Et MSDN le sauvegarde ici: http://msdn.microsoft.com/en-us/library/aa375644(VS.85).aspx. – Jelly

+0

D'après ce que je sais, l'API Activation Context fait partie de Kernel32.lib, ce qui signifie que vous n'avez rien à installer, et il est inclus dans tout système d'exploitation qui a un support pour SxS qui est WinXP SP2 et supérieur. Je l'ai fait moi-même sur WinXP SP3 et cela a fonctionné sans installation spéciale. Je ne connais pas Microsoft.Windows.Actctx, mais je suis sûr à 100% que vous pouvez appeler l'API directement en important les fonctions pertinentes de Kernel32.lib et en les invoquant directement. Comme c'est présenté à cet exemple de code http://www.mazecomputer.com/sxs/help/sxsapi3.htm –

+0

Oh, je vois. Tous les exemples sur le web que j'ai vus de faire ceci dans VBA utilisent l'objet Actctx au lieu de l'API qui est la seule raison pour laquelle j'ai conclu à l'origine que cela ne pouvait pas être fait dans le code. Apparemment, il est mis en œuvre dans les deux sens (et appelé la même chose) juste pour me confondre. Je ne devrais pas avoir trop de mal à le faire fonctionner - et cela devrait être une solution plus stable que de pirater l'IL - donc je vais déplacer le drapeau de la solution acceptée quand j'y arriverai. Merci pour l'aide! – Jelly

0

Les bibliothèques C# ne sont pas des DLL normales. Ils sont plus similaires aux bibliothèques COM qui doivent être enregistrées (tout comme les contrôles ActiveX) avant d'être utilisées; surtout lorsqu'il est appelé à partir du code non-NET.

(À moins, bien sûr, les choses ont changé ...)

+0

Mon impression que les DLL C# pouvaient être utilisées sans inscription venait d'ici: http://msdn.microsoft.com/en-us/library/ms973915.aspx où il y a un serveur C# .NET et un client non-NET. Je crois que c'est fondamentalement équivalent à ce que je veux faire autre que le fait que le client est un exécutable VB6 au lieu d'une application VBA. Y a-t-il quelque chose d'autre qui me manque? Merci! – Jelly

+0

Vous pourriez être coincé sur la partie où vous devez créer un fichier manifeste pour le client, car VBA n'est pas un programme autonome pour lequel vous pourriez en générer un. Le manifeste semble assez simple, mais je ne pourrais pas dire avec certitude comment l'associer correctement. Peut-être que vous pourriez obtenir le VBA pour exécuter un client autonome qui fait ce dont vous avez besoin? – Ioan

1

Le problème est que d'utiliser SxS, vous devez posséder l'exe pour configurer la configuration pour charger l'ensemble SxS. Vous ne "possédez" pas Access, et bien que vous puissiez supprimer la bonne configuration pour l'amener à charger votre stuff .NET COM sans inscription, ce ne serait pas un "bon citoyen". Si vous avez des problèmes avec shimming, vous pouvez configurer une DLL non managée (ou une bibliothèque de classe C# piratée avec un dllexport, voir this, par exemple) avec une exportation qui va charger le framework .NET, créer une instance de un type géré DispInterface COMVisible et renvoyez-le (la méthode doit renvoyer IDispatch). Ensuite, écrivez un VBA declare à votre fonction d'export DLL (déclaré comme renvoyant Object). Si cela n'a pas de sens, vous ne devriez probablement pas l'essayer ... :) Je l'ai déjà fait dans une situation similaire, et cela fonctionne, mais je n'ai pas d'exemple à vous montrer.

+0

C'est très intelligent et ça a du sens. Je n'avais rien trouvé quand je cherchais avant de pirater l'IL pour forcer C# à exporter une méthode. J'ai eu cette partie à travailler et je ne pense pas qu'il devrait être trop difficile de l'obtenir pour faire un point d'entrée pour retourner un objet aussi. Merci pour la suggestion! – Jelly

8

Pour ajouter aux réponses déjà existantes: avec .NET 4.0 , il est en fait assez simple de consommer une dll C# dans votre projet VBA sans enregistrer le COM.

EDIT: Je viens d'essayer cela avec le mscorlib.tlb et mscoree.tlb qui sont en C:\windows\Microsoft.NET\Framework\v2.0.50727 - chargement d'un assembly compilé dans 3.5-- et cela a fonctionné très bien. Donc, apparemment, vous n'avez pas besoin de .NET 4.0.

Voici un exemple d'utilisation d'un DLL C# dans votre projet VBA. Il est légèrement modifié de this réponse.

1) Ajouter des références aux libs type suivants votre projet VBA (Outils-> Références):

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

(utiliser le dossier Framework64 si vous exécutez

2 Office 64 bits)) Dans votre projet C#, assurez-vous que vous ajoutez l'attribut [ComVisible(true)] à votre classe:

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

vous ne le font pas besoin de chec k l'option "Enregistrer pour COM Interop". C'est seulement pour construire un objet COM standard. Vous n'avez pas non plus besoin de cocher "Make Assembly COM Visible", sauf si vous voulez que l'ensemble de l'assembly soit visible (ce qui élimine également le besoin de l'attribut COMVisible).

3) Dans votre code VBA, ajoutez un nouveau module avec ce code:

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) Copiez le DLL dans le même dossier que votre projet de bureau et exécutez le test() sous VBA.

Notes:

Il convient de noter que l'une des limites de cette technique est qu'elle ne fonctionnera pas si le .DLL est stocké sur un partage réseau à distance. Une solution simple serait de le copier dans le même dossier local sur chaque PC où il est utilisé. Une autre solution consisterait à inclure les binaires dans votre projet Access/VBA Access, et à les faire exporter par MS-Access. Une façon d'y parvenir serait de les stocker dans Base64 dans une table ou une feuille de calcul, puis de les convertir et de les exporter en tant que binaires.

J'ai pu obtenir une liaison anticipée (et donc Microsoft IntelliSense) pour travailler en créant une bibliothèque de types pour aller avec la DLL (en utilisant tlbexp), et en ajoutant une référence au TLB dans mon projet VBA, mais cela compliquer un peu les choses, car il faut que votre application VBA sache où se trouvent les fichiers DLL et TLB (et exige également que quelqu'un s'assure qu'ils sont présents).