Promit Roy hat gestern eine erste Version seines .Net-Profilers SlimTune veröffentlicht. Das Tool unterstützt .Net >2.0, Remote Profiling, Real-Time Resultate und zwei Darstellungsmöglichkeiten, die sich an den Programmen dotTrace und NProf orientieren.
In diesem kleinen Tutorial zum Windows API Code Pack werden wir uns näher mit den Shell-Interfaces zu Ordnern und Dateien in der Windows API auseinandersetzen.
Der grobe Aufbau der betreffenden Klassen im Windows API Code Pack schaut folgendermaßen aus:
Wichtig für das Tutorial sind eigentlich nur ShellFileSystemFolder für die Ordner und ShellFile für die Dateien. ShellLibrary haben wir bereits im vorherigen Tutorial verwendet.
Eigenschaften
Zugriff auf die Eigenschaften einer Datei oder eines Ordners ermöglicht die Properties-Eigenschaft des ShellObjects. Unter System finden sich alle möglichen Eigenschaften, die eine Datei besitzen kann, der Zugriff kann über zwei Varianten erfolgen:
// Entweder so:
var p = file.Properties.System.Title;
// Oder über den Namen der Eigenschaft:
var p2 = file.Properties.GetProperty<string>("System.Title");
Beide Male wird ein ShellProperty-Objekt zurückgeliefert. Den eigentlichen Inhalt der Dateieigenschaft erhalten wir schließlich über Value:
string title = file.Properties.System.Title.Value;
Darüber hinaus können wir uns natürlich auch mit LINQ bestimmte Dateien zurückliefern lassen. Um zum Beispiel um alle Dateien eines Ordners zu erhalten, die das Schlüsselwort bzw. die Markierung “Visual Studio 2010” enthalten genügt die folgende LINQ-Abfrage:
var files =
from f in ShellFileSystemFolder.FromFolderPath(@"C:\Folder\")
let k = f.Properties.System.Keywords.Value ?? Enumerable.Empty<string>()
where k.Contains("Visual Studio 2010")
select f;
foreach (var file in files)
Console.WriteLine(file.Name);
k enthält dabei entweder den String-Array von f.Properties.System.Keywords.Value, oder, falls die Eigenschaft bei der Datei nicht gesetzt wurde und null zurückgeliefert wird, eine leere String-Auflistung IEnumerable<string>.
Vorschaubilder
Das Windows API Code Pack bietet eine komfortable Möglichkeit auf die Vorschaubilder von Ordnern und Dateien, die man unter anderem vom Windows Explorer, zu zugreifen und das sowohl als System.Drawing.Bitmap, als auch als System.Windows.Media.Imaging.BitmapSource für WPF-Anwendungen. Die Einbindung in ein WPF-Image ist dementsprechend einfach.
Die Bilder stehen unter der Eigenschaft Thumbnail in den vier Größen Small, Medium, Large, ExtraLarge zur Verfügung.
<Image Source="{Binding Path=SelectedItem.Thumbnail.MediumBitmapSource}" />
Eine Verwendung in einer Anwendung könnte z. B. folgendermaßen ausschauen:
Mit dem neuen Betriebssystem Windows 7 hat Microsoft die Libraries eingeführt, die Dateien aus unterschiedlichen Ordnern zusammenfassen können.
Die Beschreibungen dieser Libraries liegen im Verzeichnis …\AppData\Roaming\Microsoft\Windows\
Libraries als XML-Dateien mit der Endung .ms-library
vor.
Für den Umgang mit den Libraries hat Microsoft der Windows Shell einige neue Interfaces spendiert. Damit .Net-Entwickler nicht leer ausgehen hat man darüberhinaus das Windows API Code Pack ins Leben gerufen, einen .Net-Wrapper, der neben den Windows 7-Neuerungen (Libraries, Jump Lists, etc.) auch DirectX 10.0/10.1/11.0, Direct2D, DirectWrite und zahlreiche andere APIs umfasst.
Arbeiten mit Libraries
Für den Einsatz der Libraries muss lediglich Microsoft.WindowsAPICodePack.Shell als Referenz zum Projekt hinzugefügt werden.
Dreh- und Angelpunkt ist die Klasse ShellLibrary, die alles nötige zum Erstellen, Laden und Bearbeiten von Libraries bereitstellt.
Libraries laden
Zum Laden steht die Load-Methode zur Verfügung, die entweder den Namen oder ein IKnownFolder-Objekt erwartet. Mehr zu Known Folders: http://msdn.microsoft.com/en-us/library/bb776911(VS.85).aspx. KnownFolders enthält eine Auflistung dieser besonderen Ordner, zu denen auch die 4 Standard-Libraries gehören. Um also die Video-Bibliothek zu laden, reicht folgende Zeile. Mit dem 2. Parameter können wir dabei festlegen, ob wir die Library verändern, z. B. neue Ordner hinzufügen oder alte entfernen, wollen.
ShellLibrary lib = ShellLibrary.Load(KnownFolders.VideosLibrary, true);
Libraries auslesen
Wir haben nun vollen Zugriff auf die Library und können z. B. alle Ordner der Library auslesen:
foreach (ShellFolder dir in lib)
Console.WriteLine(dir.ParsingName);
Libraries bearbeiten
Neben dem bloßen Auslesen können wir der Library auch neue Ordner spendieren, oder bisherige entfernen. Dabei ist zu beachten, dass die Library zuvor auch mit der entsprechenden Einstellung geladen werden musste. Der zweite Parameter der Load-Methode musste also den Wert false besitzen.
// Ordner hinzufügen
lib.Add("D:/test/");
// Ordner entfernen
lib.Remove("D:/test/");
Last but not least, lässt sich sogar der vom Explorer bekannte Dialog ins eigene Programm einbinden:
ShellLibrary.ShowManageLibraryUI(
lib.Name,
IntPtr.Zero,
"Hi there",
"Ok, let's add some stuff",
true
);
Mit dem ersten Parameter geben wir den Namen der Library an, mit der der Dialog hantieren soll, es folgt der Handler des Elternfensters, als drittes der Titel des Dialogs und schließlich der Beschreibungstext. Der Dialog liefert keinerlei Informationen über die vom Benutzer getätigten Änderungen zurück.
Libraries können für eine bestimmte Anzeige optimiert werden. Vier verschiedene stehen zur Auswahl: Dokumente, Musik, Bilder und Videos. Diese Anzeigeart lässt sich über die Eigenschaft LibraryType steuern:
lib.LibraryType = LibraryFolderType.Music;
Das Icon der Library lässt sich über IconResourceId ansprechen:
// Nutze das gleiche Icon wie die Musik-Library
lib.IconResourceId = new IconReference("imageres.dll", -1004);
Libraries erstellen
Für die Erstellung neuer Libraries kann man einfach auf den Konstruktor der ShellLibrary-Klasse zurückgreifen:
ShellLibrary test = new ShellLibrary("MyLib", false);
// Soll Musik enthalten
test.LibraryType = LibraryFolderType.Music;
Dateien auslesen
Um schließlich alle Dateien einer Library aufzulisten müssen wir uns eine eigene Methode schreiben, die alle Unterordner rekursiv durchläuft. In etwa so:
List<ShellFile> files = new List<ShellFile>();
foreach (ShellFolder dir in lib)
GetAllFiles(dir, files);
// ...
void GetAllFiles(ShellFolder parent, List<ShellFile> files)
{
foreach (ShellObject obj in parent)
{
// Check if it's a file
ShellFile file = obj as ShellFile;
if (file != null)
{
files.Add(file);
}
// Check if it is a folder
ShellFolder folder = obj as ShellFolder;
if (folder != null)
{
GetAllFiles(folder, files);
}
}
}
Ende
Fragen, Erweiterungsvorschläge, Kritik etc. können in den Kommentaren geäußert werden.
Vor zwei Tagen ist Version 1.0 des Windows API Code Pack for .Net erschienen. Damit stehen hoffentlich keine Bugs mehr meinem geplanten Tutorial über Windows 7 Libraries im Weg *yuchhe*.
Wie es sich für jeden zweitklassigen Blog gehört, hier die Auflistung der Neuerungen:
- Shell Search API Unterstützung
- Drag & Drop für Shell Objekte
- Direct3D und Direct2D Interoperabilität
- Typografie und Font Enumeration DirectWrite APIs
- Bugs fixes und Performanceverbesserungen