static int Main(string[] rgArgs)
{
Thread.CurrentThread.Name = "Main thread";
Logger.Init(FwUtils.ksSuiteName);
FdoCache.NewerWritingSystemFound += ComplainToUserAboutNewWs;
// Note to developers: Uncomment this line to be able to attach the debugger to a process for a project
// other than the initial one that gets started up in VS:
//MessageBox.Show("Attach debugger now");
try
{
#region Initialize XULRunner - required to use the geckofx WebBrowser Control (GeckoWebBrowser).
#if __MonoCS__
var xulRunnerLocation = XULRunnerLocator.GetXULRunnerLocation();
if (string.IsNullOrEmpty(xulRunnerLocation))
throw new ApplicationException("The XULRunner library is missing or has the wrong version");
var librarySearchPath = Environment.GetEnvironmentVariable("LD_LIBRARY_PATH") ?? String.Empty;
if (!librarySearchPath.Contains(xulRunnerLocation))
throw new ApplicationException("LD_LIBRARY_PATH must contain " + xulRunnerLocation);
#else
// LT-16559: Specifying a hint path is necessary on Windows, but causes a crash in Xpcom.Initialize on Linux. Go figure.
var xulRunnerLocation = XULRunnerLocator.GetXULRunnerLocation("xulrunner");
if (string.IsNullOrEmpty(xulRunnerLocation))
throw new ApplicationException("The XULRunner library is missing or has the wrong version");
#endif
Xpcom.Initialize(xulRunnerLocation);
GeckoPreferences.User["gfx.font_rendering.graphite.enabled"] = true;
#endregion Initialize XULRunner
Logger.WriteEvent("Starting app");
SetGlobalExceptionHandler();
SetupErrorReportInformation();
// We need FieldWorks here to get the correct registry key HKLM\Software\SIL\FieldWorks.
// The default without this would be HKLM\Software\SIL\SIL FieldWorks (wrong).
RegistryHelper.ProductName = "FieldWorks";
// Invoke does nothing directly, but causes BroadcastEventWindow to be initialized
// on this thread to prevent race conditions on shutdown.See TE-975
// See http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=911603&SiteID=1
#if !__MonoCS__
SystemEvents.InvokeOnEventsThread(new Action(DoNothing));
#else
// TODO-Linux: uses mono feature that is not implemented. What are the implications of this? Review.
#endif
s_threadHelper = new ThreadHelper();
// ENHANCE (TimS): Another idea for ensuring that we have only one process started for
// this project is to use a Mutex. They can be used for cross-process resource access
// and would probably be less error-prone then our current implementation since it
// doesn't use TCP connections which can get hampered by firewalls. We would probably still
// need our current listener functionality for communicating with the other FW process,
// so it may not buy us much.
// See http://kristofverbiest.blogspot.com/2008/11/creating-single-instance-application.html.
// Make sure we do this ASAP. If another FieldWorks.exe is started we need
// to make sure it can find this one to ask about its project. (FWR-595)
CreateRemoteRequestListener();
#if DEBUG
WriteExecutablePathSettingForDevs();
#endif
if (IsInSingleFWProccessMode())
{
Logger.WriteEvent("Exiting: Detected single process mode");
return 0;
}
if (MigrateProjectsTo70())
{
Logger.WriteEvent("Migration to Version 7 was still needed.");
}
// Enable visual styles. Ignored on Windows 2000. Needs to be called before
// we create any controls! Unfortunately, this alone is not good enough. We
// also need to use a manifest, because some ListView and TreeView controls
// in native code do not have icons if we just use this method. This is caused
// by a bug in XP.
Application.EnableVisualStyles();
// initialize ICU
Icu.InitIcuDataDir();
// initialize Palaso keyboarding
KeyboardController.Initialize();
FwAppArgs appArgs = new FwAppArgs(rgArgs);
s_noUserInterface = appArgs.NoUserInterface;
s_appServerMode = appArgs.AppServerMode;
s_ui = new FwFdoUI(GetHelpTopicProvider(appArgs.AppAbbrev), s_threadHelper);
if (Settings.Default.CallUpgrade)
{
Settings.Default.Upgrade();
Settings.Default.CallUpgrade = false;
}
var reportingSettings = Settings.Default.Reporting;
if (reportingSettings == null)
{
// Note: to simulate this, currently it works to delete all subfolders of
// (e.g.) C:\Users\thomson\AppData\Local\SIL\FieldWorks.exe_Url_tdkbegygwiuamaf3mokxurci022yv1kn
// That guid may depend on version or something similar; it's some artifact of how the Settings persists.
s_noPreviousReportingSettings = true;
reportingSettings = new ReportingSettings();
Settings.Default.Reporting = reportingSettings; // to avoid a defect in Settings, rely on the Save in the code below
}
// Allow develpers and testers to avoid cluttering our analytics by setting an environment variable (FEEDBACK = false)
var feedbackEnvVar = Environment.GetEnvironmentVariable("FEEDBACK");
if (feedbackEnvVar != null)
{
reportingSettings.OkToPingBasicUsageData = feedbackEnvVar.ToLower().Equals("true") || feedbackEnvVar.ToLower().Equals("yes");
}
// Note that in FLEx we are using this flag to indicate whether we can send usage data at all.
// Despite its name, Cambell says this is the original intent (I think there may have been
// some thought of adding flags one day to control sending more detailed info, but if 'basic
// navigation' is suppressed nothing is sent). May want to consider renaming to something like
// OkToPingAtAll, but that affects other Palaso clients.
// The usage reporter does not currently send anything at all if the flag is false, but to make
// sure, we don't even initialize reporting if it is false.
// (Note however that it starts out true. Thus, typically a few pings will be sent
// on the very first startup, before the user gets a chance to disable it.)
if (reportingSettings.OkToPingBasicUsageData)
{
UsageReporter.Init(reportingSettings, "flex.palaso.org", "UA-39238981-3",
#if DEBUG
true
#else
false
#endif
);
// Init updates various things in the ReportingSettings, such as the number of times
// the application has been launched and the 'previous' version.
Settings.Default.Save();
}
// e.g. the first time the user runs FW8, we need to copy a bunch of registry keys
// from HKCU/Software/SIL/FieldWorks/7.0 -> FieldWorks/8.
FwRegistryHelper.UpgradeUserSettingsIfNeeded();
// initialize client-server services to use Db4O backend
ClientServerServices.SetCurrentToDb4OBackend(s_ui, FwDirectoryFinder.FdoDirectories);
// initialize the TE styles path so that ScrMappingList can load default styles
ScrMappingList.TeStylesPath = FwDirectoryFinder.TeStylesPath;
if (appArgs.ShowHelp)
{
ShowCommandLineHelp();
return 0;
}
else if (!string.IsNullOrEmpty(appArgs.ChooseProjectFile))
{
ProjectId projId = ChooseLangProject(null, GetHelpTopicProvider(FwUtils.ksFlexAbbrev));
if (projId == null)
return 1; // User probably canceled
try
{
// Use PipeHandle because this will probably be used to locate a named pipe using
// PipeHandle as the identifier.
File.WriteAllText(appArgs.ChooseProjectFile, projId.Handle, Encoding.UTF8);
}
catch (Exception e)
{
Logger.WriteError(e);
return 2;
}
return 0;
}
if (!SetUICulture(appArgs))
return 0; // Error occurred and user chose not to continue.
if (FwRegistryHelper.FieldWorksRegistryKeyLocalMachine == null && FwRegistryHelper.FieldWorksRegistryKey == null)
{
// See LT-14461. Some users have managed to get their computers into a state where
// neither HKML nor HKCU registry entries can be read. We don't know how this is possible.
// This is so far the best we can do.
var expected = "HKEY_LOCAL_MACHINE/Software/SIL/FieldWorks/" + FwRegistryHelper.FieldWorksRegistryKeyName;
MessageBoxUtils.Show(string.Format(Properties.Resources.ksHklmProblem, expected), Properties.Resources.ksHklmCaption);
return 0;
}
s_fwManager = new FieldWorksManager();
if (!string.IsNullOrEmpty(appArgs.BackupFile))
{
LaunchRestoreFromCommandLine(appArgs);
if (s_teApp == null && s_flexApp == null)
return 0; // Restore was cancelled or failed, or another process took care of it.
if (!String.IsNullOrEmpty(s_LinkDirChangedTo))
{
NonUndoableUnitOfWorkHelper.Do(s_cache.ActionHandlerAccessor,
() => s_cache.LangProject.LinkedFilesRootDir = s_LinkDirChangedTo);
}
}
else if (!LaunchApplicationFromCommandLine(appArgs))
return 0; // Didn't launch, but probably not a serious error
// Create a listener for this project for applications using FLEx as a LexicalProvider.
LexicalProviderManager.StartLexicalServiceProvider(s_projectId, s_cache);
#if __MonoCS__
UglyHackForXkbIndicator();
#endif
// Application was started successfully, so start the message loop
Application.Run();
}
catch (ApplicationException ex)
{
MessageBox.Show(ex.Message, FwUtils.ksSuiteName);
return 2;
}
catch (Exception ex)
{
SafelyReportException(ex, s_activeMainWnd, true);
return 2;
}
finally
{
StaticDispose();
if (Xpcom.IsInitialized)
{
// The following line appears to be necessary to keep Xpcom.Shutdown()
// from triggering a scary looking "double free or corruption" message most
// of the time. But the Xpcom.Shutdown() appears to be needed to keep the
// program from hanging around sometimes after it supposedly exits.
// Doing the shutdown here seems cleaner than using an ApplicationExit
// delegate.
var foo = new GeckoWebBrowser();
Xpcom.Shutdown();
}
}
return 0;
}