Это работает на Windows Server 2012 и IIS 8.5.
Важно понимать, что рабочий IIS работает на другом сеансе сервера терминалов, чем обычные приложения. Очень похоже на службу Windows.
Поэтому, когда приложение, открывающее файл с памятью, ему нужно создать его с помощью префикса «Глобальный», добавленного к имени. Но также необходимо добавить дескриптор безопасности или идентификатор. В C# это будет выглядеть следующим образом:
string MMF_Name = @"Global\MyMemoryMappedFileName";
var security = new MemoryMappedFileSecurity();
security.AddAccessRule(new System.Security.AccessControl.AccessRule<MemoryMappedFileRights>(new SecurityIdentifier(WellKnownSidType.WorldSid, null)
, MemoryMappedFileRights.FullControl
, AccessControlType.Allow)
);
var mmf = MemoryMappedFile.CreateOrOpen(MMF_Name
, 1024 * 1024
, MemoryMappedFileAccess.ReadWrite
, MemoryMappedFileOptions.None
, security
, System.IO.HandleInheritability.Inheritable);
В C++ это будет выглядеть следующим образом:
TCHAR szName[] = TEXT("Global\MyMemoryMappedFileName");
HANDLE hMapFile;
LPCTSTR pBuf;
SECURITY_DESCRIPTOR sd;
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
printf("InitializeSecurityDescriptor failed %d\n", GetLastError());
if (!SetSecurityDescriptorDacl(&sd, true, 0, false))
printf("SetSecurityDescriptorDacl failed %d\n", GetLastError());
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = false;
hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE, // use paging file
&sa, // default security
PAGE_READWRITE, // read/write access
0, // maximum object size (high-order DWORD)
BUF_SIZE, // maximum object size (low-order DWORD)
szName); // name of mapping object
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not create file mapping object (%d).\n"),
GetLastError());
return 1;
}
Приложение создания таких объектов необходимо начать с правами администратора.
Теперь, когда клиент, как и работник IIS, пытается получить доступ к файлу, ему необходимо использовать правильное имя, а также использовать префикс «Глобальный». В C# это будет выглядеть так:
string MMF_Name = @"Global\MyMemoryMappedFileName";
var MMF = MemoryMappedFile.OpenExisting(MMF_Name
, MemoryMappedFileRights.ReadWrite
, HandleInheritability.Inheritable);
В C++:
TCHAR szName[] = TEXT("Global\\MyMemoryMappedFileName");
HANDLE hMapFile;
LPCTSTR pBuf;
hMapFile = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // read/write access
TRUE, // !!!!! do inherit the name
szName); // name of mapping object
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not open file mapping object (%d).\n"),
GetLastError());
return 1;
}
Когда все это сделано. Работник IIS должен иметь доступ к приложению через файл с отображением памяти. Не нужно менять личность работника. Фактически, я запускаю его в настройках по умолчанию.
Что касается Windows, рабочий процесс IIS идентичен любому другому процессу и имеет все права доступа к учетной записи пользователя, в которой он работает. Вы уверены, что код верен? Можете ли вы успешно открыть файл, если f.e. вы запускаете тот же код в стандартном процессе? – Massimo
Да, я могу успешно использовать файл с памятью. В другом потоке кто-то сказал мне, что мне нужно создать файл с префиксом «Global /». Я тоже попробую. – chhenning
Это * COULD * будет еще одной проблемой UAC (хотя она должна влиять на стандартный процесс так же, как и процесс IIS). Можете ли вы попробовать отключить UAC? – Massimo