2015-03-31 42 views
4

我在C#這做以下的事情申請工作後刪除EXE:的Windows:執行

  1. 通過Process.Start()

我寫一個EXE磁盤

  • 執行EXE現在試圖確保EXE在關閉後將被刪除。 最簡單的方法是在使用File.Create創建EXE時設置參數FileOptions.DeleteOnClose

    但是,這意味着EXE在使用時無法執行。一旦文件句柄關閉,EXE會在執行之前立即被刪除。

    有沒有辦法在我的應用程序中保留對EXE的「弱引用」,它不鎖定文件並允許執行它?另外,有沒有辦法解開EXE執行文件句柄仍然打開?還有其他明顯的解決方案嗎?

    CLARIFICATION A:我知道有其他方法可以刪除正在使用的文件,這些文件最終會刪除文件(例如重新啓動時)。然而,我正在尋找一種方法,在開始執行時立即刪除該文件,而該文件是由操作系統處理的(例如,當運行一個首先執行該文件然後刪除該文件的批處理文件時,如果該批處理作業已終止,該文件將保留在磁盤上)。

    CLARIFICATION B:解釋更大的圖片:應用程序接收並解密可執行文件。解密後,該文件應該被執行。但是,我想確保解密版本的EXE不會保留在磁盤上。理想情況下,我也想阻止用戶複製解密後的EXE。但是,由於解密應用程序是以同一用戶的身份運行的,因此這兩者在系統上具有相同的權限時,將無法以真正安全的方式實現。

  • +0

    我不同意。我對DeleteOnClose的使用實際上來自於該特定問題的評分最高的答案中鏈接到的文章。 MoveFileEx將最終刪除文件(即重新啓動後),而不是在關閉文件後立即刪除文件。因此,我認爲這個問題是您所鏈接問題的答案之一的具體後續問題。 – 0x90 2015-03-31 07:24:19

    +0

    您試圖實現的功能無法使用'Fileoptions.DeleteOnClose'來完成,因爲在其他進程寫入時無法執行程序文件。 (我可以告訴你爲什麼,但它對這個話題沒有任何作用,而且在評論中沒有足夠的空間)。恐怕你必須分三步完成:寫 - >開始 - >刪除。 – mg30rg 2015-03-31 07:34:03

    +1

    嗯。這聽起來像個壞主意。你究竟在做什麼? – Luaan 2015-03-31 08:02:02

    回答

    8

    你可以使用Process.WaitForExit

    var process = Process.Start(processPath); 
    process.WaitForExit(); 
    
    // File.Delete(processPath); // Not strong enough (thanks to Binary Worrier) 
    DeleteOrDie(processPath); // Will attempts anything to delete the file. 
    

    但它給複製EXE從您所著它的可能性。

    一個好的解決方案是從內存中運行它。

    如果你的目標EXE是一個CLR程序,您可以使用Assembly.Load功能:

    // read the file and put data in bin 
    ... 
    Assembly a = Assembly.Load(bin); 
    MethodInfo method = a.EntryPoint; 
    if (method == null) throw new NoEntryPointException(); 
    object o = a.CreateInstance(method.Name); 
    method.Invoke(o, null); 
    

    更多細節here

    如果要加載/內存執行任何EXE,您可以使用Nebbett’s Shuttle的方法,但是你需要code it in C/C++和C#撥打電話吧。

    此外,它看起來像微軟不喜歡它(安全問題),我不認爲你可以從C#只能實現它。好的反病毒可能會檢測到它。

    +0

    +1:如果進程終止和關閉文件的窗口之間存在延遲,則可能需要在_catch/wait 10ms/retry_循環中包含File.Delete。 – 2015-04-02 15:39:11

    +0

    不錯,這是一個合理的答案。謝謝。如果調用進程在執行期間被終止,WaitForExit()方法會將EXE留在磁盤上,但仍然存在。 /不幸的是,我們不僅針對CLR計劃,而且Nebbett的飛機可能是一個可行的選擇。我將把問題留出一段時間,看看還有什麼可以進來的。 – 0x90 2015-04-03 07:43:45

    2

    在一個不是很好的方式,但一個方法,可以給你你想要什麼,我建議這個解決方案:
    (我用的一些輸入參數的Console Application該解決方案)

    [1:]寫函數來檢查打開的過程:

    /// <summary> 
    /// Check application is running by the name of its process ("processName"). 
    /// </summary> 
    static bool IsProcessOpen(string processName) 
    { 
        foreach (Processing.Process clsProcess in Processing.Process.GetProcesses()) 
        { 
         if (clsProcess.ProcessName.ToUpper().Contains(processName.ToUpper())) 
           return true; 
        } 
        return false; 
    } 
    

    [2:]定義一些變量:

    static bool IamRunning = true; 
    static int checkDuration = 1;  // in seconds 
    

    [3:]使用線程用於運行檢查循環:

    Thread t = new Thread(delegate() { 
        DateTime lastCheck = DateTime.MinValue; 
        while (IamRunning) 
        { 
         var now = DateTime.Now; 
         int dd = (now.Hour - lastCheck.Hour) * 3600 + (now.Minute - lastCheck.Minute) * 60 + now.Second - lastCheck.Second; 
         if (dd >= checkDuration) 
          if (!IsProcessOpen("ProcessName")) 
          { 
           delApplication(); // You have a function to delete ... 
           break; 
          } 
        } 
    }); 
    t.SetApartmentState(ApartmentState.STA); 
    t.Start(); 
    

    [4:]使用在節目的結束一個循環:

    while (t.ThreadState == ThreadState.Running) 
    { 
        // just wait. 
    } 
    

    注:這個解決方案由我的低端電腦Console Application有50%的CPU使用率。

    +0

    你有50%的使用率(佔你的兩個CPU之一的100%),因爲你有一個無限循環,並且沒有'Thread.Sleep'它。此外,使用它將避免你的(糟糕的編碼)DateTime差異計算(只需使用'(DateTime.Now.Hour - lastCheck).Second')。你忘了做'lastCheck = now;'。 – Orace 2015-04-08 11:19:51

    +0

    @Orace謝謝,我問一個[問題](http://stackoverflow.com/q/29530946/4519059)有關;)。 – 2015-04-09 06:35:45