Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2010.09.26;
Скачать: CL | DM;

Вниз

Файлы в Windows 7   Найти похожие ветки 

 
AK-47   (2010-06-23 10:21) [0]

У меня возникла проблема с использованием программ в Windows7. Файлы в каталоге "Programm Files" меняются независимо для разных пользователей, то есть у одного пользователя поменялся какой-нибудь файл, у другого остался старый.
Вот, что я нашел по этому поводу в интернете:

С появлением Windows Vista/Windows 7 изменились некоторые принципы и правила программирования, которые необходимо знать программисту.

Очень многие программы по-прежнему копируют свои файлы в папки Program
Files, Windows или в корень системного диска (обычно диск C:). Также программы вносят изменения в реестр, используя ветку HKLM/Software. Но в Windows 7 возникает одна проблема: файлы или значения параметров в реестре не создаются или не обновляются. В чем дело?

Итак, обычные симптомы проблем:

   * ваша программа пытается писать в указанных папках или ветке реестра, но файлы там не появляются.
   * вы переключаетесь на другую учетную запись и ваше приложение не может найти файлы, записанные в папках Program Files, Windows или в корне системного диска
   * После отключения или включения User Account Control (UAC) ваше приложение не может найти файлы в папках Program Files или Windows

Эти проблемы возникают из-за виртуализации (UAC Virtualization). До выхода Windows Vista, обычно все работали с правами администратора и программы могли свободно переписывать системные файлы, значения в реестре и т.д. В Windows Vista принцип работы был изменен, и обычный пользователь с правами админа фактически работал уже с правами стандартного пользователя. Как это выглядело на практике.

Предположим, ваше приложение пытается внести изменения в файле C:\Program
Files\Contoso\Settings.ini, но обычный пользователь не имеет доступа к папке Program Files, и операция записи перенаправляется в файл C:\Users\Username\AppData\Local\VirtualStore\Program
Files\Contoso\settings.ini. Аналогично, если приложение пытается записать что-то в разделе реестра HKEY_LOCAL_MACHINE\Software\Contoso\, то запись перенаправляется в ветку HKEY_CURRENT_USER\Software\Classes\VirtualStore\MACHINE\Software\Contoso или
HKEY_USERS\UserSID_Classes\VirtualStore\Machine\Software\Contoso.

Как правильно вести себя в этих случаях? Виртуализация используется для совместимости с уже существующими программами. Если вы создаете свои новые программы, совместимые с  Windows 7, то вам следует избегать подобных случаев. Обязательно протестируйте свои программы под правами обычного пользователя, а не под правами администратора.

Если у вас уже есть старая программа, то измените ее в соответствии с новыми требованиями. Вам необходимо:

   * Удостовериться, что приложение сохраняет данные  только в пользовательских папках %alluserprofile% или в папках, имеющих полный доступ (настройки ACL).
   * Определить известную стандартную папку, в которую вы хотите записать данные. Данные, которыми будут пользоваться все пользователи, нужно записывать в соответствующие папки, доступные для всех. Данные для отдельного пользователя записываются в папку, доступную только этому пользователю.
   * Данные (логи, настройки, сохранение в играх) нужно сохранять в папку Documents
     (или указанную пользователем папку)
   * Не задавайте в коде жестко прописанные пути к файлам и папкам. Используйте стандартные функции для определения корректных путей к папке Windows и других известных папок: функция System.Environment.GetFolderPath позволяет получить пути к файлам Environment.SpecialFolder.CommonApplicationData
     Environment.SpecialFolder.LocalApplicationData
     Environment.SpecialFolder.ApplicationData.
     Также можно использовать следующие переменные среды:
     %ALLUSERSPROFILE%
     %LOCALAPPDATA%
     %APPDATA%

Используя Проводник, найдите ваши пропавшие файлы в папке VirtualStore, которая хранит перенаправленные файлы, которые вы пытались записать в запрещенные места.
Ищите эту папку в %localappdata%\VirtualStore. Если вы не можете найти эту папку, то попробуйте команду dir %userprofile%\yourfile.dat /s /a в командной строке (обычно папка находится в C:\Users\user name\AppData\Local\VirtualStore). Также файлы могут находиться в подпапках виртуализированной папки. Если там нашлись ваши файлы, то это служит лишним доказательством, что сработал механизм UAC virtualization и вам нужно принимать меры по исправлению ситуации.


Как программно сделать, чтобы каталог стал общим для всех пользователей?


 
RWolf ©   (2010-06-23 12:08) [1]

Может, всё-таки лучше использовать специально выделенные для этого каталоги? %AllUsersProfile%, %PROGRAMDATA%, %TEMP%?


 
Dennis I. Komarov ©   (2010-06-23 12:17) [2]


> Как программно сделать, чтобы каталог стал общим для всех
> пользователей?

Мелкомягкие понабрали по объявлением, а терь проги крутых перцов не работают на этих недоосях...


 
Демо ©   (2010-06-23 15:04) [3]


> а терь проги крутых перцов не работают на этих недоосях.
> ..


Скорее некоторые недопрограммеры не разбираются в операционных системах.


 
KilkennyCat ©   (2010-06-23 17:15) [4]


> * Не задавайте в коде жестко прописанные пути к файлам и
> папкам. Используйте стандартные функции для определения
> корректных путей к папке Windows и других известных папок:
>  функция System.Environment.GetFolderPath позволяет получить
> пути к файлам Environment.SpecialFolder.CommonApplicationData
>      Environment.SpecialFolder.LocalApplicationData
>      Environment.SpecialFolder.ApplicationData.
>      Также можно использовать следующие переменные среды:
>
>      %ALLUSERSPROFILE%
>      %LOCALAPPDATA%
>      %APPDATA%

это правило было всегда, вот только его используют не все, так что семерка не виноватая.


 
Кто б сомневался ©   (2010-06-23 21:44) [5]

Ну что тут можно сказать............... Не используйте тэг "код"!!! Невозможно же читать текст с таким расстояниями между буквами!


 
AK-47   (2010-06-28 17:18) [6]

Если кому-то интересно, то вот код для работы с правами доступа:


uses
 Windows, SysUtils, AclAPI, AccCtrl, ComObj, Forms;

const
 cAllUsers = "S-1-1-0"; // S-R-I-S-S пользователя "Все"

 // Следующие константы взяты из модуля JwaWinNT
 STANDARD_RIGHTS_WRITE    = READ_CONTROL;
 FILE_READ_DATA           = $0001;
 FILE_WRITE_DATA          = $0002;
 FILE_APPEND_DATA         = $0004;
 FILE_READ_EA             = $0008;
 FILE_WRITE_EA            = $0010;
 FILE_READ_ATTRIBUTES     = $0080;
 FILE_WRITE_ATTRIBUTES    = $0100;
 FILE_EXECUTE             = $0020;

 FILE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $1FF;

 FILE_GENERIC_READ = (STANDARD_RIGHTS_READ or FILE_READ_DATA or
   FILE_READ_ATTRIBUTES or FILE_READ_EA or SYNCHRONIZE);

 FILE_GENERIC_WRITE = (STANDARD_RIGHTS_WRITE or FILE_WRITE_DATA or
   FILE_WRITE_ATTRIBUTES or FILE_WRITE_EA or FILE_APPEND_DATA or SYNCHRONIZE);

 FILE_GENERIC_EXECUTE = (STANDARD_RIGHTS_EXECUTE or FILE_READ_ATTRIBUTES or
   FILE_EXECUTE or SYNCHRONIZE);

 MainFileRights = FILE_GENERIC_READ or FILE_GENERIC_WRITE or FILE_GENERIC_EXECUTE;

// Проверяет имеет ли диск на котором запущена программа файловую систему NTFS
function IsNTFS: Boolean;
// Проверяет есть ли у пользователя "Все" права на запись в указанный каталог
function IsCanWriteForAllUsers(const aDir: String): Boolean;
// Делает, чтобы у пользователя "Все" были права на запись
function SetDirSecurityForAllUsers(const aDir: String): Boolean;
// Возвращает имя пользователя "Все" или другой аналог названия этого пользователя в системе
function GetAllUsersName: String;

implementation

// Проверяет может ли указанный пользователь писать в указанный каталог
function IsCanWrite(const aDir: String; aSID: PSID): Boolean;
 // Проверка на то, что A входит в B
 function BIncludeA(const A, B: DWORD): Boolean;
 var
   i: Integer;
   vCurBit: DWORD;
 begin
   Result := True;
   for i := 0 to 31 do
   begin
     vCurBit := 1 shl i;
     if (A and vCurBit) > 0 then
     begin
       if (B And vCurBit) = 0 then
       begin
         Result := False;
         Exit;
       end;
     end;
   end;
 end;

type
 ACL_SIZE_INFORMATION = record
   AceCount: DWORD;
   AclBytesInUse: DWORD;
   AclBytesFree: DWORD;
 end;

 _ACE_HEADER = record
   AceType : BYTE;
   AceFlags : BYTE;
   AceSize : WORD;
 end;

 ACCESS_ACE = record
   Header : _ACE_HEADER;
   Mask : ACCESS_MASK;
   SidStart : DWORD;
 end;

var
 i: Integer;
 pDACL: PACL;
 pSD: PSECURITY_DESCRIPTOR;
 vRes: Cardinal;
 aclInfo: ACL_SIZE_INFORMATION;
 ace: ^ACCESS_ACE;
 SID: PSID;
begin
 Result := False;
 // Получаем текущую информацию о правах доступа
 vRes := GetNamedSecurityInfo(Pchar(aDir), SE_FILE_OBJECT,
   DACL_SECURITY_INFORMATION, nil, nil, PACL(@pDACL), nil, pSD);
 if vRes <> ERROR_SUCCESS then
   Exit;

 GetAclInformation(pDACL^, @aclInfo, sizeOf(aclInfo), AclSizeInformation);

 // Теперь запускаем цикл перебора всех записей
 for i := 0 to aclInfo.AceCount-1 do
 begin
   // получаем текущую запись
   if not (GetAce(pDACL^, i, Pointer(ace))) then
     continue;

   SID := PSID(@((ace)^.SidStart));

   if EqualSid(SID, aSID) then
   begin
     Result := BIncludeA(FILE_GENERIC_WRITE, ace^.Mask);
     Exit;
   end;
 end;
end;

function SetFileAccessRights(AFile, AUser: String; AMask: DWORD; INHERIT:Integer): Boolean;
var
 psd             : PSECURITY_DESCRIPTOR;
 dwSize          : DWord;
 bDaclPresent    : Bool;
 bDaclDefaulted  : Bool;
 OldAcl          : PACL;
 NewAcl          : PACL;
 sd              : SECURITY_DESCRIPTOR;
 ea              : EXPLICIT_ACCESS;
begin
 Result := False;
 if WIN32Platform <> VER_PLATFORM_WIN32_NT then
   Exit;
 psd := nil;
 NewAcl := nil;
 bDaclDefaulted := True;
 if not GetFileSecurity(PChar(AFile), DACL_SECURITY_INFORMATION, Pointer(1),
          0, dwSize) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
 begin
   try
     psd := HeapAlloc(GetProcessHeap, 8, dwSize);
     if psd <> nil then
     begin
       BuildExplicitAccessWithName(@ea, PChar(AUser), AMask, SET_ACCESS,INHERIT);

       //GetNamedSecurityInfo(PChar(AFile), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, OldACL, nil, psd);
       Result := GetFileSecurity(PChar(AFile), DACL_SECURITY_INFORMATION, psd, dwSize, dwSize);

       Result := GetSecurityDescriptorDacl(psd, bDaclPresent, OldAcl, bDaclDefaulted);
       if not Result then
         Exit;
       Result := (SetEntriesInAcl(1, @ea, OldAcl, NewAcl) = ERROR_SUCCESS);
       if not Result then
         Exit;
       Result := InitializeSecurityDescriptor(@sd, SECURITY_DESCRIPTOR_REVISION);
       if not Result then
         Exit;
       Result := SetSecurityDescriptorDacl(@sd, True, NewAcl, False);
       if not Result then
         Exit;
       Result := SetFileSecurity(PChar(AFile), DACL_SECURITY_INFORMATION, @sd);
     end;
   finally
     if NewAcl <> nil then
       LocalFree(HLocal(NewAcl));
     if psd <> nil then
       HeapFree(GetProcessHeap, 0, psd);
   end;
 end;
end;

// Получаем имя пользователя по SID
function GetSidName(Sid : PSID; out aName: String): Boolean;
var
 lpName,lpDomain : PWideChar;
 cbName,cbDomain : Cardinal;
 peUse : Cardinal;
begin
 Result := False;
 cbName:=64;
 cbDomain:=64;

 GetMem(lpName,cbName*SizeOf(WideChar));
 GetMem(lpDomain,cbDomain*SizeOf(WideChar));
 try
   if not LookupAccountSidW(nil,Sid,lpName,cbName,lpDomain,cbDomain,peUse)
      and (GetLastError=122) then
   begin
     ReAllocMem(lpName,cbName*SizeOf(WideChar));
     ReAllocMem(lpDomain,cbDomain*SizeOf(WideChar));

     if not LookupAccountSidW(nil,Sid,lpName,cbName,lpDomain,cbDomain,peUse) then
       Exit;
   end;
   aName := lpName;
   Result := True;
 finally
   FreeMem(lpName);
   Freemem(lpDomain);
 end;
end;

function ConvertStringSidToSidW(StringSid : PWideChar; var Sid : PSID):Boolean;stdcall;external "advapi32.dll";

function GetAllUsersName: String;
var
 vSID: PSID;
begin
 vSID := nil;
 try
   if ConvertStringSidToSidW(cAllUsers, vSID) then
   begin
     if not GetSidName(vSID, Result) then
       Result := "Все";
   end
   else
     Result := "Все";
 finally
   if nil <> vSID then LocalFree(cardinal(vSID));
 end;
end;

function IsNTFS: Boolean;
var
 fso, drv: OleVariant;
begin
 fso := CreateOleObject("Scripting.FileSystemObject");
 drv := fso.GetDrive(fso.GetDriveName(Application.ExeName));
 IsNTFS := drv.FileSystem = "NTFS"
end;

function IsCanWriteForAllUsers(const aDir: String): Boolean;
var
 SID: PSID;
begin
 Result := False;
 if not DirectoryExists(aDir) then
   Exit;

 ConvertStringSidToSidW("S-1-1-0", Sid);

 Result := IsCanWrite(aDir, Sid);
end;

function SetDirSecurityForAllUsers(const aDir: String): Boolean;
var
 vUserName: String;
begin
 Result := False;
 if not DirectoryExists(aDir) then
   Exit;

 vUserName := GetAllUsersName;
 Result := SetFileAccessRights(aDir, vUserName, MainFileRights, SUB_CONTAINERS_AND_OBJECTS_INHERIT);
end;



Страницы: 1 вся ветка

Текущий архив: 2010.09.26;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.01 c
6-1226523473
Yozch1
2008-11-12 23:57
2010.09.26
Учесть в программе используемый в системе Proxy


8-1205781369
VoVan
2008-03-17 22:16
2010.09.26
midi->wav


2-1277647865
New555
2010-06-27 18:11
2010.09.26
Обработка события onMouseMove


2-1277877991
AK-47
2010-06-30 10:06
2010.09.26
Конвертация из *.docx в *.doc


15-1277274062
AK-47
2010-06-23 10:21
2010.09.26
Файлы в Windows 7