ABOUT Visual Basic Programmieren Programmierung Download Downloads Tips & Tricks Tipps & Tricks Know-How Praxis VB VBA Visual Basic for Applications VBS VBScript Scripting Windows ActiveX COM OLE API ComputerPC Microsoft Office Microsoft Office 97 Office 2000 Access Word Winword Excel Outlook Addins ASP Active Server Pages COMAddIns ActiveX-Controls OCX UserControl UserDocument Komponenten DLL EXE
Diese Seite wurde zuletzt aktualisiert am 09.06.2000

Diese Seite wurde zuletzt aktualisiert am 09.06.2000
Aktuell im ABOUT Visual Basic-MagazinGrundlagenwissen und TechnologienKnow How, Tipps und Tricks rund um Visual BasicActiveX-Komponenten, Controls, Klassen und mehr...AddIns für die Visual Basic-IDE und die VBA-IDEVBA-Programmierung in MS-Office und anderen AnwendungenScripting-Praxis für den Windows Scripting Host und das Scripting-ControlTools, Komponenten und Dienstleistungen des MarktesRessourcen für Programmierer (Bücher, Job-Börse)Dies&Das...

Themen und Stichwörter im ABOUT Visual Basic-Magazin
Code, Beispiele, Komponenten, Tools im Überblick, Shareware, Freeware
Ihre Service-Seite, Termine, Job-Börse
Melden Sie sich an, um in den vollen Genuss des ABOUT Visual Basic-Magazins zu kommen!
Informationen zum ABOUT Visual Basic-Magazin, Kontakt und Impressum

Zurück...

Volkszählung

Zurück...


Anzeige

(-hg) mailto:hg_refcounter@aboutvb.de

Die Lebensdauer einer Objekt-Instanz hängt davon ab, wie viele Referenzen auf sie existieren. Jede zusätzliche Referenz auf eine Instanz, die etwa in einer in einer Objekt-Variablen oder einer Collection abgelegt wird, erhöht den Referenzzähler dieser Instanz. Dieser wird von Visual Basic im Verborgenen verwaltet und ist eigentlich nicht zugänglich. Und erst wenn die letzte Referenz auf die Objekt-Instanz wieder freigegeben ist (Objekt-Variable gleich Nothing gesetzt, Objekt aus einer Collection entfernt), der Referenzzähler also wieder 0 ist, kann ein Objekt terminieren und (bei Forms, VB-Klassen oder UserControls usw.) das Terminate-Ereignis ausgelöst werden. Genau so kann ein ActiveX-Server (DLL, EXE oder OCX) auch nicht terminieren kann, wenn irgendwo auf der Client-Seite (Ihre Anwendung) noch eine Objekt-Referenz existiert.

Bei komplexeren Anwendungen kann es leicht passieren, dass Sie eine Objekt-Referenz ein wenig aus den Augen verloren haben. Interessant wäre es da sicherlich, den Referenz-Zähler überwachen zu können - lediglich die Initialize- und Terminate-Ereignisse eine Debug-Meldung im Direkt-Fenster ausgeben zu lassen, hilft in Bezug darauf nämlich nicht sonderlich viel.

Wie gesagt: Visual Basic verbirgt zwar offiziell den Referenz-Zähler vor uns - doch er ist trotzdem vorhanden. Er steht nämlich im Arbeitsspeicher genau hinter der Stelle, an der Visual Basic die Referenz auf die "Ur-Instanz", nämlich auf die bei allen COM-Objekten vorhandene Schnittstelle IUnknown abgelegt hat.

Die Speicher-Adresse der Schnittstellen-Referenz rückt Visual Basic freiwillig über die (allerdings nicht dokumentierte) Funktion ObjPtr heraus. Den Inhalt der Speicherstelle dahinter können wir jedoch nicht direkt lesen. Doch mit der API-Funktion MSDN Library - API RtlMoveMemory (CopyMemory)CopyMemory (die eigentlich RtlMoveMemory heißt, jedoch meistens unter diesem Namen deklariert wird) können wir den dort stehenden Wert in eine eigene Variable des Datentyps Long kopieren (siehe auch Vom Zeiger zur Variablen"Vom Zeiger zur Variablen".

Der Hilfsfunktion GetRefCount übergeben Sie eine Referenz auf das betreffende Objekt und erhalten die Zahl der Referenzen zurück. Sollten Sie eine Objekt-Referenz übergeben, die nur ein Nothing enthält, versucht die Funktion gar nicht erst, den Referenz-Zähler zu kopieren. Sie wird vielmehr sogleich abgebrochen und der Rückgabewert ist folglich 0.

Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
 (Dest As Any, Source As Any, ByVal Bytes As Long)

Public Function GetRefCount(Object As IUnknown) As Long
  Dim nRefCount As Long
  
  If Object Is Nothing Then
    Exit Function
  Else
    CopyMemory nRefCount, ByVal (ObjPtr(Object)) + 4, 4
    GetRefCount = nRefCount - 2
  End If
End Function

Sie mögen sich vielleicht darüber wundern, warum der kopierte Referenz-Zähler noch um 2 vermindert wird. Wenn Sie diese Zeile einmal versuchsweise auskommentieren, werden Sie feststellen, dass die Zählung offensichtlich nicht stimmt. Sie scheint um eben diese 2 zu hoch zu sein. Der Grund hierfür ist jedoch bei näherer Betrachtung klar: Bei der Übergabe an unsere Funktion wird der Referenz-Zähler bereits um 1 erhöht. Ein weiteres Mal wird er bei der Übergabe an die Funktion ObjPtr erhöht. Diese beiden Zählungen müssen wir natürlich wieder abziehen, um eine korrekte Zählung zu erhalten.

Ein interessantes, mir aber zur Zeit noch unerklärliches Phänomen tritt in Erscheinung, wenn die Referenz-Zählung für ein Form aus dem Code-Modul dieses Forms heraus aufgerufen wird. Die Zahl der Referenzen ist dann um weitere 2 zu hoch. Allem Anschein nach hat dies aber nichts damit zu tun, welches Form (bei mehreren Forms) in einem Projekt das gerade aktive Form ist. Und es hat wohl auch nichts damit zu tun, ob ein Form geladen ist oder nicht. Selbst wenn der Aufruf von GetRefCount indirekt erfolgt, also etwa über eine Hilfsfunktion in einem Standard-Modul, ändert dies nichts an diesem seltsamen Zuwachs. Erfolgt der Aufruf jedoch direkt von einem anderen Modul aus, etwa aus irgend einem Ereignis in einem anderen Form-Modul, stimmt der Referenz-Zähler wieder.

Im Zuge der bisher leider fruchtlosen Versuche, für dieses Verhalten eine Erklärung zu finden, habe ich aber eine andere interessante Entdeckung gemacht. Der Referenz-Zähler eines Forms ist nämlich um 1 höher, wenn es geladen ist. Zur zuverlässigen Ermittlung des Ladezustands eines Forms kann dieser Unterschied im Referenz-Zähler jedoch nur dann dienen, wenn Sie sicher sein können, dass keine weiteren Referenzen existieren, oder aber wenn Sie deren Zahl genau kennen.

Der Referenz-Zähler ist auch ein Indiz für die Natur der globalen Instanzen der Forms eines Projekts, die Sie ja direkt über den (Objekt-)Namen eines Forms aufrufen und laden können, ohne sie ausdrücklich instanzieren zu müssen. Selbst wenn Sie die globale Instanz eines Forms entladen und gleich Nothing setzen, werden Sie beim Aufruf von GetRefCount hierfür den Wert 1 erhalten. Ähnlich wie bei "As New ..." deklarierten Objekten legt nämlich Visual Basic automatisch eine Instanz im Hintergrund an (wenn auch nur gewissermaßen vorbereitend und noch nicht voll initialisiert), sobald Sie darauf zugreifen.

Die Referenz-Zahl von Steuerelementen können Sie übrigens mit GetRefCount nicht ermitteln, zumindest nicht für VB-eigene Steuerelemente. Sie erhalten kein sinnvolles Ergebnis, sondern immer eine gleiche, feststehende Zahl. Bei nicht VB-eigenen Steuerelementen können Sie allerdings den Referenz-Zähler des eigentlichen, über die Object-Eigenschaft erreichbaren Steuerelement-Objekts ermitteln. Allerdings ist der Wert auch hier wieder um 2 zu hoch, wenn Sie GetRefCount aus dem Form heraus aufrufen, auf dem das Steuerelement platziert ist.


Modul modRefCounter (modRefCounter.bas - ca. 0,6 KB)


Artikel
Zum Download-Bereich dieses Artikel
Mail an den Autor dieses Artikels

KnowHow
Zur KnowHow-Übersicht

KnowHow-Themen
Themen - Allgemeines
Themen - Entwicklungsumgebung (VB-IDE)
Themen - Forms
Themen - Steuerelemente (Controls)
Themen - Grafik
Themen - Dateien
Themen - UserControls
Themen - Einsteiger-Tipps
Themen - Wussten Sie...?

Übersicht nach Titeln in alphabetischer Reihenfolge
Übersicht nach Erscheinungsdatum

Schnellsuche



Zum Seitenanfang

Copyright © 1999 - 2016 Harald M. Genauck, ip-pro gmbh  /  Impressum

Zum Seitenanfang

Zurück...

Zurück...

Download Internet Explorer