把從http://www.afterdawn.com/software/source_codes/paint.net.cfm下載到的PDN3.05源碼下載 下來後,解壓出來src目錄下就是PDN的解決方案目錄了,可以使用VS2005或VS2008打開解決方案。
在所有工程中,核心的工程為 Data\Effects\Paintdotnet\PdnLib\SystemLayer。而其中 Paintdotnet是啟動項目,程序從Startup.cs啟動。
現在我們就來看看PDN的啟動有什麼奧秘吧。
Startup的構造函數接受一個string[]作為啟動參數。
應用程序從Main方法啟動,我們一起一步一步看看PDN是怎麼啟動的。
使用Main方法的啟動參數構造一個新的Startup對象,並調用Start方法。
Start方法中,一進來就注冊了應用程序域的異常事件,這樣做,就防止了應用程序域中的任何未捕 捉到異常彈出.net異常對話窗口導致用戶不知所措。
接下來檢查系統DPI兼容,在這裡我們一路跟蹤定義,進入了SafeNativeMethods類中,發現此類不簡 單,這裡除了方法定義外,沒有方法的實現,都是清一色的[DllImport]。小弟系井底之蛙,一開始搞不 懂這個屬性是什麼意思,於是翻查MSDN:
發現[DllImport]描述的方法,都是調用了windows本身的非托管代碼,並一定要加上extend關鍵字以 及都必須為靜態方法。
而在此調用的SetProcessDPIAware說明在此:http://msdn.microsoft.com/zh- cn/library/aa970067.aspx
接下來如果啟動參數中不包含"/skipRepairAttempt",進入StartPart2。
PDN對應多種語言系統,並能加載不同的語言資源,這是怎麼做到的呢?
跟蹤進入Settings類,在類的頂部,定義了兩個只讀變量:
public static readonly Settings SystemWide = new Settings (Microsoft.Win32.Registry.LocalMachine);
public static readonly Settings CurrentUser = new Settings (Microsoft.Win32.Registry.CurrentUser);
這兩個變量獲取了注冊表中LocalMachine和CurrentUser鍵的所有值,返回Startup中,StartPart2中 第一句就是查詢CurrentUser的"LanguageName"的值,這個鍵是在安裝PDN時寫入的,在注冊表的路徑 “HKEY_CURRENT_USER\Software\Paint.Net\”中。在我機器上該值為“zh-CN”,使用該值構造 CultureInfo,並設置到當前進程中:
本地化設置
1CultureInfo ci = new CultureInfo(locale, true);//new CultureInfo("zh-CN",true)
2Thread.CurrentThread.CurrentUICulture = ci;
3
為當前主進程設置了本地化信息後,並在以後使用ResourceManager,就能查找資源文件中的相應資 源了。
接下來的事就比較瑣碎了,檢查系統版本,設置主窗體的尺寸等。貼下相關代碼及注釋:
1 // 檢查系統版本
2 if (!OS.CheckOSRequirement())
3 {
4 string message = PdnResources.GetString("Error.OSRequirement");
5 Utility.ErrorBox(null, message);
6 return;
7 }
8
9 // 檢查啟動參數是否含有升級參數
10 if (this.args.Length == 1 &&
11 this.args[0] == Updates.UpdatesOptionsDialog.CommandLineParameter)
12 {
13 Updates.UpdatesOptionsDialog.ShowUpdateOptionsDialog(null, false);
14 }
15 else
16 {
17 SingleInstanceManager singleInstanceManager = new SingleInstanceManager("PaintDotNet");
18
19 // If this is not the first instance of PDN.exe, then forward the command-line
20 // parameters over to the first instance.
21 if (!singleInstanceManager.IsFirstInstance)
22 {
23 singleInstanceManager.FocusFirstInstance();
24
25 foreach (string arg in this.args)
26 {
27 singleInstanceManager.SendInstanceMessage(arg, 30);
28 }
29
30 singleInstanceManager.Dispose();
31 singleInstanceManager = null;
32
33 return;
34 }
35
36 // 構造新窗口
37 this.mainForm = new MainForm(this.args);
38
39 // 設置屏幕旋轉方位及主窗體尺寸
40 if (this.mainForm.ScreenAspect < 1.0)
41 {
42 int width = mainForm.Width;
43 int height = mainForm.Height;
44
45 this.mainForm.Width = height;
46 this.mainForm.Height = width;
47 }
48
49 // 使用主顯示器顯示窗口
50 Screen screen = Screen.FromControl(this.mainForm);
51
52 Rectangle intersect = Rectangle.Intersect(screen.Bounds, mainForm.Bounds);
53 if (intersect.Width == 0 || intersect.Height == 0)
54 {
55 mainForm.Location = new Point(screen.Bounds.Left + 16, screen.Bounds.Top + 16);
56 }
57
58 // 修正窗體尺寸
59 if (this.mainForm.Width < 200)
60 {
61 this.mainForm.Width = 200; // this value was chosen arbitrarily
62 }
63
64 if (this.mainForm.Height < 200)
65 {
66 this.mainForm.Height = 200; // this value was chosen arbitrarily
67 }
68
69 this.mainForm.SingleInstanceManager = singleInstanceManager;
70 singleInstanceManager = null; // mainForm owns it now
71
做完以上,就啟動主窗體了!
總結一下,在PDN程序啟動時,做了以下事情:
注冊應用程序未捕捉異常事件、使用啟動參數調用相應方法啟動窗體、設置本地化資源、為主窗體顯 示尺寸及位置校正。