CreateFileMapping() 即使在重新启动后也会返回"already exists";如何删除旧的命名共享内存?

CreateFileMapping() returning "already exists" even after reboot; how to remove old Named Shared Memory?

本文关键字:删除 何删除 内存 共享 already 重新启动 exists CreateFileMapping 返回      更新时间:2023-10-16

我有一系列由主exe通过使用CreateFileMapping()和MapViewOfFile()创建的命名共享内存控制的从属exe。

我正在通过Visual Studio调试Master,当我得到我需要的东西时,我只是告诉Visual Studio"停止调试"。不好的举动,因为命名共享内存保持活动状态,重新启动后它仍然存在!

我尝试通过查看错误代码来识别命名共享内存,看到它是 183(已经存在)并要求现有的命名共享内存,但失败了。

无论哪种方式,我都很乐意:在发现它已经存在时删除/删除它,或者在发现已经存在时重复使用它。目前,我被困住了。我想我可以创建一个不同的名字,但那个已经存在的该死的名字可能会永远在那里徘徊......

无论如何,下面是定义我的命名共享内存控制逻辑的C++类:

enum ServerSharedMemReturnCodes {
    Success,                    // everything worked!
    SharedMemAlreadyGrabbed,    // EnableSharedMemoryAccess() error: _mapFile was not NULL!
    OpenFileMappingFailed,      // EnableSharedMemoryAccess() error: OpenFileMapping() filed!
    MapViewOfFileFailed         // EnableSharedMemoryAccess() error: MapViewOfFile() filed!
};
class ServerSharedMem {
public:
    ServerSharedMem() {
        _mapFile         = NULL;
        _serverCommLinks = NULL;
    }
    ~ServerSharedMem() {
        // Deactivate(); called explicitly at shutdown rather than here
    }
    /* our Named Shared Memory needs to be "activated" by the Master (installed to shared virtual memory). This does that. */
    inline int Activate( void ) {
        char *caller = "ServerSharedMem::Activate";
        if (_mapFile != NULL) {
            DebugMessage( caller, "Named Shared Memory already activated!" );
            return false;
        }
        TCHAR smName[]      = TEXT(CEX_SHAREDMEM_NAME);
        int   sharedMemSize = sizeof(ServerCommLink) * CEX_MAX_SERVER_COUNT;
        // debug logic: print out size and name:
        size_t convertedChars = 0;
        char   bsjnk[1024];
        errno_t err = wcstombs_s( &convertedChars, bsjnk, 1024, smName, sizeof(smName));
        if (err != 0) {
            DebugMessage( caller, "wcstombs_s  failed!" );
        } 
        char bsjnk2[1024];
        sprintf_s( bsjnk2, 1024, "sharedMemSize is '%d' bytes and smName is '%s'", sharedMemSize, bsjnk );
        DebugMessage( caller, bsjnk2 ); // size is 16832, name is "GlobalCEX_ActiveTasks"

        // let's create a Named Shared Memory block:
        _mapFile = CreateFileMapping( INVALID_HANDLE_VALUE,   // request a paging file
                                      NULL,                   // default security
                                      PAGE_READWRITE | SEC_COMMIT, // read/write access and hold entirely in RAM
                                      0,                      // high-order DWORD of max file size
                                      sharedMemSize,          // low-order DWORD of max file size
                                      smName );               // name of our named shared memory
        if (_mapFile == NULL) {
            DebugMessage( caller, "failed to create Named Shared Memory!" );
            DWORD errCode = GetLastError();
            if (errCode == 183) { // already exists! we did not shutdown cleanly
               DebugMessage( caller, "It appears to already exist! Attempting to grab it!" );
               ServerSharedMemReturnCodes retCode = EnableSharedMemoryAccess();
               if (retCode == Success) {
                  DebugMessage( caller, "Yes! Got it!" );
                  for (int i = 0; i < CEX_MAX_SERVER_COUNT; i++) {
                      _serverCommLinks[i].Init();
                      _serverCommLinks[i].SetServerId( i );
                  }
                  return true;
               }
               static CHAR errBuffer[CEX_CMDBUFFER_SIZE];
                va_list     errArgs[256];
                FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,NULL,errCode,0,errBuffer,CEX_CMDBUFFER_SIZE,errArgs);
                DebugMessage( caller, errBuffer );
                sprintf_s( errBuffer, CEX_CMDBUFFER_SIZE, "error code is '%d'", errCode );
                DebugMessage( caller, errBuffer ); // still 183, already exists
            }
            /*
            static CHAR errBuffer[CEX_CMDBUFFER_SIZE];
            va_list     errArgs[256];
            FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,NULL,errCode,0,errBuffer,CEX_CMDBUFFER_SIZE,errArgs);
            DebugMessage( caller, errBuffer );
            sprintf_s( errBuffer, CEX_CMDBUFFER_SIZE, "error code is '%d'", errCode );
            DebugMessage( caller, errBuffer ); */
            return false;
        }
        else {
            _serverCommLinks = (ServerCommLink *)MapViewOfFile(_mapFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
            if (_serverCommLinks == NULL) {
                CloseHandle(_mapFile);
                _mapFile = NULL;
                DebugMessage( caller, "MapViewOfFile() failed!" );
                return false;
            }
            else {
                for (int i = 0; i < CEX_MAX_SERVER_COUNT; i++) {
                    _serverCommLinks[i].Init();
                    _serverCommLinks[i].SetServerId( i );
                }
                return true;
            }
        }
    }
    /* upon program shutdown, Named Shared Memory needs to be removed from Shared Virtual Memory. This does that. */
    inline void Deactivate( void ) {
        char *caller = "ServerSharedMem::Deactivate";
        if (_mapFile) {
            if (_serverCommLinks) {
                UnmapViewOfFile( _serverCommLinks );
                _serverCommLinks = NULL;
                DebugMessage( caller, "Unmapped Named Shared Memory view." );
            }
            CloseHandle(_mapFile);
            _mapFile = NULL;
            DebugMessage( caller, "Closed Named Shared Memory handle." );
        }
    }
    /* Slaves use this to gain access to the Named Shared Memory setup by their Master */
    inline ServerSharedMemReturnCodes EnableSharedMemoryAccess( void ) {
        if (_mapFile != NULL) {
            return SharedMemAlreadyGrabbed;
        }
        TCHAR smName[] = TEXT(CEX_SHAREDMEM_NAME);
        _mapFile = OpenFileMapping( FILE_MAP_READ | FILE_MAP_WRITE, FALSE, smName );
        if (_mapFile == NULL) {
            return OpenFileMappingFailed;
        }
        else {
            _serverCommLinks = (ServerCommLink *)MapViewOfFile( _mapFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0 );
            return Success;
        }
    }
    /* Slaves use this to release their hold on their view of the Named Shared Memory */
    inline void ReleaseSharedMemoryAccess( void ) {
        char *caller = "ServerSharedMem::ReleaseSharedMemoryAccess";
        if (_mapFile != NULL) {
            if (_serverCommLinks != NULL) {
                UnmapViewOfFile( _serverCommLinks );
                _serverCommLinks = NULL;
                DebugMessage( caller, "Unmapped Named Shared Memory view." );
            }
            else DebugMessage( caller, "No active Named Shared Memory view!" );
            CloseHandle(_mapFile);
            DebugMessage( caller, "Closed Named Shared Memory handle." );
        }
        else DebugMessage( caller, "No Named Shared Memory!" );
    }
    /* pass in a return code, get back a string describing the code */
    inline char *ReturnCodeInfo( ServerSharedMemReturnCodes code ) {
        switch (code) {
        case Success:                 return "Success.";
        case SharedMemAlreadyGrabbed: return "Shared memory access has already been enabled.";
        case OpenFileMappingFailed:   return "Unable to open Named Shared Memory!";
        case MapViewOfFileFailed:     return "Unable to map view of Named Shared Memory!";
        default:                      return "Unknown return code!!!";
        }
    }
    inline int Active( void ) { return(_serverCommLinks ? true : false); }
    /* returns the requested server;s communication link if Named Shared Memory is activated/enabled */
    inline ServerCommLink *GetServerCommLink( int serverId ) {
        if (!_serverCommLinks)
            return NULL;
        if ((serverId >= 0) && (serverId < CEX_MAX_SERVER_COUNT)) {
            return &_serverCommLinks[serverId];
        }
        return NULL;
    }
private:
    HANDLE         _mapFile;           // our Named Shared Memory handle
    ServerCommLink *_serverCommLinks;  // will point to shared memory, an array of size CEX_MAX_SERVER_COUNT
};

Visual Studio 需要以管理员身份运行才能启动 IDE,才能具有创建命名共享对象的正确权限。