Utiliser fonctions VB.Net depuis VBA dans Excel
Bonjour,
Je vous précise un peu tout ça, car j'ai du mal à trouver de la documentation là-dessus. Soit une application Windows Forms réalisée en VB.Net. L'objectif est de pouvoir faire appel aux fonctions de la classe "Excel" de cette application depuis une macro VBA dans un classeur Excel.
Comment faire ?
UDF dans excel,fonctions utilisateurs en vb.net
bonjour
Creer les fameux UDF en vb.net et les integrer à Excel?
Oui c'est possible, et c'est une des lacunes des VSTO dont beaucoup d'utilisateurs Excel se plaignent.
1/creer un projet librairies de classes normal
2/renommer la classe dans le nom que vous voulez.
3/mettre un namespace avec un nom court de preference(il faciltera la recherche de la lib)
4/pas la peine de mettre visible pour com(il est mis par code)
voici un exemple avec une fonction chaine,2 fonctions numeriques.
ici le code :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
'1/ Imports InteropService est necessaire pour permettre l'interactiion avec
' une application com(excel)
'2/noter qu'il ne s'agit que de fonctions utilisateurs UDF(user defined function)
'3/si l'on veut des sub on utilise les add-in VSTO
Imports System.Runtime.InteropServices
<ClassInterface(ClassInterfaceType.AutoDual), ComVisible(True)> _
Public Class LibFonctionsExcel
'fonction chaine
Public Function EchoInput(ByVal v1 As Integer) As String
Return "You entered " & v1.ToString
End Function
'fonction numerique 1
Public Function DiviserParDeux(ByVal D As Double) As Double
Return D / 2
End Function
'fonction numerique 2
Public Function DivideParQuatre(ByVal D As Double) As Double
Return D / 4
End Function
'cree un guid et une cle sur le serveur
<ComRegisterFunctionAttribute()> _
Public Shared Sub RegisterFunction(ByVal type As Type)
Microsoft.Win32.Registry.ClassesRoot.CreateSubKey("CLSID\\{" & _
type.GUID.ToString().ToUpper() + "}\\Programmable")
End Sub
'supprime la cle sur le serveur
<ComUnregisterFunctionAttribute()> _
Public Shared Sub UnregisterFunction(ByVal type As Type)
Microsoft.Win32.Registry.ClassesRoot.DeleteSubKey("CLSID\\{" & _
type.GUID.ToString().ToUpper() + "}\\Programmable")
End Sub
End Class |
4/ creer l'executable dll
5/ lancer excel à l'exterieur de visual studio
6/outils excel->macro complementaires->automatisation
7/dans la boite de dialogue rechercher la lib :namespace.nomclasseUDF
8/OK (si le message mscoree.dll cannot be found,repondre non et ok)
9/allez dans la feuille 1 ,function et rechercher vos functions bien pretes.
Une autre approche est de creer une librairie normale en .net,visible com , de la referencer en vba(car interopcom creer un fichier TBL pour ce faire) ,de mettre en place une macro qui appelle cette fonction...
bon code..............
Utiliser fonctions VB.Net depuis VBA dans Excel
rebonjour
quand j'ai bien vu ta replique à sinople,eh bien je te confirme la 2eme approche utiliser une lib .net en vba (une classe complete quoi ...creer en .net )
voici comment proceder simplement:
1/projet lib .net normal
2/supprimer la classe cree
3/ajouter un nouvel element->class com
Nota-Bene:ne touche pas au constructeur cree sous peine de deboire pour ta classe com(lit preambule genere vs 2008 ou vs2010)
4/ici le code VB.NET de la classe complete par 2 proprietes et une methode
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
<ComClass(ComClass1.ClassId, ComClass1.InterfaceId, ComClass1.EventsId)> _
Public Class ComClass1
#Region "GUID COM"
' Ces GUID fournissent l'identité COM pour cette classe
' et ses interfaces COM. Si vous les modifiez, les clients
' existants ne pourront plus accéder à la classe.
Public Const ClassId As String = "18ae69b0-ef5a-447e-91f7-8ccd5c328bef"
Public Const InterfaceId As String = "782e5dbe-8665-4881-9f58-37c78f77f598"
Public Const EventsId As String = "d68cf810-27dd-4e3d-9438-27f348800c11"
#End Region
' Une classe COM pouvant être créée doit avoir Public Sub New()
' sans paramètre, sinon, la classe ne sera pas
' inscrite dans le Registre COM et ne pourra pas être créée
' via CreateObject.
Public Sub New()
MyBase.New()
End Sub
Private x_nom As String
Public Property NOM() As String
Get
Return x_nom
End Get
Set(ByVal value As String)
x_nom = value
End Set
End Property
Private x_valeur As Double
Public Property VALEUR() As Double
Get
Return x_valeur
End Get
Set(ByVal value As Double)
x_valeur = value
End Set
End Property
Public Sub METHOD1()
VALEUR = VALEUR * 2.0
End Sub
End Class |
5/generer la solution
6/lance un excel
7/dans le nouveau classeur cree un projet userform VBA avec un bouton command et un textbox
7/dans l'editeur VBA fais Outils->References->click->boite de dialogue (cherche ta lib ComClass1 comme par exemple) ->coche->ok
8/ dans l'edit VBA tapes ceci
Code:
1 2 3 4 5 6 7 8 9
|
Dim objNet As ComClass1
Private Sub CommandButton1_Click()
Set objNet = New ComClass1
objNet.NOM = "paul"
objNet.VALEUR = 150#
Call objNet.METHOD1
TextBox1.Text = CStr(objNet.VALEUR)
End Sub |
Ainsi faisait Guillaume Tell avec son arc.............(la suisse me rappelle les bandes dessines et guillaume tell)....
bon code............
enregistrer un automation add-in,udf com
bonjour devuranie
excuse-moi pour le retard dans la reponse.
tu parles de fichier .dll.lequel?
il faut dans l'environnement com distinguer 2 types :
1/ UDF => est un COM add-in c.a.d sans interaction avec l'Interface Excel(ca regroupe toutes les fonctions. l'interface est fourni par Excel).
distinguo fondamental :il est destine à un utilisateur.
2/la lib => est un Automation Add-In et il peut avoir meme une interface graphique(si tu appelles à l'interieur une classe form).
distinguo fondamental :il est destine à un developpeur(sdk).
Bien maintenant deployement:
1/cas
-signer l'assembly avec nom fort
-copie le fichier dll (et le tlb est ajoute auto par le projet setup msi) dans dossier application.C'est ce dossier que tu deploies.
-enregistrer le tlb sur la machine user
-ajouter SetSecurity eventuellement.
Sur une machine User Excel ne connait pas l'existence de cette dll et son tlb.
(sur ta machine dev quand tu fais build VS enregistre à ton insu le tlb-coulisses).
Il faut enregistrer l'assembly avec l'utilitaire Regasm.exe quand tu deploie chez un user (regsver32 est reserve pour le "vrai" monde Com-rappelle toi ce que j'ai dit dans premier post).
Ici le code pour l'utilitaire regasm pour deployement:
Code:
1 2 3
|
'cette instruction command line cree tlb et l'enregistre sur la machine user
Regasm demo.dll /tlb: demo.tlb |
l'ennui est que pour un add-in Com on ne peut pas le faire par code.
aussi faut-il avoir dans le dossier installation l'utilitaire regasm.exe
2/cas
-signer l'assembly avec nom fort
-copie le fichier dll (et le tlb est ajoute auto par le projet setup msi) dans dossier application.C'est ce dossier que tu deploies.
-ce cas est le cas du deploiement SDK qui est simplement copie dans un dossier de la machine dev du developpeur d'application .
Celui-ci se chargera d'enregistrer la lib sur sa machine avec regasm et de referencer le tlb manuellement dans son projet.
Il existe une autre approche plus sure et balise par microsoft pour creer un automation Add-In (2e cas) avec une classe COM
C'est simplement utiliser un add-in VSTO Excel pour atteindre le meme objectif.Tu peux declarer ta classe avec prop et methodes dans l'add-in VSTO et l'appeler à partir de vba.
Methode recommende par Microsoft.
jette un coup d'oeil sur cet article de la MSDN LIB :http://www.google.fr/url?sa=t&source...jktoS44LCVbn-Q
C'est pour cela que j'ai repondu dans le premier post en focalisant sur le 1er cas (UDF) que ne peut resoudre un add-in.
Deploiement: ah ,au passage sur beaucoup de forums certains se meprennent en voulant deployer une SDK comme si c'etait une application destine à un utilisateur lambda.
Deployer une app destine à un user lambda est effictivement plus delicat (application exe en general).
je m'excuse de confondre une arbalete plus evolue qu'un arc....
bon code.......
automation com,formulaire à instancier
bonjour,
Il me semble qu'il faut se contenter d'une simple classe sans aspect visuel,parce que l'interaction d'un controle WinForm .Net avec un objet COM n'est pas simple meme pour un vrai objet COM.
Une des difficultes est d'acceder aux proprietes du WinForm (textebox,bouton et autres ....pour gerer leurs valeurs ), comme illustrer ici dans cet article de la lib MSDN
http://www.google.fr/url?sa=t&source...J2LlArCT36_i5A
Pour utiliser un WinForm comme controle utilisateur et l'integrer dans ton application Excel VBA il vaut mieux utiliser Toolkit WinForms prevu à cet effet par Microsoft(comporte la majeure partie des controls courants .net).
Petit defaut du toolkit: on integre les controles par code,pas par un designer.
Disponible sur son site avec un assistant (toolkit gratuit).
Il comporte des exemples de code tres clair et un run-time redistribuale.
Ici le lien Microsoft pour WinForms Toolskit:
http://www.google.fr/url?sa=t&source...KY9q9LF_NZ76Qg
Je ne garantis rien dans ta facon de proceder,mais moi je prefere rester dans des demarches balises.
appel de composants net via un classe com de VS
Bonjour devuranie
message 'Variable objet ou variable de bloc With non défini" .
C'est un probleme d'instanciation d'un objet ou d'une simple variable(verifie le code .net si tu n' a pas oublie quelque chose)
Verifie egalement le marshalling des types ,les erreur sur les types entrainent un rejet sans appel .
Il ne faut s'attendre à des conversions forcees (genre je mets un entier il va convertir en reel)
Aussi compiler en VB..NET en strict on et en VBA en strict on,par mesure de precaution.
Enfin effectivement tu as raison ,tu peux appeler une autre Classe
"MaClasse" et meme un Winform quoique c'est un peu acrobatique (j'ai fait surtout les add-in office) parce dans la tete il faut avoir "2 cases" etanches une Com et une Net.
bon voici une autre piste que tu peux explorer et toujours dans la meme direction.
une interface IDispatch COM au lieu d'une classe COM et des appels à des Winforms directement dans la classe Com pour echanger des donnees.
code vb.net du projet ClassLibraryInterfaceCom:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
'----------Attribut IntefaceIDispatch garantit que :---------------
'les parameters et valeurs retour de ses methodes strictement compatible automation (type= VARIANT structure).
<Guid("2BE90767-90E8-454a-A9CD-5FD243862E6A"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface _ComClass1Inteface
<DispId(1)> Property NOM() As String
<DispId(2)> Property VALEUR() As Double
<DispId(3)> Sub METHOD1()
<DispId(4)> Function FNTITRE(ByVal NB As Integer, ByVal TITRE As String) As String
<DispId(5)> Sub AfficheFrmComToNet()
<DispId(6)> Sub UpdateFrmComToNet()
End Interface
'Interface pour les evenements(inutilise)
<Guid("400FCE44-F9B7-415e-9925-AA9052FB7571"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface ComClass1Events
End Interface
'attribut ClassInterface(ClassInterfaceType.None) empeche l'exportation de la classe mais
'laisse visible uniquement l'interface pour les appels clients pour eviter des desagrements
'en cas de rajout de proprietes ou methodes non-exportables
'on peut l'appeler par "New" ou par son nom : "set myobject = createobject ("ComClassInteface") "
<Guid("D8493A7F-B03B-4ce5-B934-0333E3DE44CD"), ClassInterface(ClassInterfaceType.None), ProgId("ComClassInteface"), ComSourceInterfaces(GetType(ComClass1Events))> _
Public Class ComClass1Inteface
Implements _ComClass1Inteface
' Une classe COM pouvant être créée doit avoir Public Sub New()
' sans paramètre, sinon, la classe ne sera pas
' inscrite dans le Registre COM et ne pourra pas être créée
' via CreateObject.
'---------le WinForm----------------------------------------
Dim formeToNet As frmComToNet
Dim fn_titre As String = ""
Public Sub New()
MyBase.New()
Me.fn_titre = ""
Me.x_nom = ""
Me.x_valeur = 0.0
Me.formeToNet = New frmComToNet
End Sub
Public Function FNTITRE(ByVal NB As Integer, ByVal TITRE As String) As String Implements _ComClass1Inteface.FNTITRE
fn_titre = TITRE & "Numero -> " & NB.ToString
Return TITRE & "Numero -> " & NB.ToString
End Function
Public Sub METHOD1() Implements _ComClass1Inteface.METHOD1
VALEUR = VALEUR * 2.0
End Sub
Private x_nom As String
Public Property NOM() As String Implements _ComClass1Inteface.NOM
Get
Return x_nom
End Get
Set(ByVal value As String)
x_nom = value
End Set
End Property
Private x_valeur As Double
Public Property VALEUR() As Double Implements _ComClass1Inteface.VALEUR
Get
Return x_valeur
End Get
Set(ByVal value As Double)
x_valeur = value
End Set
End Property
'---------------AFFICHE VALEURS DEPUIS Excel VBA---------------
Public Sub AfficheFrmComToNet() Implements _ComClass1Inteface.AfficheFrmComToNet
Me.formeToNet.Show()
Me.formeToNet.txtNom.Text = Me.NOM
Me.formeToNet.txtValeur.Text = Me.VALEUR.ToString
Me.formeToNet.txtFNTITRE.Text = Me.fn_titre
End Sub
'---------------AFFECTE & AFFICHE VALEURS VERS Excel VBA ->SUITE AU CLICK BOUTON---------------
Public Sub UpdateFrmComToNet() Implements _ComClass1Inteface.UpdateFrmComToNet
Me.NOM = Me.formeToNet.x_Nom
Me.VALEUR = Me.formeToNet.x_Valeur
End Sub
End Class
'-------------FORME APPELEE DEPUIS CLASSE ComClass1Inteface------------
Imports System
Imports System.Windows.Forms
Imports System.Runtime.InteropServices
Public Class frmComToNet
'2 parametre transmis à FNTITRE dans ComClass1Inteface
Public x_Nom As String
Public x_Valeur As Double
Public x_paramNB As Integer
Public x_paramTITRE As String
Public Sub New()
' Cet appel est requis par le Concepteur Windows Form.
InitializeComponent()
' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
'FENETRE AU DESSUS DES FENETRES VBA et EXCEL(pratique)
'-----------------------------------------------------
Me.TopMost = True
End Sub
'AFFICHE LES VALEURS DEPUIS ComClass1Inteface
Private Sub btnDepuisCom_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDepuisCom.Click
MessageBox.Show("Valeurs depuis ComClass1Inteface")
End Sub
'ENVOIE VALEURS CONTROLES NET vers EXCEL
Private Sub btnVersCom_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnVersCom.Click
Me.txtNom.Text = "FREDERIC depuis NET"
Me.txtValeur.Text = "1500,0"
Me.txtParam1Titre.Text = "255"
Me.txtParam2Titre.Text = "TITRE depuis NET...."
x_Nom = Me.txtNom.Text
x_Valeur = Double.Parse(Me.txtValeur.Text, Globalization.NumberStyles.AllowDecimalPoint)
x_paramNB = Integer.Parse(Me.txtParam1Titre.Text)
x_paramTITRE = Me.txtParam2Titre.Text
End Sub
End Class |
code VBA du classeur:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
'-------------Code pour Classe COM avec Interface----------------
Dim objNet As ClassLibraryInterfaceCom.ComClass1Inteface
'AFFECTE DANS VBA & AFFICHE DANS WINFORM NET
Private Sub cmdAffecteDansVBA_Click()
'Appel aux Prop et Methodes de ComClass1Inteface
Set objNet = New ClassLibraryInterfaceCom.ComClass1Inteface
objNet.NOM = "Paul"
objNet.VALEUR = 150#
Call objNet.METHOD1
txtNOM.Text = objNet.NOM
txtVALEUR.Text = CStr(objNet.VALEUR)
txtFNTITRE.Text = objNet.FNTITRE(2, " Titre depuis EXCEL :")
Call objNet.AfficheFrmComToNet
End Sub
'AFFICHE DEPUIS NET
Private Sub cmdLitDepuisCOM_Click()
Call objNet.UpdateFrmComToNet
lblNOM_fromNet.Caption = objNet.NOM
lblVALEUR_fromNet.Caption = objNet.VALEUR
End Sub |
bon code..............