Programmaufrufe innerhalb von C/C++-Programmen
weiter zu Aufruf von Programmen in Linux2. Aufruf von Programmen in Windows Teil 1: ShellExecute
Die hier zugrunde liegende Problemstellung ist die einer Button-Leiste, mit der Programme geöffnet werden. Die Code-Beispiele sind Ausschnitte aus dem Programm silidock.
Einleitung:
Die Windows-API bietet mehrere Möglichkeiten Programme aufzurufen. Der Weg über die Funktion
ShellExecute ist vielleicht der, welcher am häufigsten beschritten wird, deshalb wird er
hier kurz vorgestellt.
Die für den hier vorgesehenen Zweck bessere Alternative ist jedoch die Funktion
CreateProcess.
ShellExecute ist leistungsfähiger und flexibler, sie kann nicht nur Programme starten,
sondern auch Dokumente ausdrucken, Dateiinhalte anzeigen und vieles mehr. Damit sind jedoch nicht
nur Einbußen bezüglich der Performance verbunden, sondern auch ein höheres Sicherheitsrisiko.
CreateProcess kann nicht viel mehr als das, was hier beabsichtigt ist und das ist eine gute
Voraussetzung.
Zur Erinnerung: Wir programmieren in Windows, Backlashs müssen "escaped" werden: "C:\\pfad\\dateie.exe",
sonst wird der Backlash als Escape-Sequenz interpretiert.
ShellExecute
ShellExecute ist nicht dazu gedacht, Informationen über die geöffneten Programme zu erhalten;
dafür ist die Funktion
ShellExecuteEx
vorgesehen.
Es wird von Microsoft sozusagen als "good practice" empfohlen, immmer vor einem Aufruf von ShellExecute das Component Object Model (COM) zu initialisiern, das unter anderem eine Interprozesskommunikation ermöglicht. Da ShellExecute nach der hier bevorzugten Strategie ohnehin schon leistungsstärker ist als gewünscht, soll die Funktion jedoch nicht noch zusätzlich aufgebläht werden um zahlreiche Funktionen, die gar nicht benötigt werden und hier lediglich weitere potenzielle Sicherheitslücken bedeuten.
ShellExecute ist ab Windows XP verfügbar ( weitere Infos) .
Syntax:
HINSTANCE ShellExecute(
_In_opt_ HWND hwnd, // Zeiger auf Fenster, wird benutzt, um beispielsweise einen Error-Code anzuzeigen, sonst NULL
_In_opt_ LPCTSTR lpOperation, // ein Verb, das die auszuführende Aktion beschreibt: edit, explore, find, open, print oder NULL
_In_ LPCTSTR lpFile, // auszuführende Datei
_In_opt_ LPCTSTR lpParameters, // Parameter, wenn die Datei ausführbar ist oder NULL
_In_opt_ LPCTSTR lpDirectory, // Verzeichnis, in der die Aktion ausgeführt werden soll oder NULL (= aktuelles Verzeichnis)
_In_ INT nShowCmd // Flag für die Anzeige der Datei oder des Programms:
// z.B. maximiert (SW_SHOWMAXIMIZED) oder
// minimiert und nicht aktivieren (SW_SHOWMINNOACTIVE) oder
// einfach aktivieren und anzeigen (SW_SHOW)
);
Entweder lpFile/Datei oder lpDirectoty/Verzeichnis müssen mit absolutem Pfad angegeben werden.
Die Beschreibung der Funktion basiert auf Windows-spezifischen Datentypen und Codeanmerkungen.
_In_ und _In_opt_ werden in der Microsoft-Quellcodeanmerkungssprache (SAL) definiert.
_In_ bedeutet einfach, dass Daten an die aufgerufene Funktion übergeben und als
schreibgeschützt behandelt werden. Im Gegensatz zu _In_opt_, bei der die Parameter optional sind,
sind bei einem einfachen _In_ die Parameter Pflicht.
Die hier benutzten Windows-Datentypen:
HWND - Zeiger auf ein Fenster
LPCTSTR - char*, wenn Unicode definiert ist als Zeiger auf einen 16-bit Unicode char (LPCWSTR),
sonst auf einen 8-bit (ANSI) char (LPCSTR)
INT - 32-bit signed Integer
Der Rückgabewert ist ein Zeiger mit einem Wert > 32 wenn die Funktion erfolgreich ausgeführt wurde.
Über einen Wert <=32 können diverse Fehlerfälle abgefragt werden.
Code-Schnipsel:
// C++ Header
#include <iostream>
#include <sstream>
// C-Header
extern "C" {
#include <windows.h>
#include <Shellapi.h>
#include <Winuser.h> // for error messages
}
void execute_program(const char* program_call, const char* param )
{
int ex = (int) ShellExecute(NULL, "open", program_call, param, NULL, SW_SHOW );
if(ex <= 32)
{
stringstream ss; // parse error code to string
ss << ex;
string ex_str = ss.str();
string note = ex_str + string(": An error occured when calling: ") + program_call + "\n";
string error_string = "";
if (ex == ERROR_FILE_NOT_FOUND)
{
error_string = "Specified file not found.";
}
else if (ex == ERROR_BAD_FORMAT)
{
error_string = "Invalid .exe file.";
}
else if (ex == SE_ERR_ACCESSDENIED)
{
error_string = "No access to file.";
}
else if (ex == SE_ERR_NOASSOC)
{
error_string = "No application associated with the given file name extension.";
}
else if (ex == SE_ERR_OOM)
{
error_string = "Not enough memory.";
}
else
{
error_string = "Unexpected error.";
}
MessageBox(NULL, (note + error_string ).c_str(), NULL, MB_OK ); // owner window, message, title, buttons
}
}
"open" startet im Falle einer ausführbaren Datei das Programm, kann aber auch Webseiten,
Verzeichnisse oder Textdateien öffnen oder alles Mögliche tun, sofern das in die Registry eingetragen wird.
weiter zu Teil 2: CreateProcess