在記憶體中裝載並執行程式或程式集

草上爬發表於2009-03-22
最近單位一直很忙很忙,前段時間也忙著寫些公司申請專利相關的文件,並整合通用MIS框架,所以沒有太多閒暇寫自己的部落格。今天又看了看反射的東西,忽然發現Assembly類的內容真是豐富啊!!而且,發現了之前我並沒有過多關注的方法,但是,卻是非常的實用和強大!我們以一個示例來闡述之。

眾所周知,副檔名為EXE的檔案在Windows下為二進位制可執行檔案,一旦這個可執行檔案處於執行狀態,作業系統會把這個二進位制檔案對映到記憶體中去,並將其加以鎖定。一般情況下,包括作業系統在內的任何程式都無法將這個處於執行狀態的可執行檔案移動、更名或刪除。不過,在.Net下利用Assembly類,我們對此就有了完美的解決方案。我們可以在記憶體中裝載程式集並執行之,而好處就是我們可以隨意移動、更名和刪除這個處於執行中的程式或程式集檔案。當然,該解決方案僅針對.Net程式或程式集。

示例方案中有兩個窗體程式,WindowsFormsApplication1.exe 和 WindowsFormsApplication2.exe,第一個程式的窗體上會有個button,用於在記憶體中裝載第二個程式,當第二個程式的主窗體顯示後,我們便可以輕鬆的將 WindowsFormsApplication2.exe 移動、更名和刪除,Windows 根本不會提示什麼"檔案正在使用,無法...."之類的提示了。

首先,為了動態的在記憶體中裝載程式或程式集,我們以檔案流的方式讀取二進位制檔案,並將其以位元組的形式儲存在陣列中,程式碼如下:
            FileStream fs = new  FileStream(Application.StartupPath+
                                             "\\WindowsFormsApplication2.exe", FileMode.Open);
            BinaryReader br = new BinaryReader(fs);
            byte[] bin = br.ReadBytes(Convert.ToInt32(fs.Length));
            fs.Close();
            br.Close();

然後,利用 Assembly 類的 Load 過載方法,以陣列的形式載入該程式集。程式碼如下:
            Assembly a = Assembly.Load(bin);

隨後我們需要獲得程式集的入口點,並將其以 MethodInfo 型別儲存下來,程式碼如下:
            method = a.EntryPoint; //獲得記憶體中可執行檔案的入口點

C++程式設計師都清楚,所謂程式入口點其實就是main函式的記憶體地址,有了程式的main方法的地址,我們只要呼叫即可了。程式碼如下:
            if (method != null)
            {
                method.Invoke(null, null);
            }

上述程式碼編譯時會100%正確,但是程式執行到 method.Invoke(null, null); 時會出現異常,經過反覆測試後發現,我們必須在一個新的執行緒上來執行對main方法的呼叫!

            System.Threading.Thread thd;
            System.Threading.ThreadStart ts; //線上程上執行特定的方法

            ts = new System.Threading.ThreadStart(RunNewApp);
            thd = new System.Threading.Thread(ts);
            thd.Start();

詳細程式碼參見示例程式。該示例在Windows XP3 + Visual Studio 2008 SP1 下編譯除錯透過。




 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14325734/viewspace-573385/,如需轉載,請註明出處,否則將追究法律責任。

相關文章