Merged Win32 updates. Added full warnings on g++. Fixed bug in

client when handling server rejection.
This commit is contained in:
crs
2004-02-28 12:19:49 +00:00
parent 612a2054e6
commit 54acf38d82
74 changed files with 2333 additions and 2185 deletions

View File

@@ -14,6 +14,7 @@
#include "CConfig.h"
#include "LaunchUtil.h"
#include "CMSWindowsUtil.h"
#include "CArch.h"
#include "resource.h"
#include "stdfstream.h"
@@ -23,32 +24,13 @@
CString
getString(DWORD id)
{
char buffer[1024];
buffer[0] = '\0';
LoadString(s_instance, id, buffer, sizeof(buffer) / sizeof(buffer[0]));
return buffer;
return CMSWindowsUtil::getString(s_instance, id);
}
CString
getErrorString(DWORD error)
{
char* buffer;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
0,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&buffer,
0,
NULL) == 0) {
return getString(IDS_ERROR);
}
else {
CString result(buffer);
LocalFree(buffer);
return result;
}
return CMSWindowsUtil::getErrorString(s_instance, error, IDS_ERROR);
}
void

View File

@@ -332,8 +332,8 @@ BEGIN
"Synergy is not configured to start automatically."
IDS_INSTALL_LABEL "Install"
IDS_UNINSTALL_LABEL "Uninstall"
IDS_INSTALL_GENERIC_ERROR "Install failed: %{1}."
IDS_UNINSTALL_GENERIC_ERROR "Uninstall failed: %{1}."
IDS_INSTALL_GENERIC_ERROR "Install failed: %{1}"
IDS_UNINSTALL_GENERIC_ERROR "Uninstall failed: %{1}"
IDS_INSTALL_TITLE "Installed Auto-Start"
IDS_INSTALLED_SYSTEM "Installed auto-start. Synergy will now automatically start each time you start your computer."
IDS_INSTALLED_USER "Installed auto-start. Synergy will now automatically start each time you log in."
@@ -348,6 +348,7 @@ BEGIN
IDS_SERVER_IS_CLIENT "Please enter the computer name of the synergy server, not\nthe name of this computer, in the Server Host Name field."
IDS_ADD_SCREEN "Add Screen"
IDS_EDIT_SCREEN "Edit Screen %{1}"
IDS_ERROR_CODE "Error code: %{1}"
END
#endif // English (U.S.) resources

View File

@@ -41,6 +41,7 @@
#define IDS_ADD_SCREEN 37
#define IDS_EDIT_SCREEN 38
#define IDS_INVALID_TIME 39
#define IDS_ERROR_CODE 39
#define IDD_MAIN 101
#define IDD_ADD 102
#define IDD_WAIT 103

View File

@@ -21,18 +21,19 @@
#include "CArchTaskBarWindows.h"
#include "resource.h"
static const UINT g_stateToIconID[CMSWindowsClientTaskBarReceiver::kMaxState] =
//
// CMSWindowsClientTaskBarReceiver
//
const UINT CMSWindowsClientTaskBarReceiver::s_stateToIconID[kMaxState] =
{
IDI_TASKBAR_NOT_RUNNING,
IDI_TASKBAR_NOT_WORKING,
IDI_TASKBAR_NOT_CONNECTED,
IDI_TASKBAR_NOT_CONNECTED,
IDI_TASKBAR_CONNECTED
};
//
// CMSWindowsClientTaskBarReceiver
//
CMSWindowsClientTaskBarReceiver::CMSWindowsClientTaskBarReceiver(
HINSTANCE appInstance, const CBufferedLogOutputter* logBuffer) :
CClientTaskBarReceiver(),
@@ -41,7 +42,7 @@ CMSWindowsClientTaskBarReceiver::CMSWindowsClientTaskBarReceiver(
m_logBuffer(logBuffer)
{
for (UInt32 i = 0; i < kMaxState; ++i) {
m_icon[i] = loadIcon(g_stateToIconID[i]);
m_icon[i] = loadIcon(s_stateToIconID[i]);
}
m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR));
@@ -171,7 +172,7 @@ CMSWindowsClientTaskBarReceiver::primaryAction()
const IArchTaskBarReceiver::Icon
CMSWindowsClientTaskBarReceiver::getIcon() const
{
return reinterpret_cast<Icon>(m_icon[getState()]);
return reinterpret_cast<Icon>(m_icon[getStatus()]);
}
void

View File

@@ -58,6 +58,7 @@ private:
HMENU m_menu;
HICON m_icon[kMaxState];
const CBufferedLogOutputter* m_logBuffer;
static const UINT s_stateToIconID[];
};
#endif

View File

@@ -19,7 +19,8 @@
// CXWindowsClientTaskBarReceiver
//
CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver()
CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver(
const CBufferedLogOutputter*)
{
// add ourself to the task bar
ARCH->addReceiver(this);

View File

@@ -17,10 +17,12 @@
#include "CClientTaskBarReceiver.h"
class CBufferedLogOutputter;
//! Implementation of CClientTaskBarReceiver for X Windows
class CXWindowsClientTaskBarReceiver : public CClientTaskBarReceiver {
public:
CXWindowsClientTaskBarReceiver();
CXWindowsClientTaskBarReceiver(const CBufferedLogOutputter*);
virtual ~CXWindowsClientTaskBarReceiver();
// IArchTaskBarReceiver overrides

View File

@@ -48,6 +48,7 @@ synergyc_LDADD = \
$(DEPTH)/lib/io/libio.a \
$(DEPTH)/lib/mt/libmt.a \
$(DEPTH)/lib/base/libbase.a \
$(DEPTH)/lib/common/libcommon.a \
$(DEPTH)/lib/arch/libarch.a \
$(X_LIBS) \
$(X_PRE_LIBS) \

View File

@@ -3,6 +3,8 @@
// Used by synergyc.rc
//
#define IDS_FAILED 1
#define IDS_INIT_FAILED 2
#define IDS_UNCAUGHT_EXCEPTION 3
#define IDI_SYNERGY 101
#define IDI_TASKBAR_NOT_RUNNING 102
#define IDI_TASKBAR_NOT_WORKING 103

View File

@@ -26,6 +26,7 @@
#include "CFunctionEventJob.h"
#include "CLog.h"
#include "CString.h"
#include "CStringUtil.h"
#include "LogOutputters.h"
#include "CArch.h"
#include "XArch.h"
@@ -33,8 +34,9 @@
#define DAEMON_RUNNING(running_)
#if WINDOWS_LIKE
#include "CMSWindowsScreen.h"
#include "CArchMiscWindows.h"
#include "CMSWindowsScreen.h"
#include "CMSWindowsUtil.h"
#include "CMSWindowsClientTaskBarReceiver.h"
#include "resource.h"
#undef DAEMON_RUNNING
@@ -51,6 +53,9 @@
#define DAEMON_NAME "synergyc"
#endif
typedef int (*StartupFunc)(int, char**);
static void parse(int argc, const char* const* argv);
//
// program arguments
//
@@ -64,7 +69,8 @@ public:
m_backend(false),
m_restartable(true),
m_daemon(true),
m_logFilter(NULL)
m_logFilter(NULL),
m_serverAddress(NULL)
{ s_instance = this; }
~CArgs() { s_instance = NULL; }
@@ -76,7 +82,7 @@ public:
bool m_daemon;
const char* m_logFilter;
CString m_name;
CNetworkAddress m_serverAddress;
CNetworkAddress* m_serverAddress;
};
CArgs* CArgs::s_instance = NULL;
@@ -97,6 +103,18 @@ createScreen()
#endif
}
static
CClientTaskBarReceiver*
createTaskBarReceiver(const CBufferedLogOutputter* logBuffer)
{
#if WINDOWS_LIKE
return new CMSWindowsClientTaskBarReceiver(
CMSWindowsScreen::getInstance(), logBuffer);
#elif UNIX_LIKE
return new CXWindowsClientTaskBarReceiver(logBuffer);
#endif
}
//
// platform independent main
@@ -292,7 +310,7 @@ startClient()
try {
clientScreen = openClientScreen();
s_client = openClient(ARG->m_name,
ARG->m_serverAddress, clientScreen);
*ARG->m_serverAddress, clientScreen);
s_clientScreen = clientScreen;
LOG((CLOG_NOTE "started client"));
s_client->connect();
@@ -338,7 +356,7 @@ stopClient()
static
int
realMain()
mainLoop()
{
// start the client. if this return false then we've failed and
// we shouldn't retry.
@@ -350,8 +368,8 @@ realMain()
// run event loop. if startClient() failed we're supposed to retry
// later. the timer installed by startClient() will take care of
// that.
DAEMON_RUNNING(true);
CEvent event;
DAEMON_RUNNING(true);
EVENTQUEUE->getEvent(event);
while (event.getType() != CEvent::kQuit) {
EVENTQUEUE->dispatchEvent(event);
@@ -369,45 +387,65 @@ realMain()
return kExitSuccess;
}
/*
static
void
realMainEntry(void* vresult)
int
daemonMainLoop(int, const char**)
{
*reinterpret_cast<int*>(vresult) = realMain();
CSystemLogger sysLogger(DAEMON_NAME);
return mainLoop();
}
static
int
runMainInThread(void)
standardStartup(int argc, char** argv)
{
int result = 0;
CThread appThread(new CFunctionJob(&realMainEntry, &result));
try {
#if WINDOWS_LIKE
MSG msg;
while (appThread.waitForEvent(-1.0) == CThread::kEvent) {
// check for a quit event
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
CThread::getCurrentThread().cancel();
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#else
appThread.wait(-1.0);
#endif
return result;
// parse command line
parse(argc, argv);
// daemonize if requested
if (ARG->m_daemon) {
return ARCH->daemonize(DAEMON_NAME, &daemonMainLoop);
}
catch (XThread&) {
appThread.cancel();
appThread.wait(-1.0);
throw;
else {
return mainLoop();
}
}
*/
static
int
run(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
{
// general initialization
CSocketMultiplexer multiplexer;
CEventQueue eventQueue;
ARG->m_serverAddress = new CNetworkAddress;
ARG->m_pname = ARCH->getBasename(argv[0]);
// install caller's output filter
if (outputter != NULL) {
CLOG->insert(outputter);
}
// save log messages
CBufferedLogOutputter logBuffer(1000);
CLOG->insert(&logBuffer, true);
// make the task bar receiver. the user can control this app
// through the task bar.
s_taskBarReceiver = createTaskBarReceiver(&logBuffer);
// run
int result = startup(argc, argv);
// done with task bar receiver
delete s_taskBarReceiver;
// done with log buffer
CLOG->remove(&logBuffer);
delete ARG->m_serverAddress;
return result;
}
//
@@ -588,7 +626,7 @@ parse(int argc, const char* const* argv)
// save server address
try {
ARG->m_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
*ARG->m_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
}
catch (XSocketAddress& e) {
LOG((CLOG_PRINT "%s: %s" BYE,
@@ -676,192 +714,106 @@ byeThrow(int x)
static
int
daemonStartup(int argc, const char** argv)
daemonNTMainLoop(int argc, const char** argv)
{
CSystemLogger sysLogger(DAEMON_NAME);
// have to cancel this thread to quit
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
// catch errors that would normally exit
bye = &byeThrow;
// parse command line
parse(argc, argv);
// cannot run as backend if running as a service
ARG->m_backend = false;
// run as a service
return CArchMiscWindows::runDaemon(realMain);
return CArchMiscWindows::runDaemon(mainLoop);
}
static
int
daemonStartup95(int, const char**)
daemonNTStartup(int, char**)
{
CSystemLogger sysLogger(DAEMON_NAME);
return runMainInThread();
bye = &byeThrow;
return ARCH->daemonize(DAEMON_NAME, &daemonNTMainLoop);
}
static
int
run(int argc, char** argv)
void
showError(HINSTANCE instance, const char* title, UINT id, const char* arg)
{
// windows NT family starts services using no command line options.
// since i'm not sure how to tell the difference between that and
// a user providing no options we'll assume that if there are no
// arguments and we're on NT then we're being invoked as a service.
// users on NT can use `--daemon' or `--no-daemon' to force us out
// of the service code path.
if (argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
try {
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
}
catch (XArchDaemon& e) {
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
}
return kExitFailed;
}
// parse command line
parse(argc, argv);
// daemonize if requested
if (ARG->m_daemon) {
// start as a daemon
if (CArchMiscWindows::isWindows95Family()) {
try {
return ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
}
catch (XArchDaemon& e) {
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
}
return kExitFailed;
}
else {
// cannot start a service from the command line so just
// run normally (except with log messages redirected).
CSystemLogger sysLogger(DAEMON_NAME);
return runMainInThread();
}
}
else {
// run
return runMainInThread();
}
CString fmt = CMSWindowsUtil::getString(instance, id);
CString msg = CStringUtil::format(fmt.c_str(), arg);
MessageBox(NULL, msg.c_str(), title, MB_OK | MB_ICONWARNING);
}
int WINAPI
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
{
CArch arch(instance);
CLOG;
CArgs args;
// save instance
CMSWindowsScreen::init(instance);
// get program name
ARG->m_pname = ARCH->getBasename(__argv[0]);
// send PRINT and FATAL output to a message box
CLOG->insert(new CMessageBoxOutputter);
// save log messages
CBufferedLogOutputter logBuffer(1000);
CLOG->insert(&logBuffer, true);
// make the task bar receiver. the user can control this app
// through the task bar.
s_taskBarReceiver = new CMSWindowsClientTaskBarReceiver(instance,
&logBuffer);
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
int result;
try {
// run in foreground or as a daemon
result = run(__argc, __argv);
CArch arch(instance);
CMSWindowsScreen::init(instance);
CLOG;
// FIXME
// CThread::getCurrentThread().setPriority(-14);
CArgs args;
// windows NT family starts services using no command line options.
// since i'm not sure how to tell the difference between that and
// a user providing no options we'll assume that if there are no
// arguments and we're on NT then we're being invoked as a service.
// users on NT can use `--daemon' or `--no-daemon' to force us out
// of the service code path.
StartupFunc startup = &standardStartup;
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
startup = &daemonNTStartup;
}
// send PRINT and FATAL output to a message box
int result = run(__argc, __argv, new CMessageBoxOutputter, startup);
// let user examine any messages if we're running as a backend
// by putting up a dialog box before exiting.
if (args.m_backend && s_hasImportantLogMessages) {
showError(instance, args.m_pname, IDS_FAILED, "");
}
delete CLOG;
return result;
}
catch (XBase& e) {
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, e.what());
throw;
}
catch (XArch& e) {
showError(instance, __argv[0], IDS_INIT_FAILED, e.what().c_str());
return kExitFailed;
}
catch (...) {
// note that we don't rethrow thread cancellation. we'll
// be exiting soon so it doesn't matter. what we'd like
// is for everything after this try/catch to be in a
// finally block.
result = kExitFailed;
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, "<unknown>");
throw;
}
// done with task bar receiver
delete s_taskBarReceiver;
// done with log buffer
CLOG->remove(&logBuffer);
// let user examine any messages if we're running as a backend
// by putting up a dialog box before exiting.
if (ARG->m_backend && s_hasImportantLogMessages) {
char msg[1024];
msg[0] = '\0';
LoadString(instance, IDS_FAILED, msg, sizeof(msg) / sizeof(msg[0]));
MessageBox(NULL, msg, ARG->m_pname, MB_OK | MB_ICONWARNING);
}
delete CLOG;
return result;
}
#elif UNIX_LIKE
static
int
daemonStartup(int, const char**)
{
CSystemLogger sysLogger(DAEMON_NAME);
return realMain();
}
int
main(int argc, char** argv)
{
CArch arch;
CLOG;
// go really fast
CThread::getCurrentThread().setPriority(-14);
CSocketMultiplexer multiplexer;
CEventQueue eventQueue;
// get program name
CArgs args;
ARG->m_pname = ARCH->getBasename(argv[0]);
// make the task bar receiver. the user can control this app
// through the task bar.
s_taskBarReceiver = new CXWindowsClientTaskBarReceiver;
// parse command line
parse(argc, argv);
// daemonize if requested
int result;
if (ARG->m_daemon) {
try {
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
}
catch (XArchDaemon&) {
LOG((CLOG_CRIT "failed to daemonize"));
result = kExitFailed;
}
try {
int result;
CArch arch;
CLOG;
CArgs args;
result = run(argc, argv, NULL, &standardStartup);
delete CLOG;
return result;
}
else {
result = realMain();
catch (XBase& e) {
LOG((CLOG_CRIT "Uncaught exception: %s\n", e.what()));
throw;
}
catch (XArch& e) {
LOG((CLOG_CRIT "Initialization failed: %s" BYE, e.what().c_str()));
return kExitFailed;
}
catch (...) {
LOG((CLOG_CRIT "Uncaught exception: <unknown exception>\n"));
throw;
}
// done with task bar receiver
delete s_taskBarReceiver;
return result;
}
#else

View File

@@ -99,6 +99,8 @@ END
STRINGTABLE DISCARDABLE
BEGIN
IDS_FAILED "Synergy is about to quit with errors or warnings. Please check the log then click OK."
IDS_INIT_FAILED "Synergy failed to initialize: %{1}"
IDS_UNCAUGHT_EXCEPTION "Uncaught exception: %{1}"
END
#endif // English (U.S.) resources

View File

@@ -21,7 +21,11 @@
#include "CArchTaskBarWindows.h"
#include "resource.h"
static const UINT g_stateToIconID[CMSWindowsServerTaskBarReceiver::kMaxState] =
//
// CMSWindowsServerTaskBarReceiver
//
const UINT CMSWindowsServerTaskBarReceiver::s_stateToIconID[kMaxState] =
{
IDI_TASKBAR_NOT_RUNNING,
IDI_TASKBAR_NOT_WORKING,
@@ -29,10 +33,6 @@ static const UINT g_stateToIconID[CMSWindowsServerTaskBarReceiver::kMaxState] =
IDI_TASKBAR_CONNECTED
};
//
// CMSWindowsServerTaskBarReceiver
//
CMSWindowsServerTaskBarReceiver::CMSWindowsServerTaskBarReceiver(
HINSTANCE appInstance, const CBufferedLogOutputter* logBuffer) :
CServerTaskBarReceiver(),
@@ -41,7 +41,7 @@ CMSWindowsServerTaskBarReceiver::CMSWindowsServerTaskBarReceiver(
m_logBuffer(logBuffer)
{
for (UInt32 i = 0; i < kMaxState; ++i) {
m_icon[i] = loadIcon(g_stateToIconID[i]);
m_icon[i] = loadIcon(s_stateToIconID[i]);
}
m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR));
@@ -77,12 +77,7 @@ CMSWindowsServerTaskBarReceiver::showStatus()
std::string status = getToolTip();
// get the connect clients, if any
typedef std::vector<CString> CClientList;
CClientList clients;
CServer* server = getServer();
if (server != NULL) {
server->getClients(clients);
}
const CClients& clients = getClients();
// done getting status
unlock();
@@ -92,7 +87,7 @@ CMSWindowsServerTaskBarReceiver::showStatus()
SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str());
child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_CLIENTS);
SendMessage(child, LB_RESETCONTENT, 0, 0);
for (CClientList::const_iterator index = clients.begin();
for (CClients::const_iterator index = clients.begin();
index != clients.end(); ) {
const char* client = index->c_str();
if (++index == clients.end()) {
@@ -191,7 +186,7 @@ CMSWindowsServerTaskBarReceiver::primaryAction()
const IArchTaskBarReceiver::Icon
CMSWindowsServerTaskBarReceiver::getIcon() const
{
return reinterpret_cast<Icon>(m_icon[getState()]);
return reinterpret_cast<Icon>(m_icon[getStatus()]);
}
void

View File

@@ -58,6 +58,7 @@ private:
HMENU m_menu;
HICON m_icon[kMaxState];
const CBufferedLogOutputter* m_logBuffer;
static const UINT s_stateToIconID[];
};
#endif

View File

@@ -19,7 +19,8 @@
// CXWindowsServerTaskBarReceiver
//
CXWindowsServerTaskBarReceiver::CXWindowsServerTaskBarReceiver()
CXWindowsServerTaskBarReceiver::CXWindowsServerTaskBarReceiver(
const CBufferedLogOutputter*)
{
// add ourself to the task bar
ARCH->addReceiver(this);

View File

@@ -17,10 +17,12 @@
#include "CServerTaskBarReceiver.h"
class CBufferedLogOutputter;
//! Implementation of CServerTaskBarReceiver for X Windows
class CXWindowsServerTaskBarReceiver : public CServerTaskBarReceiver {
public:
CXWindowsServerTaskBarReceiver();
CXWindowsServerTaskBarReceiver(const CBufferedLogOutputter*);
virtual ~CXWindowsServerTaskBarReceiver();
// IArchTaskBarReceiver overrides

View File

@@ -48,6 +48,7 @@ synergys_LDADD = \
$(DEPTH)/lib/io/libio.a \
$(DEPTH)/lib/mt/libmt.a \
$(DEPTH)/lib/base/libbase.a \
$(DEPTH)/lib/common/libcommon.a \
$(DEPTH)/lib/arch/libarch.a \
$(X_LIBS) \
$(X_PRE_LIBS) \

View File

@@ -3,6 +3,8 @@
// Used by synergys.rc
//
#define IDS_FAILED 1
#define IDS_INIT_FAILED 2
#define IDS_UNCAUGHT_EXCEPTION 3
#define IDI_SYNERGY 101
#define IDI_TASKBAR_NOT_RUNNING 102
#define IDI_TASKBAR_NOT_WORKING 103

View File

@@ -28,6 +28,8 @@
#include "CEventQueue.h"
#include "CFunctionEventJob.h"
#include "CLog.h"
#include "CString.h"
#include "CStringUtil.h"
#include "LogOutputters.h"
#include "CArch.h"
#include "XArch.h"
@@ -36,8 +38,9 @@
#define DAEMON_RUNNING(running_)
#if WINDOWS_LIKE
#include "CMSWindowsScreen.h"
#include "CArchMiscWindows.h"
#include "CMSWindowsScreen.h"
#include "CMSWindowsUtil.h"
#include "CMSWindowsServerTaskBarReceiver.h"
#include "resource.h"
#undef DAEMON_RUNNING
@@ -63,6 +66,10 @@
#define SYS_CONFIG_NAME "synergy.conf"
#endif
typedef int (*StartupFunc)(int, char**);
static void parse(int argc, const char* const* argv);
static void loadConfig();
//
// program arguments
//
@@ -90,8 +97,8 @@ public:
const char* m_configFile;
const char* m_logFilter;
CString m_name;
CNetworkAddress m_synergyAddress;
CConfig m_config;
CNetworkAddress* m_synergyAddress;
CConfig* m_config;
};
CArgs* CArgs::s_instance = NULL;
@@ -112,6 +119,18 @@ createScreen()
#endif
}
static
CServerTaskBarReceiver*
createTaskBarReceiver(const CBufferedLogOutputter* logBuffer)
{
#if WINDOWS_LIKE
return new CMSWindowsServerTaskBarReceiver(
CMSWindowsScreen::getInstance(), logBuffer);
#elif UNIX_LIKE
return new CXWindowsServerTaskBarReceiver(logBuffer);
#endif
}
//
// platform independent main
@@ -299,11 +318,11 @@ startServer()
CPrimaryClient* primaryClient = NULL;
CClientListener* listener = NULL;
try {
CString name = ARG->m_config.getCanonicalName(ARG->m_name);
CString name = ARG->m_config->getCanonicalName(ARG->m_name);
serverScreen = openServerScreen();
primaryClient = openPrimaryClient(name, serverScreen);
listener = openClientListener(ARG->m_config.getSynergyAddress());
s_server = openServer(ARG->m_config, primaryClient);
listener = openClientListener(ARG->m_config->getSynergyAddress());
s_server = openServer(*ARG->m_config, primaryClient);
s_serverScreen = serverScreen;
s_primaryClient = primaryClient;
s_listener = listener;
@@ -372,26 +391,26 @@ stopServer()
static
int
realMain()
mainLoop()
{
// if configuration has no screens then add this system
// as the default
if (ARG->m_config.begin() == ARG->m_config.end()) {
ARG->m_config.addScreen(ARG->m_name);
if (ARG->m_config->begin() == ARG->m_config->end()) {
ARG->m_config->addScreen(ARG->m_name);
}
// set the contact address, if provided, in the config.
// otherwise, if the config doesn't have an address, use
// the default.
if (ARG->m_synergyAddress.isValid()) {
ARG->m_config.setSynergyAddress(ARG->m_synergyAddress);
if (ARG->m_synergyAddress->isValid()) {
ARG->m_config->setSynergyAddress(*ARG->m_synergyAddress);
}
else if (!ARG->m_config.getSynergyAddress().isValid()) {
ARG->m_config.setSynergyAddress(CNetworkAddress(kDefaultPort));
else if (!ARG->m_config->getSynergyAddress().isValid()) {
ARG->m_config->setSynergyAddress(CNetworkAddress(kDefaultPort));
}
// canonicalize the primary screen name
CString primaryName = ARG->m_config.getCanonicalName(ARG->m_name);
CString primaryName = ARG->m_config->getCanonicalName(ARG->m_name);
if (primaryName.empty()) {
LOG((CLOG_CRIT "unknown screen name `%s'", ARG->m_name.c_str()));
return kExitFailed;
@@ -407,8 +426,8 @@ realMain()
// run event loop. if startServer() failed we're supposed to retry
// later. the timer installed by startServer() will take care of
// that.
DAEMON_RUNNING(true);
CEvent event;
DAEMON_RUNNING(true);
EVENTQUEUE->getEvent(event);
while (event.getType() != CEvent::kQuit) {
EVENTQUEUE->dispatchEvent(event);
@@ -426,43 +445,71 @@ realMain()
return kExitSuccess;
}
/* XXX
static
void
realMainEntry(void* vresult)
int
daemonMainLoop(int, const char**)
{
*reinterpret_cast<int*>(vresult) = realMain();
CSystemLogger sysLogger(DAEMON_NAME);
return mainLoop();
}
static
int
runMainInThread(void)
standardStartup(int argc, char** argv)
{
int result = 0;
CThread appThread(new CFunctionJob(&realMainEntry, &result));
try {
#if WINDOWS_LIKE
MSG msg;
while (appThread.waitForEvent(-1.0) == CThread::kEvent) {
// check for a quit event
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
CThread::getCurrentThread().cancel();
}
}
}
#else
appThread.wait(-1.0);
#endif
return result;
// parse command line
parse(argc, argv);
// load configuration
loadConfig();
// daemonize if requested
if (ARG->m_daemon) {
return ARCH->daemonize(DAEMON_NAME, &daemonMainLoop);
}
catch (XThread&) {
appThread.cancel();
appThread.wait(-1.0);
throw;
else {
return mainLoop();
}
}
*/
static
int
run(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
{
// general initialization
CSocketMultiplexer multiplexer;
CEventQueue eventQueue;
ARG->m_synergyAddress = new CNetworkAddress;
ARG->m_config = new CConfig;
ARG->m_pname = ARCH->getBasename(argv[0]);
// install caller's output filter
if (outputter != NULL) {
CLOG->insert(outputter);
}
// save log messages
CBufferedLogOutputter logBuffer(1000);
CLOG->insert(&logBuffer, true);
// make the task bar receiver. the user can control this app
// through the task bar.
s_taskBarReceiver = createTaskBarReceiver(&logBuffer);
// run
int result = startup(argc, argv);
// done with task bar receiver
delete s_taskBarReceiver;
// done with log buffer
CLOG->remove(&logBuffer);
delete ARG->m_config;
delete ARG->m_synergyAddress;
return result;
}
//
// command line parsing
@@ -606,7 +653,7 @@ parse(int argc, const char* const* argv)
else if (isArg(i, argc, argv, "-a", "--address", 1)) {
// save listen address
try {
ARG->m_synergyAddress = CNetworkAddress(argv[i + 1],
*ARG->m_synergyAddress = CNetworkAddress(argv[i + 1],
kDefaultPort);
}
catch (XSocketAddress& e) {
@@ -723,7 +770,7 @@ loadConfig(const char* pathname)
if (!configStream) {
throw XConfigRead("cannot open file");
}
configStream >> ARG->m_config;
configStream >> *ARG->m_config;
LOG((CLOG_DEBUG "configuration read successfully"));
return true;
}
@@ -828,197 +875,107 @@ byeThrow(int x)
static
int
daemonStartup(int argc, const char** argv)
daemonNTMainLoop(int argc, const char** argv)
{
CSystemLogger sysLogger(DAEMON_NAME);
// catch errors that would normally exit
bye = &byeThrow;
// parse command line
parse(argc, argv);
// cannot run as backend if running as a service
ARG->m_backend = false;
// load configuration
loadConfig();
// run as a service
return CArchMiscWindows::runDaemon(realMain);
return CArchMiscWindows::runDaemon(mainLoop);
}
static
int
daemonStartup95(int, const char**)
daemonNTStartup(int, char**)
{
CSystemLogger sysLogger(DAEMON_NAME);
return runMainInThread();
bye = &byeThrow;
return ARCH->daemonize(DAEMON_NAME, &daemonNTMainLoop);
}
static
int
run(int argc, char** argv)
void
showError(HINSTANCE instance, const char* title, UINT id, const char* arg)
{
// windows NT family starts services using no command line options.
// since i'm not sure how to tell the difference between that and
// a user providing no options we'll assume that if there are no
// arguments and we're on NT then we're being invoked as a service.
// users on NT can use `--daemon' or `--no-daemon' to force us out
// of the service code path.
if (argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
try {
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
}
catch (XArchDaemon& e) {
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
}
return kExitFailed;
}
// parse command line
parse(argc, argv);
// load configuration
loadConfig();
// daemonize if requested
if (ARG->m_daemon) {
// start as a daemon
if (CArchMiscWindows::isWindows95Family()) {
try {
return ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
}
catch (XArchDaemon& e) {
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
}
return kExitFailed;
}
else {
// cannot start a service from the command line so just
// run normally (except with log messages redirected).
CSystemLogger sysLogger(DAEMON_NAME);
return runMainInThread();
}
}
else {
// run
return runMainInThread();
}
CString fmt = CMSWindowsUtil::getString(instance, id);
CString msg = CStringUtil::format(fmt.c_str(), arg);
MessageBox(NULL, msg.c_str(), title, MB_OK | MB_ICONWARNING);
}
int WINAPI
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
{
CArch arch(instance);
CLOG;
CArgs args;
// save instance
CMSWindowsScreen::init(instance);
// get program name
ARG->m_pname = ARCH->getBasename(__argv[0]);
// send PRINT and FATAL output to a message box
CLOG->insert(new CMessageBoxOutputter);
// save log messages
CBufferedLogOutputter logBuffer(1000);
CLOG->insert(&logBuffer, true);
// make the task bar receiver. the user can control this app
// through the task bar.
s_taskBarReceiver = new CMSWindowsServerTaskBarReceiver(instance,
&logBuffer);
int result;
try {
// run in foreground or as a daemon
result = run(__argc, __argv);
CArch arch(instance);
CMSWindowsScreen::init(instance);
CLOG;
// FIXME
// CThread::getCurrentThread().setPriority(-14);
CArgs args;
// windows NT family starts services using no command line options.
// since i'm not sure how to tell the difference between that and
// a user providing no options we'll assume that if there are no
// arguments and we're on NT then we're being invoked as a service.
// users on NT can use `--daemon' or `--no-daemon' to force us out
// of the service code path.
StartupFunc startup = &standardStartup;
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
startup = &daemonNTStartup;
}
// send PRINT and FATAL output to a message box
int result = run(__argc, __argv, new CMessageBoxOutputter, startup);
// let user examine any messages if we're running as a backend
// by putting up a dialog box before exiting.
if (args.m_backend && s_hasImportantLogMessages) {
showError(instance, args.m_pname, IDS_FAILED, "");
}
delete CLOG;
return result;
}
catch (XBase& e) {
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, e.what());
throw;
}
catch (XArch& e) {
showError(instance, __argv[0], IDS_INIT_FAILED, e.what().c_str());
return kExitFailed;
}
catch (...) {
// note that we don't rethrow thread cancellation. we'll
// be exiting soon so it doesn't matter. what we'd like
// is for everything after this try/catch to be in a
// finally block.
result = kExitFailed;
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, "<unknown>");
throw;
}
// done with task bar receiver
delete s_taskBarReceiver;
// done with log buffer
CLOG->remove(&logBuffer);
// let user examine any messages if we're running as a backend
// by putting up a dialog box before exiting.
if (ARG->m_backend && s_hasImportantLogMessages) {
char msg[1024];
msg[0] = '\0';
LoadString(instance, IDS_FAILED, msg, sizeof(msg) / sizeof(msg[0]));
MessageBox(NULL, msg, ARG->m_pname, MB_OK | MB_ICONWARNING);
}
delete CLOG;
return result;
}
#elif UNIX_LIKE
static
int
daemonStartup(int, const char**)
{
CSystemLogger sysLogger(DAEMON_NAME);
return realMain();
}
int
main(int argc, char** argv)
{
CArch arch;
CLOG;
// go really fast
CThread::getCurrentThread().setPriority(-14);
CSocketMultiplexer multiplexer;
CEventQueue eventQueue;
// get program name
CArgs args;
ARG->m_pname = ARCH->getBasename(argv[0]);
// make the task bar receiver. the user can control this app
// through the task bar.
s_taskBarReceiver = new CXWindowsServerTaskBarReceiver;
// parse command line
parse(argc, argv);
// load configuration
loadConfig();
// daemonize if requested
int result;
if (ARG->m_daemon) {
try {
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
}
catch (XArchDaemon&) {
LOG((CLOG_CRIT "failed to daemonize"));
result = kExitFailed;
}
try {
int result;
CArch arch;
CLOG;
CArgs args;
result = run(argc, argv, NULL, &standardStartup);
delete CLOG;
return result;
}
else {
result = realMain();
catch (XBase& e) {
LOG((CLOG_CRIT "Uncaught exception: %s\n", e.what()));
throw;
}
catch (XArch& e) {
LOG((CLOG_CRIT "Initialization failed: %s" BYE, e.what().c_str()));
return kExitFailed;
}
catch (...) {
LOG((CLOG_CRIT "Uncaught exception: <unknown exception>\n"));
throw;
}
// done with task bar receiver
delete s_taskBarReceiver;
return result;
}
#else

View File

@@ -102,6 +102,8 @@ END
STRINGTABLE DISCARDABLE
BEGIN
IDS_FAILED "Synergy is about to quit with errors or warnings. Please check the log then click OK."
IDS_INIT_FAILED "Synergy failed to initialize: %{1}"
IDS_UNCAUGHT_EXCEPTION "Uncaught exception: %{1}"
END
#endif // English (U.S.) resources