MapViewOfFile совместно используется 32-битными и 64-битными процессами.

Я пытаюсь использовать MapViewOfFile в 64-битном процессе для файла, который уже сопоставлен с памятью другого 32-битного процесса. Это терпит неудачу и дает мне ошибку «отказано в доступе». Это известное ограничение Windows или я что-то не так делаю? Тот же код отлично работает с двумя 32-битными процессами.

Код выглядит примерно так:

hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, szShmName);
if (NULL == hMapFile)
{   /* failed to open - create new (this happens in the 32 bit app) */
   SECURITY_ATTRIBUTES  sa;
   sa.nLength = sizeof(SECURITY_ATTRIBUTES);
   sa.bInheritHandle = FALSE;  
   /* give access to members of administrators group */
   BOOL success = ConvertStringSecurityDescriptorToSecurityDescriptor(
            "D:(A;OICI;GA;;;BA)",
            SDDL_REVISION_1,
            &(sa.lpSecurityDescriptor),
            NULL);
   HANDLE hShmFile = CreateFile(FILE_XXX_SHM, 
            FILE_ALL_ACCESS, 0, 
            &sa, 
            OPEN_ALWAYS, 0, NULL);

   hMapFile = CreateFileMapping(hShmFile, &sa, PAGE_READWRITE, 
            0, 
            SHM_SIZE, 
            szShmName);

   CloseHandle(hShmFile);
}

// this one fails in 64 bit app
pShm = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, SHM_SIZE); 

person MK.    schedule 16.03.2010    source источник
comment
Вы проверили, перенаправляется ли путь в каталог VirtualStore? Монитор процесса может помочь.   -  person bk1e    schedule 16.03.2010


Ответы (1)


Когда вы вызываете CreateFile в 32-разрядном приложении, вы передаете 0 для параметра общего доступа, что означает, что совместное использование запрещено. Изменение этого значения на FILE_SHARE_READ | FiLE_SHARE_WRITE, вероятно, было бы шагом в правильном направлении.

Редактировать: я только что собрал демо, которое работает (по крайней мере, для меня):

#include <windows.h>
#include <iostream>

static const char map_name[] = "FileMapping1";
static const char event1_name[] = "EventName1";
static const char event2_name[] = "EventName2";

int main() { 
    HANDLE mapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, map_name);

    if (NULL == mapping) {
        std::cout << "Calling CreateFile\n";
        HANDLE file = CreateFile("MappedFile", 
            FILE_ALL_ACCESS, 
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            NULL, 
            OPEN_ALWAYS, 
            0, 
            NULL);
        std::cout << "Creating File mapping\n";
        mapping = CreateFileMapping(file, NULL, PAGE_READWRITE, 0, 65536, map_name);

        std::cout << "Closing file handle\n";
        CloseHandle(file);
    }

    std::cout << "Mapping view of file\n";
    char *memory = (char *)MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 65536);
    if (memory == NULL) {
        std::cerr << "Mapping Failed.\n";
        return 1;
    }
    std::cout << "Mapping succeeded\n";

    HANDLE event = CreateEvent(NULL, false, false, event1_name);

    if (GetLastError()==ERROR_ALREADY_EXISTS) {
        std::cout <<"Waiting to receive string:\n";
        WaitForSingleObject(event, INFINITE);
        std::cout << "Received: " << memory;
        HANDLE event2 = CreateEvent(NULL, false, false, event2_name);
        SetEvent(event2);
    }
    else {
        char string[] = "This is the shared string";
        std::cout << "Sending string: " << string << "\n";
        strncpy(memory, string, sizeof(string));
        SetEvent(event);
        HANDLE event2 = CreateEvent(NULL, false, false, event2_name);
        WaitForSingleObject(event2, INFINITE);
    }   
    return 0;
}

Любая комбинация 32- или 64-битных исполняемых файлов работает нормально.

Edit2: обратите внимание, однако, что это чисто код демонстрационного уровня. Например, имя каждого общего объекта обычно должно содержать GUID-строку, чтобы предотвратить случайное столкновение с другими программами. Я также пропустил довольно много проверок ошибок, не говоря уже о той незначительной детали, что этот код не делает ничего полезного.

person Jerry Coffin    schedule 16.03.2010
comment
Спасибо Джерри, интересно, что это работает для вас. Я не думаю, что это моя проблема, потому что флаг отсутствия совместного использования передается только в CreateFile; этот файл немедленно закрывается, поэтому он не должен применяться. Также он отлично работает для обмена между несколькими 32-битными приложениями, но ломается только тогда, когда одно из них 64-битное. Я попытаюсь запустить ваш код. - person MK.; 16.03.2010
comment
Думаю, я понял это. Размер файла был определен на основе размера структуры, которая больше в 64-битной системе, потому что time_t там 64-битный, и мы заставляем наш time_ts по-прежнему быть 32-битным в 32-битных сборках. По какой-то причине указание размера области, превышающего размер, существующий в MapViewOfFile, завершается ошибкой с отказом в доступе. Спасибо! - person MK.; 17.03.2010