GhostDoc jetzt auch für Visual Studio 2008

27. Januar 2009 Keine Kommentare »

Das beliebte Add-In GhostDoc für Visual Studio gibt es jetzt auch für die 2008 Version.

GhostDoc unterstützt den Entwickler beim Kommentieren des Quelltexts. GhostDoc erzeugt XML-Kommentare und schlägt dem Entwickler auch Kommentartext für die Zusammenfassung der Methode vor.

Und so funktioniert’s: Die Installationsdatei hier runterladen und installieren. In Visual Studio findet man nun unter Extras > GhostDoc > Configure GhostDoc die Möglichkeit zum Anpassen der Kommentarregeln.

Weitere Infos auch in folgendem Beitrag:  GhostDoc – Kommentare wie aus Geisterhand

Tags:, ,

Bookmarken bei... del.icio.us:GhostDoc jetzt auch für Visual Studio 2008 furl:GhostDoc jetzt auch für Visual Studio 2008 Y!:GhostDoc jetzt auch für Visual Studio 2008

PDFs in C# unter Windows ausdrucken

10. September 2007 5 Kommentare »

Um pdf-Dokumente unter Windows aus einer .NET-Anwendung heraus auszudrucken, gibt es die verschiedensten Möglichkeiten. Es gibt zunächst einmal eine Vielzahl freier oder kostenpflichtiger Bibliotheken, mit denen mehr oder weniger komfortabel pdf-Dokumente aus .NET heraus erstellt werden können. Geht es allerdings darum, ein Dokument auszudrucken, genügen freie Angebote offenbar nicht mehr und man müsste auf eine kostenpflichtige Komponente zurückgreifen. Will man lediglich ein vorhandenes Dokument ausdrucken, schiesst man damit vermutlich mit Kanonen auf Spatzen. Ein einfacher Weg ist hier, eine vorhandene Installation von Acrobat oder dem Reader einzusetzen. Beide sind in der Lage, Dokumente auszudrucken und warum sollte man davon nicht Gebrauch machen? (Vorausetzung ist hier wie gesagt, dass eine der beiden Anwendungen auf Zielrechner vorhanden ist.)

Nun bieten der Acrobat, wie auch der Reader einem Entwickler durchaus die Möglichkeit, gegen ihre Dlls zu linken und so auf dem “offiziellen” Weg auf ihre Dienste zurückzugreifen. Da ist zunächst einmal nichts geheimnisvolles dabei. Adobe bietet zudem eine relativ umfangreiche Dokumentation der Objektmodelle des Acrobats (die sogar ein kleines Kapitel über die Anbindung an .NET beinhaltet). Der Haken hierbei ist jedoch, dass sich die Objektmodelle beider Anwendungen (und vermutlich sogar einzelner Versionen) voneinander unterscheiden. So muss bei der Erstellung der eigenen Anwendung berücksichtigt werden, welche Acrobat (Reader)-Version später auf dem Zielrechner vorgefunden wird. Jeder normale Mensch würde jetzt vermutlich erstmal an eine späte Bindung denke, um diese Unterscheidung zur Laufzeit vornehmen zu können. Das Problem hierbei ist allerdings, dass die Namen von Klassen und Methoden der installierten Acrobat-Version dann spätestens zur Laufzeit bekannt sein müssen. Sicher kriegt man das irgendwie hin – es geht aber auch einfacher.

Es gibt nämlich ausser unserer Anwendung auf dem Zielrechner noch jemanden, der das gleiche Problem hat: die Shell, resp. der Explorer. Über das Kontextmenü kann ein Dokument ausgewählt und ein Druckauftrag angestossen werden. Die Shell muss also auch wissen, welche Anwendung sich für einen bestimmten Dateityp verantwortlich fühlt, ohne einzelne Versionen berücksichtigen zu müssen. Zu diesem Zweck sind in Windows (genau genommen in der Registry) bekanntlich Dateitypen mit Anwendungen verknüpft. In .NET kann man nun genau diese Verknüpfung ausnutzen. Dazu erstellt man eine Instanz von Process aus dem Namespace System.Diagnostics. Parametriert wird diese Instanz über eine Property StartInfo. Zu diesen Parametern gehört nicht nur der Dateiname der zu öffnenden Datei, sondern auch ein sogenanntes Verb. Verbs sind die Befehle, welche die Shell an eine Anwendung beim Start (per COM, DDE oder als Kommandozeilenparameter) überträgt. Die Anwendung auf der Gegenseite sollte natürlich im Stande sein, dieses Verb zu verstehen. Windows ist hier lediglich bei der Übetragung involviert. Ein Verb wie print wird allerdings im Allgemeinen bei der Installation einer Anwendung angelegt.

Versucht man nun, aus dem Anwendungscode heraus über die Shell ein pdf Dokument auszudrucken, tritt das Problem auf, dass eine Instanz des Acrobat (Readers) in der Taskleiste erhalten bleibt. Über Process.StartInfo kann ihr das abgewöhnt werden. Der folgende Code ermöglicht es, ein pdf auszudrucken und beendet anschließend den Acrobat Reader.

Process proc = new Process ();
proc.StartInfo.CreateNoWindow = false;
proc.StartInfo.Verb = “print”;
proc.StartInfo.FileName = “C:\\test.pdf”;
proc.Start();
proc.WaitForExit(10000);
proc.CloseMainWindow();
proc.Close();

Sollen mehrere Dokumente hintereinander gedruckt werden, ist hier eine kleine Optimierung möglich: Verzichtet man auf die Beendigung des Prozesses, bleibt die Instanz des Acrobat auch nach dem Druckauftrag noch (minimiert) erhalten. Bei weiteren Druckaufträgen wird dann keine neue Instanz gebildet, sondern das Verb an diese übertragen. Man spart dadurch die Zeit für den Programmstart des Acrobat.

Tags:, , ,

Bookmarken bei... del.icio.us:PDFs in C# unter Windows ausdrucken furl:PDFs in C# unter Windows ausdrucken Y!:PDFs in C# unter Windows ausdrucken

Automatisierung von Excel mit C#

27. August 2007 2 Kommentare »

In diesem Beitrag möchte ich zwei Wege zeigen, wie man aus .NET heraus Excel-Worksheets erstellen kann. Im Beispiel werde ich eine bestehende Excel-Installation nutzen, um ein Worksheet zu erzeugen, einen kleinen Text hineinzuschreiben und anschließend abzuspeichern. Auf die gleiche Weise kann man dann Formeln editieren, Worksheets ausdrucken und Vieles mehr. (Prinzipiell gibt es auch die Möglichkeit, Worksheets ohne Mithilfe von Excel – aber mit Hilfe einer geeigneten Bibliothek – zu erzeugen. Das Paket NetAdvantage der Firma Infragistics bietet beispielsweise diese Möglichkeit.)

Will man aus einer .NET-Anwendung heraus auf eine bestehende Excel-Installation zugreifen, stellt sich die Frage, ob bereits während der Entwicklung eine DLL der entsprechenden Excel-Version vorhanden ist. Ist das der Fall, gestaltet sich das weitere Vorgehen recht einfacht:

  1. Die .NET-Anwendung muss gegen die entsprechende “Excel-DLL” linken
  2. In der Anwendung steht nun der Namensraum “Excel” zur Verfügung, der alle Typen des Excel-Objektmodells beinhaltet (VBA-Programmierern wird hier einiges bekannt vorkommen).
  3. Es wird eine Instanz von Excel.Application erzeugt. Über diese Instanz können Workbooks erzeugt oder geladen werden.
  4. Es folgt die weitere Bearbeitung des Workbooks und dessen Inhalte je nach Gusto.

Das Ganze kann dann etwa so aussehen:
[code lang="csharp"]
public void EarlyBinding (string p_strFileName) {
Excel.Application oApp = new Excel.Application ();
Workbook oWorkbook = (Workbook) oApp.Workbooks.Add ("Arbeitsmappe");
Worksheet oWorksheet = (Worksheet)oWorkbook.ActiveSheet;
oWorksheet.Cells[1, 1] = "Foobar"; oWorksheet.SaveAs (p_strFileName, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing);

oApp.Quit ();

Marshal.ReleaseComObject (oWorksheet);
Marshal.ReleaseComObject (oWorkbook);
Marshal.ReleaseComObject (oApp);
}
[/code]
Diese Methode setzt voraus, dass die Typen von Excel bereits während der Kompilierzeit bekannt sind. Das muss allerdings nicht immer gegeben sein. Möglicherweise wird die .NET-Anwendung auf einem Rechner installiert, dessen Excel-Version nicht im Vorfeld bekannt ist. Die Anwendung muss daher in der Lage sein, erst zur Laufzeit an die installierte Excel-Version zu binden. Dieses Vorgehen wird auch späte Bindung genannt (im Gegensatz zur oben gezeigten frühen Bindung).

Späte Bindung an eine unbekannte DLL setzt den Einsatz von Reflection voraus und sollte daher mit Bedacht eingesetzt werden.

[code lang="csharp"]

public void LateBinding (string p_strFileName) {
object oApp = null;
object oWorkbooks = null;
object oWorkbook = null;
object oWorksheets = null;
object oWorksheet = null;
object oRange = null;
object[] vParams;

try {
//Excel-Instantiieren
Type tpApp = Type.GetTypeFromProgID ("Excel.Application");
oApp = Activator.CreateInstance (tpApp);
//Lies WorkBooks-Collection
oWorkbooks = tpApp.InvokeMember ("Workbooks",
BindingFlags.GetProperty, null, oApp, null);
Type tpWorkBooks = oWorkbooks.GetType ();
//Erstelle ein neues WorkBook
oWorkbook = tpWorkBooks.InvokeMember ("Add",
BindingFlags.InvokeMethod, null, oWorkbooks, null);
Type tpWorkBook = oWorkbook.GetType ();
//Lies WorkSheets des neuen WorkBooks
oWorksheets = tpWorkBook.InvokeMember ("Worksheets",
BindingFlags.GetProperty, null, oWorkbook, null);
Type tpWorkSheets = oWorksheets.GetType ();

//Das erste WorkSheet soll verwendet werden
vParams = new Object[1];
vParams[0] = 1;
oWorksheet = tpWorkSheets.InvokeMember ("Item",
BindingFlags.GetProperty, null, oWorksheets, vParams);
Type tpWorkSheet = oWorksheet.GetType ();

//Ein Range-Object für die linke obere Zelle wird angefordert
vParams = new Object[2];
vParams[0] = "A1";
vParams[1] = Missing.Value;
oRange = tpWorkSheet.InvokeMember ("Range",
BindingFlags.GetProperty, null, oWorksheet, vParams);
Type tpRange = oRange.GetType ();

//Der Text "Foobar" wird der Value-Eigenschaft des Range-Objekts zugewiesen
vParams = new Object[1];
vParams[0] = "Foobar";
tpRange.InvokeMember ("Value", BindingFlags.SetProperty,
null, oRange, vParams);

//Speichern der aktuellen Arbeitsmappe
object s = Excel.XlSaveAction.xlSaveChanges;
tpWorkBook.InvokeMember ("SaveAs", BindingFlags.InvokeMethod, null, oWorkbook,
new object[] { p_strFileName });

tpApp.InvokeMember ("Quit", BindingFlags.InvokeMethod, null, oApp, null);

} catch (Exception ex) {
string strError = ex.Message;
} finally {
Marshal.ReleaseComObject (oApp);
Marshal.ReleaseComObject (oWorkbook);
Marshal.ReleaseComObject (oWorkbooks);
Marshal.ReleaseComObject (oWorksheet);
Marshal.ReleaseComObject (oWorksheets);
Marshal.ReleaseComObject (oRange);
}
}

[/code]

Die Schritte sind hier die gleichen wie im oberen Beispiel. Nicht zuletzt aus Performanzgründen ist die erste Methode allerdings zu bevorzugen.

Tags:, , ,

Bookmarken bei... del.icio.us:Automatisierung von Excel mit C# furl:Automatisierung von Excel mit C# Y!:Automatisierung von Excel mit C#