2016-04-16 1 views
1

Ich habe ein Formular, das eine Anzahl von Subs von Module1 aufruft. In Modul1 habe ich eine öffentlich deklarierte Objektvariable. Die Idee mit dieser Variable besteht darin, einen späte-gebundenen scripting.dictionary zu erstellen, um zu vermeiden, dass zu viele Referenzen zu meinem aktuellen VBA-Projekt hinzugefügt werden müssen. Das Wörterbuch wurde erfolgreich in Sub1 erstellt und ausgefüllt. Aber sobald Sub1 abgeschlossen ist und Sub2 aufgerufen wird, bemerke ich, dass die Wörterbuchvariable wieder auf ihren ursprünglichen Objekttyp zurückgesetzt wurde.Spät bindende öffentliche Objektvariable in einem Sub und Verlust von Inhalt, wenn die Ausführung zum nächsten Sub geht

Login Form:

Public progresslbl As Object, subprogresslbl As Object, progressbar As Object, webBr As Object 

Private Sub GetExports_Click() 
... 
... 
... 
progresslbl.Caption = "Requesting Exports" 
RequestExports 

'Wait for all emails to be received (reset currentsupplier and count emails, wait for currentsupplier = suppliercount) 
WaitforEmails 'Still needs to be created 

'Download Exports & Save them to destination user specifies 
DownloadFiles 


'Restore Outlook: remove temp folder and rule 
progresslbl.Caption = "Restoring Outlook Settings" 
RestoreOutlook 

Module1:

Public IE As Object, downloadTo As String, Outlook As Object, Items As Object, err As Integer, itemdic As Object 
'itemdic shows as type Object in Watch window 

Sub RequestExports() 

    Set itemdic = CreateObject("Scripting.Dictionary"): itemdic.comparemode = vbTextCompare 
    'itemdic now shows at type scripting.dictionary in Watch window 
    For x = 1 To suppliercount 
     With IE.Document 
      esplogin.subprogresslbl.Caption = "Searching for Supplier " & x & " of " & suppliercount 
      currentsupplier = ActiveSheet.Range("A" & x).Value 

      delay 3 'Wait 3 seconds to allow screen to load fully 

      .getElementById("supplierSearchTextBox").Focus 'Select Search Box 
      .getElementById("supplierSearchTextBox").Value = currentsupplier 'Fill in Search Box 

      'Invoke keypress event so the contents are detected 
      Set evt = .CreateEvent("keyboardevent"): evt.initEvent "change", True, False 
      .getElementById("supplierSearchTextBox").dispatchEvent evt 

      Dim searchButton As Object: Set searchButton = .getElementsByTagName("a")(5) 
      searchButton.Click 

      delay 3 

      Dim supplierLink As Object: Set supplierLink = .getElementsByTagName("a")(6) 
      'Cycle through list of suppliers in excel until we find another active one 
      Do While supplierLink Is Nothing 
       err = err + 1 
       esplogin.subprogresslbl.Caption = "Supplier Not Found" 
       delay 1 
       ActiveSheet.Range("A" & x).Interior.Color = vbYellow 
       If x = suppliercount Then Exit For 
       esplogin.progressbar.Width = 150/suppliercount * x 
       x = x + 1 
       esplogin.subprogresslbl.Caption = "Searching for Supplier " & x & " of " & suppliercount 
       currentsupplier = ActiveSheet.Range("A" & x).Value 
       'Select & Fill in Search Box 
       .getElementById("supplierSearchTextBox").Focus 
       .getElementById("supplierSearchTextBox").Value = currentsupplier 

       'Invoke keypress event so the contents are detected 
       Set evt = .CreateEvent("keyboardevent"): evt.initEvent "change", True, False 
       .getElementById("supplierSearchTextBox").dispatchEvent evt 

       Set searchButton = .getElementsByTagName("a")(5) 
       searchButton.Click 

       delay 2 

       Set supplierLink = .getElementsByTagName("a")(6) 
      Loop 
      'Login to supplier 
      supplierLink.Click 

      While IE.Busy 
       DoEvents 
      Wend 

      esplogin.subprogresslbl.Caption = "Exporting Supplier " & x & " of " & suppliercount 
      delay 4 

      Dim exportButton As Object: Set exportButton = .getElementsByTagName("button")(3) 
      exportButton.Click 

      delay 1 
      .getElementsByTagName("select")(0).Value = "all" 
      .getElementsByTagName("select")(1).Value = "5" 
      delay 1 
      .getElementById("btnExport").Click 'Click Export button 
      delay 2 

      'Click Ok button to close "Export sent to email" window 
      Dim exportResultOK As Object: Set exportResultOK = .getElementById("exportProductModalResul").getElementsByTagName("button")(1) 
      exportResultOK.Click 

      esplogin.subprogresslbl.Caption = "Awaiting Export Confirm. Email for Supplier " & x & " of " & suppliercount 
      delay 1 

      Set eitDashboardButton = .getElementsByTagName("a")(11) 
      eitDashboardButton.Click 
     End With 

     'Check to see if latestExport confirmation has arrived yet 
     Set latestExport = Items.Find("[Subject] = ""Product Updates Product Export confirmation""") 
     'If we haven't already found the latestExport wait and keep checking until we do 
     Do While latestExport Is Nothing 
      Set latestExport = Items.Find("[Subject] = ""Product Updates Product Export confirmation""") 
     Loop 

     esplogin.subprogresslbl.Caption = "Received Confirm. Email for Supplier " & x & " of " & suppliercount 

     With latestExport 
      BatchID = Mid(.Body, InStr(1, .Body, "Batch ID of ", vbTextCompare) + 12, InStrRev(.Body, ".", Len(.Body) - 1, vbTextCompare) - (InStr(1, .Body, "Batch ID of ", vbTextCompare) + 12)) 
      itemdic.Add currentsupplier, BatchID 
      latestExport.Subject = "Product Updates Product Export confirmation - " & currentsupplier 
      latestExport.Save 'Save the updated subject 
     End With 

     esplogin.progressbar.Width = 150/suppliercount * x 
    Next x 

    esplogin.progresslbl.Caption = "Export Requests Complete" 

    IE.Quit 
    Set IE = Nothing 
    Exit Sub 
Restore: 
    RestoreOutlook 
    MsgBox ("Issue with Export code") 
End Sub 


Sub WaitforEmails(Optional currentcount As Integer = 0) 

////As soon as the code reaches this point the item dic variable is now a type Object again and has no values 

    Dim item As Object, BatchID As String, k As Object 

    For Each item In Items 
     With item 
      If .Subject = "Product Updates: Product Export" Then 
       'Instr check for batch id (ie dic key) then whatever dic value it matches replace batch id in dic with download link 
       For Each k In itemdic.keys 
        If InStr(1, .HTMLBody, k, vbTextCompare) > 0 Then 
         'Store the download link in place of the batch id 
         itemdic(k) = Mid(.HTMLBody, InStr(1, .HTMLBody, "a href=") + 8, (InStrRev(.HTMLBody, ">here") - 2) - (InStr(1, .HTMLBody, "a href=") + 8)) 
         Exit For 
        End If 
       Next 
       currentcount = currentcount + 1 
       If currentcount = (suppliercount - errs) Then Exit For 'we have all of the emails 
      End If 
     End With 
    Next 
    If Not currentcount = (suppliercount - errs) Then Application.OnTime Now + TimeValue("00:01:00"), "WaitforEmails(currentcount)" 
    While Not currentcount = (suppliercount - errs) 
     DoEvents 
    Wend 
    Exit Sub 
Restore: 
    RestoreOutlook 
    MsgBox ("Issue with WaitforEmail code") 
End Sub 

'When moving to sub 2 itemdic now reverts back to showing as type Object in Watch window 

Sub 2() 
    'Work with items in dictionary 
    'Application or Object-defined Error I believe? 
    'Some error 
End Sub 

Meine Frage:

Gibt es eine Möglichkeit die spät binded Wörterbuch Variable haben ihre Art zu halten (und seine Inhalte/Werte) über Subs (in Modul1), ohne die Referenz hinzufügen zu müssen?

+0

hinzufügen 'debug.print itemdic. compareMode' als letzte ausführbare Anweisung in der ersten Prozedur und auch als erste ausführbare Anweisung in der zweiten Prozedur.Es gibt vier mögliche Ergebnisse (Erfolg/Misserfolg für jeweils 2 Aussagen); welches du bekommst, kann etwas darüber erzählen, wo das Problem ist. Es könnte sogar ein anderer Code sein, der zwischen den Aufrufen der beiden Subroutinen ausgeführt wird. – MikeC

+0

Ich muss bis Montag warten, um es zu debuggen, da ich Outlook aufgrund meiner Netzwerkeinschränkungen nicht mit meiner geschäftlichen E-Mail-Adresse einrichten kann. – CaffeinatedCoder

Antwort

0

Wow, so fühle ich mich wie ein echter Idiot. Das Thema hat mich die ganze Zeit im Auge behalten, zumindest teilweise. Ich glaube, die Frage war zweigleisigen:

  1. Das Projekt benötigt „gereinigt“ (exportierte das Modul und Form und sie in ein neues Projekt importiert) werden
    • Diese Pflege der itemdic nahm nicht mit Es sind Werte bei der Ankunft in der WaitforEmails Sub. Allerdings habe ich bemerkt, dass, wenn ich das Ende der ersten Sub erreichen itemdic hat den richtigen Typ und hat Werte. Was ich erkannte, ist, wenn es zurück zum Code der Benutzerform geht, zeigt es (vorrübergehend) im Überwachungsfenster als keine Werte zu haben und wieder ein Typ Objekt zu sein, was komisch ist, aber ich stelle mir vor es ist, weil das Each Fenster innerhalb der Umfang welches aktuelle Modul aktiv Code ausführt, der Sinn macht. Sobald der WaitforEmails Sub wird von der Benutzerform aufgerufen und der Code durchläuft die Zeilen in diesem Sub itemdic zeigt richtig mit Werten und als Typ Dictionary.
  2. Die key Variable, die ich in einer Schleife durch die Elemente im Wörterbuch verwenden sind falsch erklärt, es sollte erklärt werden, wie ein Variant keine Object (doh!)
1

Etwas in Sub1 muss Ihr Projekt zurücksetzen.

Folgende Arbeiten fein:

Public D As Object 

Sub sub1() 
    Set D = CreateObject("Scripting.Dictionary") 
    D.Add "hello", "world" 
End Sub 

Sub sub2() 
    Debug.Print D("hello") 
End Sub 

Sub test() 
    sub1 
    sub2 'prints "world" in the immediate window 
End Sub 

Aber - folgende Arbeiten anders:

Public D As Object 

Sub sub1() 
    Set D = CreateObject("Scripting.Dictionary") 
    D.Add "hello", "world" 
    End 
End Sub 

Sub sub2() 
    Debug.Print D("hello") 
End Sub 

Sub test() 
    sub1 
    sub2 'call doesn't print anything 
End Sub 

Achten Sie darauf, dass Sie keine Streu End in Ihrem Code haben. Wenn es nicht End ist, ist es etwas anderes. In jedem Fall gibt es definitiv keine Einschränkung in VBA über das späte Binden einer öffentlichen Objektvariable in einem Sub und das Verwenden dieses gebundenen Objekts in einem anderen.

+0

Das ist eine gute Nachricht, dass öffentliche Objekte nicht so stark eingeschränkt sind. Ich habe keine 'End'-Anrufe in Sub1. Das einzige, was ich habe, ist der Standard 'Exit Sub' direkt vor meinem Fehler-Trapping. Könnte das das verursachen? Außerdem nehme ich an, dass Sie 'test()' als UserForm's Sub verwendet haben? – CaffeinatedCoder

+1

Ich weiß es nicht. Ich habe gerade "End" in meinem Sub mit "Exit Sub" ersetzt und hatte kein Problem. Ich habe sogar einen Fehler-Handler hinzugefügt und absichtlich ausgelöst und hatte kein Problem. Kannst du es auf ein klein genug reproduzierbares Problem bringen, das insgesamt gepostet werden kann? –

+0

Sicher, ich werde meine Frage in ein bisschen aktualisieren – CaffeinatedCoder