11. Dez 2023
Lesedauer 6 Min.
Windows-Explorer-History
Ein eigenes Steuerelement für Verlaufsdaten, Teil 8
Auch der Windows Explorer speichert Verlaufsdaten, die man auslesen kann.

Die vorangegangenen Folgen dieser Serie (von [1] bis [2]) haben sich damit befasst, ein eigenes Steuerelement zu entwickeln, das alle Quellen von Verlaufsdaten ausliest, um diese Daten einheitlich präsentieren und verwalten zu können. Nun sollen auch noch die vom Windows Explorer gespeicherten Verlaufsdaten in das benutzerdefinierte Steuerelement aufgenommen werden.Jeder Windows-Anwender ist mit dem Windows Explorer vertraut. Er ist fest ins System integriert und stellt eine Vielzahl an Funktionen und auch Dialogen bereit, die auch Fremdprogramme nutzen können. Viele, aber längst nicht alle Funktionen sind dokumentiert und viele der in der Systemregistrierung (Registry) gespeicherten Daten haben einen direkten Bezug zum Windows Explorer.
Sensible Nutzungsdaten in Shellbags
Die vom Windows Explorer in der Registry abgelegten Daten werden als binäre Datenpakete, sogenannte Shellbags, gespeichert. Offenlegen können Sie diese Daten mithilfe des kostenlosen Programms Shellbag Analyzer & Cleaner [3], siehe Bild 1. Das Programm legt nicht nur die in der Registrierung abgelegten Informationen zu genutzten Ordnern offen, sondern auch die Infos zu externen Laufwerken, Suchergebnissen und Systemsteuerungsmenüs. Dabei spielt es keine Rolle, ob die Ordner noch existieren oder zwischenzeitlich gelöscht wurden. Ferner werden Infos zum letzten Zugriff, zum Pfad, zur Art, zum Daten-Slot, zum Slot-Registrierschlüssel sowie zum Anlagedatum, zum letzten Zugriffdatum und zum letzten Änderungsdatum abgelegt.
Offengelegt: vom Windows Explorer angelegte Shellbags (Bild 1)
Autor
Über diese Daten kann das Nutzungsverhalten von Benutzern nachverfolgt werden. Dementsprechend werden die Informationen häufig für forensische Analysen verwendet. Damit könnten Arbeitgeber beispielsweise überprüfen, ob Arbeitnehmer nur in den für die Arbeit benötigten Verzeichnissen unterwegs waren. Mit dem Tool Shellbag Analyzer & Cleaner [3] können Sie diese Informationen nicht nur auslesen, sondern auch bereinigen und somit unerwünschte Analysen unterbinden. Optional lassen sich die Daten auch in lesbarer Form exportieren. Die exportierte Datei wird im Textformat (CSV-Format) auf dem Desktop angelegt und kann in Datenbanken und/oder Kalkulationsprogramme importiert werden. Die interne Verwaltung erfolgt ähnlich wie die der zuletzt geöffneten Dokumente (Recent Docs), die ebenfalls binär verschlüsselt in der Registry gespeichert werden. Einzelne Einträge werden über MRUListEx-Listen zusammengefasst, die numerische Werte für Schlüsselnamen enthalten, die wiederum alle Daten im Binärformat verwalten (Bild 2).

Shellbag-Informationen im Registrierungseditor (Bild 2)
Autor
Shellbags wurden unter Windows XP in der Datei NTuser
.dat abgelegt und sind seit Windows 7 in der Datei UserClass
.dat zu finden. Alle Daten werden den Hauptknoten HKCU (HKEY_CURRENT_USER) und HKCR (HKEY_CLASSES_ROOT) (seit Windows 7) zugeordnet. Die Registrierzweige:
.dat abgelegt und sind seit Windows 7 in der Datei UserClass
.dat zu finden. Alle Daten werden den Hauptknoten HKCU (HKEY_CURRENT_USER) und HKCR (HKEY_CLASSES_ROOT) (seit Windows 7) zugeordnet. Die Registrierzweige:
NTUSER.DAT:
HKCU<span class="hljs-symbol">\S</span>oftware<span class="hljs-symbol">\M</span>icrosoft<span class="hljs-symbol">\W</span>indows<span class="hljs-symbol">\S</span>hellNoRoam<span class="hljs-symbol">\B</span>agMRU
USRCLASS.DAT:
HKCU<span class="hljs-symbol">\S</span>oftware<span class="hljs-symbol">\C</span>lasses<span class="hljs-symbol">\L</span>ocal Settings<span class="hljs-symbol">\S</span>oftware<span class="hljs-symbol">\M</span>icrosoft<span class="hljs-symbol">\</span>
<span class="hljs-symbol"> </span> Windows<span class="hljs-symbol">\S</span>hell<span class="hljs-symbol">\B</span>agMRU
HKCU<span class="hljs-symbol">\S</span>oftware<span class="hljs-symbol">\C</span>lasses<span class="hljs-symbol">\L</span>ocal Settings<span class="hljs-symbol">\S</span>oftware<span class="hljs-symbol">\M</span>icrosoft<span class="hljs-symbol">\</span>
<span class="hljs-symbol"> </span> Windows<span class="hljs-symbol">\S</span>hell<span class="hljs-symbol">\B</span>ags
Der Aufbau und die Datenverwaltung der Shellbags sind kompliziert. Detaillierte Informationen finden Sie bei Bedarf im PDF-Dokument „Windows Shellbag Forensics in Depth“ unter [4]. Alternative Tools zur Shellbag-Analyse listet die nebenstehende Tabelle 1.
Tabelle 1: Tools für Shellbag-Einträge
|
Im Rahmen des Verlaufsdatensteuerelements sollen die Shellbags nicht berücksichtigt werden. Optional können Sie diese aber später selbst ergänzen.
Windows-URLs ermitteln
An dieser Stelle sollen über Windows-API-Funktionen die im Windows Explorer angewählten URLs ermittelt und ausgegeben werden. Die URLs können Bezüge zu Webseiten und auch zu Dokumenten sein, die generell über URLs verwaltet, automatisch aufgezeichnet und bei Bedarf ausgelesen werden können. Eine Beispielanzeige im benutzerdefinierten Verlaufsdaten-Steuerelement sehen Sie in Bild 3.
Das Steuerelement listet zuletzt besuchte URLs (Bild 3)
Autor
Basis für die Informationsermittlung ist das Interface IUrlHistory, über das Sie die Internet-Explorer-Verlaufsdaten verwalten. Die Schnittstelle ist Bestandteil des Windows-API, in C++ umgesetzt und auf der Microsoft-Webseite unter [5] dokumentiert. Auf CodeProject [6] finden Sie ein C#-Beispiel, welches das Auslesen der Informationen zeigt. Alle API-Deklarationsanweisungen wurden an C# angepasst. Die Funktionalitäten zur Informationsabfrage wurden dabei in die Assembly UrlHistoryLibrary.dll ausgelagert, die sich per Verweis an beliebige .NET-Projekte anbinden lässt. Angebunden an ein eigenes Projekt muss die DLL immer zusammen mit dem eigenen Programm ausgeliefert werden.An dieser Stelle wird das Verlaufssteuerelement in Visual Basic .NET umgesetzt. Eine externe Assembly-DLL soll hier nicht verwendet werden. Folglich ist die API-Funktionalität in VB.NET zu codieren. Basis für die Analyse ist die Klasse win32api.vb, die der Steuerelementbibliothek ExtendedControlsLib hinzugefügt wurde.In der Quelldatei der Klasse befinden sich die Klassen STATURLEnumerator, SortFileTimeAscendingHelper, UrlHistoryWrapperClass und UrlHistoryClass. Teile der Klassen sind verschachtelt. In win32api.vb werden zunächst diverse Namensräume importiert, über die System-, Ein- und Ausgabefunktionen, Kollektionen, Text und Interoperabilitätsfunktionen vereinfacht nutzbar sind. Gegenüber der C#-Klasse des CodeProject-Beispiels wurden diverse Anpassungen vorgenommen, um eine korrekte Verarbeitung in VB.NET sicherzustellen.
<span class="hljs-keyword">Imports</span> System
Imports System.IO
Imports System.Collections
Imports System.Text
Imports System.Runtime.InteropServices
Public <span class="hljs-keyword">Class</span> Win32api
<span class="hljs-keyword">Public</span> <span class="hljs-keyword">Class</span> UrlHistoryClass
...
<span class="hljs-keyword">End</span> Class
End Class
Public <span class="hljs-keyword">Class</span> SortFileTimeAscendingHelper
...
<span class="hljs-keyword">End</span> Class
Public <span class="hljs-keyword">Class</span> UrlHistoryWrapperClass
<span class="hljs-keyword">Public</span> <span class="hljs-keyword">Class</span> STATURLEnumerator
...
<span class="hljs-keyword">End</span> Class
End <span class="hljs-keyword">Class</span>
Das API soll an dieser Stelle nur grundlegend beschrieben werden, ehe dann die praktische Verwendung gezeigt wird. Weiterführende Informationen entnehmen Sie bei Bedarf bitte dem Windows-API. Im ersten Schritt wird die Enumeration STATURL_QUERYFLAGS definiert, über die der Enumerationsdatentyp für die QueryUrl-API-Funktion sowie der Parameter dwFlags bestimmt werden:
<span class="hljs-keyword">Public</span> <span class="hljs-keyword">Enum</span> STATURL_QUERYFLAGS <span class="hljs-keyword">As</span> <span class="hljs-built_in">UInteger</span>
STATURL_QUERYFLAG_ISCACHED = &H10000
STATURL_QUERYFLAG_NOURL = &H20000
STATURL_QUERYFLAG_NOTITLE = &H40000
STATURL_QUERYFLAG_TOPLEVEL = &H80000
End <span class="hljs-keyword">Enum</span>
Die dwFlags-Parameter der Datenstruktur STATURL und die SetFilter-Methode werden über die Enumeration STATURLFLAGS definiert.
<span class="hljs-keyword">Public</span> <span class="hljs-keyword">Enum</span> STATURLFLAGS <span class="hljs-keyword">As</span> <span class="hljs-built_in">UInteger</span>
STATURLFLAG_ISCACHED = &H1
STATURLFLAG_ISTOPLEVEL = &H2
End <span class="hljs-keyword">Enum</span>
Entsprechend werden die Flags für die Methode AddHistoryEntry über die Enumeration ADDURL_FLAG definiert.
<span class="hljs-keyword">Public</span> <span class="hljs-keyword">Enum</span> ADDURL_FLAG <span class="hljs-keyword">As</span> <span class="hljs-built_in">UInteger</span>
ADDURL_ADDTOHISTORYANDCACHE = <span class="hljs-number">0</span>
ADDURL_ADDTOCACHE = <span class="hljs-number">1</span>
<span class="hljs-keyword">End</span> <span class="hljs-keyword">Enum</span>
Alle URL-Statistikinformationen (URL, Titel, Datum zum letzten Besuch, Datum zur letzten Aktualisierung, Verfallsdatum, Flags) werden über die Datenstruktur STATURL zusammengefasst. Die COM-Informationen werden dabei über MarshallAs-Attribute angepasst. Intern verwaltet die Datums- und Zeitinformationen der Typ ComTypes.FILETIME. Alle Daten sind öffentlich deklariert, da öffentliche Eigenschaften den Datenzugriff unter .NET mit .NET-spezifischen Rückgabewerten erleichtern. Über die öffentliche und nur lesbare Eigenschaft URL kann ein URL im Zeichenkettenformat abgefragt werden. Die Eigenschaft Title liefert den Titel, LastVisited das Datum des letzten Besuchs im .NET-Date-Format, LastUpdated das Datum der letzten Aktualisierung (.NET-Date-Format) und die Eigenschaft Expires das Verfallsdatum (.NET-Date-Format), siehe Listing 1.
Listing 1: Datenstruktur für Windows-URL-Informationen
&lt;StructLayout(LayoutKind.Sequential)&gt;<br/><span class="hljs-keyword">Public</span> <span class="hljs-keyword">Structure</span> STATURL<br/> <span class="hljs-keyword">Public</span> cbSize <span class="hljs-keyword">As</span> <span class="hljs-built_in">Integer</span><br/> &lt;MarshalAs(UnmanagedType.LPWStr)&gt;<br/> <span class="hljs-keyword">Public</span> pwcsUrl <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span><br/> &lt;MarshalAs(UnmanagedType.LPWStr)&gt;<br/> <span class="hljs-keyword">Public</span> pwcsTitle <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span><br/> <span class="hljs-keyword">Public</span> ftLastVisited <span class="hljs-keyword">As</span> ComTypes.FILETIME<br/> <span class="hljs-keyword">Public</span> ftLastUpdated <span class="hljs-keyword">As</span> ComTypes.FILETIME<br/> <span class="hljs-keyword">Public</span> ftExpires <span class="hljs-keyword">As</span> ComTypes.FILETIME<br/> <span class="hljs-keyword">Public</span> dwFlags <span class="hljs-keyword">As</span> STATURLFLAGS<br/> <span class="hljs-keyword">Public</span> <span class="hljs-keyword">ReadOnly</span> <span class="hljs-keyword">Property</span> URL <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span><br/> <span class="hljs-keyword">Get</span><br/> <span class="hljs-keyword">Return</span> pwcsUrl<br/> <span class="hljs-keyword">End</span> <span class="hljs-keyword">Get</span><br/> <span class="hljs-keyword">End</span> <span class="hljs-keyword">Property</span><br/> <span class="hljs-keyword">Public</span> <span class="hljs-keyword">ReadOnly</span> <span class="hljs-keyword">Property</span> Title <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span><br/> <span class="hljs-keyword">Get</span><br/> <span class="hljs-keyword">If</span> pwcsUrl.StartsWith(<span class="hljs-string">"file:"</span>) <span class="hljs-keyword">Then</span><br/> <span class="hljs-keyword">Return</span> CannonializeURL(pwcsUrl, <br/> shlwapi_URL.URL_UNESCAPE)<br/> .Substring(<span class="hljs-number">8</span>).Replace(<span class="hljs-string">"/"</span>c, <span class="hljs-string">"\"</span>c)<br/> <span class="hljs-keyword">Else</span><br/> <span class="hljs-keyword">Return</span> pwcsTitle<br/> <span class="hljs-keyword">End</span> <span class="hljs-keyword">If</span><br/> <span class="hljs-keyword">End</span> <span class="hljs-keyword">Get</span><br/> <span class="hljs-keyword">End</span> <span class="hljs-keyword">Property</span><br/> <span class="hljs-keyword">Public</span> <span class="hljs-keyword">ReadOnly</span> <span class="hljs-keyword">Property</span> LastVisited <span class="hljs-keyword">As</span> <span class="hljs-built_in">Date</span><br/> <span class="hljs-keyword">Get</span><br/> <span class="hljs-keyword">Return</span> FileTimeToDateTime(<br/> ftLastVisited).ToLocalTime()<br/> <span class="hljs-keyword">End</span> <span class="hljs-keyword">Get</span><br/> <span class="hljs-keyword">End</span> <span class="hljs-keyword">Property</span><br/> <span class="hljs-keyword">Public</span> <span class="hljs-keyword">ReadOnly</span> <span class="hljs-keyword">Property</span> LastUpdated <span class="hljs-keyword">As</span> <span class="hljs-built_in">Date</span><br/> <span class="hljs-keyword">Get</span><br/> <span class="hljs-keyword">Return</span> FileTimeToDateTime(<br/> ftLastUpdated).ToLocalTime()<br/> <span class="hljs-keyword">End</span> <span class="hljs-keyword">Get</span><br/> <span class="hljs-keyword">End</span> <span class="hljs-keyword">Property</span><br/> <span class="hljs-keyword">Public</span> <span class="hljs-keyword">ReadOnly</span> <span class="hljs-keyword">Property</span> Expires <span class="hljs-keyword">As</span> <span class="hljs-built_in">Date</span><br/> <span class="hljs-keyword">Get</span><br/> <span class="hljs-keyword">Try</span><br/> <span class="hljs-keyword">Return</span> FileTimeToDateTime(<br/> ftExpires).ToLocalTime()<br/> <span class="hljs-keyword">Catch</span> __unusedException1__ <span class="hljs-keyword">As</span> Exception<br/> <span class="hljs-keyword">Return</span> <span class="hljs-built_in">Date</span>.Now<br/> <span class="hljs-keyword">End</span> <span class="hljs-keyword">Try</span><br/> <span class="hljs-keyword">End</span> <span class="hljs-keyword">Get</span><br/> <span class="hljs-keyword">End</span> Property<br/>End <span class="hljs-keyword">Structure</span><br/>&lt;StructLayout(LayoutKind.Sequential)&gt;<br/> <span class="hljs-keyword">Public</span> <span class="hljs-keyword">Structure</span> UUID<br/> <span class="hljs-keyword">Public</span> Data1 <span class="hljs-keyword">As</span> <span class="hljs-built_in">Integer</span><br/> <span class="hljs-keyword">Public</span> Data2 <span class="hljs-keyword">As</span> <span class="hljs-built_in">Short</span><br/> <span class="hljs-keyword">Public</span> Data3 <span class="hljs-keyword">As</span> <span class="hljs-built_in">Short</span><br/> <span class="hljs-keyword">Public</span> Data4 <span class="hljs-keyword">As</span> <span class="hljs-built_in">Byte</span>()<br/><span class="hljs-keyword">End</span> <span class="hljs-keyword">Structure</span>
Um die Verlaufsdaten auszulesen, muss der Zugriff auf diverse COM-Schnittstellen sichergestellt werden. Die hierfür erforderlichen Deklarationen in der Syntax von VB.NET sind in Listing 2 zusammengestellt. Die Anbindung erfolgt über das Attribut ComImport und den Interface-Typ ComInterfaceType.InterfaceIsIUnknown.
Listing 2: Deklarationen zum Anbinden von COM-Schnittstellen
&lt;ComImport&gt;<br/>&lt;InterfaceType(ComInterfaceType.InterfaceIsIUnknown)&gt;<br/>&lt;Guid(<span class="hljs-string">"3C374A42-BAE4-11CF-BF7D-00AA006946EE"</span>)&gt;<br/><span class="hljs-keyword">Public</span> <span class="hljs-keyword">Interface</span> IEnumSTATURL<br/> <span class="hljs-keyword">Sub</span> [<span class="hljs-keyword">Next</span>](<span class="hljs-keyword">ByVal</span> celt <span class="hljs-keyword">As</span> <span class="hljs-built_in">Integer</span>, <br/> <span class="hljs-keyword">ByRef</span> rgelt <span class="hljs-keyword">As</span> STATURL, <br/> &lt;Out&gt; <span class="hljs-keyword">ByRef</span> pceltFetched <span class="hljs-keyword">As</span> <span class="hljs-built_in">Integer</span>)<br/> <span class="hljs-keyword">Sub</span> <span class="hljs-keyword">Skip</span>(<span class="hljs-keyword">ByVal</span> celt <span class="hljs-keyword">As</span> <span class="hljs-built_in">Integer</span>)<br/> <span class="hljs-keyword">Sub</span> Reset()<br/> <span class="hljs-keyword">Sub</span> Clone(&lt;Out&gt; <span class="hljs-keyword">ByRef</span> ppenum <span class="hljs-keyword">As</span> IEnumSTATURL)<br/> <span class="hljs-keyword">Sub</span> SetFilter(&lt;MarshalAs(UnmanagedType.LPWStr)&gt; <br/> <span class="hljs-keyword">ByVal</span> poszFilter <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span>, <br/> <span class="hljs-keyword">ByVal</span> dwFlags <span class="hljs-keyword">As</span> STATURLFLAGS)<br/><span class="hljs-keyword">End</span> <span class="hljs-keyword">Interface</span><br/>&lt;ComImport&gt;<br/>&lt;InterfaceType(ComInterfaceType.InterfaceIsIUnknown)&gt;<br/>&lt;Guid(<span class="hljs-string">"3C374A41-BAE4-11CF-BF7D-00AA006946EE"</span>)&gt;<br/><span class="hljs-keyword">Public</span> <span class="hljs-keyword">Interface</span> IUrlHistoryStg<br/> <span class="hljs-keyword">Sub</span> AddUrl(<span class="hljs-keyword">ByVal</span> pocsUrl <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span>, <br/> <span class="hljs-keyword">ByVal</span> pocsTitle <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span>, <br/> <span class="hljs-keyword">ByVal</span> dwFlags <span class="hljs-keyword">As</span> ADDURL_FLAG)<br/> <span class="hljs-keyword">Sub</span> DeleteUrl(<span class="hljs-keyword">ByVal</span> pocsUrl <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span>, <br/> <span class="hljs-keyword">ByVal</span> dwFlags <span class="hljs-keyword">As</span> <span class="hljs-built_in">Integer</span>)<br/> <span class="hljs-keyword">Sub</span> QueryUrl(&lt;MarshalAs(UnmanagedType.LPWStr)&gt; <br/> <span class="hljs-keyword">ByVal</span> pocsUrl <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span>, <br/> <span class="hljs-keyword">ByVal</span> dwFlags <span class="hljs-keyword">As</span> STATURL_QUERYFLAGS, <br/> <span class="hljs-keyword">ByRef</span> lpSTATURL <span class="hljs-keyword">As</span> STATURL)<br/> <span class="hljs-keyword">Sub</span> BindToObject(&lt;[<span class="hljs-keyword">In</span>]&gt; <span class="hljs-keyword">ByVal</span> pocsUrl <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span>, <br/> &lt;[<span class="hljs-keyword">In</span>]&gt; <span class="hljs-keyword">ByVal</span> riid <span class="hljs-keyword">As</span> UUID, <span class="hljs-keyword">ByVal</span> ppvOut <span class="hljs-keyword">As</span> IntPtr)<br/> <span class="hljs-keyword">ReadOnly</span> <span class="hljs-keyword">Property</span> EnumUrls <span class="hljs-keyword">As</span> Object<br/>End <span class="hljs-keyword">Interface</span><br/>&lt;ComImport&gt;<br/>&lt;InterfaceType(ComInterfaceType.InterfaceIsIUnknown)&gt;<br/>&lt;Guid(<span class="hljs-string">"AFA0DC11-C313-11D0-831A-00C04FD5AE38"</span>)&gt;<br/><span class="hljs-keyword">Public</span> <span class="hljs-keyword">Interface</span> IUrlHistoryStg2<br/> <span class="hljs-keyword">Inherits</span> IUrlHistoryStg<br/> <span class="hljs-keyword">Overloads</span> <span class="hljs-keyword">Sub</span> AddUrl(<span class="hljs-keyword">ByVal</span> pocsUrl <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span>, <br/> <span class="hljs-keyword">ByVal</span> pocsTitle <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span>, <br/> <span class="hljs-keyword">ByVal</span> dwFlags <span class="hljs-keyword">As</span> ADDURL_FLAG)<br/> <span class="hljs-keyword">Overloads</span> <span class="hljs-keyword">Sub</span> DeleteUrl(<span class="hljs-keyword">ByVal</span> pocsUrl <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span>, <br/> <span class="hljs-keyword">ByVal</span> dwFlags <span class="hljs-keyword">As</span> <span class="hljs-built_in">Integer</span>)<br/> <span class="hljs-keyword">Overloads</span> <span class="hljs-keyword">Sub</span> QueryUrl(<br/> &lt;MarshalAs(UnmanagedType.LPWStr)&gt; <br/> <span class="hljs-keyword">ByVal</span> pocsUrl <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span>,<br/> <span class="hljs-keyword">ByVal</span> dwFlags <span class="hljs-keyword">As</span> STATURL_QUERYFLAGS, <br/> <span class="hljs-keyword">ByRef</span> lpSTATURL <span class="hljs-keyword">As</span> STATURL)<br/> <span class="hljs-keyword">Overloads</span> <span class="hljs-keyword">Sub</span> BindToObject(&lt;[<span class="hljs-keyword">In</span>]&gt; <br/> <span class="hljs-keyword">ByVal</span> pocsUrl <span class="hljs-keyword">As</span> <span class="hljs-built_in">String</span>, &lt;[<span class="hljs-keyword">In</span>]&gt; <span class="hljs-keyword">ByVal</span> riid <span class="hljs-keyword">As</span> <br/> UUID, <span class="hljs-keyword">ByVal</span> ppvOut <span class="hljs-keyword">As</span> IntPtr)<br/> <span class="hljs-keyword">Overloads</span> <span class="hljs-keyword">ReadOnly</span> <span class="hljs-keyword">Property</span> EnumUrls <span class="hljs-keyword">As</span> <br/> Win32api.IEnumSTATURL <span class="hljs-comment">'Typ 'Object' durch </span><br/><span class="hljs-comment"> ' Enumerationsdatentyp ersetzt </span><br/><span class="hljs-comment"> Sub AddUrlAndNotify(ByVal pocsUrl As String, </span><br/><span class="hljs-comment"> ByVal pocsTitle As String, ByVal dwFlags As </span><br/><span class="hljs-comment"> Integer, ByVal fWriteHistory As Integer, </span><br/><span class="hljs-comment"> ByVal poctNotify As Object, </span><br/><span class="hljs-comment"> ByVal punkISFolder As Object)</span><br/><span class="hljs-comment"> Sub ClearHistory()</span><br/><span class="hljs-comment">End Interface</span><br/><span class="hljs-comment"><span class="hljs-doctag">&lt;ComImport&gt;</span></span><br/><span class="hljs-comment"><span class="hljs-doctag">&lt;Guid("3C374A40-BAE4-11CF-BF7D-00AA006946EE")&gt;</span></span><br/><span class="hljs-comment">Public Class UrlHistoryClass</span><br/><span class="hljs-comment">End Class</span>
Zusätzlich wird eine eindeutige schnittstellenspezifische GUID angegeben. Jedes Interface wird in einen Public Interface- und End Interface-Block eingefasst, der seinerseits die Methoden des jeweiligen Interfaces mitsamt den zugehörigen Aufrufparametern und deren Datentypen definiert. Das Interface IEnumSTATURL enumeriert die zwischengespeicherten URLs (Cached URLs). Das Interface IUrlHistoryStg verwaltet die URL-Einträge für den jeweils aktiven Benutzer.Das Interface IUrlHistoryStg2 bietet die Grundfunktionen des Interfaces IUrlHistoryStg sowie erweiterte Funktionen für die URL-Verwaltung des aktiven Benutzers (zum Beispiel Verlaufsdaten löschen, URL mit Benachrichtigung ergänzen). Abschließend wird die COM-Klasse UrlHistoryClass unter Angabe der zugehörigen GUID importiert.So viel für diesmal. In der kommenden Folge dieser Serie lernen Sie unter anderem die Klasse SortFileTimeAscendingHelper kennen, welche die Schnittstelle IComparer implementiert und zum Sortieren von Dateilisten nach Datum und Uhrzeit taugt.
Fussnoten
- Andreas Maslo, History Control, dotnetpro 6/2023, Seite 136 ff., http://www.dotnetpro.de/A2306BasicInstinct
- Andreas Maslo, MRU-Programme ermitteln, dotnetpro 12/2023, Seite 136 ff., http://www.dotnetpro.de/A2312BasicInstinct
- Shellbag Analyzer & Cleaner, http://www.dotnetpro.de/SL2401BasicInstinct1
- Windows ShellBag Forensics in Depth, http://www.dotnetpro.de/SL2401BasicInstinct2
- MS Learn, IUrlHistory, http://www.dotnetpro.de/SL2401BasicInstinct3
- Beispielprojekt auf CodeProject, http://www.dotnetpro.de/SL2401BasicInstinct4
- Shellbags Explorer und SBECmd, http://www.dotnetpro.de/SL2401BasicInstinct5
- NirSoft ShellBagsView, http://www.dotnetpro.de/SL2401BasicInstinct6