Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 6 Min.

Windows-Explorer-History

Auch der Windows Explorer speichert Verlaufsdaten, die man auslesen kann.
© dotnetpro
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:

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

Programm Beschreibung
Shellbag Analyzer & Cleaner [3] Shellbags über ein Programm mit grafischer Benutzeroberfläche auslesen, exportieren und bereinigen.
ShellBags Explorer [7] Der Shellbags Explorer von Eric Zimmerman ist ein weiteres Shellbag-Analyse-Tool mit grafischer Benutzeroberfläche.
SBECmd [7] Shellbags-Analyse-Tool für die Kommandozeile von Eric Zimmerman (Open Source).
ShellBagsView [8] Der ShellBags-Viewer von NirSoft hat eine grafische Benutzeroberfläche, kann aber auch über Kommandozeilenschalter gesteuert werden.
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, SortFileTime­AscendingHelper, UrlHistoryWrapperClass und UrlHistory­Class. 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 Enumera­tion STATURL_QUERY­FLAGS definiert, über die der Enumera­tionsdatentyp 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 = &amp;H10000
  STATURL_QUERYFLAG_NOURL = &amp;H20000
  STATURL_QUERYFLAG_NOTITLE = &amp;H40000
  STATURL_QUERYFLAG_TOPLEVEL = &amp;H80000
End <span class="hljs-keyword">Enum</span> 
Die dwFlags-Parameter der Datenstruktur STAT­URL 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 = &amp;H1
  STATURLFLAG_ISTOPLEVEL = &amp;H2
End <span class="hljs-keyword">Enum</span> 
Entsprechend werden die Flags für die Methode AddHistory­Entry ü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
&amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt;&lt;br/&gt;&lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Structure&lt;/span&gt; STATURL&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; cbSize &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Integer&lt;/span&gt;&lt;br/&gt;  &amp;lt;MarshalAs(UnmanagedType.LPWStr)&amp;gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; pwcsUrl &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;&lt;br/&gt;  &amp;lt;MarshalAs(UnmanagedType.LPWStr)&amp;gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; pwcsTitle &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; ftLastVisited &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; ComTypes.FILETIME&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; ftLastUpdated &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; ComTypes.FILETIME&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; ftExpires &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; ComTypes.FILETIME&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; dwFlags &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; STATURLFLAGS&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;ReadOnly&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Property&lt;/span&gt; URL &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;&lt;br/&gt;    &lt;span class="hljs-keyword"&gt;Get&lt;/span&gt;&lt;br/&gt;      &lt;span class="hljs-keyword"&gt;Return&lt;/span&gt; pwcsUrl&lt;br/&gt;    &lt;span class="hljs-keyword"&gt;End&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Get&lt;/span&gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;End&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Property&lt;/span&gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;ReadOnly&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Property&lt;/span&gt; Title &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;&lt;br/&gt;    &lt;span class="hljs-keyword"&gt;Get&lt;/span&gt;&lt;br/&gt;      &lt;span class="hljs-keyword"&gt;If&lt;/span&gt; pwcsUrl.StartsWith(&lt;span class="hljs-string"&gt;"file:"&lt;/span&gt;) &lt;span class="hljs-keyword"&gt;Then&lt;/span&gt;&lt;br/&gt;        &lt;span class="hljs-keyword"&gt;Return&lt;/span&gt; CannonializeURL(pwcsUrl, &lt;br/&gt;          shlwapi_URL.URL_UNESCAPE)&lt;br/&gt;          .Substring(&lt;span class="hljs-number"&gt;8&lt;/span&gt;).Replace(&lt;span class="hljs-string"&gt;"/"&lt;/span&gt;c, &lt;span class="hljs-string"&gt;"\"&lt;/span&gt;c)&lt;br/&gt;      &lt;span class="hljs-keyword"&gt;Else&lt;/span&gt;&lt;br/&gt;        &lt;span class="hljs-keyword"&gt;Return&lt;/span&gt; pwcsTitle&lt;br/&gt;      &lt;span class="hljs-keyword"&gt;End&lt;/span&gt; &lt;span class="hljs-keyword"&gt;If&lt;/span&gt;&lt;br/&gt;    &lt;span class="hljs-keyword"&gt;End&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Get&lt;/span&gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;End&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Property&lt;/span&gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;ReadOnly&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Property&lt;/span&gt; LastVisited &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Date&lt;/span&gt;&lt;br/&gt;    &lt;span class="hljs-keyword"&gt;Get&lt;/span&gt;&lt;br/&gt;      &lt;span class="hljs-keyword"&gt;Return&lt;/span&gt; FileTimeToDateTime(&lt;br/&gt;        ftLastVisited).ToLocalTime()&lt;br/&gt;    &lt;span class="hljs-keyword"&gt;End&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Get&lt;/span&gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;End&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Property&lt;/span&gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;ReadOnly&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Property&lt;/span&gt; LastUpdated &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Date&lt;/span&gt;&lt;br/&gt;    &lt;span class="hljs-keyword"&gt;Get&lt;/span&gt;&lt;br/&gt;      &lt;span class="hljs-keyword"&gt;Return&lt;/span&gt; FileTimeToDateTime(&lt;br/&gt;        ftLastUpdated).ToLocalTime()&lt;br/&gt;    &lt;span class="hljs-keyword"&gt;End&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Get&lt;/span&gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;End&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Property&lt;/span&gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;ReadOnly&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Property&lt;/span&gt; Expires &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Date&lt;/span&gt;&lt;br/&gt;    &lt;span class="hljs-keyword"&gt;Get&lt;/span&gt;&lt;br/&gt;      &lt;span class="hljs-keyword"&gt;Try&lt;/span&gt;&lt;br/&gt;        &lt;span class="hljs-keyword"&gt;Return&lt;/span&gt; FileTimeToDateTime(&lt;br/&gt;          ftExpires).ToLocalTime()&lt;br/&gt;      &lt;span class="hljs-keyword"&gt;Catch&lt;/span&gt; __unusedException1__ &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; Exception&lt;br/&gt;        &lt;span class="hljs-keyword"&gt;Return&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Date&lt;/span&gt;.Now&lt;br/&gt;      &lt;span class="hljs-keyword"&gt;End&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Try&lt;/span&gt;&lt;br/&gt;    &lt;span class="hljs-keyword"&gt;End&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Get&lt;/span&gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;End&lt;/span&gt; Property&lt;br/&gt;End &lt;span class="hljs-keyword"&gt;Structure&lt;/span&gt;&lt;br/&gt;&amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Structure&lt;/span&gt; UUID&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; Data1 &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Integer&lt;/span&gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; Data2 &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Short&lt;/span&gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; Data3 &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Short&lt;/span&gt;&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; Data4 &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Byte&lt;/span&gt;()&lt;br/&gt;&lt;span class="hljs-keyword"&gt;End&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Structure&lt;/span&gt; 
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
&amp;lt;ComImport&amp;gt;&lt;br/&gt;&amp;lt;InterfaceType(ComInterfaceType.InterfaceIsIUnknown)&amp;gt;&lt;br/&gt;&amp;lt;Guid(&lt;span class="hljs-string"&gt;"3C374A42-BAE4-11CF-BF7D-00AA006946EE"&lt;/span&gt;)&amp;gt;&lt;br/&gt;&lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Interface&lt;/span&gt; IEnumSTATURL&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Sub&lt;/span&gt; [&lt;span class="hljs-keyword"&gt;Next&lt;/span&gt;](&lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; celt &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Integer&lt;/span&gt;, &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByRef&lt;/span&gt; rgelt &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; STATURL, &lt;br/&gt;    &amp;lt;Out&amp;gt; &lt;span class="hljs-keyword"&gt;ByRef&lt;/span&gt; pceltFetched &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Integer&lt;/span&gt;)&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Sub&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Skip&lt;/span&gt;(&lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; celt &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Integer&lt;/span&gt;)&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Sub&lt;/span&gt; Reset()&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Sub&lt;/span&gt; Clone(&amp;lt;Out&amp;gt; &lt;span class="hljs-keyword"&gt;ByRef&lt;/span&gt; ppenum &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; IEnumSTATURL)&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Sub&lt;/span&gt; SetFilter(&amp;lt;MarshalAs(UnmanagedType.LPWStr)&amp;gt; &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; poszFilter &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;, &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; dwFlags &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; STATURLFLAGS)&lt;br/&gt;&lt;span class="hljs-keyword"&gt;End&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Interface&lt;/span&gt;&lt;br/&gt;&amp;lt;ComImport&amp;gt;&lt;br/&gt;&amp;lt;InterfaceType(ComInterfaceType.InterfaceIsIUnknown)&amp;gt;&lt;br/&gt;&amp;lt;Guid(&lt;span class="hljs-string"&gt;"3C374A41-BAE4-11CF-BF7D-00AA006946EE"&lt;/span&gt;)&amp;gt;&lt;br/&gt;&lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Interface&lt;/span&gt; IUrlHistoryStg&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Sub&lt;/span&gt; AddUrl(&lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; pocsUrl &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;, &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; pocsTitle &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;, &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; dwFlags &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; ADDURL_FLAG)&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Sub&lt;/span&gt; DeleteUrl(&lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; pocsUrl &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;, &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; dwFlags &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Integer&lt;/span&gt;)&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Sub&lt;/span&gt; QueryUrl(&amp;lt;MarshalAs(UnmanagedType.LPWStr)&amp;gt; &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; pocsUrl &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;, &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; dwFlags &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; STATURL_QUERYFLAGS, &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByRef&lt;/span&gt; lpSTATURL &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; STATURL)&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Sub&lt;/span&gt; BindToObject(&amp;lt;[&lt;span class="hljs-keyword"&gt;In&lt;/span&gt;]&amp;gt; &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; pocsUrl &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;, &lt;br/&gt;    &amp;lt;[&lt;span class="hljs-keyword"&gt;In&lt;/span&gt;]&amp;gt; &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; riid &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; UUID, &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; ppvOut &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; IntPtr)&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;ReadOnly&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Property&lt;/span&gt; EnumUrls &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; Object&lt;br/&gt;End &lt;span class="hljs-keyword"&gt;Interface&lt;/span&gt;&lt;br/&gt;&amp;lt;ComImport&amp;gt;&lt;br/&gt;&amp;lt;InterfaceType(ComInterfaceType.InterfaceIsIUnknown)&amp;gt;&lt;br/&gt;&amp;lt;Guid(&lt;span class="hljs-string"&gt;"AFA0DC11-C313-11D0-831A-00C04FD5AE38"&lt;/span&gt;)&amp;gt;&lt;br/&gt;&lt;span class="hljs-keyword"&gt;Public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Interface&lt;/span&gt; IUrlHistoryStg2&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Inherits&lt;/span&gt; IUrlHistoryStg&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Overloads&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Sub&lt;/span&gt; AddUrl(&lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; pocsUrl &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;, &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; pocsTitle &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;, &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; dwFlags &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; ADDURL_FLAG)&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Overloads&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Sub&lt;/span&gt; DeleteUrl(&lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; pocsUrl &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;, &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; dwFlags &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;Integer&lt;/span&gt;)&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Overloads&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Sub&lt;/span&gt; QueryUrl(&lt;br/&gt;    &amp;lt;MarshalAs(UnmanagedType.LPWStr)&amp;gt; &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; pocsUrl &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;,&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; dwFlags &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; STATURL_QUERYFLAGS, &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByRef&lt;/span&gt; lpSTATURL &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; STATURL)&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Overloads&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Sub&lt;/span&gt; BindToObject(&amp;lt;[&lt;span class="hljs-keyword"&gt;In&lt;/span&gt;]&amp;gt; &lt;br/&gt;    &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; pocsUrl &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;, &amp;lt;[&lt;span class="hljs-keyword"&gt;In&lt;/span&gt;]&amp;gt; &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; riid &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;br/&gt;    UUID, &lt;span class="hljs-keyword"&gt;ByVal&lt;/span&gt; ppvOut &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; IntPtr)&lt;br/&gt;  &lt;span class="hljs-keyword"&gt;Overloads&lt;/span&gt; &lt;span class="hljs-keyword"&gt;ReadOnly&lt;/span&gt; &lt;span class="hljs-keyword"&gt;Property&lt;/span&gt; EnumUrls &lt;span class="hljs-keyword"&gt;As&lt;/span&gt; &lt;br/&gt;    Win32api.IEnumSTATURL &lt;span class="hljs-comment"&gt;'Typ 'Object' durch &lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;    ' Enumerationsdatentyp ersetzt &lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;  Sub AddUrlAndNotify(ByVal pocsUrl As String, &lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;    ByVal pocsTitle As String, ByVal dwFlags As &lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;    Integer, ByVal fWriteHistory As Integer, &lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;    ByVal poctNotify As Object, &lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;    ByVal punkISFolder As Object)&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;  Sub ClearHistory()&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;End Interface&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;&lt;span class="hljs-doctag"&gt;&amp;lt;ComImport&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;&lt;span class="hljs-doctag"&gt;&amp;lt;Guid("3C374A40-BAE4-11CF-BF7D-00AA006946EE")&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;Public Class UrlHistoryClass&lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-comment"&gt;End Class&lt;/span&gt; 
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.
Projektdateien herunterladen

Fussnoten

  1. Andreas Maslo, History Control, dotnetpro 6/2023, Seite 136 ff., http://www.dotnetpro.de/A2306BasicInstinct
  2. Andreas Maslo, MRU-Programme ermitteln, dotnetpro 12/2023, Seite 136 ff., http://www.dotnetpro.de/A2312BasicInstinct
  3. Shellbag Analyzer & Cleaner, http://www.dotnetpro.de/SL2401BasicInstinct1
  4. Windows ShellBag Forensics in Depth, http://www.dotnetpro.de/SL2401BasicInstinct2
  5. MS Learn, IUrlHistory, http://www.dotnetpro.de/SL2401BasicInstinct3
  6. Beispielprojekt auf CodeProject, http://www.dotnetpro.de/SL2401BasicInstinct4
  7. Shellbags Explorer und SBECmd, http://www.dotnetpro.de/SL2401BasicInstinct5
  8. NirSoft ShellBagsView, http://www.dotnetpro.de/SL2401BasicInstinct6

Neueste Beiträge

DWX hakt nach: Wie stellt man Daten besonders lesbar dar?
Dass das Design von Websites maßgeblich für die Lesbarkeit der Inhalte verantwortlich ist, ist klar. Das gleiche gilt aber auch für die Aufbereitung von Daten für Berichte. Worauf besonders zu achten ist, erklären Dr. Ina Humpert und Dr. Julia Norget.
3 Minuten
27. Jun 2025
DWX hakt nach: Wie gestaltet man intuitive User Experiences?
DWX hakt nach: Wie gestaltet man intuitive User Experiences? Intuitive Bedienbarkeit klingt gut – doch wie gelingt sie in der Praxis? UX-Expertin Vicky Pirker verrät auf der Developer Week, worauf es wirklich ankommt. Hier gibt sie vorab einen Einblick in ihre Session.
4 Minuten
27. Jun 2025
„Sieh die KI als Juniorentwickler“
CTO Christian Weyer fühlt sich jung wie schon lange nicht mehr. Woran das liegt und warum er keine Angst um seinen Job hat, erzählt er im dotnetpro-Interview.
15 Minuten
27. Jun 2025
Miscellaneous

Das könnte Dich auch interessieren

UIs für Linux - Bedienoberflächen entwickeln mithilfe von C#, .NET und Avalonia
Es gibt viele UI-Frameworks für .NET, doch nur sehr wenige davon unterstützen Linux. Avalonia schafft als etabliertes Open-Source-Projekt Abhilfe.
16 Minuten
16. Jun 2025
Mythos Motivation - Teamentwicklung
Entwickler bringen Arbeitsfreude und Engagement meist schon von Haus aus mit. Diesen inneren Antrieb zu erhalten sollte für Führungskräfte im Fokus stehen.
13 Minuten
19. Jan 2017
Evolutionäres Prototyping von Business-Apps - Low Code/No Code und KI mit Power Apps
Microsoft baut Power Apps zunehmend mit Features aus, um die Low-Code-/No-Code-Welt mit der KI und der professionellen Programmierung zu verbinden.
19 Minuten
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige