我正在开发一个程序,该程序旨在与旧的C++应用程序协同工作。一个叫做“奇迹时代”的游戏。在Windows Vista或Windows 7(启用UAC )下运行时,游戏保存文件将写入虚拟化路径,而不是真实路径。
举个例子;
原始: C:\Program Files (X86)\奇迹年代\保存
虚拟化: C:\Users\UserName\AppData\Local\VirtualStore\Program文件(X86)\奇迹年代\保存
在我的.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
}
}
发布于 2011-05-16 23:09:11
如果你想要虚拟化,你需要一个没有清单的32位进程。您似乎已经有一个32位的进程,所以您需要删除清单。
我想这对你漂亮的闪亮的WinForms应用程序来说是不方便的,因为你会放弃现代的主题外观。一个简单的解决方法是在一个单独的进程中编写代码,只处理需要虚拟化的应用程序部分。这样做的另一个好处是,您的流程的其余部分不必虚拟化。
发布于 2011-05-16 22:56:15
看起来您的.Net应用程序正在作为64位应用程序运行。对此类应用程序禁用虚拟化(文件/注册表)。
你能把你的应用编译成x86吗?如果是这样的话,这应该能起到作用。
发布于 2011-05-17 17:41:49
仅供参考,我已经想到了这一点--它确实做到了我想要的;
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
}
}
https://stackoverflow.com/questions/6018484
复制相似问题