Gavin Andresen: implementation of autostart on system startup option on Linux
[novacoin.git] / init.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto\r
2 // Distributed under the MIT/X11 software license, see the accompanying\r
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.\r
4 \r
5 #include "headers.h"\r
6 \r
7 extern string GetDefaultDataDir(); /// todo: delete this later, just used by debug test\r
8 \r
9 \r
10 \r
11 \r
12 void ExitTimeout(void* parg)\r
13 {\r
14 #ifdef __WXMSW__\r
15     Sleep(5000);\r
16     ExitProcess(0);\r
17 #endif\r
18 }\r
19 \r
20 void Shutdown(void* parg)\r
21 {\r
22     static CCriticalSection cs_Shutdown;\r
23     static bool fTaken;\r
24     bool fFirstThread;\r
25     CRITICAL_BLOCK(cs_Shutdown)\r
26     {\r
27         fFirstThread = !fTaken;\r
28         fTaken = true;\r
29     }\r
30     static bool fExit;\r
31     if (fFirstThread)\r
32     {\r
33         fShutdown = true;\r
34         nTransactionsUpdated++;\r
35         DBFlush(false);\r
36         StopNode();\r
37         DBFlush(true);\r
38         CreateThread(ExitTimeout, NULL);\r
39         Sleep(50);\r
40         printf("Bitcoin exiting\n\n");\r
41         fExit = true;\r
42         exit(0);\r
43     }\r
44     else\r
45     {\r
46         while (!fExit)\r
47             Sleep(500);\r
48         Sleep(100);\r
49         ExitThread(0);\r
50     }\r
51 }\r
52 \r
53 \r
54 \r
55 \r
56 \r
57 \r
58 //////////////////////////////////////////////////////////////////////////////\r
59 //\r
60 // Startup folder\r
61 //\r
62 \r
63 #ifdef __WXMSW__\r
64 string StartupShortcutPath()\r
65 {\r
66     return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";\r
67 }\r
68 \r
69 bool GetStartOnSystemStartup()\r
70 {\r
71     return filesystem::exists(StartupShortcutPath().c_str());\r
72 }\r
73 \r
74 void SetStartOnSystemStartup(bool fAutoStart)\r
75 {\r
76     // If the shortcut exists already, remove it for updating\r
77     remove(StartupShortcutPath().c_str());\r
78 \r
79     if (fAutoStart)\r
80     {\r
81         CoInitialize(NULL);\r
82 \r
83         // Get a pointer to the IShellLink interface.\r
84         IShellLink* psl = NULL;\r
85         HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,\r
86                                 CLSCTX_INPROC_SERVER, IID_IShellLink,\r
87                                 reinterpret_cast<void**>(&psl));\r
88 \r
89         if (SUCCEEDED(hres))\r
90         {\r
91             // Get the current executable path\r
92             TCHAR pszExePath[MAX_PATH];\r
93             GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));\r
94 \r
95             // Set the path to the shortcut target\r
96             psl->SetPath(pszExePath);\r
97             PathRemoveFileSpec(pszExePath);\r
98             psl->SetWorkingDirectory(pszExePath);\r
99             psl->SetShowCmd(SW_SHOWMINNOACTIVE);\r
100 \r
101             // Query IShellLink for the IPersistFile interface for\r
102             // saving the shortcut in persistent storage.\r
103             IPersistFile* ppf = NULL;\r
104             hres = psl->QueryInterface(IID_IPersistFile,\r
105                                        reinterpret_cast<void**>(&ppf));\r
106             if (SUCCEEDED(hres))\r
107             {\r
108                 WCHAR pwsz[MAX_PATH];\r
109                 // Ensure that the string is ANSI.\r
110                 MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);\r
111                 // Save the link by calling IPersistFile::Save.\r
112                 hres = ppf->Save(pwsz, TRUE);\r
113                 ppf->Release();\r
114             }\r
115             psl->Release();\r
116         }\r
117         CoUninitialize();\r
118     }\r
119 }\r
120 \r
121 #elif defined(__WXGTK__)\r
122 \r
123 //\r
124 // Follow the Desktop Application Autostart Spec:\r
125 //  http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html\r
126 //\r
127 \r
128 boost::filesystem::path GetAutostartDir()\r
129 {\r
130     namespace fs = boost::filesystem;\r
131 \r
132     char* pszConfigHome = getenv("XDG_CONFIG_HOME");\r
133     if (pszConfigHome) return fs::path(pszConfigHome) / fs::path("autostart");\r
134     char* pszHome = getenv("HOME");\r
135     if (pszHome) return fs::path(pszHome) / fs::path(".config/autostart");\r
136     return fs::path();\r
137 }\r
138 \r
139 boost::filesystem::path GetAutostartFilePath()\r
140 {\r
141     return GetAutostartDir() / boost::filesystem::path("bitcoin.desktop");\r
142 }\r
143 \r
144 bool GetStartOnSystemStartup()\r
145 {\r
146     boost::filesystem::ifstream optionFile(GetAutostartFilePath());\r
147     if (!optionFile.good())\r
148         return false;\r
149     // Scan through file for "Hidden=true":\r
150     string line;\r
151     while (!optionFile.eof())\r
152     {\r
153         getline(optionFile, line);\r
154         if (line.find("Hidden") != string::npos &&\r
155             line.find("true") != string::npos)\r
156             return false;\r
157     }\r
158     optionFile.close();\r
159 \r
160     return true;\r
161 }\r
162 \r
163 void SetStartOnSystemStartup(bool fAutoStart)\r
164 {\r
165     if (!fAutoStart)\r
166     {\r
167         unlink(GetAutostartFilePath().native_file_string().c_str());\r
168     }\r
169     else\r
170     {\r
171         boost::filesystem::create_directories(GetAutostartDir());\r
172 \r
173         boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc);\r
174         if (!optionFile.good())\r
175         {\r
176             wxMessageBox(_("Cannot write autostart/bitcoin.desktop file"), "Bitcoin");\r
177             return;\r
178         }\r
179         // Write a bitcoin.desktop file to the autostart directory:\r
180         char pszExePath[MAX_PATH+1];\r
181         memset(pszExePath, 0, sizeof(pszExePath));\r
182         readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1);\r
183         optionFile << "[Desktop Entry]\n";\r
184         optionFile << "Type=Application\n";\r
185         optionFile << "Name=Bitcoin\n";\r
186         optionFile << "Exec=" << pszExePath << "\n";\r
187         optionFile << "Terminal=false\n";\r
188         optionFile << "Hidden=false\n";\r
189         optionFile.close();\r
190     }\r
191 }\r
192 #else\r
193 \r
194 // TODO: OSX startup stuff; see:\r
195 // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html\r
196 \r
197 bool GetStartOnSystemStartup() { return false; }\r
198 void SetStartOnSystemStartup(bool fAutoStart) { }\r
199 \r
200 #endif\r
201 \r
202 \r
203 \r
204 \r
205 \r
206 \r
207 \r
208 //////////////////////////////////////////////////////////////////////////////\r
209 //\r
210 // CMyApp\r
211 //\r
212 \r
213 // Define a new application\r
214 class CMyApp : public wxApp\r
215 {\r
216 public:\r
217     wxLocale m_locale;\r
218 \r
219     CMyApp(){};\r
220     ~CMyApp(){};\r
221     bool OnInit();\r
222     bool OnInit2();\r
223     int OnExit();\r
224 \r
225     // Hook Initialize so we can start without GUI\r
226     virtual bool Initialize(int& argc, wxChar** argv);\r
227 \r
228     // 2nd-level exception handling: we get all the exceptions occurring in any\r
229     // event handler here\r
230     virtual bool OnExceptionInMainLoop();\r
231 \r
232     // 3rd, and final, level exception handling: whenever an unhandled\r
233     // exception is caught, this function is called\r
234     virtual void OnUnhandledException();\r
235 \r
236     // and now for something different: this function is called in case of a\r
237     // crash (e.g. dereferencing null pointer, division by 0, ...)\r
238     virtual void OnFatalException();\r
239 };\r
240 \r
241 IMPLEMENT_APP(CMyApp)\r
242 \r
243 bool CMyApp::Initialize(int& argc, wxChar** argv)\r
244 {\r
245     if (argc > 1 && argv[1][0] != '-' && (!fWindows || argv[1][0] != '/') &&\r
246         wxString(argv[1]) != "start")\r
247     {\r
248         fCommandLine = true;\r
249     }\r
250     else if (!fGUI)\r
251     {\r
252         fDaemon = true;\r
253     }\r
254     else\r
255     {\r
256         // wxApp::Initialize will remove environment-specific parameters,\r
257         // so it's too early to call ParseParameters yet\r
258         for (int i = 1; i < argc; i++)\r
259         {\r
260             wxString str = argv[i];\r
261             #ifdef __WXMSW__\r
262             if (str.size() >= 1 && str[0] == '/')\r
263                 str[0] = '-';\r
264             char pszLower[MAX_PATH];\r
265             strlcpy(pszLower, str.c_str(), sizeof(pszLower));\r
266             strlwr(pszLower);\r
267             str = pszLower;\r
268             #endif\r
269             // haven't decided which argument to use for this yet\r
270             if (str == "-daemon" || str == "-d" || str == "start")\r
271                 fDaemon = true;\r
272         }\r
273     }\r
274 \r
275 #ifdef __WXGTK__\r
276     if (fDaemon || fCommandLine)\r
277     {\r
278         // Call the original Initialize while suppressing error messages\r
279         // and ignoring failure.  If unable to initialize GTK, it fails\r
280         // near the end so hopefully the last few things don't matter.\r
281         {\r
282             wxLogNull logNo;\r
283             wxApp::Initialize(argc, argv);\r
284         }\r
285 \r
286         if (fDaemon)\r
287         {\r
288             // Daemonize\r
289             pid_t pid = fork();\r
290             if (pid < 0)\r
291             {\r
292                 fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);\r
293                 return false;\r
294             }\r
295             if (pid > 0)\r
296                 pthread_exit((void*)0);\r
297         }\r
298 \r
299         return true;\r
300     }\r
301 #endif\r
302 \r
303     return wxApp::Initialize(argc, argv);\r
304 }\r
305 \r
306 bool CMyApp::OnInit()\r
307 {\r
308     bool fRet = false;\r
309     try\r
310     {\r
311         fRet = OnInit2();\r
312     }\r
313     catch (std::exception& e) {\r
314         PrintException(&e, "OnInit()");\r
315     } catch (...) {\r
316         PrintException(NULL, "OnInit()");\r
317     }\r
318     if (!fRet)\r
319         Shutdown(NULL);\r
320     return fRet;\r
321 }\r
322 \r
323 extern int g_isPainting;\r
324 \r
325 bool CMyApp::OnInit2()\r
326 {\r
327 #ifdef _MSC_VER\r
328     // Turn off microsoft heap dump noise\r
329     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);\r
330     _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));\r
331 #endif\r
332 #if _MSC_VER >= 1400\r
333     // Disable confusing "helpful" text message on abort, ctrl-c\r
334     _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);\r
335 #endif\r
336 #if defined(__WXMSW__) && defined(__WXDEBUG__) && wxUSE_GUI\r
337     // Disable malfunctioning wxWidgets debug assertion\r
338     g_isPainting = 10000;\r
339 #endif\r
340 #if wxUSE_GUI\r
341     wxImage::AddHandler(new wxPNGHandler);\r
342 #endif\r
343 #if defined(__WXMSW__ ) || defined(__WXMAC__)\r
344     SetAppName("Bitcoin");\r
345 #else\r
346     SetAppName("bitcoin");\r
347 #endif\r
348 #ifndef __WXMSW__\r
349     umask(077);\r
350 #endif\r
351 #ifdef __WXMSW__\r
352 #if wxUSE_UNICODE\r
353     // Hack to set wxConvLibc codepage to UTF-8 on Windows,\r
354     // may break if wxMBConv_win32 implementation in strconv.cpp changes.\r
355     class wxMBConv_win32 : public wxMBConv\r
356     {\r
357     public:\r
358         long m_CodePage;\r
359         size_t m_minMBCharWidth;\r
360     };\r
361     if (((wxMBConv_win32*)&wxConvLibc)->m_CodePage == CP_ACP)\r
362         ((wxMBConv_win32*)&wxConvLibc)->m_CodePage = CP_UTF8;\r
363 #endif\r
364 #endif\r
365 \r
366     // Load locale/<lang>/LC_MESSAGES/bitcoin.mo language file\r
367     m_locale.Init(wxLANGUAGE_DEFAULT, 0);\r
368     m_locale.AddCatalogLookupPathPrefix("locale");\r
369     if (!fWindows)\r
370     {\r
371         m_locale.AddCatalogLookupPathPrefix("/usr/share/locale");\r
372         m_locale.AddCatalogLookupPathPrefix("/usr/local/share/locale");\r
373     }\r
374     m_locale.AddCatalog("wxstd"); // wxWidgets standard translations, if any\r
375     m_locale.AddCatalog("bitcoin");\r
376 \r
377     //\r
378     // Parameters\r
379     //\r
380     if (fCommandLine)\r
381     {\r
382         int ret = CommandLineRPC(argc, argv);\r
383         exit(ret);\r
384     }\r
385 \r
386     ParseParameters(argc, argv);\r
387     if (mapArgs.count("-?") || mapArgs.count("--help"))\r
388     {\r
389         wxString strUsage = string() +\r
390           _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +\r
391             "  bitcoin [options]       \t" + "\n" +\r
392             "  bitcoin [command]       \t" + _("Send command to bitcoin running with -server or -daemon\n") +\r
393             "  bitcoin [command] -?    \t" + _("Get help for a command\n") +\r
394             "  bitcoin help            \t" + _("List commands\n") +\r
395           _("Options:\n") +\r
396             "  -gen            \t  " + _("Generate coins\n") +\r
397             "  -gen=0          \t  " + _("Don't generate coins\n") +\r
398             "  -min            \t  " + _("Start minimized\n") +\r
399             "  -datadir=<dir>  \t  " + _("Specify data directory\n") +\r
400             "  -proxy=<ip:port>\t  " + _("Connect through socks4 proxy\n") +\r
401             "  -addnode=<ip>   \t  " + _("Add a node to connect to\n") +\r
402             "  -connect=<ip>   \t  " + _("Connect only to the specified node\n") +\r
403             "  -server         \t  " + _("Accept command line and JSON-RPC commands\n") +\r
404             "  -daemon         \t  " + _("Run in the background as a daemon and accept commands\n") +\r
405             "  -?              \t  " + _("This help message\n");\r
406 \r
407 #if defined(__WXMSW__) && wxUSE_GUI\r
408         // Tabs make the columns line up in the message box\r
409         wxMessageBox(strUsage, "Bitcoin", wxOK);\r
410 #else\r
411         // Remove tabs\r
412         strUsage.Replace("\t", "");\r
413         fprintf(stderr, "%s", ((string)strUsage).c_str());\r
414 #endif\r
415         return false;\r
416     }\r
417 \r
418     if (mapArgs.count("-datadir"))\r
419         strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir));\r
420 \r
421     if (mapArgs.count("-debug"))\r
422         fDebug = true;\r
423 \r
424     if (mapArgs.count("-printtodebugger"))\r
425         fPrintToDebugger = true;\r
426 \r
427     if (!fDebug && !pszSetDataDir[0])\r
428         ShrinkDebugFile();\r
429     printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");\r
430     printf("Bitcoin version %d.%d.%d%s beta, OS version %s\n", VERSION/10000, (VERSION/100)%100, VERSION%100, pszSubVer, ((string)wxGetOsDescription()).c_str());\r
431     printf("System default language is %d %s\n", m_locale.GetSystemLanguage(), ((string)m_locale.GetSysName()).c_str());\r
432     printf("Language file %s (%s)\n", (string("locale/") + (string)m_locale.GetCanonicalName() + "/LC_MESSAGES/bitcoin.mo").c_str(), ((string)m_locale.GetLocale()).c_str());\r
433 \r
434         /// debug - for now, just watching if these match\r
435         if (pszSetDataDir[0] == 0)\r
436         {\r
437             if (GetDefaultDataDir() != GetDataDir())\r
438                 printf("**** GetDefaultDataDir() %s != %s\n", GetDefaultDataDir().c_str(), GetDataDir().c_str());\r
439             else\r
440                 printf("OK GetDefaultDataDir() %s == %s\n", GetDefaultDataDir().c_str(), GetDataDir().c_str());\r
441         }\r
442 \r
443     if (mapArgs.count("-loadblockindextest"))\r
444     {\r
445         CTxDB txdb("r");\r
446         txdb.LoadBlockIndex();\r
447         PrintBlockTree();\r
448         return false;\r
449     }\r
450 \r
451     //\r
452     // Limit to single instance per user\r
453     // Required to protect the database files if we're going to keep deleting log.*\r
454     //\r
455 #ifdef __WXMSW__\r
456     // todo: wxSingleInstanceChecker wasn't working on Linux, never deleted its lock file\r
457     //  maybe should go by whether successfully bind port 8333 instead\r
458     wxString strMutexName = wxString("bitcoin_running.") + getenv("HOMEPATH");\r
459     for (int i = 0; i < strMutexName.size(); i++)\r
460         if (!isalnum(strMutexName[i]))\r
461             strMutexName[i] = '.';\r
462     wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);\r
463     if (psingleinstancechecker->IsAnotherRunning())\r
464     {\r
465         printf("Existing instance found\n");\r
466         unsigned int nStart = GetTime();\r
467         loop\r
468         {\r
469             // TODO: find out how to do this in Linux, or replace with wxWidgets commands\r
470             // Show the previous instance and exit\r
471             HWND hwndPrev = FindWindowA("wxWindowClassNR", "Bitcoin");\r
472             if (hwndPrev)\r
473             {\r
474                 if (IsIconic(hwndPrev))\r
475                     ShowWindow(hwndPrev, SW_RESTORE);\r
476                 SetForegroundWindow(hwndPrev);\r
477                 return false;\r
478             }\r
479 \r
480             if (GetTime() > nStart + 60)\r
481                 return false;\r
482 \r
483             // Resume this instance if the other exits\r
484             delete psingleinstancechecker;\r
485             Sleep(1000);\r
486             psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);\r
487             if (!psingleinstancechecker->IsAnotherRunning())\r
488                 break;\r
489         }\r
490     }\r
491 #endif\r
492 \r
493     // Bind to the port early so we can tell if another instance is already running.\r
494     // This is a backup to wxSingleInstanceChecker, which doesn't work on Linux.\r
495     string strErrors;\r
496     if (!BindListenPort(strErrors))\r
497     {\r
498         wxMessageBox(strErrors, "Bitcoin");\r
499         return false;\r
500     }\r
501 \r
502     //\r
503     // Load data files\r
504     //\r
505     if (fDaemon)\r
506         fprintf(stdout, "bitcoin server starting\n");\r
507     strErrors = "";\r
508     int64 nStart;\r
509 \r
510     printf("Loading addresses...\n");\r
511     nStart = GetTimeMillis();\r
512     if (!LoadAddresses())\r
513         strErrors += _("Error loading addr.dat      \n");\r
514     printf(" addresses   %15"PRI64d"ms\n", GetTimeMillis() - nStart);\r
515 \r
516     printf("Loading block index...\n");\r
517     nStart = GetTimeMillis();\r
518     if (!LoadBlockIndex())\r
519         strErrors += _("Error loading blkindex.dat      \n");\r
520     printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);\r
521 \r
522     printf("Loading wallet...\n");\r
523     nStart = GetTimeMillis();\r
524     bool fFirstRun;\r
525     if (!LoadWallet(fFirstRun))\r
526         strErrors += _("Error loading wallet.dat      \n");\r
527     printf(" wallet      %15"PRI64d"ms\n", GetTimeMillis() - nStart);\r
528 \r
529     printf("Done loading\n");\r
530 \r
531         //// debug print\r
532         printf("mapBlockIndex.size() = %d\n",   mapBlockIndex.size());\r
533         printf("nBestHeight = %d\n",            nBestHeight);\r
534         printf("mapKeys.size() = %d\n",         mapKeys.size());\r
535         printf("mapPubKeys.size() = %d\n",      mapPubKeys.size());\r
536         printf("mapWallet.size() = %d\n",       mapWallet.size());\r
537         printf("mapAddressBook.size() = %d\n",  mapAddressBook.size());\r
538 \r
539     if (!strErrors.empty())\r
540     {\r
541         wxMessageBox(strErrors, "Bitcoin");\r
542         return false;\r
543     }\r
544 \r
545     // Add wallet transactions that aren't already in a block to mapTransactions\r
546     ReacceptWalletTransactions();\r
547 \r
548     //\r
549     // Parameters\r
550     //\r
551     if (mapArgs.count("-printblockindex") || mapArgs.count("-printblocktree"))\r
552     {\r
553         PrintBlockTree();\r
554         return false;\r
555     }\r
556 \r
557     if (mapArgs.count("-printblock"))\r
558     {\r
559         string strMatch = mapArgs["-printblock"];\r
560         int nFound = 0;\r
561         for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)\r
562         {\r
563             uint256 hash = (*mi).first;\r
564             if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)\r
565             {\r
566                 CBlockIndex* pindex = (*mi).second;\r
567                 CBlock block;\r
568                 block.ReadFromDisk(pindex);\r
569                 block.BuildMerkleTree();\r
570                 block.print();\r
571                 printf("\n");\r
572                 nFound++;\r
573             }\r
574         }\r
575         if (nFound == 0)\r
576             printf("No blocks matching %s were found\n", strMatch.c_str());\r
577         return false;\r
578     }\r
579 \r
580     if (mapArgs.count("-gen"))\r
581     {\r
582         if (mapArgs["-gen"].empty())\r
583             fGenerateBitcoins = true;\r
584         else\r
585             fGenerateBitcoins = (atoi(mapArgs["-gen"].c_str()) != 0);\r
586     }\r
587 \r
588     if (mapArgs.count("-proxy"))\r
589     {\r
590         fUseProxy = true;\r
591         addrProxy = CAddress(mapArgs["-proxy"]);\r
592         if (!addrProxy.IsValid())\r
593         {\r
594             wxMessageBox(_("Invalid -proxy address"), "Bitcoin");\r
595             return false;\r
596         }\r
597     }\r
598 \r
599     if (mapArgs.count("-addnode"))\r
600     {\r
601         foreach(string strAddr, mapMultiArgs["-addnode"])\r
602         {\r
603             CAddress addr(strAddr, NODE_NETWORK);\r
604             addr.nTime = 0; // so it won't relay unless successfully connected\r
605             if (addr.IsValid())\r
606                 AddAddress(addr);\r
607         }\r
608     }\r
609 \r
610     //\r
611     // Create the main window and start the node\r
612     //\r
613     if (!fDaemon)\r
614         CreateMainWindow();\r
615 \r
616     if (!CheckDiskSpace())\r
617         return false;\r
618 \r
619     RandAddSeedPerfmon();\r
620 \r
621     if (!CreateThread(StartNode, NULL))\r
622         wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");\r
623 \r
624     if (mapArgs.count("-server") || fDaemon)\r
625         CreateThread(ThreadRPCServer, NULL);\r
626 \r
627     if (fFirstRun)\r
628         SetStartOnSystemStartup(true);\r
629 \r
630     return true;\r
631 }\r
632 \r
633 int CMyApp::OnExit()\r
634 {\r
635     Shutdown(NULL);\r
636     return wxApp::OnExit();\r
637 }\r
638 \r
639 bool CMyApp::OnExceptionInMainLoop()\r
640 {\r
641     try\r
642     {\r
643         throw;\r
644     }\r
645     catch (std::exception& e)\r
646     {\r
647         PrintException(&e, "CMyApp::OnExceptionInMainLoop()");\r
648         wxLogWarning("Exception %s %s", typeid(e).name(), e.what());\r
649         Sleep(1000);\r
650         throw;\r
651     }\r
652     catch (...)\r
653     {\r
654         PrintException(NULL, "CMyApp::OnExceptionInMainLoop()");\r
655         wxLogWarning("Unknown exception");\r
656         Sleep(1000);\r
657         throw;\r
658     }\r
659     return true;\r
660 }\r
661 \r
662 void CMyApp::OnUnhandledException()\r
663 {\r
664     // this shows how we may let some exception propagate uncaught\r
665     try\r
666     {\r
667         throw;\r
668     }\r
669     catch (std::exception& e)\r
670     {\r
671         PrintException(&e, "CMyApp::OnUnhandledException()");\r
672         wxLogWarning("Exception %s %s", typeid(e).name(), e.what());\r
673         Sleep(1000);\r
674         throw;\r
675     }\r
676     catch (...)\r
677     {\r
678         PrintException(NULL, "CMyApp::OnUnhandledException()");\r
679         wxLogWarning("Unknown exception");\r
680         Sleep(1000);\r
681         throw;\r
682     }\r
683 }\r
684 \r
685 void CMyApp::OnFatalException()\r
686 {\r
687     wxMessageBox(_("Program has crashed and will terminate.  "), "Bitcoin", wxOK | wxICON_ERROR);\r
688 }\r