【问题标题】:Help with Windows Visa / 7 UAC file system virtualisation帮助 Windows Visa / 7 UAC 文件系统虚拟化
【发布时间】:2011-08-26 11:37:56
【问题描述】:

我正在开发一个旨在与旧 C++ 应用程序一起运行的程序。一款名为《奇迹时代》的游戏。在 Windows Vista 或 Windows 7(启用 UAC)下运行时,游戏保存文件将写入虚拟化路径而不是真实路径。

例如;

原文: C:\Program Files (x86)\Age of Wonders\Save

虚拟化: C:\Users\UserName\AppData\Local\VirtualStore\Program Files (x86)\Age of Wonders\Save

在我的 .Net 应用程序中,我从电子邮件服务器下载文件并将它们放在保存文件夹中,如果我尝试写入原始路径,我会在启用 UAC 时收到未经授权的访问异常。 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
    }
}

【问题讨论】:

    标签: windows windows-7 windows-vista uac


    【解决方案1】:

    仅供参考,我想出了这个 - 确实可以满足我的要求;

    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
        }
    }
    

    【讨论】:

      【解决方案2】:

      如果您想要虚拟化,您需要一个没有清单的 32 位进程。您似乎已经有一个 32 位进程,因此您需要摆脱清单。

      我预计这对于您漂亮的闪亮 WinForms 应用程序会带来不便,因为您将放弃现代主题外观。一个简单的解决方法是在单独的进程中对此进行编码,以仅处理需要虚拟化的应用程序部分。这样做的额外好处是您的流程的其余部分不必虚拟化。

      【讨论】:

        【解决方案3】:

        看起来您的 .Net 应用程序正在作为 64 位应用程序运行。此类应用程序禁用虚拟化(文件/注册表)。

        您可以将您的应用程序编译为 x86 吗?如果是这样,那应该可以解决问题。

        【讨论】:

        • 我的一些用户仍然使用 x86,所以我已经编译到 x86。
        • 其实我的编译器设置为Any CPU。
        • 所以在 x64 机器上虚拟化将被禁用
        猜你喜欢
        • 1970-01-01
        • 2013-08-31
        • 1970-01-01
        • 1970-01-01
        • 2016-09-28
        • 2011-12-03
        • 1970-01-01
        • 1970-01-01
        • 2016-03-15
        相关资源
        最近更新 更多