Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members

launcher.cpp

00001 /*
00002  * synergy -- mouse and keyboard sharing utility
00003  * Copyright (C) 2002 Chris Schoeneman
00004  * 
00005  * This package is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * found in the file COPYING that should have accompanied this file.
00008  * 
00009  * This package is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  */
00014 
00015 #include "CConfig.h"
00016 #include "KeyTypes.h"
00017 #include "OptionTypes.h"
00018 #include "ProtocolTypes.h"
00019 #include "CLog.h"
00020 #include "CStringUtil.h"
00021 #include "CArch.h"
00022 #include "CArchMiscWindows.h"
00023 #include "XArch.h"
00024 #include "Version.h"
00025 #include "stdvector.h"
00026 #include "resource.h"
00027 
00028 // these must come after the above because it includes windows.h
00029 #include "LaunchUtil.h"
00030 #include "CAddScreen.h"
00031 #include "CAdvancedOptions.h"
00032 #include "CAutoStart.h"
00033 #include "CGlobalOptions.h"
00034 #include "CHotkeyOptions.h"
00035 #include "CInfo.h"
00036 #include "CScreensLinks.h"
00037 
00038 typedef std::vector<CString> CStringList;
00039 
00040 class CChildWaitInfo {
00041 public:
00042     HWND                m_dialog;
00043     HANDLE              m_child;
00044     DWORD               m_childID;
00045     HANDLE              m_ready;
00046     HANDLE              m_stop;
00047 };
00048 
00049 static const char* s_debugName[][2] = {
00050     { TEXT("Error"),   "ERROR" },
00051     { TEXT("Warning"), "WARNING" },
00052     { TEXT("Note"),    "NOTE" },
00053     { TEXT("Info"),    "INFO" },
00054     { TEXT("Debug"),   "DEBUG" },
00055     { TEXT("Debug1"),  "DEBUG1" },
00056     { TEXT("Debug2"),  "DEBUG2" }
00057 };
00058 static const int s_defaultDebug = 1;    // WARNING
00059 static const int s_minTestDebug = 3;    // INFO
00060 
00061 HINSTANCE s_instance = NULL;
00062 
00063 static CGlobalOptions*      s_globalOptions   = NULL;
00064 static CAdvancedOptions*    s_advancedOptions = NULL;
00065 static CHotkeyOptions*      s_hotkeyOptions   = NULL;
00066 static CScreensLinks*       s_screensLinks    = NULL;
00067 static CInfo*               s_info            = NULL;
00068 
00069 static bool     s_userConfig = true;
00070 static time_t   s_configTime = 0;
00071 static CConfig  s_lastConfig;
00072 
00073 static const TCHAR* s_mainClass   = TEXT("GoSynergy");
00074 static const TCHAR* s_layoutClass = TEXT("SynergyLayout");
00075 
00076 enum SaveMode {
00077     SAVE_QUITING,
00078     SAVE_NORMAL,
00079     SAVE_QUIET
00080 };
00081 
00082 //
00083 // program arguments
00084 //
00085 
00086 #define ARG CArgs::s_instance
00087 
00088 class CArgs {
00089 public:
00090     CArgs() { s_instance = this; }
00091     ~CArgs() { s_instance = NULL; }
00092 
00093 public:
00094     static CArgs*       s_instance;
00095     CConfig             m_config;
00096     CStringList         m_screens;
00097 };
00098 
00099 CArgs*                  CArgs::s_instance = NULL;
00100 
00101 
00102 static
00103 BOOL CALLBACK
00104 addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
00105 
00106 static
00107 bool
00108 isClientChecked(HWND hwnd)
00109 {
00110     HWND child = getItem(hwnd, IDC_MAIN_CLIENT_RADIO);
00111     return isItemChecked(child);
00112 }
00113 
00114 static
00115 void
00116 enableMainWindowControls(HWND hwnd)
00117 {
00118     bool client = isClientChecked(hwnd);
00119     enableItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_LABEL, client);
00120     enableItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT, client);
00121     enableItem(hwnd, IDC_MAIN_SERVER_SCREENS_LABEL, !client);
00122     enableItem(hwnd, IDC_MAIN_SCREENS, !client);
00123     enableItem(hwnd, IDC_MAIN_OPTIONS, !client);
00124     enableItem(hwnd, IDC_MAIN_HOTKEYS, !client);
00125 }
00126 
00127 static
00128 bool
00129 execApp(const char* app, const CString& cmdLine, PROCESS_INFORMATION* procInfo)
00130 {
00131     // prepare startup info
00132     STARTUPINFO startup;
00133     startup.cb              = sizeof(startup);
00134     startup.lpReserved      = NULL;
00135     startup.lpDesktop       = NULL;
00136     startup.lpTitle         = NULL;
00137     startup.dwX             = (DWORD)CW_USEDEFAULT;
00138     startup.dwY             = (DWORD)CW_USEDEFAULT;
00139     startup.dwXSize         = (DWORD)CW_USEDEFAULT;
00140     startup.dwYSize         = (DWORD)CW_USEDEFAULT;
00141     startup.dwXCountChars   = 0;
00142     startup.dwYCountChars   = 0;
00143     startup.dwFillAttribute = 0;
00144     startup.dwFlags         = STARTF_FORCEONFEEDBACK;
00145     startup.wShowWindow     = SW_SHOWDEFAULT;
00146     startup.cbReserved2     = 0;
00147     startup.lpReserved2     = NULL;
00148     startup.hStdInput       = NULL;
00149     startup.hStdOutput      = NULL;
00150     startup.hStdError       = NULL;
00151 
00152     // prepare path to app
00153     CString appPath = getAppPath(app);
00154 
00155     // put path to app in command line
00156     CString commandLine = "\"";
00157     commandLine += appPath;
00158     commandLine += "\" ";
00159     commandLine += cmdLine;
00160 
00161     // start child
00162     if (CreateProcess(NULL, (char*)commandLine.c_str(),
00163                                 NULL,
00164                                 NULL,
00165                                 FALSE,
00166                                 CREATE_DEFAULT_ERROR_MODE |
00167                                     CREATE_NEW_PROCESS_GROUP |
00168                                     NORMAL_PRIORITY_CLASS,
00169                                 NULL,
00170                                 NULL,
00171                                 &startup,
00172                                 procInfo) == 0) {
00173         return false;
00174     }
00175     else {
00176         return true;
00177     }
00178 }
00179 
00180 static
00181 CString
00182 getCommandLine(HWND hwnd, bool testing, bool silent)
00183 {
00184     CString cmdLine;
00185 
00186     // add constant testing args
00187     if (testing) {
00188         cmdLine += " -z --no-restart --no-daemon";
00189     }
00190 
00191     // can't start as service on NT
00192     else if (!CArchMiscWindows::isWindows95Family()) {
00193         cmdLine += " --no-daemon";
00194     }
00195 
00196     // get the server name
00197     CString server;
00198     bool isClient = isClientChecked(hwnd);
00199     if (isClient) {
00200         // check server name
00201         HWND child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
00202         server = getWindowText(child);
00203         if (!ARG->m_config.isValidScreenName(server)) {
00204             if (!silent) {
00205                 showError(hwnd, CStringUtil::format(
00206                                 getString(IDS_INVALID_SERVER_NAME).c_str(),
00207                                 server.c_str()));
00208             }
00209             SetFocus(child);
00210             return CString();
00211         }
00212 
00213         // compare server name to local host.  a common error
00214         // is to provide the client's name for the server.  we
00215         // don't bother to check the addresses though that'd be
00216         // more accurate.
00217         if (CStringUtil::CaselessCmp::equal(ARCH->getHostName(), server)) {
00218             if (!silent) {
00219                 showError(hwnd, CStringUtil::format(
00220                                 getString(IDS_SERVER_IS_CLIENT).c_str(),
00221                                 server.c_str()));
00222             }
00223             SetFocus(child);
00224             return CString();
00225         }
00226     }
00227 
00228     // debug level.  always include this.
00229     if (true) {
00230         HWND child = getItem(hwnd, IDC_MAIN_DEBUG);
00231         int debug  = (int)SendMessage(child, CB_GETCURSEL, 0, 0);
00232 
00233         // if testing then we force the debug level to be no less than
00234         // s_minTestDebug.   what's the point of testing if you can't
00235         // see the debugging info?
00236         if (testing && debug < s_minTestDebug) {
00237             debug = s_minTestDebug;
00238         }
00239 
00240         cmdLine    += " --debug ";
00241         cmdLine    += s_debugName[debug][1];
00242     }
00243 
00244     // add advanced options
00245     cmdLine += s_advancedOptions->getCommandLine(isClient, server);
00246 
00247     return cmdLine;
00248 }
00249 
00250 static
00251 bool
00252 launchApp(HWND hwnd, bool testing, HANDLE* thread, DWORD* threadID)
00253 {
00254     if (thread != NULL) {
00255         *thread = NULL;
00256     }
00257     if (threadID != NULL) {
00258         *threadID = 0;
00259     }
00260 
00261     // start daemon if it's installed and we're not testing
00262     if (!testing && CAutoStart::startDaemon()) {
00263         return true;
00264     }
00265 
00266     // decide if client or server
00267     const bool isClient = isClientChecked(hwnd);
00268     const char* app = isClient ? CLIENT_APP : SERVER_APP;
00269 
00270     // prepare command line
00271     CString cmdLine = getCommandLine(hwnd, testing, false);
00272     if (cmdLine.empty()) {
00273         return false;
00274     }
00275 
00276     // start child
00277     PROCESS_INFORMATION procInfo;
00278     if (!execApp(app, cmdLine, &procInfo)) {
00279         showError(hwnd, CStringUtil::format(
00280                                 getString(IDS_STARTUP_FAILED).c_str(),
00281                                 getErrorString(GetLastError()).c_str()));
00282         return false;
00283     }
00284 
00285     // don't need process handle
00286     CloseHandle(procInfo.hProcess);
00287 
00288     // save thread handle and thread ID if desired
00289     if (thread != NULL) {
00290         *thread = procInfo.hThread;
00291     }
00292     if (threadID != NULL) {
00293         *threadID = procInfo.dwThreadId;
00294     }
00295 
00296     return true;
00297 }
00298 
00299 static
00300 BOOL CALLBACK
00301 waitDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
00302 {
00303     // only one wait dialog at a time!
00304     static CChildWaitInfo* info = NULL;
00305 
00306     switch (message) {
00307     case WM_INITDIALOG:
00308         // save info pointer
00309         info = reinterpret_cast<CChildWaitInfo*>(lParam);
00310 
00311         // save hwnd
00312         info->m_dialog = hwnd;
00313 
00314         // signal ready
00315         SetEvent(info->m_ready);
00316 
00317         return TRUE;
00318 
00319     case WM_COMMAND:
00320         switch (LOWORD(wParam)) {
00321         case IDCANCEL:
00322         case IDOK:
00323             // signal stop
00324             SetEvent(info->m_stop);
00325 
00326             // done
00327             EndDialog(hwnd, 0);
00328             return TRUE;
00329         }
00330     }
00331 
00332     return FALSE;
00333 }
00334 
00335 static
00336 DWORD WINAPI
00337 waitForChildThread(LPVOID vinfo)
00338 {
00339     CChildWaitInfo* info = reinterpret_cast<CChildWaitInfo*>(vinfo);
00340 
00341     // wait for ready
00342     WaitForSingleObject(info->m_ready, INFINITE);
00343 
00344     // wait for thread to complete or stop event
00345     HANDLE handles[2];
00346     handles[0] = info->m_child;
00347     handles[1] = info->m_stop;
00348     DWORD n = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
00349 
00350     // if stop was raised then terminate child and wait for it
00351     if (n == WAIT_OBJECT_0 + 1) {
00352         PostThreadMessage(info->m_childID, WM_QUIT, 0, 0);
00353         WaitForSingleObject(info->m_child, INFINITE);
00354     }
00355 
00356     // otherwise post IDOK to dialog box
00357     else {
00358         PostMessage(info->m_dialog, WM_COMMAND, MAKEWPARAM(IDOK, 0), 0);
00359     }
00360 
00361     return 0;
00362 }
00363 
00364 static
00365 void
00366 waitForChild(HWND hwnd, HANDLE thread, DWORD threadID)
00367 {
00368     // prepare info for child wait dialog and thread
00369     CChildWaitInfo info;
00370     info.m_dialog  = NULL;
00371     info.m_child   = thread;
00372     info.m_childID = threadID;
00373     info.m_ready   = CreateEvent(NULL, TRUE, FALSE, NULL);
00374     info.m_stop    = CreateEvent(NULL, TRUE, FALSE, NULL);
00375 
00376     // create a thread to wait on the child thread and event
00377     DWORD id;
00378     HANDLE waiter = CreateThread(NULL, 0, &waitForChildThread, &info,0, &id);
00379 
00380     // do dialog that let's the user terminate the test
00381     DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_WAIT), hwnd,
00382                                 (DLGPROC)waitDlgProc, (LPARAM)&info);
00383 
00384     // force the waiter thread to finish and wait for it
00385     SetEvent(info.m_ready);
00386     SetEvent(info.m_stop);
00387     WaitForSingleObject(waiter, INFINITE);
00388 
00389     // clean up
00390     CloseHandle(waiter);
00391     CloseHandle(info.m_ready);
00392     CloseHandle(info.m_stop);
00393 }
00394 
00395 static
00396 void
00397 initMainWindow(HWND hwnd)
00398 {
00399     // append version number to title
00400     CString titleFormat = getString(IDS_TITLE);
00401     setWindowText(hwnd, CStringUtil::format(titleFormat.c_str(), kApplication, kVersion));
00402 
00403     // load configuration
00404     bool configLoaded =
00405         loadConfig(ARG->m_config, s_configTime, s_userConfig);
00406     if (configLoaded) {
00407         s_lastConfig = ARG->m_config;
00408     }
00409 
00410     // get settings from registry
00411     bool isServer = configLoaded;
00412     int debugLevel = s_defaultDebug;
00413     CString server;
00414     HKEY key = CArchMiscWindows::openKey(HKEY_CURRENT_USER, getSettingsPath());
00415     if (key != NULL) {
00416         if (isServer && CArchMiscWindows::hasValue(key, "isServer")) {
00417             isServer = (CArchMiscWindows::readValueInt(key, "isServer") != 0);
00418         }
00419         if (CArchMiscWindows::hasValue(key, "debug")) {
00420             debugLevel = static_cast<int>(
00421                                 CArchMiscWindows::readValueInt(key, "debug"));
00422             if (debugLevel < 0) {
00423                 debugLevel = 0;
00424             }
00425             else if (debugLevel > CLog::kDEBUG2) {
00426                 debugLevel = CLog::kDEBUG2;
00427             }
00428         }
00429         server = CArchMiscWindows::readValueString(key, "server");
00430         CArchMiscWindows::closeKey(key);
00431     }
00432 
00433     // choose client/server radio buttons
00434     HWND child;
00435     child = getItem(hwnd, IDC_MAIN_CLIENT_RADIO);
00436     setItemChecked(child, !isServer);
00437     child = getItem(hwnd, IDC_MAIN_SERVER_RADIO);
00438     setItemChecked(child, isServer);
00439 
00440     // set server name
00441     child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
00442     setWindowText(child, server);
00443 
00444     // debug level
00445     child = getItem(hwnd, IDC_MAIN_DEBUG);
00446     for (unsigned int i = 0; i < sizeof(s_debugName) /
00447                                 sizeof(s_debugName[0]); ++i) {
00448         SendMessage(child, CB_ADDSTRING, 0, (LPARAM)s_debugName[i][0]);
00449     }
00450     SendMessage(child, CB_SETCURSEL, debugLevel, 0);
00451 
00452     // update controls
00453     enableMainWindowControls(hwnd);
00454 }
00455 
00456 static
00457 bool
00458 saveMainWindow(HWND hwnd, SaveMode mode, CString* cmdLineOut = NULL)
00459 {
00460     DWORD errorID = 0;
00461     CString arg;
00462     CString cmdLine;
00463 
00464     // save dialog state
00465     bool isClient = isClientChecked(hwnd);
00466     HKEY key = CArchMiscWindows::addKey(HKEY_CURRENT_USER, getSettingsPath());
00467     if (key != NULL) {
00468         HWND child;
00469         child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
00470         CArchMiscWindows::setValue(key, "server", getWindowText(child));
00471         child = getItem(hwnd, IDC_MAIN_DEBUG);
00472         CArchMiscWindows::setValue(key, "debug",
00473                                 SendMessage(child, CB_GETCURSEL, 0, 0));
00474         CArchMiscWindows::setValue(key, "isServer", isClient ? 0 : 1);
00475         CArchMiscWindows::closeKey(key);
00476     }
00477 
00478     // save user's configuration
00479     if (!s_userConfig || ARG->m_config != s_lastConfig) {
00480         time_t t;
00481         if (!saveConfig(ARG->m_config, false, t)) {
00482             errorID = IDS_SAVE_FAILED;
00483             arg     = getErrorString(GetLastError());
00484             goto failed;
00485         }
00486         if (s_userConfig) {
00487             s_configTime = t;
00488             s_lastConfig = ARG->m_config;
00489         }
00490     }
00491 
00492     // save autostart configuration
00493     if (CAutoStart::isDaemonInstalled()) {
00494         if (s_userConfig || ARG->m_config != s_lastConfig) {
00495             time_t t;
00496             if (!saveConfig(ARG->m_config, true, t)) {
00497                 errorID = IDS_AUTOSTART_SAVE_FAILED;
00498                 arg     = getErrorString(GetLastError());
00499                 goto failed;
00500             }
00501             if (!s_userConfig) {
00502                 s_configTime = t;
00503                 s_lastConfig = ARG->m_config;
00504             }
00505         }
00506     }
00507 
00508     // get autostart command
00509     cmdLine = getCommandLine(hwnd, false, mode == SAVE_QUITING);
00510     if (cmdLineOut != NULL) {
00511         *cmdLineOut = cmdLine;
00512     }
00513     if (cmdLine.empty()) {
00514         return (mode == SAVE_QUITING);
00515     }
00516 
00517     // save autostart command
00518     if (CAutoStart::isDaemonInstalled()) {
00519         try {
00520             CAutoStart::reinstallDaemon(isClient, cmdLine);
00521             CAutoStart::uninstallDaemons(!isClient);
00522         }
00523         catch (XArchDaemon& e) {
00524             errorID = IDS_INSTALL_GENERIC_ERROR;
00525             arg     = e.what();
00526             goto failed;
00527         }
00528     }
00529 
00530     return true;
00531 
00532 failed:
00533     CString errorMessage =
00534         CStringUtil::format(getString(errorID).c_str(), arg.c_str());
00535     if (mode == SAVE_QUITING) {
00536         errorMessage += "\n";
00537         errorMessage += getString(IDS_UNSAVED_DATA_REALLY_QUIT);
00538         if (askVerify(hwnd, errorMessage)) {
00539             return true;
00540         }
00541     }
00542     else if (mode == SAVE_NORMAL) {
00543         showError(hwnd, errorMessage);
00544     }
00545     return false;
00546 }
00547 
00548 static
00549 LRESULT CALLBACK
00550 mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
00551 {
00552     switch (message) {
00553     case WM_ACTIVATE:
00554         if (LOWORD(wParam) != WA_INACTIVE) {
00555             // activated
00556 
00557             // see if the configuration changed
00558             if (isConfigNewer(s_configTime, s_userConfig)) {
00559                 CString message = getString(IDS_CONFIG_CHANGED);
00560                 if (askVerify(hwnd, message)) {
00561                     time_t configTime;
00562                     bool userConfig;
00563                     CConfig newConfig;
00564                     if (loadConfig(newConfig, configTime, userConfig) &&
00565                         userConfig == s_userConfig) {
00566                         ARG->m_config = newConfig;
00567                         s_lastConfig  = ARG->m_config;
00568                     }
00569                     else {
00570                         message = getString(IDS_LOAD_FAILED);
00571                         showError(hwnd, message);
00572                         s_lastConfig = CConfig();
00573                     }
00574                 }
00575             }
00576         }
00577         else {
00578             // deactivated;  write configuration
00579             if (!isShowingDialog()) {
00580                 saveMainWindow(hwnd, SAVE_QUIET);
00581             }
00582         }
00583         break;
00584 
00585     case WM_COMMAND:
00586         switch (LOWORD(wParam)) {
00587         case IDCANCEL:
00588             // save data
00589             if (saveMainWindow(hwnd, SAVE_QUITING)) {
00590                 // quit
00591                 PostQuitMessage(0);
00592             }
00593             return 0;
00594 
00595         case IDOK:
00596         case IDC_MAIN_TEST: {
00597             // note if testing
00598             const bool testing = (LOWORD(wParam) == IDC_MAIN_TEST);
00599 
00600             // save data
00601             if (saveMainWindow(hwnd, SAVE_NORMAL)) {
00602                 // launch child app
00603                 DWORD threadID;
00604                 HANDLE thread;
00605                 if (!launchApp(hwnd, testing, &thread, &threadID)) {
00606                     return 0;
00607                 }
00608 
00609                 // handle child program
00610                 if (testing) {
00611                     // wait for process to stop, allowing the user to kill it
00612                     waitForChild(hwnd, thread, threadID);
00613 
00614                     // clean up
00615                     CloseHandle(thread);
00616                 }
00617                 else {
00618                     // don't need thread handle
00619                     if (thread != NULL) {
00620                         CloseHandle(thread);
00621                     }
00622 
00623                     // notify of success: now disabled - it's silly to notify a success
00624                     //askOkay(hwnd, getString(IDS_STARTED_TITLE), getString(IDS_STARTED));
00625 
00626                     // quit
00627                     PostQuitMessage(0);
00628                 }
00629             }
00630             return 0;
00631         }
00632 
00633         case IDC_MAIN_AUTOSTART: {
00634             CString cmdLine;
00635             if (saveMainWindow(hwnd, SAVE_NORMAL, &cmdLine)) {
00636                 // run dialog
00637                 CAutoStart autoStart(hwnd, !isClientChecked(hwnd), cmdLine);
00638                 autoStart.doModal();
00639             }
00640             return 0;
00641         }
00642 
00643         case IDC_MAIN_CLIENT_RADIO:
00644         case IDC_MAIN_SERVER_RADIO:
00645             enableMainWindowControls(hwnd);
00646             return 0;
00647 
00648         case IDC_MAIN_SCREENS:
00649             s_screensLinks->doModal();
00650             break;
00651 
00652         case IDC_MAIN_OPTIONS:
00653             s_globalOptions->doModal();
00654             break;
00655 
00656         case IDC_MAIN_ADVANCED:
00657             s_advancedOptions->doModal(isClientChecked(hwnd));
00658             break;
00659 
00660         case IDC_MAIN_HOTKEYS:
00661             s_hotkeyOptions->doModal();
00662             break;
00663 
00664         case IDC_MAIN_INFO:
00665             s_info->doModal();
00666             break;
00667         }
00668 
00669     default:
00670         break;
00671     }
00672     return DefDlgProc(hwnd, message, wParam, lParam);
00673 }
00674 
00675 int WINAPI
00676 WinMain(HINSTANCE instance, HINSTANCE, LPSTR cmdLine, int nCmdShow)
00677 {
00678     CArch arch(instance);
00679     CLOG;
00680     CArgs args;
00681 
00682     s_instance = instance;
00683 
00684     // if "/uninstall" is on the command line then just stop and
00685     // uninstall the service and quit.  this is the only option
00686     // but we ignore any others.
00687     if (CString(cmdLine).find("/uninstall") != CString::npos) {
00688         CAutoStart::uninstallDaemons(false);
00689         CAutoStart::uninstallDaemons(true);
00690         return 0;
00691     }
00692 
00693     // register main window (dialog) class
00694     WNDCLASSEX classInfo;
00695     classInfo.cbSize        = sizeof(classInfo);
00696     classInfo.style         = CS_HREDRAW | CS_VREDRAW;
00697     classInfo.lpfnWndProc   = &mainWndProc;
00698     classInfo.cbClsExtra    = 0;
00699     classInfo.cbWndExtra    = DLGWINDOWEXTRA;
00700     classInfo.hInstance     = instance;
00701     classInfo.hIcon         = (HICON)LoadImage(instance,
00702                                     MAKEINTRESOURCE(IDI_SYNERGY),
00703                                     IMAGE_ICON,
00704                                     32, 32, LR_SHARED);
00705     classInfo.hCursor       = LoadCursor(NULL, IDC_ARROW);
00706     classInfo.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1);
00707     classInfo.lpszMenuName  = NULL;
00708     classInfo.lpszClassName = s_mainClass;
00709     classInfo.hIconSm       = (HICON)LoadImage(instance,
00710                                     MAKEINTRESOURCE(IDI_SYNERGY),
00711                                     IMAGE_ICON,
00712                                     16, 16, LR_SHARED);
00713     RegisterClassEx(&classInfo);
00714 
00715     // create main window
00716     HWND mainWindow = CreateDialog(s_instance,
00717                             MAKEINTRESOURCE(IDD_MAIN), 0, NULL);
00718 
00719     // prep windows
00720     initMainWindow(mainWindow);
00721     s_globalOptions   = new CGlobalOptions(mainWindow, &ARG->m_config);
00722     s_advancedOptions = new CAdvancedOptions(mainWindow, &ARG->m_config);
00723     s_hotkeyOptions   = new CHotkeyOptions(mainWindow, &ARG->m_config); 
00724     s_screensLinks    = new CScreensLinks(mainWindow, &ARG->m_config);
00725     s_info            = new CInfo(mainWindow);
00726 
00727     // show window
00728     ShowWindow(mainWindow, nCmdShow);
00729 
00730     // main loop
00731     MSG msg;
00732     bool done = false;
00733     do {
00734         switch (GetMessage(&msg, NULL, 0, 0)) {
00735         case -1:
00736             // error
00737             break;
00738 
00739         case 0:
00740             // quit
00741             done = true;
00742             break;
00743 
00744         default:
00745             if (!IsDialogMessage(mainWindow, &msg)) {
00746                 TranslateMessage(&msg);
00747                 DispatchMessage(&msg);
00748             }
00749             break;
00750         }
00751     } while (!done);
00752 
00753     return msg.wParam;
00754 }

Generated on Fri Nov 6 00:21:15 2009 for synergy-plus by  doxygen 1.3.9.1