常见的可写应用程序文件放在哪里?

17

我认为CSIDL_COMMON_APPDATA\company\product应该是放置应用程序所有用户都可以使用并且应用程序可以修改的公共文件的位置,但是,在Vista上这是一个只读位置,除非由安装程序进行更改(根据MSDN- http://msdn.microsoft.com/en-us/library/ms995853.aspx),那么...最好怎么办呢?修改位置的安全设置以允许写入或改用CSIDL_COMMON_DOCUMENTS\company\product?也许有第三种选择?

此外,Microsoft是否有任何“官方”建议?

4个回答

15

修改AppData目录的特定子目录的安全性(来自您提供的链接):

CSIDL_COMMON_APPDATA此文件夹应用于不特定于用户的应用程序数据。例如,应用程序可以将拼写检查词典,剪贴画数据库或日志文件存储在CSIDL_COMMON_APPDATA文件夹中。此信息不会漫游,并可供使用计算机的任何人使用。默认情况下,对于普通(非管理员、非电源)用户,此位置是只读的。如果应用程序要求普通用户对CSIDL_COMMON_APPDATA的应用程序特定子目录具有写访问权限,则应用程序必须在应用程序设置期间明确修改该子目录上的安全性。修改后的安全性必须在供应商问卷中记录。


是的,我也是这么想的。但似乎微软不希望你把文件放在那里,而是使用COMMON_DOCUMENTS。谢谢。 - dennisV
你从哪里得到的信息说他们不希望你把文件放在那里?看起来他们很乐意让你把文件放在那里——你应该把它们放在自己的子目录中,并正确管理安全性。 - 1800 INFORMATION
我想是这样,但修改安全性是一个额外的步骤,我认为(也许是错误的)是为了阻止人们将这个文件夹用于可写文件。 - dennisV
2
不,这是为了确保应用数据文件彼此隔离而采取的额外步骤。然后您被迫考虑用户应该具有什么访问权限,并相应地授予它。 - 1800 INFORMATION

5

以下是一个简单的示例,展示了如何在通用应用程序数据文件夹(CSIDL_COMMON_APPDATA)中为所有用户创建具有读/写权限的文件和文件夹。任何用户都可以运行此代码,以授予其他用户对文件和文件夹的写入权限:

#include <windows.h>

#include <shlobj.h>
#pragma comment(lib, "shell32.lib")

// for PathAppend
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")

#include <stdio.h>
#include <aclapi.h>
#include <tchar.h>
#pragma comment(lib, "advapi32.lib")    

#include <iostream>
#include <fstream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    DWORD dwRes, dwDisposition;
    PSID pEveryoneSID = NULL;
    PACL pACL = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    EXPLICIT_ACCESS ea;
    SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
    SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
    SECURITY_ATTRIBUTES sa;

    // Create a well-known SID for the Everyone group.
    if (!AllocateAndInitializeSid(&SIDAuthWorld, 1,
                     SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0,
                     &pEveryoneSID))
    {
        _tprintf(_T("AllocateAndInitializeSid Error %u\n"), GetLastError());
        goto Cleanup;
    }

    // Initialize an EXPLICIT_ACCESS structure for an ACE.
    // The ACE will allow Everyone access to files & folders you create.
    ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
    ea.grfAccessPermissions = 0xFFFFFFFF;
    ea.grfAccessMode = SET_ACCESS;

    // both folders & files will inherit this ACE
    ea.grfInheritance= CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE;
    ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea.Trustee.ptstrName  = (LPTSTR) pEveryoneSID;

    // Create a new ACL that contains the new ACEs.
    dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
    if (ERROR_SUCCESS != dwRes)
    {
        _tprintf(_T("SetEntriesInAcl Error %u\n"), GetLastError());
        goto Cleanup;
    }

    // Initialize a security descriptor.
    pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
    if (NULL == pSD)
    {
        _tprintf(_T("LocalAlloc Error %u\n"), GetLastError());
        goto Cleanup;
    }

    if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
    {
        _tprintf(_T("InitializeSecurityDescriptor Error %u\n"), GetLastError());
        goto Cleanup;
    }

    // Add the ACL to the security descriptor.
    if (!SetSecurityDescriptorDacl(pSD,
            TRUE,     // bDaclPresent flag
            pACL,
            FALSE))   // not a default DACL
    {
        _tprintf(_T("SetSecurityDescriptorDacl Error %u\n"), GetLastError());
        goto Cleanup;
    }

    // Initialize a security attributes structure.
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = pSD;
    sa.bInheritHandle = FALSE;



    TCHAR szPath[MAX_PATH];

    if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, szPath))) 
    {
        PathAppend(szPath, TEXT("Your Shared Folder"));

        if (!CreateDirectory(szPath, &sa)
            && GetLastError() != ERROR_ALREADY_EXISTS) 
        {
            goto Cleanup;
        }

        PathAppend(szPath, TEXT("textitup.txt"));

        HANDLE hFile = CreateFile(szPath, GENERIC_READ | GENERIC_WRITE, 0, &sa, CREATE_ALWAYS, 0, 0);
        if (hFile == INVALID_HANDLE_VALUE)
            goto Cleanup;
        else
            CloseHandle(hFile);

        //TODO: do the writing
        ofstream fsOut;
        fsOut.exceptions(ios::eofbit | ios::failbit | ios::badbit);
        fsOut.open(szPath, ios::out | ios::binary | ios::trunc);

        fsOut << "Hello world!\n";
        fsOut.close();
    }

Cleanup:

    if (pEveryoneSID) 
        FreeSid(pEveryoneSID);
    if (pACL) 
        LocalFree(pACL);
    if (pSD) 
        LocalFree(pSD);

    return 0;
}

2
我认为这篇文章可能能回答一些问题,但对许多人来说似乎是一个困难的问题。
显然,CSIDL_COMMON_DOCUMENTS提供了一个常见的解决方案。

抱歉,我不明白那如何回答问题。我知道如何获取路径,但我想问的是正确的路径是什么。 - dennisV
是的,谢谢。很遗憾这个问题没有官方答案。 - dennisV

1

可以在这里找到有关Vista/UAC的指南。在该页面中搜索"CSIDL",您将找到一些"官方"答案。


谢谢 - 这一切都指向我最初计划使用的目录。我想这就是正确的答案 :) - dennisV
发现自己一直是正确的感觉真好,不是吗?;-) - Christoffer Lette

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接