OSDN Git Service

設定ファイルの読み込みを MyApplication.InitCulture より手前に移動
[opentween/open-tween.git] / OpenTween / ApplicationEvents.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2007-2012 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
3 //           (c) 2008-2012 Moz (@syo68k)
4 //           (c) 2008-2012 takeshik (@takeshik) <http://www.takeshik.org/>
5 //           (c) 2010-2012 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
6 //           (c) 2010-2012 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
7 //           (c) 2012      Egtra (@egtra) <http://dev.activebasic.com/egtra/>
8 //           (c) 2012      kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
9 // All rights reserved.
10 // 
11 // This file is part of OpenTween.
12 // 
13 // This program is free software; you can redistribute it and/or modify it
14 // under the terms of the GNU General public License as published by the Free
15 // Software Foundation; either version 3 of the License, or (at your option)
16 // any later version.
17 // 
18 // This program is distributed in the hope that it will be useful, but
19 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General public License
21 // for more details.
22 // 
23 // You should have received a copy of the GNU General public License along
24 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
25 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
26 // Boston, MA 02110-1301, USA.
27
28 using System;
29 using System.Collections.Generic;
30 using System.IO;
31 using System.Linq;
32 using System.Diagnostics;
33 using System.Windows.Forms;
34 using System.Text.RegularExpressions;
35 using System.Threading;
36 using System.Threading.Tasks;
37 using System.Globalization;
38 using System.Reflection;
39 using Microsoft.Win32;
40 using OpenTween.Setting;
41
42 namespace OpenTween
43 {
44     internal class MyApplication
45     {
46         /// <summary>
47         /// 起動時に指定されたオプションを取得します
48         /// </summary>
49         public static IDictionary<string, string> StartupOptions { get; private set; }
50
51         /// <summary>
52         /// アプリケーションのメイン エントリ ポイントです。
53         /// </summary>
54         [STAThread]
55         static int Main(string[] args)
56         {
57             if (!CheckRuntimeVersion())
58             {
59                 var message = string.Format(Properties.Resources.CheckRuntimeVersion_Error, ".NET Framework 4.5.1");
60                 MessageBox.Show(message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
61                 return 1;
62             }
63
64             StartupOptions = ParseArguments(args);
65
66             if (!SetConfigDirectoryPath())
67                 return 1;
68
69             SettingManager.LoadAll();
70
71             InitCulture();
72
73             // 同じ設定ファイルを使用する OpenTween プロセスの二重起動を防止する
74             string pt = MyCommon.settingPath.Replace("\\", "/") + "/" + Application.ProductName;
75             using (Mutex mt = new Mutex(false, pt))
76             {
77                 if (!mt.WaitOne(0, false))
78                 {
79                     var text = string.Format(MyCommon.ReplaceAppName(Properties.Resources.StartupText1), MyCommon.GetAssemblyName());
80                     MessageBox.Show(text, MyCommon.ReplaceAppName(Properties.Resources.StartupText2), MessageBoxButtons.OK, MessageBoxIcon.Information);
81
82                     TryActivatePreviousWindow();
83                     return 1;
84                 }
85
86                 TaskScheduler.UnobservedTaskException += (s, e) =>
87                 {
88                     e.SetObserved();
89                     OnUnhandledException(e.Exception.Flatten());
90                 };
91                 Application.ThreadException += (s, e) => OnUnhandledException(e.Exception);
92                 AppDomain.CurrentDomain.UnhandledException += (s, e) => OnUnhandledException((Exception)e.ExceptionObject);
93
94                 Application.EnableVisualStyles();
95                 Application.SetCompatibleTextRenderingDefault(false);
96                 Application.Run(new TweenMain());
97
98                 mt.ReleaseMutex();
99
100                 return 0;
101             }
102         }
103
104         /// <summary>
105         /// 動作中の .NET Framework のバージョンが適切かチェックします
106         /// </summary>
107         private static bool CheckRuntimeVersion()
108         {
109             // Mono 上で動作している場合はバージョンチェックを無視します
110             if (Type.GetType("Mono.Runtime", false) != null)
111                 return true;
112
113             // .NET Framework 4.5.1 以降で動作しているかチェックする
114             // 参照: http://msdn.microsoft.com/en-us/library/hh925568%28v=vs.110%29.aspx
115
116             using (var lmKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
117             using (var ndpKey = lmKey.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\"))
118             {
119                 var releaseKey = (int)ndpKey.GetValue("Release");
120                 return releaseKey >= 378675;
121             }
122         }
123
124         /// <summary>
125         /// “/key:value”形式の起動オプションを解釈し IDictionary に変換する
126         /// </summary>
127         /// <remarks>
128         /// 不正な形式のオプションは除外されます。
129         /// また、重複したキーのオプションが入力された場合は末尾に書かれたオプションが採用されます。
130         /// </remarks>
131         internal static IDictionary<string, string> ParseArguments(IEnumerable<string> arguments)
132         {
133             var optionPattern = new Regex(@"^/(.+?)(?::(.*))?$");
134
135             return arguments.Select(x => optionPattern.Match(x))
136                 .Where(x => x.Success)
137                 .GroupBy(x => x.Groups[1].Value)
138                 .ToDictionary(x => x.Key, x => x.Last().Groups[2].Value);
139         }
140
141         private static void TryActivatePreviousWindow()
142         {
143             // 実行中の同じアプリケーションのウィンドウ・ハンドルの取得
144             var prevProcess = GetPreviousProcess();
145             if (prevProcess == null)
146             {
147                 return;
148             }
149
150             IntPtr windowHandle = NativeMethods.GetWindowHandle((uint)prevProcess.Id, Application.ProductName);
151             if (windowHandle != IntPtr.Zero)
152             {
153                 NativeMethods.SetActiveWindow(windowHandle);
154             }
155         }
156
157         private static Process GetPreviousProcess()
158         {
159             var currentProcess = Process.GetCurrentProcess();
160             try
161             {
162                 return Process.GetProcessesByName(currentProcess.ProcessName)
163                     .Where(p => p.Id != currentProcess.Id)
164                     .FirstOrDefault(p => p.MainModule.FileName.Equals(currentProcess.MainModule.FileName, StringComparison.OrdinalIgnoreCase));
165             }
166             catch
167             {
168                 return null;
169             }
170         }
171
172         private static void OnUnhandledException(Exception ex)
173         {
174             if (MyCommon.ExceptionOut(ex))
175             {
176                 Application.Exit();
177             }
178         }
179
180         private static bool IsEqualCurrentCulture(string CultureName)
181         {
182             return Thread.CurrentThread.CurrentUICulture.Name.StartsWith(CultureName, StringComparison.Ordinal);
183         }
184
185         public static string CultureCode
186         {
187             get
188             {
189                 if (MyCommon.cultureStr == null)
190                 {
191                     MyCommon.cultureStr = SettingManager.Common.Language;
192                     if (MyCommon.cultureStr == "OS")
193                     {
194                         if (!IsEqualCurrentCulture("ja") &&
195                            !IsEqualCurrentCulture("en") &&
196                            !IsEqualCurrentCulture("zh-CN"))
197                         {
198                             MyCommon.cultureStr = "en";
199                         }
200                     }
201                 }
202                 return MyCommon.cultureStr;
203             }
204         }
205
206         public static void InitCulture()
207         {
208             try
209             {
210                 var culture = CultureInfo.CurrentCulture;
211                 if (CultureCode != "OS")
212                     culture = new CultureInfo(CultureCode);
213
214                 CultureInfo.DefaultThreadCurrentUICulture = culture;
215                 Thread.CurrentThread.CurrentUICulture = culture;
216             }
217             catch (Exception)
218             {
219             }
220         }
221
222         private static bool SetConfigDirectoryPath()
223         {
224             string configDir;
225             if (StartupOptions.TryGetValue("configDir", out configDir) && !string.IsNullOrEmpty(configDir))
226             {
227                 // 起動オプション /configDir で設定ファイルの参照先を変更できます
228                 if (!Directory.Exists(configDir))
229                 {
230                     var text = string.Format(Properties.Resources.ConfigDirectoryNotExist, configDir);
231                     MessageBox.Show(text, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
232                     return false;
233                 }
234
235                 MyCommon.settingPath = Path.GetFullPath(configDir);
236             }
237             else
238             {
239                 if (File.Exists(Path.Combine(Application.StartupPath, "roaming")))
240                 {
241                     MyCommon.settingPath = MySpecialPath.UserAppDataPath();
242                 }
243                 else
244                 {
245                     MyCommon.settingPath = Application.StartupPath;
246                 }
247             }
248
249             return true;
250         }
251     }
252 }