Abou Chleih

{the magic lies between the brackets}

Menü Schließen

Schlagwort: office

Signieren von Visual Studio for Office Add-Ins (autom. Installation)

Bei normalen Windows Desktop oder Windows Phone Applikationen ist ein Signieren der Applikation nicht dringend nötig bzw. nur wenn die Herkunft des Executables verifiziert werden soll um lästige Abfragen zu vermeiden.
Auch bei sogenannten Visual Studio for Office Add-Ins (kurs: vsto) ist dies normalerweise nicht erforderlich.
Es sei denn, man will die Add-Ins nicht manuell per Registry Eintrag oder Bestätigungdialogen installieren, sondern automatisiert.
Egal welchen Fall man bevorzugt, man benötigt zu allererst die Visual Studio for Office Runtime (VSTOR).

Nach der Installation können wir nun mit einem Doppelklick auf die .vsto-Datei das Add-In installieren, allerdings bisher nur mit folgender Warnung:
warn_install_addin

Bei einer Automatisierung des Installationsprozesses soll dies nicht mehr passieren und der Prozess insgesamt im Hintergrund ausgeführt werden (silent install).
Dies funktioniert mit Hilfe der VSTOR – siehe Link oben – und der darin enthaltenen VSTOInstaller.exe.
Diese befindet sich nach der Installation im Verzeichnis C:\Program Files (x86)\Common Files\Microsoft Shared\VSTO\10.0.

Ein Start des Programms gibt uns direkt alle verfügbaren Parameter zurück (Ein Doppelklick auf eine ,vsto-Datei ruft übrigens auch nur dieses Programm mit dem Parameter /i <.vsto-Pfad> auf)

VSTOInstaller.exe [[/install <URL> ] | [/uninstall <URL>]] [/silent] [/help]

/install, /i: Projektmappe installieren. Nach dieser Option muss der vollqualifizierte Pfad eines Bereitstellungsmanifests im Format „http://“, „https://“ oder „\\Servername\Ordnername“ angegeben werden.

/uninstall, /u: Projektmappe deinstallieren. Nach dieser Option muss der vollqualifizierte Pfad eines Bereitstellungsmanifests im Format „http://“, „https://“ oder „\\Servername\Ordnername“ angegeben werden.

/silent, /s: Ohne Eingabeaufforderungen oder Informationseingaben installieren oder deinstallieren.

Nun wissen wir, dass der Aufruf für unsere Add-In Installation wie folgt aussehen muss:
VSTOInstaller.exe /i "<PFADZURVSTODATEI>" /s

Führen wir dies nun aus, werden wir merken, dass das Add-In nicht installiert ist.
Der Grund ist ganz einfach: Eine silent Installation lässt sich nur durchführen, wenn das Programm/Add-In mit einem validen Zertifikat signiert ist.

Natürlich könnten wir uns jetzt für viel Geld ein ordentliches Zertifikat von einer Authority kaufen, allerdings kostet das viel Zeit und Geld.
Zumal wir unsere Software meist nicht verkaufen, sondern nur intern nutzen.

Lösung: Eigenes Zertifikat mit Kette

Was braucht man für ein valides Zertifikat?

  • Eine gültige Certificate Chain, zu deutsch: Zertifikatskette, kurz: eine höherwertige Zertifizierungsstelle (Authority) muss das Zertifikat des Clients bestätigen.
  • Eine .pfx-Datei, mit welcher wir das Visual Studio Projekt signieren
  • Eine GPO, mit der wir die Zertifikate in unserem Netzwerk bekannt machen (wir selbst sind schließlich keine zertifizierte Authority, sonst könnten wir ja einfach Zertifikate von google.de erstellen und uns dafür ausgeben ;) )

Fangen wir also an.
Wir müssen ein Zertifikat erstellen – für eine Authority (wir fangen ganz oben in der Hierarchie an).
Was wir benötigen, ist also ein Programm, welches uns Zertifikate erstellt: MakeCert.exe – Documentation/Parameter Specification

Dieses Programm finden wir abhängig von der Visual Studio Version und den SDKs in einem der folgenden Pfade:

  • C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\makecert.exe
  • C:\Program Files (x86)\Windows Kits\8.0\bin\x86\makecert.exe

Wenn man sich die Dokumentation des Tools durchliest, kann man schnell entdecken, wohin die Reise nun geht:

makecert
-n "CN=MeinAuthorityName" #CN= muss immer voranstehen; specifies a name for the certificate.
-cy authority #Defines Certificate type (here: authority)
-a sha1 #Hash algorithm
-sv "MeinPrivateKeyFileFuerDieAuthority.pvk" #Name of the subject's .pvk file. Wird erstellt, wenn nicht vorhanden
-r "MeinAuthorityZertifikat.cer" #Creates a self-signed certificate.

Nun werden wir aufgefordert ein Passwort für das Private Key File zu erstellen (dies sollte ein kompliziertes Passwort sein).

Nun haben wir folgende Dateien:

  • MeinPrivateKeyFileFuerDieAuthority.pvk
  • MeinAuthorityZertifikat.cer

Diese benötigen wir nun, um ein Client Zertifikat zu erstellen, welches von unserer Authority ausgestellt ist (Chain).

makecert 
-n "CN=MeinClientZertifikatName" #specifies name of certificate
-ic "MeinAuthorityZertifikat.cer" #Location of the issuers certificate.
-iv "MeinPrivateKeyFileFuerDieAuthority.pvk" #Issuers (Aussteller = Authority) private key file.
-a sha1 #Hash algorithm
-sky exchange #Für Zertifikate nutzt man exchange (KeyExchange)
-pe #Marks the private key as exportable.
-sv "MeinPrivateKeyFileFuerDasClientZertifikat.pvk" #Erstellt ein .pvk file, falls nicht vorhanden für das Client Zertifikat &nbsp; 
"MeinClientZertifikat.cer" #Erstellt das Zertifikat mit angegebenem Namen

Nun werden wir entsprechend aufgefordert die Passwörter für das Authority Key File einzugeben, das Kennwort für das ClientZertifikatKeyFile zu definieren.
Als Ergebnis haben wir nun unser Client Zertifikat mit Private Key file.

  • MeinPrivateKeyFileFuerDasClientZertifikat.pvk
  • MeinClientZertifikat.cer

Die Zertifikatskette ist nun komplett, fehlt noch das .pfx File.

Um unsere Zertifikate in das .pfx Format zu konvertieren, bietet uns Microsoft ein Tool namens pvk2pfx.exe  an.

pvk2pfx.exe 
-pvk MeinPrivateKeyFileFuerDasClientZertifikat.pvk #Verweis auf das Private Key File des Clients
-spc MeinClientZertifikat.cer #Verweis auf das Cleint Zertifikat
-pfx MeinPfxZertifikat.pfx #Erstellt ein .pfx File 
-pi PasswortDesPrivateKeyFiles #Optional! Dialog kann ebenfalls genutzt werden 

Nun haben wir unser .pfx-File mit dem wir unsere Visual Studio Projekt signieren können.
Dazu einfach in das entsprechende

 Projekt -> Rechtsklick -> Eigenschaften -> Signierung -> Aus Datei wählen

und das entsprechende Zertifikat (.pfx) auswählen.

Signierung_VisualStudio

Nun müssen wir die Zertifikate und damit die Kette noch per GPO bekannt/valide machen.
Dies ist aber ein Thema für einen anderen Tag.

[C#] Auslesen einer Excel Datei #2 – OleDB

Teil 1: [C#] Auslesen einer Excel Datei #1 – Interop-Assembly

OleDB steht für Object Linking and Embedding, Database und bietet einem im Gegensatz zu Interop-Assembly die Möglichkeit auf verschiedenste Datenquellen (bspw. auch auf Datenbanken zuzugreifen). Zugleich muss im Gegensatz zu Interop-Assembly kein Microsoft Excel installiert sein und die meisten Controls, wie z.B. DataGridView, akzeptieren out-of-the-box die Datenquelle (Data Source) welche OleDB bietet.

Hier ein Zitat aus dem MSDN:

OLE DB is a set of COM-based interfaces that expose data from a variety of sources. OLE DB interfaces provide applications with uniform access to data stored in diverse information sources, or data stores. These interfaces support the amount of DBMS functionality appropriate to the data store, enabling the data store to share its data.

OleDB hat einige Vorteile gegenüber Interop-Assembly:

  • Microsoft Excel muss nicht installiert sein
  • Es ist um einiger schneller als Interop

Natürlich aber auch Nachteile

  • OleDB bietet im Vergleich zu Interop in Bezug auf Excel weniger Möglichkeiten, vor allem bezüglich Zelleninformationen, wie Farbe, Rahmen oder Formatierung

Nun aber zur Nutzung von OleDB

Normalerweise bindet Visual Studio automatisch System.Data-Assembly ein und wir müssen nur noch den Namespace mittels

using System.Data.OleDb;

einbinden

Sollte es dennoch zu folgender Fehlermeldung

Fehler 1

Der Typ- oder Namespacename „OleDb“ ist im Namespace „System.Data“ nicht vorhanden. (Fehlt ein Assemblyverweis?)

müssen wir einen Assemblyverweis erstellen.

Dazu einfach mit der rechten Maustaste auf „Verweise“ klicken:

20130811_OleDBTest - Microsoft Visual Studio_000033

„Verweis hinzufügen“ wählen und in den Framework-Assemblys nach System-Data suchen und diese Assembly dann wählen.20130811_Verweis-Manager - OleDBTest_000034

Zu guter Letzt noch mit „OK“ bestätigen.

Ich persönlich bevorzuge es Objekten mittels using eine definierte Gültigkeit zuzuweisen, dies bedeutet, dass das in der Using-Anweisung definierte Objekt nach dem Verlassen der Anweisung nicht mehr benötigt wird und zerstört werden kann.

Dadurch ist es aber nötig den ConnectionString, vor dem Erstellen der OleDbConnection zu definieren und per Paramter zu übergeben.
Um einen ConnectionString zu erstellen, verwende ich den OleDbConnectionStringBuilder:

Dieser bietet eine einfache Möglichkeit, den Inhalt von Verbindungszeichenfolgen zu erstellen und zu verwalten, die von der OleDbConnection-Klasse verwendet werden.


OleDbConnectionStringBuilder csbuilder = new OleDbConnectionStringBuilder();
 csbuilder.Provider = "Microsoft.ACE.OLEDB.12.0";
 csbuilder.DataSource = "Pfad zu Excel-Datei";
 csbuilder.Add("Extended Properties", "Excel 12.0 Xml;HDR=YES");

Der Provider ist eine Softwarebibliothek, welche die nötigen Werkzeuge bietet, um auf eine Datenquelle zuzugreifen. Im ConnectionString werden die Informationen, welche den Provider in die Lage versetzen auf die Quelle zuzugreifen, hinterlegt.
Für ConnectionStrings empfehle ich: http://www.connectionstrings.com/

Im Property DataSource wird der Pfad zu Excel-Datei angegeben.

Mittels der Methode Add werden die Informationen hinterlegt, welche den Typ der Datei und Informationen zum Inhalt definieren.
In diesem Beispiel wird hinterlegt, dass es sich um eine Excel-Datei handelt, welche mit Excel 2010 erstellt wurde(Excel 12.0) und deren erste Zeile Überschriften(Header/HDR) sind.

Da nun die wichtigsten Eigenschaften definiert wurden, können wir das erste Tabellenblatt der Excel-Datei auslesen.
Dazu verwenden wir die SQL-Abfrage

SELECT * FROM [“ + Name_des_Tabellenblattes + „]

(Die eckigen Klammern werden zwingend benötigt)

             using (OleDbConnection connection = new OleDbConnection(csbuilder.ConnectionString))
            {
                DataTable sheet1 = new DataTable();
                connection.Open();
                string sqlQuery = @"SELECT * FROM [" + Name_des_Tabellenblattes + "]";
                using (OleDbDataAdapter adapter = new OleDbDataAdapter(sqlQuery, connection))
                {
                    adapter.Fill(sheet1);
                    excelData_dataGridView.DataSource = sheet1;
                }
                connection.Close();
            }

Und erstellen ein Objekt vom Typ OleDbDataAdapter mit den Parametern „SQL-Query“ und dem ConnectionString.
Danach füllen wir den DataTable mittels adapter.Fill(Name_des_DataTables) und füllen ein DataGridView mittels

DataGridView.DataSource = Name_des_DataTables;

Namen der Tabellenblätter auslesen

Nun ist natürlich ungeschickt den Namen des Tabellenblattes hartcodiert im Code zu hinterlegen.
Um die Tabellenblattnamen auszulesen und in ein StringArray zu laden verwenden wir folgenden Code:

OleDbConnectionStringBuilder csbuilder = new OleDbConnectionStringBuilder();
csbuilder.Provider = "Microsoft.ACE.OLEDB.12.0";
csbuilder.DataSource = pExcelPath;
csbuilder.Add("Extended Properties", "Excel 12.0 Xml;HDR=YES");

System.Data.DataTable dt = null;

using (OleDbConnection connection = new OleDbConnection(csbuilder.ConnectionString))
{
    connection.Open();
    dt = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
    connection.Close();
}

String[] excelSheets = new String[dt.Rows.Count];

int i = 0;
foreach (DataRow row in dt.Rows)
{
    excelSheets[i] = row["TABLE_NAME"].ToString();
    i++;
}

Mit dem StringArray kann man nun eine ganze Menge anfangen.
Ich habe beispielsweise das StringArray als Parameter an ein Objekt einer Form übergeben, welches jeden String im Array(mittels foreach-Schleife) in eine ListView kopiert und man so das gewünschte Tabellenblatt auswählen kann.

DemoProjekt

Hier könnt ihr das Demoprojekt herunterladen:

20130811_Verweis-Manager - OleDBTest_000034

OleDBTest

[C#] Auslesen einer Excel Datei #1 – Interop-Assembly

Um Daten aus einer Excel-Datei in das Programm zu laden, gibt es mehrere Wege:

  • Zugriff auf die Excel-Datei über die Interop-Schnittstelle
  • Zugriff auf die Excel-Datei über einen Datenbank-Provider (hier: OLEDB)

Beginnen wir mit dem ersten genannten Weg, dem Zugriff über die Interop-Assembly.
Um einen Zugriff zu erhalten, müssen wir zuerst die Assembly einbinden, dies tun wir, indem wir einen Verweis auf die DLL hinzufügen.
Dazu klicken wir mit der rechten Maustaste auf das Item „Verweise“ im gewünschten Projekt und betätigen das Feld „Verweis hinzufügen…“.
Verweis_hinzufügen

Anschließend öffnet sich Dialog, indem wir einige DLLs finden.
Wir benötigen die Microsoft.Office.Interop.Excel-DLL, welche im Reiter .NET zu finden ist.

Interop_Excel_Verweis
Anschließend binden wir den Namespace der DLL in das Projekt (die gewünschte Klasse) ein.

 using Microsoft.Office.Interop.Excel; 

Nun zum eigentlichen Auslesen.
Zuerst müssen wir die verschiedenen Variablen anlegen, die Excel benötigt:

  • Die Excel-Applikation
  • Das Workbook
  • Das Worksheet
ApplicationClass app = new ApplicationClass(); //Die Excel-Applikation
Workbook book = null; //Das Workbook
Worksheet sheet = null; //Das Worksheet

Nun weisen wir die Werte zu:

 book = app.Workbooks.Open(path, Missing.Value, Missing.Value,
                                         Missing.Value, Missing.Value, Missing.Value, Missing.Value,
                                         Missing.Value, Missing.Value, Missing.Value, Missing.Value,
                                         Missing.Value, Missing.Value, Missing.Value, Missing.Value);

Dies lässt Excel das Workbook öffnen.
Falls dies im Hintergrund geschehen soll (Excel soll nicht sichtbar laufen), müssen folgende Optionen gesetzt sein:

 app.Visible = false;
app.ScreenUpdating = false;
app.DisplayAlerts = false; 

Nun da wir das komplette Excel-File geöffnet haben, wollen wir die Dateien der verschiedenen Worksheets (zu Deutsch: Tabellenblätter) auslesen.
Dazu weisen wir dem Objekt vom Typ Worksheet das Worksheet aus dem Excel-File zu:

 sheet = (Worksheet)book.Worksheets[1]; 

Es ist zu beachten, dass hier das erste Worksheet auch den Index 1 hat. (Kein zero-based-indexing!)
Jetzt lesen wir das Worksheet aus. Dazu muss man angeben, ab welcher Zelle und bis zu welcher Zelle man auslesen will, man muss also einen Bereich (eine Range) angeben.
Für dies existiert die Klasse Range.
Nun weisen wir der Range den gesamten Bereich zu, in dem Werte stehen.
Dazu erstellen wir ein char-Array bzw. einen string (ein String ist ein char-Array):

 string alphabet= "ABCDEFGHIJKLMNOPQRSTUVQXYZ"; 

Nun lesen wir aus, wie viele Spalten es gibt:

 int colCount = sheet.UsedRange.Columns.Count; 

Den Buchstaben der letzten Spalte bekommen wir nun ganz einfach durch Nutzen des Index (colCount):

 char lastColChar = alphabet[iColumnCount]; 

Um die letzte genutzte Spalte zu finden nutzen wir:

int rowCount = sheet.UsedRange.Rows.Count; 

Die Range definieren wir dann wie folgt:

 Range range = sheet.get_Range("A1", lastColChar.toString() + rowCount.toString()); 

Der erste Parameter definiert die obere, rechte Zelle, der zweite die untere, linke.
Nun haben wir den Bereich definiert.
Das Auslesen ist nun sehr simpel:
Da wir alle benötigten Daten haben, können wir ein Array erstellen und das Array schnell füllen:

 object[,] myExcelFileValues = (object[,])range.Value2; 

Nun haben wir alle Zellen im Speicher und können Excel beenden (!!!), dies ist wichtig, da die Datei sonst nicht freigegeben wird.
Dies geschieht nach dem First-In-Last-Out-Prinzip.
Zuerst löschen wir also das Range-Objekt:

 range = null; 

Nun löschen wir das Worksheet und rufen den GarbageCollector auf:

Marshal.FinalReleaseComObject(sheet);
app.DisplayAlerts = false;
sheet = null; 
GC.Collect();
GC.WaitForPendingFinalizers(); 

Anschließend lassen wir das Workbook schließen und löschen das Workbook-Objekt:

  book.Close(false, Missing.Value, Missing.Value); 
 Marshal.FinalReleaseComObject(book);
 book = null;

Daraufhin schließen wir Excel/die Applikation und löschen diese aus dem Speicher:

 app.Quit();
Marshal.FinalReleaseComObject(app);
app = null; 

Nun ist das Programm beendet.

© 2018 Abou Chleih. Alle Rechte vorbehalten.

Thema von Anders Norén.