1/* 2 * Copyright (c) 2005 Alexander Gottwald 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 * 22 * Except as contained in this notice, the name(s) of the above copyright 23 * holders shall not be used in advertising or otherwise to promote the sale, 24 * use or other dealings in this Software without prior written authorization. 25 */ 26#include "window/util.h" 27#include "window/wizard.h" 28#include "resources/resources.h" 29#include "config.h" 30#include <prsht.h> 31#include <commctrl.h> 32 33#include <stdexcept> 34 35#include <X11/Xlib.h> 36 37/// @brief Send WM_ENDSESSION to all program windows. 38/// This will shutdown the started xserver 39BOOL CALLBACK KillWindowsProc(HWND hwnd, LPARAM lParam) 40{ 41 SendMessage(hwnd, WM_ENDSESSION, 0, 0); 42 return TRUE; 43} 44 45/// @brief Actual wizard implementation. 46/// This is based on generic CWizard but handles the special dialogs 47class CMyWizard : public CWizard 48{ 49 public: 50 private: 51 CConfig config; /// Storage for config options. 52 public: 53 /// @brief Constructor. 54 /// Set wizard pages. 55 CMyWizard() : CWizard() 56 { 57 AddPage(IDD_DISPLAY, IDS_DISPLAY_TITLE, IDS_DISPLAY_SUBTITLE); 58 AddPage(IDD_CLIENTS, IDS_CLIENTS_TITLE, IDS_CLIENTS_SUBTITLE); 59 AddPage(IDD_PROGRAM, IDS_PROGRAM_TITLE, IDS_PROGRAM_SUBTITLE); 60 AddPage(IDD_XDMCP, IDS_XDMCP_TITLE, IDS_XDMCP_SUBTITLE); 61 //AddPage(IDD_FONTPATH, IDS_FONTPATH_TITLE, IDS_FONTPATH_SUBTITLE); 62 AddPage(IDD_CLIPBOARD, IDS_CLIPBOARD_TITLE, IDS_CLIPBOARD_SUBTITLE); 63 AddPage(IDD_FINISH, IDS_FINISH_TITLE, IDS_FINISH_SUBTITLE); 64 } 65 66 virtual void LoadConfig(const char *filename) 67 { 68 try { 69 config.Load(filename); 70 } catch (std::runtime_error &e) 71 { 72 printf("Fehler: %s\n", e.what()); 73 } 74 } 75 76 /// @brief Handle the PSN_WIZNEXT message. 77 /// @param hwndDlg Handle to active page dialog. 78 /// @param index Index of current page. 79 /// @return TRUE if the message was handled. FALSE otherwise. 80 virtual BOOL WizardNext(HWND hwndDlg, unsigned index) 81 { 82#ifdef _DEBUG 83 printf("%s %d\n", __FUNCTION__, index); 84#endif 85 switch (PageID(index)) 86 { 87 case IDD_DISPLAY: 88 // Check for select window mode 89 if (IsDlgButtonChecked(hwndDlg, IDC_MULTIWINDOW)) 90 config.window = CConfig::MultiWindow; 91 else if (IsDlgButtonChecked(hwndDlg, IDC_FULLSCREEN)) 92 config.window = CConfig::Fullscreen; 93 else if (IsDlgButtonChecked(hwndDlg, IDC_WINDOWED)) 94 config.window = CConfig::Windowed; 95 else if (IsDlgButtonChecked(hwndDlg, IDC_NODECORATION)) 96 config.window = CConfig::Nodecoration; 97 else 98 { 99 SetWindowLong(hwndDlg, DWL_MSGRESULT, -1); 100 return TRUE; 101 } 102 // Get selected display number 103 { 104 char buffer[512]; 105 GetDlgItemText(hwndDlg, IDC_DISPLAY, buffer, 512); 106 buffer[511] = 0; 107 config.display = buffer; 108 } 109 // Check for valid input 110 if (config.display.empty()) 111 SetWindowLong(hwndDlg, DWL_MSGRESULT, -1); 112 else 113 SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIENTS); 114 return TRUE; 115 case IDD_CLIENTS: 116 // Check for select client startup method 117 if (IsDlgButtonChecked(hwndDlg, IDC_CLIENT)) 118 { 119 config.client = CConfig::StartProgram; 120 SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_PROGRAM); 121 } else if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP)) 122 { 123 config.client = CConfig::XDMCP; 124 SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_XDMCP); 125 } else if (IsDlgButtonChecked(hwndDlg, IDC_CLIENT_NONE)) 126 { 127 config.client = CConfig::NoClient; 128 SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIPBOARD); 129 } else 130 SetWindowLong(hwndDlg, DWL_MSGRESULT, -1); 131 return TRUE; 132 case IDD_PROGRAM: 133 // Check wether local or remote client should be started 134 if (IsDlgButtonChecked(hwndDlg, IDC_CLIENT_LOCAL)) 135 config.local = true; 136 else if (IsDlgButtonChecked(hwndDlg, IDC_CLIENT_REMOTE)) 137 config.local = false; 138 else 139 { 140 SetWindowLong(hwndDlg, DWL_MSGRESULT, -1); 141 return TRUE; 142 } 143 // Read program, user and host name 144 { 145 char buffer[512]; 146 GetDlgItemText(hwndDlg, IDC_CLIENT_USER, buffer, 512); 147 buffer[511] = 0; 148 config.user = buffer; 149 GetDlgItemText(hwndDlg, IDC_CLIENT_HOST, buffer, 512); 150 buffer[511] = 0; 151 config.host = buffer; 152 GetDlgItemText(hwndDlg, IDC_CLIENT_PROGRAM, buffer, 512); 153 buffer[511] = 0; 154 config.program = buffer; 155 } 156 // Check for valid input 157 if (!config.local && (config.host.empty() || config.program.empty())) 158 SetWindowLong(hwndDlg, DWL_MSGRESULT, -1); 159 else 160 SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIPBOARD); 161 return TRUE; 162 case IDD_XDMCP: 163 // Check for broadcast 164 if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP_BROADCAST)) 165 config.broadcast = true; 166 else if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP_QUERY)) 167 config.broadcast = false; 168 else 169 { 170 SetWindowLong(hwndDlg, DWL_MSGRESULT, -1); 171 return TRUE; 172 } 173 // Check for indirect mode 174 if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP_INDIRECT)) 175 config.indirect = true; 176 else 177 config.indirect = false; 178 // Read hostname 179 { 180 char buffer[512]; 181 GetDlgItemText(hwndDlg, IDC_XDMCP_HOST, buffer, 512); 182 buffer[511] = 0; 183 config.xdmcp_host = buffer; 184 } 185 // Check for valid input 186 if (!config.broadcast && config.xdmcp_host.empty()) 187 SetWindowLong(hwndDlg, DWL_MSGRESULT, -1); 188 else 189 SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIPBOARD); 190 return TRUE; 191 case IDD_CLIPBOARD: 192 // check for clipboard 193 if (IsDlgButtonChecked(hwndDlg, IDC_CLIPBOARD)) 194 config.clipboard = true; 195 else 196 config.clipboard = false; 197 // read parameters 198 { 199 char buffer[512]; 200 GetDlgItemText(hwndDlg, IDC_EXTRA_PARAMS, buffer, 512); 201 buffer[511] = 0; 202 config.extra_params = buffer; 203 } 204 SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_FINISH); 205 return TRUE; 206 default: 207 break; 208 } 209 return FALSE; 210 } 211 /// @brief Handle PSN_WIZFINISH message. 212 /// @param hwndDlg Handle to active page dialog. 213 /// @param index Index of current page. 214 /// @return TRUE if the message was handled. FALSE otherwise. 215 virtual BOOL WizardFinish(HWND hwndDlg, unsigned index) 216 { 217#ifdef _DEBUG 218 printf("finish %d\n", index); 219#endif 220 return FALSE; 221 } 222 /// @brief Handle PSN_WIZBACK message. 223 /// Basicly handles switching to proper page (skipping XDMCP or program page 224 /// if required). 225 /// @param hwndDlg Handle to active page dialog. 226 /// @param index Index of current page. 227 /// @return TRUE if the message was handled. FALSE otherwise. 228 virtual BOOL WizardBack(HWND hwndDlg, unsigned index) 229 { 230 switch (PageID(index)) 231 { 232 case IDD_PROGRAM: 233 case IDD_XDMCP: 234 SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIENTS); 235 return TRUE; 236 case IDD_FONTPATH: 237 case IDD_CLIPBOARD: // temporary. fontpath is disabled 238 switch (config.client) 239 { 240 case CConfig::NoClient: 241 SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIENTS); 242 return TRUE; 243 case CConfig::StartProgram: 244 SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_PROGRAM); 245 return TRUE; 246 case CConfig::XDMCP: 247 SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_XDMCP); 248 return TRUE; 249 } 250 break; 251 } 252 return FALSE; 253 } 254 /// @brief Handle PSN_SETACTIVE message. 255 /// @param hwndDlg Handle to active page dialog. 256 /// @param index Index of current page. 257 /// @return TRUE if the message was handled. FALSE otherwise. 258 virtual BOOL WizardActivate(HWND hwndDlg, unsigned index) 259 { 260#ifdef _DEBUG 261 printf("%s %d\n", __FUNCTION__, index); 262#endif 263 switch (PageID(index)) 264 { 265 case IDD_CLIENTS: 266 // Enable or disable XDMCP radiobutton and text 267 EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP), config.window != CConfig::MultiWindow); 268 EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP_DESC), config.window != CConfig::MultiWindow); 269 break; 270 } 271 return FALSE; 272 } 273 protected: 274 /// @brief Enable or disable the control for remote clients. 275 /// @param hwndDlg Handle to active page dialog. 276 /// @param state State of control group. 277 void EnableRemoteProgramGroup(HWND hwndDlg, BOOL state) 278 { 279 EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_PROTOCOL), state); 280 EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_HOST), state); 281 EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_USER), state); 282 EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_PROTOCOL_DESC), state); 283 EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_HOST_DESC), state); 284 EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_USER_DESC), state); 285 } 286 /// @brief Enable or disable the control for XDMCP connection. 287 /// @param hwndDlg Handle to active page dialog. 288 /// @param state State of control group. 289 void EnableXDMCPQueryGroup(HWND hwndDlg, BOOL state) 290 { 291 EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP_HOST), state); 292 EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP_INDIRECT), state); 293 } 294 /// @brief Fill program box with default values. 295 /// @param hwndDlg Handle to active page dialog. 296 void FillProgramBox(HWND hwndDlg) 297 { 298 HWND cbwnd = GetDlgItem(hwndDlg, IDC_CLIENT_PROGRAM); 299 if (cbwnd == NULL) 300 return; 301 SendMessage(cbwnd, CB_RESETCONTENT, 0, 0); 302 SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "xterm"); 303 SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "startkde"); 304 SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "gnome-session"); 305 SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) ".xinitrc"); 306 SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "wmaker"); 307 SendMessage(cbwnd, CB_SETCURSEL, 0, 0); 308 } 309 /// @brief Fill protocol box with default values. 310 /// @param hwndDlg Handle to active page dialog. 311 void FillProtocolBox(HWND hwndDlg) 312 { 313 HWND cbwnd = GetDlgItem(hwndDlg, IDC_CLIENT_PROTOCOL); 314 if (cbwnd == NULL) 315 return; 316 SendMessage(cbwnd, CB_RESETCONTENT, 0, 0); 317 SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "Putty"); 318 //SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "OpenSSH"); 319 SendMessage(cbwnd, CB_SETCURSEL, 0, 0); 320 } 321 void ShowSaveDialog(HWND parent) 322 { 323 char szTitle[512]; 324 char szFilter[512]; 325 char szFileTitle[512]; 326 char szFile[MAX_PATH]; 327 HINSTANCE hInst = GetModuleHandle(NULL); 328 329 LoadString(hInst, IDS_SAVE_TITLE, szTitle, sizeof(szTitle)); 330 LoadString(hInst, IDS_SAVE_FILETITLE, szFileTitle, sizeof(szFileTitle)); 331 LoadString(hInst, IDS_SAVE_FILTER, szFilter, sizeof(szFilter)); 332 for (unsigned i=0; szFilter[i]; i++) 333 if (szFilter[i] == '%') 334 szFilter[i] = '\0'; 335 336 strcpy(szFile, "config.xlaunch"); 337 338 OPENFILENAME ofn; 339 memset(&ofn, 0, sizeof(OPENFILENAME)); 340 ofn.lStructSize = sizeof(OPENFILENAME); 341 ofn.hwndOwner = parent; 342 ofn.lpstrFilter = szFilter; 343 ofn.lpstrFile= szFile; 344 ofn.nMaxFile = sizeof(szFile)/ sizeof(*szFile); 345 ofn.lpstrFileTitle = szFileTitle; 346 ofn.nMaxFileTitle = sizeof(szFileTitle); 347 ofn.lpstrInitialDir = (LPSTR)NULL; 348 ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT; 349 ofn.lpstrTitle = szTitle; 350 351 if (GetSaveFileName(&ofn)) 352 { 353 try { 354 config.Save(ofn.lpstrFile); 355 } catch (std::runtime_error &e) 356 { 357 printf("Fehler: %s\n", e.what()); 358 } 359 } 360 } 361 public: 362 363 /// @brief Handle messages fo the dialog pages. 364 /// @param hwndDlg Handle of active dialog. 365 /// @param uMsg Message code. 366 /// @param wParam Message parameter. 367 /// @param lParam Message parameter. 368 /// @param psp Handle to sheet paramters. 369 virtual INT_PTR PageDispatch(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam, PROPSHEETPAGE *psp) 370 { 371 HWND hwnd; 372 switch (uMsg) 373 { 374 case WM_INITDIALOG: 375 switch (PageID(PageIndex(psp))) 376 { 377 case IDD_DISPLAY: 378 // Init display dialog. Enable correct check buttons 379 switch (config.window) 380 { 381 default: 382 case CConfig::MultiWindow: 383 CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, IDC_MULTIWINDOW); 384 break; 385 case CConfig::Fullscreen: 386 CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, IDC_FULLSCREEN); 387 break; 388 case CConfig::Windowed: 389 CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, IDC_WINDOWED); 390 break; 391 case CConfig::Nodecoration: 392 CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, IDC_NODECORATION); 393 break; 394 } 395 // Set display number 396 SetDlgItemText(hwndDlg, IDC_DISPLAY, config.display.c_str()); 397 break; 398 case IDD_CLIENTS: 399 // Init client dialog. Enable correct check buttons 400 switch (config.client) 401 { 402 default: 403 case CConfig::NoClient: 404 CheckRadioButton(hwndDlg, IDC_CLIENT_NONE, IDC_CLIENT, IDC_CLIENT_NONE); 405 break; 406 case CConfig::StartProgram: 407 CheckRadioButton(hwndDlg, IDC_CLIENT_NONE, IDC_CLIENT, IDC_CLIENT); 408 break; 409 case CConfig::XDMCP: 410 CheckRadioButton(hwndDlg, IDC_CLIENT_NONE, IDC_CLIENT, IDC_XDMCP); 411 break; 412 } 413 break; 414 case IDD_PROGRAM: 415 // Init program dialog. Check local and remote buttons 416 CheckRadioButton(hwndDlg, IDC_CLIENT_LOCAL, IDC_CLIENT_REMOTE, config.local?IDC_CLIENT_LOCAL:IDC_CLIENT_REMOTE); 417 EnableRemoteProgramGroup(hwndDlg, config.local?FALSE:TRUE); 418 // Fill combo boxes 419 FillProgramBox(hwndDlg); 420 FillProtocolBox(hwndDlg); 421 // Set edit fields 422 if (!config.program.empty()) 423 SetDlgItemText(hwndDlg, IDC_CLIENT_PROGRAM, config.program.c_str()); 424 SetDlgItemText(hwndDlg, IDC_CLIENT_USER, config.user.c_str()); 425 SetDlgItemText(hwndDlg, IDC_CLIENT_HOST, config.host.c_str()); 426 break; 427 case IDD_XDMCP: 428 // Init XDMCP dialog. Check broadcast and indirect button 429 CheckRadioButton(hwndDlg, IDC_XDMCP_QUERY, IDC_XDMCP_BROADCAST, config.broadcast?IDC_XDMCP_BROADCAST:IDC_XDMCP_QUERY); 430 CheckDlgButton(hwndDlg, IDC_XDMCP_INDIRECT, config.indirect?BST_CHECKED:BST_UNCHECKED); 431 EnableXDMCPQueryGroup(hwndDlg, config.broadcast?FALSE:TRUE); 432 // Set hostname 433 SetDlgItemText(hwndDlg, IDC_XDMCP_HOST, config.xdmcp_host.c_str()); 434 break; 435 case IDD_CLIPBOARD: 436 CheckDlgButton(hwndDlg, IDC_CLIPBOARD, config.clipboard?BST_CHECKED:BST_UNCHECKED); 437 SetDlgItemText(hwndDlg, IDC_EXTRA_PARAMS, config.extra_params.c_str()); 438 break; 439 440 } 441 case WM_COMMAND: 442 // Handle control messages 443 switch (LOWORD(wParam)) 444 { 445 // Handle clicks on images. Check proper radiobutton 446 case IDC_MULTIWINDOW_IMG: 447 case IDC_FULLSCREEN_IMG: 448 case IDC_WINDOWED_IMG: 449 case IDC_NODECORATION_IMG: 450 CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, LOWORD(wParam)-4); 451 SetFocus(GetDlgItem(hwndDlg, LOWORD(wParam)-4)); 452 break; 453 // Disable unavailable controls 454 case IDC_CLIENT_REMOTE: 455 case IDC_CLIENT_LOCAL: 456 EnableRemoteProgramGroup(hwndDlg, LOWORD(wParam) == IDC_CLIENT_REMOTE); 457 break; 458 case IDC_XDMCP_QUERY: 459 case IDC_XDMCP_BROADCAST: 460 EnableXDMCPQueryGroup(hwndDlg, LOWORD(wParam) == IDC_XDMCP_QUERY); 461 break; 462 case IDC_FINISH_SAVE: 463 ShowSaveDialog(hwndDlg); 464 break; 465 } 466 } 467 // pass messages to parent 468 return CWizard::PageDispatch(hwndDlg, uMsg, wParam, lParam, psp); 469 } 470 471 /// @brief Try to connect to server. 472 /// Repeat until successful, server died or maximum number of retries 473 /// reached. 474 Display *WaitForServer(HANDLE serverProcess) 475 { 476 int ncycles = 120; /* # of cycles to wait */ 477 int cycles; /* Wait cycle count */ 478 Display *xd; 479 480 for (cycles = 0; cycles < ncycles; cycles++) { 481 if ((xd = XOpenDisplay(NULL))) { 482 return xd; 483 } 484 else { 485 if (WaitForSingleObject(serverProcess, 1000) == WAIT_TIMEOUT) 486 continue; 487 } 488 } 489 return NULL; 490 } 491 492 /// @brief Do the actual start of Xming and clients 493 void StartUp() 494 { 495 std::string buffer; 496 std::string client; 497 498 // Construct display strings 499 std::string display_id = ":" + config.display; 500 std::string display = "localhost" + display_id + ":0"; 501 502#ifdef _DEBUG 503 // Debug only: Switch to Xming installation directory 504 SetCurrentDirectory("C:\\Programme\\Xming"); 505#endif 506 507 // Build Xming commandline 508 buffer = "Xming " + display_id + " "; 509 switch (config.window) 510 { 511 case CConfig::MultiWindow: 512 buffer += "-multiwindow "; 513 break; 514 case CConfig::Fullscreen: 515 buffer += "-fullscreen "; 516 break; 517 case CConfig::Nodecoration: 518 buffer += "-nodecoration "; 519 break; 520 default: 521 break; 522 } 523 // Add XDMCP parameter 524 if (config.client == CConfig::XDMCP) 525 { 526 if (config.broadcast) 527 buffer += "-broadcast "; 528 else 529 { 530 if (config.indirect) 531 buffer += "-indirect "; 532 else 533 buffer += "-query "; 534 buffer += config.xdmcp_host; 535 buffer += " "; 536 } 537 } 538 if (config.clipboard) 539 buffer += "-clipboard "; 540 if (!config.extra_params.empty()) 541 { 542 buffer += config.extra_params; 543 buffer += " "; 544 } 545 546 // Construct client commandline 547 if (config.client == CConfig::StartProgram) 548 { 549 if (!config.local) 550 { 551 char cmdline[512]; 552 std::string host = config.host; 553 if (!config.user.empty()) 554 host = config.user + "@" + config.host; 555 if (config.protocol == "Putty") 556 snprintf(cmdline,512,"plink -X %s %s", 557 host.c_str(),config.program.c_str()); 558 else 559 snprintf(cmdline,512,"ssh -Y %s %s", 560 host.c_str(),config.program.c_str()); 561 client += cmdline; 562 } else 563 client += config.program.c_str(); 564 } 565 566 // Prepare program startup 567 STARTUPINFO si, sic; 568 PROCESS_INFORMATION pi, pic; 569 HANDLE handles[2]; 570 DWORD hcount = 0; 571 Display *dpy = NULL; 572 573 ZeroMemory( &si, sizeof(si) ); 574 si.cb = sizeof(si); 575 ZeroMemory( &pi, sizeof(pi) ); 576 ZeroMemory( &sic, sizeof(sic) ); 577 sic.cb = sizeof(sic); 578 ZeroMemory( &pic, sizeof(pic) ); 579 580 // Start Xming process. 581#ifdef _DEBUG 582 printf("%s\n", buffer.c_str()); 583#endif 584 if( !CreateProcess( NULL, (CHAR*)buffer.c_str(), NULL, NULL, 585 FALSE, 0, NULL, NULL, &si, &pi )) 586 throw win32_error("CreateProcess failed"); 587 handles[hcount++] = pi.hProcess; 588 589 if (!client.empty()) 590 { 591 // Set DISPLAY variable 592 SetEnvironmentVariable("DISPLAY",display.c_str()); 593 594 // Wait for server to startup 595 dpy = WaitForServer(pi.hProcess); 596 if (dpy == NULL) 597 { 598 while (hcount--) 599 TerminateProcess(handles[hcount], (DWORD)-1); 600 throw std::runtime_error("Connection to server failed"); 601 } 602 603#ifdef _DEBUG 604 printf("%s\n", client.c_str()); 605#endif 606 607 // Hide a console window 608 // FIXME: This may make it impossible to enter the password 609 sic.dwFlags = STARTF_USESHOWWINDOW; 610 sic.wShowWindow = SW_HIDE; 611 612 // Start the child process. 613 if( !CreateProcess( NULL, (CHAR*)client.c_str(), NULL, NULL, 614 FALSE, 0, NULL, NULL, &sic, &pic )) 615 { 616 DWORD err = GetLastError(); 617 while (hcount--) 618 TerminateProcess(handles[hcount], (DWORD)-1); 619 throw win32_error("CreateProcess failed", err); 620 } 621 handles[hcount++] = pic.hProcess; 622 } 623 624 // Wait until any child process exits. 625 DWORD ret = WaitForMultipleObjects(hcount, handles, FALSE, INFINITE ); 626 627#ifdef _DEBUG 628 printf("killing process!\n"); 629#endif 630 // Check if Xming is still running 631 DWORD exitcode; 632 GetExitCodeProcess(pi.hProcess, &exitcode); 633 unsigned counter = 0; 634 while (exitcode == STILL_ACTIVE) 635 { 636 if (++counter > 10) 637 TerminateProcess(pi.hProcess, (DWORD)-1); 638 else 639 // Shutdown Xming (the soft way!) 640 EnumThreadWindows(pi.dwThreadId, KillWindowsProc, 0); 641 Sleep(500); 642 GetExitCodeProcess(pi.hProcess, &exitcode); 643 } 644 // Kill the client 645 TerminateProcess(pic.hProcess, (DWORD)-1); 646 647 // Close process and thread handles. 648 CloseHandle( pi.hProcess ); 649 CloseHandle( pi.hThread ); 650 CloseHandle( pic.hProcess ); 651 CloseHandle( pic.hThread ); 652 } 653}; 654 655int main(int argc, char **argv) 656{ 657 try { 658 InitCommonControls(); 659 CMyWizard dialog; 660 661 bool skip_wizard = false; 662 663 for (int i = 1; i < argc; i++) 664 { 665 if (argv[i] == NULL) 666 continue; 667 668 std::string arg(argv[i]); 669 if (arg == "-load" && i + 1 < argc) 670 { 671 i++; 672 dialog.LoadConfig(argv[i]); 673 continue; 674 } 675 if (arg == "-run" && i + 1 < argc) 676 { 677 i++; 678 dialog.LoadConfig(argv[i]); 679 skip_wizard = true; 680 continue; 681 } 682 } 683 684 int ret = 0; 685 if (skip_wizard || (ret =dialog.ShowModal()) != 0) 686 dialog.StartUp(); 687#ifdef _DEBUG 688 printf("return %d\n", ret); 689#endif 690 return 0; 691 } catch (std::runtime_error &e) 692 { 693 printf("Fehler: %s\n", e.what()); 694 return -1; 695 } 696} 697 698 699 700 701