2011-05-16 66 views
1

我正在開發一個與舊C++應用程序配合使用的程序。一款名爲Age of Wonders的遊戲。在Windows Vista或Windows 7下運行(啓用UAC)時,遊戲保存文件將寫入虛擬化路徑而不是真實路徑。Windows Visa/7 UAC文件系統虛擬化幫助

因此,例如;

原文: C:\ Program Files文件(x86)的\奇觀\保存

虛擬年齡: C:\ Users \用戶名\ AppData \本地\ VirtualStore \程序文件(x86)\奇蹟時代\ Save

在我的.Net應用程序中,我從電子郵件服務器下載文件,並將它們放在Save文件夾中,如果我嘗試寫入原始路徑,則在啓用UAC時收到Unauthorized Access Exception。 Windows不會自動將它轉換爲虛擬路徑。我一直在通過讓我的用戶以管理員身份運行應用程序來解決此問題。不過,我想製作一個更優雅的解決方案。

我可以編寫一些代碼來處理異常並寫入我的代碼中的虛擬路徑,但我認爲更好的解決方案是以某種方式將程序切換到某種模式,以便由Windows本身完成,而不是我的代碼。我覺得這對未來版本的Windows來說是一個更好的長期解決方案。

我花時間在互聯網上搜索,我發現其他人正在討論這個問題,但沒有人提供任何實際可用的幫助。這裏是我看過的鏈接;

Should I use a VirtualStore solution on Vista?

Create Process with FS Virtualization Enabled

http://us.generation-nt.com/answer/using-settokeninformation-control-file-system-virtualization-vista-help-37057472.html

我需要的解決方案不涉及需要修改他們的系統設置或創建的任何帳戶下等

所以運行過程中用戶,下面我有一個簡單的Windows窗體應用程序的代碼。它有一個按鈕和一個複選框,該複選框用於切換虛擬化模式,並且按鈕將一個小文本文件寫入Program Files文件夾。我希望能夠使用它來測試虛擬化行爲。所以我期望當複選框被選中時,File.txt被寫入到虛擬路徑中。

如果任何人都可以幫我填寫空白函數,我會非常感激。提前致謝。

using System; 
using System.Collections.Generic; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.IO; 
public partial class Form1 : Form 
{ 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     try 
     { 
      string testText = "Dave was here"; 
      File.WriteAllText("C:\\Program Files\\DaveTest\\File.txt", testText); 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.ToString()); 
     } 
    } 

    private void checkBox1_CheckedChanged(object sender, EventArgs e) 
    { 
     SetVirtualization(checkBox1.Checked); 
    } 

    private void SetVirtualization(bool enabled) 
    { 
     //What code do I need here, please provide examples than can be used 
    } 
} 

回答

1

看起來像.net應用程序正在運行一個64位的應用程序。此類應用程序的虛擬化(文件/註冊表)被禁用。

你可以將你的應用程序編譯爲x86嗎?如果是這樣,應該做的伎倆。

+0

我的一些用戶無論如何都在x86上,所以我已經編譯到x86。 – 2011-05-16 15:05:42

+0

其實,我的編譯器集被設置爲Any CPU。 – 2011-05-16 15:14:38

+0

因此,在x64機器上虛擬化將被禁用 – Vagaus 2011-05-16 16:08:17

2

如果你想虛擬化,你需要一個沒有清單的32位進程。你似乎已經有了一個32位的進程,所以你需要擺脫清單。

我認爲這會給你的閃亮的WinForms應用程序帶來不便,因爲你會放棄現代主題的外觀。一個簡單的解決方法是在單獨的進程中對其進行編碼,以僅處理需要虛擬化的應用程序部分。這樣做的額外好處是您的其他流程不必虛擬化。

0

僅供參考,我想出了這個 - 哪些做我想做的事情;

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Diagnostics; 
using System.Runtime.InteropServices; 

namespace VirtualizationTest 
{ 
    public class FileVirtualizationHelper 
    { 
     #region Win32 API routines 

     enum TOKEN_INFORMATION_CLASS 
     { 
      TokenUser = 1, 
      TokenGroups, 
      TokenPrivileges, 
      TokenOwner, 
      TokenPrimaryGroup, 
      TokenDefaultDacl, 
      TokenSource, 
      TokenType, 
      TokenImpersonationLevel, 
      TokenStatistics, 
      TokenRestrictedSids, 
      TokenSessionId, 
      TokenGroupsAndPrivileges, 
      TokenSessionReference, 
      TokenSandBoxInert, 
      TokenAuditPolicy, 
      TokenOrigin, 
      MaxTokenInfoClass // MaxTokenInfoClass should always be the last enum 
     } 

     const UInt32 MAXIMUM_ALLOWED = 0x2000000; 

     [DllImport("kernel32.dll", SetLastError = true)] 
     static extern Boolean CloseHandle(IntPtr hSnapshot); 

     [DllImport("advapi32", SetLastError = true), System.Security.SuppressUnmanagedCodeSecurityAttribute] 
     static extern Boolean OpenProcessToken(IntPtr ProcessHandle, // handle to process 
              UInt32 DesiredAccess, // desired access to process 
              ref IntPtr TokenHandle); // handle to open access token 

     [DllImport("advapi32.dll", SetLastError = true)] 
     static extern Boolean SetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, ref UInt32 TokenInformation, UInt32 TokenInformationLength); 

     #endregion 

     #region Public Methods 

     public static bool Enable() 
     { 
      return SetVirtualization(true); 
     } 

     public static bool Disable() 
     { 
      return SetVirtualization(false); 
     } 

     #endregion 

     #region Private Methods 

     private static bool SetVirtualization(bool DoEnable) 
     { 
      IntPtr Token = (IntPtr)0; 
      UInt32 EnableValue = DoEnable ? (UInt32)1 : (UInt32)0; 
      UInt32 EnableValueSize = sizeof(UInt32); 

      if (!OpenProcessToken(Process.GetCurrentProcess().Handle, MAXIMUM_ALLOWED, ref Token)) 
      { 
       return false; 
      } 
      if (!SetTokenInformation(Token, (TOKEN_INFORMATION_CLASS)24, ref EnableValue, EnableValueSize)) 
      { 
       CloseHandle(Token); 
       return false; 
      } 
      CloseHandle(Token); 
      return true; 
     } 

     #endregion 
    } 
}