Message de compilation VBA manquant pour le nom de méthode erroné
Considérons le code suivant:
Public Sub VBACompilerIsMad()
Dim Ap As Application
Dim Wb As Workbook
Dim Ws As Worksheet
Debug.Print Ap.XXX ' No compile error
Debug.Print Wb.XXX ' No compile error
Debug.Print Ws.XXX ' Compile error
End Sub
quand je compile ceci, j'obtiens une erreur de compilation pour faire référence à un membre inexistant de Worksheet
. Cependant, si je commenter la dernière ligne, il n'y a pas d'erreur de compilation, même si ni Application
ni Workbook
avoir une méthode ou une propriété XXX
. C'est comme si j'avais déclaré Ap
et Wb
Object
variables.
pourquoi le compilateur traite Application
/ Workbook
différemment de Worksheet
?
Sont il y a toutes les autres classes comme cela, que le compilateur semble traiter comme si elles étaient <!--7?
4 réponses
comme je l'ai expliqué (kudos go respectivement), il s'agit d'une fonctionnalité COM.
par défaut COM suppose qu'une interface est extensible, c'est-à-dire qu'elle permet d'ajouter des membres au moment de l'exécution. Si ce n'est pas le comportement souhaité, on peut appliquer l' [nonextensible]
l'attribut à la définition de l'interface, qui déclare que l'interface n'accepte que les méthodes explicitement définies dans la bibliothèque de type.
dispinterface _Application
et dispinterface _Workbook
ne pas avoir ce drapeau dans le type Excel bibliothèque, dispinterface _Worksheet
ne.
Même, ADO's dispinterface _Connection
ne pas [nonextensible]
,dispinterface _Command
ne.
Pour en savoir qui sont extensibles, ajouter une référence à TypeLib Info
dans les Références du projet et de l'exécution:
Dim t As tli.TLIApplication
Set t = New tli.TLIApplication
Dim ti As tli.TypeLibInfo
Set ti = t.TypeLibInfoFromFile("excel.exe")
Dim i As tli.InterfaceInfo
For Each i In ti.Interfaces
If (i.AttributeMask And tli.TYPEFLAG_FNONEXTENSIBLE) <> tli.TYPEFLAG_FNONEXTENSIBLE Then
Debug.Print i.Name
End If
Next
vous verrez que presque toutes les interfaces sont extensibles ici, donc la plupart d'entre elles sortent de la fenêtre de débogage et vous ne verrez que les dernières. Changer <>
=
pour imprimer ceux qui ne sont pas extensibles, il y sont beaucoup moins d'entre eux.
Un peu d'une hypothèse:
vous pouvez appeler une procédure stockée sur un ADODB.Objet de connexion comme une méthode native (en bas).
(Les exemples de ce sur plusieurs les sites msdn ont l'air étrangement dérangés).
Il y a donc un mécanisme comme "méthodes anonymes/dynamiques" dans VBS/VBA.
Il peut être un mécanisme similaire activé ici Application
et Workbook
classes - bien que je ne vois pas où et comment exactement.
un test soutient l'idée de base:
J'ai testé cela avec une référence à Microsoft ActiveX Data Objects 2.8 Library
:
Public Sub testCompiler()
Dim cn As ADODB.Connection
Dim cmd As ADODB.Command
Debug.Print cn.XXX
Debug.Print cmd.XXX
End Sub
cn.XXX
jeter une erreur de compilation, cmd.XXX
ne.
GSerg la réponse est en effet exceptionnelle, j'adore l'ensemble de la bibliothèque de type COM IDL et comment certains attributs il peut gouverner le comportement dans le VBA Excel IDE. Que cette connaissance étrange de COM soit transmise longtemps! Et, je me rends compte que cette question a été vidée pour donner cette réponse plus de répit, mais quand une prime est placée il apparaît sur mon radar et j'ai une vue sur cette question.
donc, bien que la réponse de GSerg donne le mécanisme, elle ne donne pas la raison, c'est-à-dire qu'elle donne le comment mais pas le pourquoi. Je vais tenter de répondre au "pourquoi".
Certains de la réponse pourquoi est déjà donné par Martin Rouleau (OP) dans ses commentaires sur Application
et WorksheetFunction
. Ceci, pour moi, est une raison convaincante de garder Application
extensible et je ne vais pas considérer Application
plus d'.
tournons-nous vers Workbook
et Worksheet
et nous ferions mieux de commencer avec un peu de code pour démontrer, donc vous aurez besoin de commencer avec deux nouveaux cahiers, appelez-les MyWorkbook.xlsm
et OtherWorkbook.xlsm
. Donc quelques instructions:
OtherWorkbook.xlsm
aller dans le module de code ThisWorkbook
et coller le code
Option Explicit
Public Function SomeFunctionExportedOffOtherWorkbook() As String
SomeFunctionExportedOffOtherWorkbook = "Hello Matt's Mug!"
End Function
MyWorkbook.xlsm
Sheet1
module de code et coller le code
Option Explicit
Public Function SomeFunctionExportedOffCodeBehindSheet1() As String
SomeFunctionExportedOffCodeBehindSheet1 = "Hello Martin Roller!"
End Function
maintenant, dans le VBA IDE changer le nom de code de Sheet1
codebehindSheet1
Maintenant, dans un nouveau module standard en MyWorkbook.xlsm
ajouter le code suivant
Sub TestingObjectLikeInterfacesOfWorkbookAndCodeBehindWorksheet_RunMany()
'* For this example please rename the 'CodeName' for Sheet1 to be "codebehindSheet1" using the IDE
Debug.Assert ThisWorkbook.Worksheets.Item("Sheet1").CodeName = "codebehindSheet1"
Dim wb As Workbook
Set wb = Application.Workbooks.Item("OtherWorkbook")
'* Workbook dispinterface needs to not marked with nonextensible attribute
'* so that it doesn't trip up over exported function in another workbook
'* below SomeFunctionExportedOffOtherWorkbook is defined in the ThisWorkbook module of the workbook "OtherWorkbook.xlsm"
Debug.Print wb.SomeFunctionExportedOffOtherWorkbook
'*Not allowed --> Dim foo As Sheet1
'*have to call by the 'code behind' name which is usually Sheet1 but which we changed to illustrate the point
Debug.Print codebehindSheet1.SomeFunctionExportedOffCodeBehindSheet1
End Sub
maintenant, exécutez ce code ci-dessus.
vous avez probablement lu le code et avec un peu de chance vous avez compris ce que je veux dire mais laissez-moi épeler c'. Nous avons besoin d' Workbook
pour rester extensible car il peut contenir une référence à un autre classeur qui peut exporter une méthode ou une fonction et nous ne voulons pas d'erreurs de compilation.
Cependant, pour le Worksheet
, pour faire une exportation similaire nous ajoutons de nouveau du code au code derrière module mais il y a une différence dans le référencement du module: on saisit une référence à ce code derrière module en utilisant son nom de code VBA, la plupart des gens ne changent pas cela de Sheet1 (c'est pourquoi vous avez été invité à modifier ci-dessus).
ainsi l'interface obtenue par le code derrière le nom du module doit être extensible et non pas L'Excel.Feuille de travail interface.
P.S. quiconque a une copie de TLI.dll?
comme solution de contournement il pourrait être possible de créer votre propre interface
et implémenter cette interface. Alors déclarez une variable comme INewInterface
et tous les messages compilateur sera là :). Voici un exemple simple avec interface personnalisée pour un UserForm
. HTH
Interface
Public CancelButton As MSForms.CommandButton
Public DataList As MSForms.ListBox
Public CommandBox As MSForms.TextBox
mise en oeuvre
Implements IMyForm
Private Property Set IMyForm_CancelButton(ByVal RHS As MSForms.ICommandButton)
End Property
Private Property Get IMyForm_CancelButton() As MSForms.ICommandButton
End Property
Private Property Set IMyForm_CommandBox(ByVal RHS As MSForms.IMdcText)
End Property
Private Property Get IMyForm_CommandBox() As MSForms.IMdcText
End Property
Private Property Set IMyForm_DataList(ByVal RHS As MSForms.IMdcList)
End Property
Private Property Get IMyForm_DataList() As MSForms.IMdcList
End Property
Utilisation
Remarque: MyForm
est un formulaire VBA existant qui a été ajouté au projet.