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 WbObject 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?

21
demandé sur Community 2015-01-29 18:28:33

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.

22
répondu GSerg 2017-05-23 12:09:24

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.

6
répondu KekuSemau 2015-01-29 18:12:40

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.xlsmSheet1 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 Sheet1codebehindSheet1 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?

2
répondu S Meaden 2017-01-11 18:11:01

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

enter image description here

Remarque: MyForm est un formulaire VBA existant qui a été ajouté au projet.

0
répondu dee 2017-01-12 15:31:56