我有一个使用Visual Studio 2010构建的安装项目。
安装程序在将应用程序及其所有依赖项安装到正确的子目录和程序数据目录方面工作正常。
但是,我注意到安装程序创建的每个目录(根文件夹及其所有子目录)都没有“写入”权限。添加到“用户”组目录的唯一权限是:
无论用户是否将应用程序安装为“管理员”,都会发生这种明显的默认权限设置。
对我来说,安装程序没有为正在安装的应用程序使用的文件夹提供“写入”权限,这似乎很奇怪 - 安装程序在{{1}中创建的文件夹更加令人困惑应用程序数据库的文件夹没有获得“写入”权限。
我的问题是,有没有办法配置安装项目,以便在创建文件夹时,我们可以告诉它提供什么类型的权限以及向谁提供。在我的情况下,我需要提供(应用程序的)根目录及其所有子目录,以及放置在“Users Group”的ProgramData
文件夹“读/写”权限中的文件夹。从技术上讲,我很乐意将“完全控制”的目标交给“用户组”。
答案 0 :(得分:36)
我想我的其他帖子因为有点过于笼统而被删除了,所以我在下面对其进行了改进:
要做的是做一个自定义动作。这非常简单,请查看MSDN演练以编写C#自定义操作here。您将更改权限的代码放在Install方法中:
按照链接中的前几个步骤获取从安装程序解决方案引用的新安装程序项目。你必须这样做,所以你可以构建一个在安装结束时调用的dll。
实际上为用户设置读/写权限有点棘手,而我能得到的最接近的是为Authenticated Users设置。我拼凑了一些我在互联网上找到的其他解决方案:
public override void Install(IDictionary stateSaver)
{
// This gets the named parameters passed in from your custom action
string folder = Context.Parameters["folder"];
// This gets the "Authenticated Users" group, no matter what it's called
SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null);
// Create the rules
FileSystemAccessRule writerule = new FileSystemAccessRule(sid, FileSystemRights.Write, AccessControlType.Allow);
if (!string.IsNullOrEmpty(folder) && Directory.Exists(folder))
{
// Get your file's ACL
DirectorySecurity fsecurity = Directory.GetAccessControl(folder);
// Add the new rule to the ACL
fsecurity.AddAccessRule(writerule);
// Set the ACL back to the file
Directory.SetAccessControl(folder, fsecurity);
}
// Explicitly call the overriden method to properly return control to the installer
base.Install(stateSaver);
}
然后,当您创建自定义操作时,编辑其属性,并在CustomActionData属性下添加类似的内容:
/folder="[CommonAppDataFolder][ProductName]"
答案 1 :(得分:11)
默认情况下,用户组在Program Files等每个计算机位置没有写访问权限。这是与安装无关的Windows标准。但是,在安装过程中,您可以设置所需的任何权限。
Windows Installer确实支持自定义权限,但Visual Studio不提供设置它们的方法。因此,Visual Studio中唯一的解决方案是自定义操作。
不幸的是,Visual Studio不支持附加的自定义操作。因此,使用XCACLS.EXE设置权限只有在将其包含在程序包中时才会起作用(它将与文件一起安装在目标计算机上)。
更简洁但更复杂的解决方案是自己编写自定义操作(使用自定义代码)来设置所需的权限。
最快,最干净的解决方案是使用不同的设置创作工具,提供对权限的更多控制。
答案 2 :(得分:7)
private static void GrantAccess(string file)
{
bool exists = System.IO.Directory.Exists(file);
if (!exists)
{
DirectoryInfo di = System.IO.Directory.CreateDirectory(file);
Console.WriteLine("The Folder is created Sucessfully");
}
else
{
Console.WriteLine("The Folder already exists");
}
DirectoryInfo dInfo = new DirectoryInfo(file);
DirectorySecurity dSecurity = dInfo.GetAccessControl();
dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow));
dInfo.SetAccessControl(dSecurity);
}
上述代码会将文件夹的访问权限设置为对每个用户(每个人)进行完全控制/读写。
答案 3 :(得分:3)
行为是设计的。程序不应该修改自己(因此它们的安装目录)除了更新之外的任何东西(再次可以使用Windows安装程序完成而没有问题)。如果您使用的是.NET,isolated storage是存储用户数据的绝佳位置。
答案 4 :(得分:3)
DirectoryInfo info = new DirectoryInfo(path[x]);
DirectorySecurity security = info.GetAccessControl();
security.AddAccessRule(new FileSystemAccessRule(logonName, FileSystemRights.Modify, InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow));
security.AddAccessRule(new FileSystemAccessRule(logonName, FileSystemRights.Modify, InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow));
info.SetAccessControl(security);
如果要保存和访问ProgramData文件夹中的多个文件,设置继承部分也很重要。
答案 5 :(得分:1)
将defaultLocation更改为: C:[制造商] [产品名称] 您可以使用任何喜欢的驱动器来更改驱动器C。 See this picture
答案 6 :(得分:0)
如上所述,用户组在程序文件中没有写入权限。 如果您不想处理安装程序类或Wix(如果它是一个简单的程序),只需更喜欢在Windows Volume下安装您的软件。
我在谈论 Visual Studio安装向导: 更改应用程序文件夹' DefaultLocation '属性 从[ProgramFilesFolder]到目标机器上文件系统中的[WindowsVolume] [制造商] [ProductName]。
答案 7 :(得分:0)
我将要复制的文件夹放在C:\ Program Files(x86)目录中的安装向导的“应用程序文件夹”部分中的文件夹中。
然后在程序运行时检查所需的文件夹是否在正确的位置,如果没有,则将其复制到正确的目录中。
所以代码是:
import cv2
import numpy as np
# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Filter out large non-connecting objects
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area < 500:
cv2.drawContours(thresh,[c],0,0,-1)
# Morph open using elliptical shaped kernel
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=3)
# Find circles
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area > 20 and area < 50:
((x, y), r) = cv2.minEnclosingCircle(c)
cv2.circle(image, (int(x), int(y)), int(r), (36, 255, 12), 2)
cv2.imshow('thresh', thresh)
cv2.imshow('opening', opening)
cv2.imshow('image', image)
cv2.waitKey()
希望这会有所帮助。
答案 8 :(得分:0)
在安装应用程序后尝试写入SQLite数据库时,我也偶然发现了文件系统权限。
如该线程中所述,可以将数据文件放入用户的AppData文件夹中,而无需修改程序文件等中的权限。 AppData还设置了用户权限以允许默认写入。
在安装程序项目中,这是通过在安装程序文件系统中添加“用户的应用程序数据文件夹”来完成的,在该文件系统下可以创建应用程序文件夹。然后将数据库文件添加到此应用程序文件夹中。在安装过程中,将在AppData文件夹中创建带有数据库文件的应用程序文件夹。
用于创建指向AppData文件夹的数据库连接字符串的代码如下:
public static Environment.SpecialFolder DataPath = Environment.SpecialFolder.ApplicationData;
public static string ConnectionString = "Data Source=" + Environment.GetFolderPath(DataPath) + "\\ApplicationName\\database.SQLite";
我在Visual Studio 2019中使用了此解决方案。