xenocara/xserver/hw/xwin/xlaunch/main.cc
2006-11-26 18:13:41 +00:00

701 lines
24 KiB
C++

/*
* Copyright (c) 2005 Alexander Gottwald
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name(s) of the above copyright
* holders shall not be used in advertising or otherwise to promote the sale,
* use or other dealings in this Software without prior written authorization.
*/
#include "window/util.h"
#include "window/wizard.h"
#include "resources/resources.h"
#include "config.h"
#include <prsht.h>
#include <commctrl.h>
#include <stdexcept>
#include <X11/Xlib.h>
/// @brief Send WM_ENDSESSION to all program windows.
/// This will shutdown the started xserver
BOOL CALLBACK KillWindowsProc(HWND hwnd, LPARAM lParam)
{
SendMessage(hwnd, WM_ENDSESSION, 0, 0);
return TRUE;
}
/// @brief Actual wizard implementation.
/// This is based on generic CWizard but handles the special dialogs
class CMyWizard : public CWizard
{
public:
private:
CConfig config; /// Storage for config options.
public:
/// @brief Constructor.
/// Set wizard pages.
CMyWizard() : CWizard()
{
AddPage(IDD_DISPLAY, IDS_DISPLAY_TITLE, IDS_DISPLAY_SUBTITLE);
AddPage(IDD_CLIENTS, IDS_CLIENTS_TITLE, IDS_CLIENTS_SUBTITLE);
AddPage(IDD_PROGRAM, IDS_PROGRAM_TITLE, IDS_PROGRAM_SUBTITLE);
AddPage(IDD_XDMCP, IDS_XDMCP_TITLE, IDS_XDMCP_SUBTITLE);
//AddPage(IDD_FONTPATH, IDS_FONTPATH_TITLE, IDS_FONTPATH_SUBTITLE);
AddPage(IDD_CLIPBOARD, IDS_CLIPBOARD_TITLE, IDS_CLIPBOARD_SUBTITLE);
AddPage(IDD_FINISH, IDS_FINISH_TITLE, IDS_FINISH_SUBTITLE);
}
virtual void LoadConfig(const char *filename)
{
try {
config.Load(filename);
} catch (std::runtime_error &e)
{
printf("Fehler: %s\n", e.what());
}
}
/// @brief Handle the PSN_WIZNEXT message.
/// @param hwndDlg Handle to active page dialog.
/// @param index Index of current page.
/// @return TRUE if the message was handled. FALSE otherwise.
virtual BOOL WizardNext(HWND hwndDlg, unsigned index)
{
#ifdef _DEBUG
printf("%s %d\n", __FUNCTION__, index);
#endif
switch (PageID(index))
{
case IDD_DISPLAY:
// Check for select window mode
if (IsDlgButtonChecked(hwndDlg, IDC_MULTIWINDOW))
config.window = CConfig::MultiWindow;
else if (IsDlgButtonChecked(hwndDlg, IDC_FULLSCREEN))
config.window = CConfig::Fullscreen;
else if (IsDlgButtonChecked(hwndDlg, IDC_WINDOWED))
config.window = CConfig::Windowed;
else if (IsDlgButtonChecked(hwndDlg, IDC_NODECORATION))
config.window = CConfig::Nodecoration;
else
{
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
return TRUE;
}
// Get selected display number
{
char buffer[512];
GetDlgItemText(hwndDlg, IDC_DISPLAY, buffer, 512);
buffer[511] = 0;
config.display = buffer;
}
// Check for valid input
if (config.display.empty())
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
else
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIENTS);
return TRUE;
case IDD_CLIENTS:
// Check for select client startup method
if (IsDlgButtonChecked(hwndDlg, IDC_CLIENT))
{
config.client = CConfig::StartProgram;
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_PROGRAM);
} else if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP))
{
config.client = CConfig::XDMCP;
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_XDMCP);
} else if (IsDlgButtonChecked(hwndDlg, IDC_CLIENT_NONE))
{
config.client = CConfig::NoClient;
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIPBOARD);
} else
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
return TRUE;
case IDD_PROGRAM:
// Check wether local or remote client should be started
if (IsDlgButtonChecked(hwndDlg, IDC_CLIENT_LOCAL))
config.local = true;
else if (IsDlgButtonChecked(hwndDlg, IDC_CLIENT_REMOTE))
config.local = false;
else
{
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
return TRUE;
}
// Read program, user and host name
{
char buffer[512];
GetDlgItemText(hwndDlg, IDC_CLIENT_USER, buffer, 512);
buffer[511] = 0;
config.user = buffer;
GetDlgItemText(hwndDlg, IDC_CLIENT_HOST, buffer, 512);
buffer[511] = 0;
config.host = buffer;
GetDlgItemText(hwndDlg, IDC_CLIENT_PROGRAM, buffer, 512);
buffer[511] = 0;
config.program = buffer;
}
// Check for valid input
if (!config.local && (config.host.empty() || config.program.empty()))
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
else
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIPBOARD);
return TRUE;
case IDD_XDMCP:
// Check for broadcast
if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP_BROADCAST))
config.broadcast = true;
else if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP_QUERY))
config.broadcast = false;
else
{
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
return TRUE;
}
// Check for indirect mode
if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP_INDIRECT))
config.indirect = true;
else
config.indirect = false;
// Read hostname
{
char buffer[512];
GetDlgItemText(hwndDlg, IDC_XDMCP_HOST, buffer, 512);
buffer[511] = 0;
config.xdmcp_host = buffer;
}
// Check for valid input
if (!config.broadcast && config.xdmcp_host.empty())
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
else
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIPBOARD);
return TRUE;
case IDD_CLIPBOARD:
// check for clipboard
if (IsDlgButtonChecked(hwndDlg, IDC_CLIPBOARD))
config.clipboard = true;
else
config.clipboard = false;
// read parameters
{
char buffer[512];
GetDlgItemText(hwndDlg, IDC_EXTRA_PARAMS, buffer, 512);
buffer[511] = 0;
config.extra_params = buffer;
}
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_FINISH);
return TRUE;
default:
break;
}
return FALSE;
}
/// @brief Handle PSN_WIZFINISH message.
/// @param hwndDlg Handle to active page dialog.
/// @param index Index of current page.
/// @return TRUE if the message was handled. FALSE otherwise.
virtual BOOL WizardFinish(HWND hwndDlg, unsigned index)
{
#ifdef _DEBUG
printf("finish %d\n", index);
#endif
return FALSE;
}
/// @brief Handle PSN_WIZBACK message.
/// Basicly handles switching to proper page (skipping XDMCP or program page
/// if required).
/// @param hwndDlg Handle to active page dialog.
/// @param index Index of current page.
/// @return TRUE if the message was handled. FALSE otherwise.
virtual BOOL WizardBack(HWND hwndDlg, unsigned index)
{
switch (PageID(index))
{
case IDD_PROGRAM:
case IDD_XDMCP:
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIENTS);
return TRUE;
case IDD_FONTPATH:
case IDD_CLIPBOARD: // temporary. fontpath is disabled
switch (config.client)
{
case CConfig::NoClient:
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIENTS);
return TRUE;
case CConfig::StartProgram:
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_PROGRAM);
return TRUE;
case CConfig::XDMCP:
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_XDMCP);
return TRUE;
}
break;
}
return FALSE;
}
/// @brief Handle PSN_SETACTIVE message.
/// @param hwndDlg Handle to active page dialog.
/// @param index Index of current page.
/// @return TRUE if the message was handled. FALSE otherwise.
virtual BOOL WizardActivate(HWND hwndDlg, unsigned index)
{
#ifdef _DEBUG
printf("%s %d\n", __FUNCTION__, index);
#endif
switch (PageID(index))
{
case IDD_CLIENTS:
// Enable or disable XDMCP radiobutton and text
EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP), config.window != CConfig::MultiWindow);
EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP_DESC), config.window != CConfig::MultiWindow);
break;
}
return FALSE;
}
protected:
/// @brief Enable or disable the control for remote clients.
/// @param hwndDlg Handle to active page dialog.
/// @param state State of control group.
void EnableRemoteProgramGroup(HWND hwndDlg, BOOL state)
{
EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_PROTOCOL), state);
EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_HOST), state);
EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_USER), state);
EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_PROTOCOL_DESC), state);
EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_HOST_DESC), state);
EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_USER_DESC), state);
}
/// @brief Enable or disable the control for XDMCP connection.
/// @param hwndDlg Handle to active page dialog.
/// @param state State of control group.
void EnableXDMCPQueryGroup(HWND hwndDlg, BOOL state)
{
EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP_HOST), state);
EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP_INDIRECT), state);
}
/// @brief Fill program box with default values.
/// @param hwndDlg Handle to active page dialog.
void FillProgramBox(HWND hwndDlg)
{
HWND cbwnd = GetDlgItem(hwndDlg, IDC_CLIENT_PROGRAM);
if (cbwnd == NULL)
return;
SendMessage(cbwnd, CB_RESETCONTENT, 0, 0);
SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "xterm");
SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "startkde");
SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "gnome-session");
SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) ".xinitrc");
SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "wmaker");
SendMessage(cbwnd, CB_SETCURSEL, 0, 0);
}
/// @brief Fill protocol box with default values.
/// @param hwndDlg Handle to active page dialog.
void FillProtocolBox(HWND hwndDlg)
{
HWND cbwnd = GetDlgItem(hwndDlg, IDC_CLIENT_PROTOCOL);
if (cbwnd == NULL)
return;
SendMessage(cbwnd, CB_RESETCONTENT, 0, 0);
SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "Putty");
//SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "OpenSSH");
SendMessage(cbwnd, CB_SETCURSEL, 0, 0);
}
void ShowSaveDialog(HWND parent)
{
char szTitle[512];
char szFilter[512];
char szFileTitle[512];
char szFile[MAX_PATH];
HINSTANCE hInst = GetModuleHandle(NULL);
LoadString(hInst, IDS_SAVE_TITLE, szTitle, sizeof(szTitle));
LoadString(hInst, IDS_SAVE_FILETITLE, szFileTitle, sizeof(szFileTitle));
LoadString(hInst, IDS_SAVE_FILTER, szFilter, sizeof(szFilter));
for (unsigned i=0; szFilter[i]; i++)
if (szFilter[i] == '%')
szFilter[i] = '\0';
strcpy(szFile, "config.xlaunch");
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = parent;
ofn.lpstrFilter = szFilter;
ofn.lpstrFile= szFile;
ofn.nMaxFile = sizeof(szFile)/ sizeof(*szFile);
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = sizeof(szFileTitle);
ofn.lpstrInitialDir = (LPSTR)NULL;
ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;
ofn.lpstrTitle = szTitle;
if (GetSaveFileName(&ofn))
{
try {
config.Save(ofn.lpstrFile);
} catch (std::runtime_error &e)
{
printf("Fehler: %s\n", e.what());
}
}
}
public:
/// @brief Handle messages fo the dialog pages.
/// @param hwndDlg Handle of active dialog.
/// @param uMsg Message code.
/// @param wParam Message parameter.
/// @param lParam Message parameter.
/// @param psp Handle to sheet paramters.
virtual INT_PTR PageDispatch(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam, PROPSHEETPAGE *psp)
{
HWND hwnd;
switch (uMsg)
{
case WM_INITDIALOG:
switch (PageID(PageIndex(psp)))
{
case IDD_DISPLAY:
// Init display dialog. Enable correct check buttons
switch (config.window)
{
default:
case CConfig::MultiWindow:
CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, IDC_MULTIWINDOW);
break;
case CConfig::Fullscreen:
CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, IDC_FULLSCREEN);
break;
case CConfig::Windowed:
CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, IDC_WINDOWED);
break;
case CConfig::Nodecoration:
CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, IDC_NODECORATION);
break;
}
// Set display number
SetDlgItemText(hwndDlg, IDC_DISPLAY, config.display.c_str());
break;
case IDD_CLIENTS:
// Init client dialog. Enable correct check buttons
switch (config.client)
{
default:
case CConfig::NoClient:
CheckRadioButton(hwndDlg, IDC_CLIENT_NONE, IDC_CLIENT, IDC_CLIENT_NONE);
break;
case CConfig::StartProgram:
CheckRadioButton(hwndDlg, IDC_CLIENT_NONE, IDC_CLIENT, IDC_CLIENT);
break;
case CConfig::XDMCP:
CheckRadioButton(hwndDlg, IDC_CLIENT_NONE, IDC_CLIENT, IDC_XDMCP);
break;
}
break;
case IDD_PROGRAM:
// Init program dialog. Check local and remote buttons
CheckRadioButton(hwndDlg, IDC_CLIENT_LOCAL, IDC_CLIENT_REMOTE, config.local?IDC_CLIENT_LOCAL:IDC_CLIENT_REMOTE);
EnableRemoteProgramGroup(hwndDlg, config.local?FALSE:TRUE);
// Fill combo boxes
FillProgramBox(hwndDlg);
FillProtocolBox(hwndDlg);
// Set edit fields
if (!config.program.empty())
SetDlgItemText(hwndDlg, IDC_CLIENT_PROGRAM, config.program.c_str());
SetDlgItemText(hwndDlg, IDC_CLIENT_USER, config.user.c_str());
SetDlgItemText(hwndDlg, IDC_CLIENT_HOST, config.host.c_str());
break;
case IDD_XDMCP:
// Init XDMCP dialog. Check broadcast and indirect button
CheckRadioButton(hwndDlg, IDC_XDMCP_QUERY, IDC_XDMCP_BROADCAST, config.broadcast?IDC_XDMCP_BROADCAST:IDC_XDMCP_QUERY);
CheckDlgButton(hwndDlg, IDC_XDMCP_INDIRECT, config.indirect?BST_CHECKED:BST_UNCHECKED);
EnableXDMCPQueryGroup(hwndDlg, config.broadcast?FALSE:TRUE);
// Set hostname
SetDlgItemText(hwndDlg, IDC_XDMCP_HOST, config.xdmcp_host.c_str());
break;
case IDD_CLIPBOARD:
CheckDlgButton(hwndDlg, IDC_CLIPBOARD, config.clipboard?BST_CHECKED:BST_UNCHECKED);
SetDlgItemText(hwndDlg, IDC_EXTRA_PARAMS, config.extra_params.c_str());
break;
}
case WM_COMMAND:
// Handle control messages
switch (LOWORD(wParam))
{
// Handle clicks on images. Check proper radiobutton
case IDC_MULTIWINDOW_IMG:
case IDC_FULLSCREEN_IMG:
case IDC_WINDOWED_IMG:
case IDC_NODECORATION_IMG:
CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, LOWORD(wParam)-4);
SetFocus(GetDlgItem(hwndDlg, LOWORD(wParam)-4));
break;
// Disable unavailable controls
case IDC_CLIENT_REMOTE:
case IDC_CLIENT_LOCAL:
EnableRemoteProgramGroup(hwndDlg, LOWORD(wParam) == IDC_CLIENT_REMOTE);
break;
case IDC_XDMCP_QUERY:
case IDC_XDMCP_BROADCAST:
EnableXDMCPQueryGroup(hwndDlg, LOWORD(wParam) == IDC_XDMCP_QUERY);
break;
case IDC_FINISH_SAVE:
ShowSaveDialog(hwndDlg);
break;
}
}
// pass messages to parent
return CWizard::PageDispatch(hwndDlg, uMsg, wParam, lParam, psp);
}
/// @brief Try to connect to server.
/// Repeat until successful, server died or maximum number of retries
/// reached.
Display *WaitForServer(HANDLE serverProcess)
{
int ncycles = 120; /* # of cycles to wait */
int cycles; /* Wait cycle count */
Display *xd;
for (cycles = 0; cycles < ncycles; cycles++) {
if ((xd = XOpenDisplay(NULL))) {
return xd;
}
else {
if (WaitForSingleObject(serverProcess, 1000) == WAIT_TIMEOUT)
continue;
}
}
return NULL;
}
/// @brief Do the actual start of Xming and clients
void StartUp()
{
std::string buffer;
std::string client;
// Construct display strings
std::string display_id = ":" + config.display;
std::string display = "localhost" + display_id + ":0";
#ifdef _DEBUG
// Debug only: Switch to Xming installation directory
SetCurrentDirectory("C:\\Programme\\Xming");
#endif
// Build Xming commandline
buffer = "Xming " + display_id + " ";
switch (config.window)
{
case CConfig::MultiWindow:
buffer += "-multiwindow ";
break;
case CConfig::Fullscreen:
buffer += "-fullscreen ";
break;
case CConfig::Nodecoration:
buffer += "-nodecoration ";
break;
default:
break;
}
// Add XDMCP parameter
if (config.client == CConfig::XDMCP)
{
if (config.broadcast)
buffer += "-broadcast ";
else
{
if (config.indirect)
buffer += "-indirect ";
else
buffer += "-query ";
buffer += config.xdmcp_host;
buffer += " ";
}
}
if (config.clipboard)
buffer += "-clipboard ";
if (!config.extra_params.empty())
{
buffer += config.extra_params;
buffer += " ";
}
// Construct client commandline
if (config.client == CConfig::StartProgram)
{
if (!config.local)
{
char cmdline[512];
std::string host = config.host;
if (!config.user.empty())
host = config.user + "@" + config.host;
if (config.protocol == "Putty")
snprintf(cmdline,512,"plink -X %s %s",
host.c_str(),config.program.c_str());
else
snprintf(cmdline,512,"ssh -Y %s %s",
host.c_str(),config.program.c_str());
client += cmdline;
} else
client += config.program.c_str();
}
// Prepare program startup
STARTUPINFO si, sic;
PROCESS_INFORMATION pi, pic;
HANDLE handles[2];
DWORD hcount = 0;
Display *dpy = NULL;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
ZeroMemory( &sic, sizeof(sic) );
sic.cb = sizeof(sic);
ZeroMemory( &pic, sizeof(pic) );
// Start Xming process.
#ifdef _DEBUG
printf("%s\n", buffer.c_str());
#endif
if( !CreateProcess( NULL, (CHAR*)buffer.c_str(), NULL, NULL,
FALSE, 0, NULL, NULL, &si, &pi ))
throw win32_error("CreateProcess failed");
handles[hcount++] = pi.hProcess;
if (!client.empty())
{
// Set DISPLAY variable
SetEnvironmentVariable("DISPLAY",display.c_str());
// Wait for server to startup
dpy = WaitForServer(pi.hProcess);
if (dpy == NULL)
{
while (hcount--)
TerminateProcess(handles[hcount], (DWORD)-1);
throw std::runtime_error("Connection to server failed");
}
#ifdef _DEBUG
printf("%s\n", client.c_str());
#endif
// Hide a console window
// FIXME: This may make it impossible to enter the password
sic.dwFlags = STARTF_USESHOWWINDOW;
sic.wShowWindow = SW_HIDE;
// Start the child process.
if( !CreateProcess( NULL, (CHAR*)client.c_str(), NULL, NULL,
FALSE, 0, NULL, NULL, &sic, &pic ))
{
DWORD err = GetLastError();
while (hcount--)
TerminateProcess(handles[hcount], (DWORD)-1);
throw win32_error("CreateProcess failed", err);
}
handles[hcount++] = pic.hProcess;
}
// Wait until any child process exits.
DWORD ret = WaitForMultipleObjects(hcount, handles, FALSE, INFINITE );
#ifdef _DEBUG
printf("killing process!\n");
#endif
// Check if Xming is still running
DWORD exitcode;
GetExitCodeProcess(pi.hProcess, &exitcode);
unsigned counter = 0;
while (exitcode == STILL_ACTIVE)
{
if (++counter > 10)
TerminateProcess(pi.hProcess, (DWORD)-1);
else
// Shutdown Xming (the soft way!)
EnumThreadWindows(pi.dwThreadId, KillWindowsProc, 0);
Sleep(500);
GetExitCodeProcess(pi.hProcess, &exitcode);
}
// Kill the client
TerminateProcess(pic.hProcess, (DWORD)-1);
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
CloseHandle( pic.hProcess );
CloseHandle( pic.hThread );
}
};
int main(int argc, char **argv)
{
try {
InitCommonControls();
CMyWizard dialog;
bool skip_wizard = false;
for (int i = 1; i < argc; i++)
{
if (argv[i] == NULL)
continue;
std::string arg(argv[i]);
if (arg == "-load" && i + 1 < argc)
{
i++;
dialog.LoadConfig(argv[i]);
continue;
}
if (arg == "-run" && i + 1 < argc)
{
i++;
dialog.LoadConfig(argv[i]);
skip_wizard = true;
continue;
}
}
int ret = 0;
if (skip_wizard || (ret =dialog.ShowModal()) != 0)
dialog.StartUp();
#ifdef _DEBUG
printf("return %d\n", ret);
#endif
return 0;
} catch (std::runtime_error &e)
{
printf("Fehler: %s\n", e.what());
return -1;
}
}