Где разместить общие файлы приложений, доступные для записи?
Я думал так CSIDL_COMMON_APPDATA\company\product
должно быть место для размещения файлов, которые являются общими для всех пользователей приложения и которые приложение может изменять, однако в Vista это место доступно только для чтения, если только оно не изменено установщиком (согласно MSDN - http://msdn.microsoft.com/en-us/library/ms995853.aspx), так что... что лучше? Измените настройки безопасности местоположения, чтобы разрешить запись или использование CSIDL_COMMON_DOCUMENTS\company\product
вместо? Может быть, есть третий вариант?
Кроме того, есть ли где-нибудь "официальная" рекомендация Microsoft по этому поводу?
4 ответа
Измените только безопасность в определенном подкаталоге каталога AppData (это по предоставленной вами ссылке):
CSIDL_COMMON_APPDATA Эта папка должна использоваться для данных приложения, которые не зависят от пользователя. Например, приложение может хранить словарь проверки орфографии, базу данных клип-арта или файл журнала в папке CSIDL_COMMON_APPDATA. Эта информация не будет перемещаться и доступна любому, кто использует компьютер. По умолчанию это местоположение доступно только для чтения для обычных (не администратор, не администратор) пользователей. Если приложению требуется, чтобы обычные пользователи имели права на запись в конкретный подкаталог приложения CSIDL_COMMON_APPDATA, то приложение должно явно изменить безопасность в этом подкаталоге во время установки приложения. Измененная безопасность должна быть задокументирована в Вопроснике Продавца.
Вот простой пример, показывающий, как создавать файлы и папки с правами чтения / записи для всех пользователей в папке "Общие данные приложения" (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;
}
Я думаю, что этот пост может ответить на некоторые вопросы, но для многих это кажется трудной проблемой.
Видимо, CSIDL_COMMON_DOCUMENTS предоставляет общий обходной путь
Руководство по Vista/UAC можно найти здесь. Поиск на этой странице для "CSIDL
"и вы найдете некоторые" официальные "ответы.