这个问题几乎说明了一切.
我有一个带有旧组件的应用程序,如果启用了运行时主题,则该组件无效.但如果我不启用它们,应用程序总是会弄乱虚拟商店.
谢谢!
更新:
使用下面的Mark解决方案,应用程序不再写入虚拟存储.但是,现在它不会访问它需要的tdb文件(Tiny Database文件).此tdb文件与写入虚拟存储的文件相同.关于如何让它访问tdb文件并仍然阻止编写虚拟存储的任何想法?
您需要向您的exe添加清单(资源).
清单中是一个XML资源,其内容类似于下面的内容.TrustInfo是导致不使用VirtualStore的关键部分.
此示例引用了Microsoft.Windows.Common-Controls程序集,该程序集启用运行时主题.如果从清单中删除它,您仍然可以保留TrustInfo部分.
Vista使用TrustInfo来确定应用程序"知道"有关UAC的限制,并且不将VirtualStore用于该应用程序
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="Delphi 7"
version="7.1.0.0"
processorArchitecture="*"/>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
publicKeyToken="6595b64144ccf1df"
language="*"
processorArchitecture="*"/>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
Run Code Online (Sandbox Code Playgroud)
这是一个页面,其中详细介绍了如何创建和使用清单文件:http:
//ruminatedrumblings.blogspot.com/2008/03/vista-uac-manifest.html
以及Application Manifest Schema上的Microsoft页面:http:
//msdn.microsoft.com/en-us/library/bb756929.aspx
当然,一旦执行此操作,您将无法再将数据写入c:\ program files \或打开UAC的其他受保护位置.这就是微软首先创建虚拟商店的原因.它旨在使旧的应用程序保持运行,以期能够写入那些(现在受保护的)位置.
您有几个不同的选择:
1:更改文件位置
将tdb文件移动到其他位置.这是理想的情况,但可能需要更多的代码更改.有关建议,请参阅" 围绕Windows UAC限制进行设计的正确方法 "这一问题.Microsoft建议存储用户未在"Application Data"文件夹下命名的数据.我试过这个但是这使得用户很难找到将数据移动到另一台计算机的数据.我已将所有用户数据(即使用户未专门保存文件)移动到"我的文档"文件夹.这样当他们得到一台新计算机时,他们就可以移动"我的文档"(而且大多数都会这样做),我的所有应用程序数据也会移动.
2:更改文件的权限以允许标准用户读/写文件.您的安装程序可以执行此操作,也可以在事后更新它,但您需要以管理员身份运行才能进行更改.
3:强制您的应用程序以管理员身份运行.如果设置了执行层面是"requireAdministrator"作为Sertac指出,你将能够写入文件,但您的用户会得到一个UAC提升提示每次运行应用程序的时间.
另请注意,如果要升级已运行并将数据保存到虚拟存储的用户,则无法自动将该数据移动到新位置.将清单添加到应用程序后,它将开始查看实际位于c:\ program files*下的文件.您可能需要在虚拟存储中查找文件并将其复制到用户的新位置.以下是一个例子.在我看来,许可证文件存储在安装目录下.升级我的应用程序后,我需要查找旧的许可证文件并将它们移动到新位置:
procedure TResetMain.CopyVirtFiles();
var
VirtLicDir: string;
NewLicDir: string;
FileOp: TSHFileOp;
TempPath : array[0..MAX_PATH] of Char;
begin
SHGetFolderPath(Application.Handle, CSIDL_LOCAL_APPDATA, 0, 0, TempPath);
VirtLicDir := TempPath + '\VirtualStore\Program Files\My Company\Licenses';
NewLicDir := GetMyConfigDir();
if NewLicDir <> '' then
begin
NewLicDir := IncludeTrailingPathDelimiter(NewLicDir) + 'User Licenses';
end;
// If the Virtual license directory exists but not the new directory we
// know this is the first time the updated application has been run
// and we need to move the files to the correct location.
if DirectoryExists(VirtLicDir) and Not DirectoryExists(NewLicDir) then
begin
ForceDirectories(NewLicDir);
FileOp := TSHFileOp.Create(nil);
FileOp.FileList.Add(VirtLicDir + '\*.*');
FileOp.Destination := NewLicDir;
FileOp.Action := faMove;
FileOp.SHOptions := [ofFilesOnly, ofNoConfirmation, ofNoConfirmMKDir, ofRenameOnCollision, ofSilent];
FileOp.Execute;
FreeAndNil(FileOp);
end;
end;
Run Code Online (Sandbox Code Playgroud)