| |
| |
Immer wenn ich von Zeit zu Zeit Visual C# Express bemühe, um kleine
Tools zu basteln, die mir den einen oder anderen Vorgang auf meinem
PC erleichtern sollen, habe ich hin und wieder das Problem, an bestimmten
Stellen bei der Programmierung an banalen Kleinigkeiten hängen zu
bleiben. Soll heißen, ich durchforste dann wieder einmal sämtliche
Internetforen, Google bis zum umfallen und am Ende habe ich dann das
Problem global gelöst aber für die Lösung meines Problems war dann
doch nicht das Richtige dabei. Also selber ran, austesten und probieren
bis die ganze Sache passt. Warum also diese Seite ? Zum einen habe
ich hier für mich einen schnellen Überblick über Probleme aus der
Vergangenheit und was ich mir einmal notiert habe bleibt besser im
Gedächtnis. Andererseits, sollte sich irgend jemand auf diese Seite
verirren auf der Suche nach einer Lösung und diese hier finden, hat
sich der ganze Aufwand für mich schon mehr als gelohnt.
|
| |
| Ping abgeben und Ergebnis
auswerten |
|
Dieses Beispiel veranschaulicht eine einfache Vorgehensweise um zu
Prüfen, ob ein Remotehost existiert. Zuerst einmal, in welchem
Namespace versteckt sich die Ping Methode und anschließend Zugriff
auf diese.
using System.Net.NetworkInformation;
Ping myPing = new Ping();
Jetzt kann man einen Ping absetzen, muss diesen jedoch noch auswerten:
try
{
// hat mehrere Überladungen, steht alles in der Hilfe
PingReply testReply = myPing.Send([string hostname / ip],[int timeout]);
if (testReply.Status == IPStatus.Success) [ alles bestens ];
}
catch { [remotehost konnte nicht erreicht werden ] }
Das ganze in einen try-catch Block setzen, da bei nichterreichen des
Remotehosts ein Fehler generiert wird. Ein simples Beispiel, bei dem
nur die Verfügbarkeit eines Remotehosts geprüft wird. Das ganze lässt
sich natürlich noch beliebig verfeinern.
|
| Netzlaufwerk verbinden |
|
Zum Verbinden mit einem Netzlaufwerk gibt es zwei Lösungsansätze.
Einfach ein System.Diagnostics.Process.Start ausführen und über die
Shell in gewohnter Weise ein net use ... aufrufen. In meinen Augen
ist dies jedoch die unelegantere Methode. Ich verwende für dieses
Problem nachfolgendes Beispiel : zuerst einen Verweis einfügen
-> COM -> Windows Script Host Object Model Im Projektexplorer unter
Verweise sollte dann der Eintrag IWshRuntimeLibrary erscheinen.
using IWshRuntimeLibrary;
Jetzt erfolgen diverse Variablendeklarationen:
object updateProfile = true;
object username = null;
object password = null;
string localName = [der Laufwerksbuchstabe in der Form Z: ]
string remoteName = [der Netzwerkpfad wie etwa \\test\testshare]
Nun geht es zum eigentlichen Zugriff auf die IWshRuntimeLibrary.
WshNetwork myNet = new WshNetwork();
try
{
myNet.MapNetworkDrive(localName, remoteName, ref updateProfile, ref username, ref password);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Wenn alles geklappt hat sollte im Windows Dateiexplorer die Verbindung
sichtbar sein ( als kleine Kontrolle ). Bei Verbindungsproblemen erscheint
eine Messagebox mit der jeweiligen Fehlerbeschreibung.
|
| Netzlaufwerk trennen
|
|
Die gleichen Vorraussetzungen wie bei Netzlaufwerk verbinden. Zugriff
über IWshRuntimeLibrary
WshNetwork myNet = new WshNetwork();
string driveLetter = "[den Laufwerksbuchstaben]";
object force = true;
object updateProfile = true;
try
{
myNet.RemoveNetworkDrive(driveLetter, ref force, ref updateProfile);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Ist alles selbsterklärend, bei Fehler wieder Messagebox mit Fehlerbeschreibung.
|
| Combobox mit grafischer
Auswahlliste |
Warum eine grafische Auswahlliste ? Nun, ich hatte eine Liste von
IP-Adressen auf die ich mittels Combobox zugreifen wollte. Da diese
Adressen aus verschiedenen Ländern waren, suchte ich nach einer Möglichkeit,
dies farblich oder grafisch hervorzuheben. Also vor jede Adresse die
Landesfahne und so gehts :

Um die Auswahlliste im ComboBox Steuerelement so zu formatieren benutzt
man den DrawItem Handler. Es wird davon ausgegangen, das die ComboBox
bereits existiert. Zuerst einmal teilt man der ComboBox mit,
das man in sie zeichnen möchte:
ComboBox.DrawMode = DrawMode.OwnerDrawFixed;
Dann ein DrawItem Event Handler initialisieren:
ComboBox.DrawItem += new DrawItemEventHandler(ComboBox_DrawItem);
Dass ganze muss natürlich geschehen, bevor das Formular gezeichnet
wird also im Initialisierungsteil der Anwendung. Jetzt kann die ComboBox
mit Einträgen gefüllt werden entweder über den Designer oder .items.add().
Wenn keine Einträge vorhanden sind, ist auch später keine Grafik zu
sehen. Im Grunde liegen die Grafiken nur über der jeweiligen Auswahl.
Jetzt die dazu gehörige Methode:
private void ComboBox_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
Image[] myImage = new Image[30];
myImage[0] = Image.FromFile("flag_germany.gif");
...
myImage[29] = Image.FromFile("flag_usa.gif");
Um die Grafiken zu initialisieren gibt es sicherlich elegantere Methoden,
hier dient es jedoch nur zur Veranschaulichung.
Als nächstes
zeichnen wir die Flaggen:
e.Graphics.DrawImage(myImage[0], new Point(2, 2));
...
e.Graphics.DrawImage(myImage[29], new Point(2, 452));
Warum an erster Position 2,2 ? Meine Grafiken haben eine Höhe von
11 Punkten. Die ItemsHeight Eigenschaft der ComboBox ist 15. Um die
Grafik nun schön vertikal zentriert zu zeichnen, einfach zwei Punkte
ober und unterhalb freilassen. Jede weitere Grafik verschiebt sich
dann um 15 Punkte nach unten also 2, 17, 32 usw. Die 2 für den X-Wert,
damit die Grafik nicht ganz vorn am Menü klebt.
Jetzt den dazugehörigen
Eintrag:
e.Graphics.DrawString("192.168.0.1", this.Font, Brushes.Black, new Point(20, 2));
...
e.Graphics.DrawString("192.168.0.30", this.Font, Brushes.Black, new Point(20, 452));
}
Gleiche Vorgehensweise wie bei DrawImage, nur die X-Position jetzt
ein wenig versetzt. Wie weit, sollte man ausprobieren.
Das
war es auch schon, beim ersten Zugriff auf die ComboBox werden die
Grafiken gezeichnet. Das ganze funktioniert jedoch nicht für zur Laufzeit
hinzugefügte Einträge.
Das diese Vorgehensweise nicht die optimale
Lösung sein kann, ist mir bewußt. Ich habe jedoch erreicht, was ich
wollte.
|
| UnauthorizedAccessException
bei Aufruf von Directory.GetDirectories mit Option SearchOption.AllDirectories
|
|
Ein kleines Problem mit großer Wirkung. Es sollten alle Verzeichnisse
nebst Unterverzeichnissen eines beliebigen Pfades ausgelesen werden.
Directory.GetDirectories(@"c:\","*.*",SearchOption.AllDirectories);
Das war der Plan, doch wie sich herausstellen sollte bricht die ganze
Sache in dem Moment ab, wo der Zugriff auf ein geschütztes Verzeichniss
erfolgt mit dem Ergebnis, das ein Fehler erzeugt wird und keine Daten
übermittelt werden. In meinen Augen ist die SearchOption.AllDirectories
Option völlig sinnlos wenn sie dieses Problem so behandelt. Also selber
programmieren:
public void rootDirectory(string directory)
{
rootDirectory(new DirectoryInfo(directory));
}
private void rootDirectory(DirectoryInfo directory)
{
DirectoryInfo[] subDirectories = directory.GetDirectories();
foreach (DirectoryInfo subDirectory in subDirectories)
{
try
{
rootDirectory(subDirectory);
// hier können beispielsweise die Verzeichnissnamen ausgelesen werden
// mit subDirectory.FullName ( incl. Pfad )
}
catch (UnauthorizedAccessException ex)
{
continue;
}
}
}
Bei dieser Methode werden die geschützten Verzeichnisse mit erfasst
jedoch nicht deren Inhalt. Aufgerufen wird das ganze dann über rootDirectory(@"c:\");
oder wie auch immer. Das Ganze ist natürlich erst der Grobschliff,
Verfeinerungen wie Rückgabewerte etc. müssen natürlich noch eingefügt
werden. Im Grunde eine simple Lösung, darauf zu kommen war nicht so
einfach wegen diesem verflixten SearchOption.AllDirectories.
|
| Rechner herunterfahren
|
|
Hin und wieder ist es notwendig, den Rechner ohne beisein des Users
herunterzufahren. Einmal mit Boardmitteln durch direkten Aufruf
der Datei shutdown.exe oder durch direkte Programmierung. Der Vorteil
der direkten Programmierung liegt auf der Hand: shutdown.exe muss
nicht vorhanden sein. ( ist z.B. bei Windows XP der Fall ) Also
zuerst die Möglichkeit mit shutdown.exe:
System.Diagnostics.Process.Start("Shutdown", "-s -t 10");
Recht simpel aber wie gesagt, wenn keine shutdown.exe vorhanden ist,
funktioniert die ganze Sache leider nicht. Die sicherere und auch
elegantere Methode ist deshalb meiner Meinung nach die direkte Programmierung.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
namespace Shutdown
{
class Program
{
static void Main(string[] args)
{
ManagementBaseObject mboShutdown = null;
ManagementClass mcWin32 = new ManagementClass("Win32_OperatingSystem");
mcWin32.Get();
// Ohne Security-Privilegs geht nichts
mcWin32.Scope.Options.EnablePrivileges = true;
ManagementBaseObject mboShutdownParams =
mcWin32.GetMethodParameters("Win32Shutdown");
// Siehe nachfolgende Bedeutung der Flags
mboShutdownParams["Flags"] = "1";
mboShutdownParams["Reserved"] = "0";
foreach (ManagementObject manObj in mcWin32.GetInstances())
mboShutdown = manObj.InvokeMethod("Win32Shutdown", mboShutdownParams, null);
}
}
}
Die Flags: Shutdown - 1 Reboot - 2 Force - 4
Die Bedeutung
der einzelnen Flags sollte eigentlich selbsterklärend sein.
|
| |
| Bei Fragen oder Kritik oder was weiss ich bitte eine Mail an
csharp@lumack.de |
|