赞
踩
目录
windows进程间通信是写多进程程序的必修课,高实时性、安全、数据量大的通信方式是很必要的,今天我们来看看文件映射
文件映射通过将文件的部分或全部内容映射到一个或多个进程的虚拟地址空间,使得这些进程可以像访问普通内存一样访问文件内容。这个过程涉及以下步骤:
CreateFileMapping
,创建一个文件映射对象。这个对象表示文件的映射视图。MapViewOfFile
函数将文件映射对象的一个视图映射到进程的地址空间中。用于创建或打开一个文件。
- HANDLE CreateFile(
- LPCSTR lpFileName,
- DWORD dwDesiredAccess,
- DWORD dwShareMode,
- LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- DWORD dwCreationDisposition,
- DWORD dwFlagsAndAttributes,
- HANDLE hTemplateFile
- );
参数:
lpFileName
(LPCSTR): 文件名。dwDesiredAccess
(DWORD): 访问权限。常见值包括 GENERIC_READ
、GENERIC_WRITE
等。dwShareMode
(DWORD): 共享模式。常见值包括 FILE_SHARE_READ
、FILE_SHARE_WRITE
等。lpSecurityAttributes
(LPSECURITY_ATTRIBUTES): 安全属性指针,可为 NULL。dwCreationDisposition
(DWORD): 如何创建文件。常见值包括 CREATE_NEW
、CREATE_ALWAYS
、OPEN_EXISTING
等。dwFlagsAndAttributes
(DWORD): 文件属性和标志。常见值包括 FILE_ATTRIBUTE_NORMAL
、FILE_FLAG_OVERLAPPED
等。hTemplateFile
(HANDLE): 模板文件句柄,可为 NULL。 为了确保文件映射的安全性,可以使用 Windows 的安全属性(SECURITY_ATTRIBUTES
)来设置访问控制权限。这样可以限制哪些进程可以访问或修改映射的文件内容。
为了确保文件映射的安全性,可以使用 Windows 的安全属性(
SECURITY_ATTRIBUTES
)来设置访问控制权限。这些安全属性允许您指定一个安全描述符,该描述符定义了哪些用户和组可以访问或修改映射的文件内容。以下是如何使用SECURITY_ATTRIBUTES
结构来设置访问控制权限的步骤:
- 创建一个安全描述符:使用
InitializeSecurityDescriptor
函数初始化一个安全描述符。- 设置访问控制列表 (ACL):使用
SetSecurityDescriptorDacl
函数为安全描述符设置一个访问控制列表 (ACL),定义访问权限。- 初始化
SECURITY_ATTRIBUTES
结构:将安全描述符包含在SECURITY_ATTRIBUTES
结构中。- 传递
SECURITY_ATTRIBUTES
结构:在调用CreateFileMapping
或其他相关 API 时,将SECURITY_ATTRIBUTES
结构传递给它们。
- // 定义安全描述符字符串 (SDDL)
- // 这里设置为允许所有用户读取和写入
- LPCSTR sddl = "D:P(A;;GA;;;WD)";
-
- // 创建一个安全描述符
- PSECURITY_DESCRIPTOR pSD = NULL;
- if (!ConvertStringSecurityDescriptorToSecurityDescriptorA(sddl, SDDL_REVISION_1, &pSD, NULL)) {
- // 处理错误
- printf("ConvertStringSecurityDescriptorToSecurityDescriptorA 错误: %d\n", GetLastError());
- return 1;
- }
-
- // 初始化 SECURITY_ATTRIBUTES 结构
- SECURITY_ATTRIBUTES sa;
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.lpSecurityDescriptor = pSD;
- sa.bInheritHandle = FALSE;
-
- // 创建或打开文件
- HANDLE hFile = CreateFile(
- "example.txt",
- GENERIC_READ | GENERIC_WRITE,
- 0,
- &sa, // 使用自定义的安全属性
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- NULL
- );
关键点说明:
- 安全描述符字符串 (SDDL): 示例中的 SDDL
"D:P(A;;GA;;;WD)"
设置了一个允许所有用户读取和写入的安全描述符。您可以根据需求调整这个字符串以设置不同的权限。- ConvertStringSecurityDescriptorToSecurityDescriptorA: 将 SDDL 转换为实际的安全描述符。
- SECURITY_ATTRIBUTES: 包含了安全描述符,用于设置文件和文件映射对象的安全属性。
通过上述步骤和示例代码,您可以设置文件映射的安全属性,控制哪些进程可以访问或修改映射的文件内容。
总之,文件映射是一种高效、灵活的进程间通信机制,特别适合需要处理大块数据并且要求高实时性和高安全性的场景。通过合理的权限设置和内存管理,可以充分利用文件映射的优势,提高系统的整体性能。
用于创建一个文件映射对象。
- HANDLE CreateFileMapping(
- HANDLE hFile,
- LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
- DWORD flProtect,
- DWORD dwMaximumSizeHigh,
- DWORD dwMaximumSizeLow,
- LPCSTR lpName
- );
参数:
hFile
(HANDLE): 文件句柄。lpFileMappingAttributes
(LPSECURITY_ATTRIBUTES): 安全属性指针,可为 NULL。flProtect
(DWORD): 保护属性。常见值包括 PAGE_READONLY
、PAGE_READWRITE
等。dwMaximumSizeHigh
(DWORD): 映射文件的最大尺寸(高位)。dwMaximumSizeLow
(DWORD): 映射文件的最大尺寸(低位)。lpName
(LPCSTR): 文件映射对象的名字,可为 NULL。返回值: 成功返回文件映射对象句柄,失败返回 NULL。
- HANDLE hFileMapping = CreateFileMapping(
- hFile,
- NULL,
- PAGE_READWRITE,
- 0,
- 1024,
- "Local\\MyFileMapping"
- );
-
- if (hFileMapping == NULL) {
- // 处理错误
- }
将文件映射对象的一个视图映射到进程的地址空间中。
- LPVOID MapViewOfFile(
- HANDLE hFileMappingObject,
- DWORD dwDesiredAccess,
- DWORD dwFileOffsetHigh,
- DWORD dwFileOffsetLow,
- SIZE_T dwNumberOfBytesToMap
- );
参数:
hFileMappingObject
(HANDLE): 文件映射对象句柄。dwDesiredAccess
(DWORD): 访问权限。常见值包括 FILE_MAP_READ
、FILE_MAP_WRITE
等。dwFileOffsetHigh
(DWORD): 文件偏移量的高位。dwFileOffsetLow
(DWORD): 文件偏移量的低位。dwNumberOfBytesToMap
(SIZE_T): 映射的字节数。返回值: 成功返回映射视图的指针,失败返回 NULL。
- LPVOID lpBaseAddress = MapViewOfFile(
- hFileMapping,
- FILE_MAP_READ,
- 0,
- 0,
- 0
- );
-
- if (lpBaseAddress == NULL) {
- // 处理错误
- }
解除文件视图的映射。
- BOOL UnmapViewOfFile(
- LPCVOID lpBaseAddress
- );
- if (!UnmapViewOfFile(lpBaseAddress)) {
- // 处理错误
- }
关闭文件、文件映射对象或文件视图的句柄。
- BOOL CloseHandle(
- HANDLE hObject
- );
- if (!CloseHandle(hFile)) {
- // 处理错误
- }
-
- if (!CloseHandle(hFileMapping)) {
- // 处理错误
- }
为了确保文件映射的安全性,可以使用 Windows 的安全属性(SECURITY_ATTRIBUTES
)来设置访问控制权限。这样可以限制哪些进程可以访问或修改映射的文件内容。
总之,文件映射是一种高效、灵活的进程间通信机制,特别适合需要处理大块数据并且要求高实时性和高安全性的场景。通过合理的权限设置和内存管理,可以充分利用文件映射的优势,提高系统的整体性能。
在 Windows 底层,文件映射的实现涉及多个关键组件和机制,包括内存管理器、文件系统、内核对象和虚拟内存管理。以下是 Windows 底层实现文件映射的主要步骤和机制:
当应用程序调用 CreateFile
函数时,Windows 内核通过文件系统驱动程序将文件打开并创建一个文件句柄。文件系统驱动程序负责处理文件的底层访问,包括读写操作、权限检查和文件缓存。
调用 CreateFileMapping
时,Windows 内核创建一个文件映射对象。这涉及到以下几个步骤:
当应用程序调用 MapViewOfFile
时,Windows 内核的内存管理器开始工作:
多个进程可以通过文件映射对象共享内存。不同进程调用 OpenFileMapping
和 MapViewOfFile
来访问同一个文件映射对象:
当进程调用 UnmapViewOfFile
时,内存管理器解除文件视图的映射:
FILE_OBJECT
和 SECTION_OBJECT
数据结构表示。MmCreateSection
、MmMapViewOfSection
、MmUnmapViewOfSection
等函数用于管理文件映射的创建、映射和解除映射。- graph TD;
- A[应用程序] -->|调用 CreateFile| B[文件系统驱动]
- B -->|返回文件句柄| A
- A -->|调用 CreateFileMapping| C[内核]
- C -->|创建文件映射对象| D[内存管理器]
- D -->|建立文件与内存关联| C
- A -->|调用 MapViewOfFile| D
- D -->|分配虚拟地址空间| A
- A -->|访问映射视图| D
- D -->|通过页错误加载内容| E[物理内存]
- A -->|调用 UnmapViewOfFile| D
- D -->|解除映射视图| A
- C -->|引用计数清零时释放资源| D
fileMap基础共享通信代码:
- #include <windows.h>
- #include <iostream>
- #include <string>
- #include <stdexcept>
- #include <memory>
-
- class SharedMemory {
- public:
- SharedMemory(const std::wstring& name, size_t size);
- ~SharedMemory();
-
- bool create();
- bool open();
- void write(const std::wstring& data);
- std::wstring read();
- void close();
- void signal(); // 用于通知另一个进程数据已写入
- void wait(); // 用于等待另一个进程写入数据
-
- private:
- std::wstring name_;
- size_t size_;
- HANDLE hFile_;
- HANDLE hMapFile_;
- LPVOID lpBase_;
- HANDLE hEvent_;
-
- void cleanup();
- void checkAndThrow(bool condition, const std::wstring& errorMessage);
- };
-
-
-
-
- #include "sharedMemoryW.h"
- // 构造函数
- SharedMemory::SharedMemory(const std::wstring& name, size_t size)
- : name_(name), size_(size), hFile_(NULL), hMapFile_(NULL), lpBase_(NULL), hEvent_(NULL) {}
-
- // 析构函数
- SharedMemory::~SharedMemory() {
- close();
- }
-
- // 创建文件映射对象和事件对象
- bool SharedMemory::create() {
- hFile_ = CreateFileW(name_.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- checkAndThrow(hFile_ != INVALID_HANDLE_VALUE, L"Unable to create file.");
-
- hMapFile_ = CreateFileMappingW(hFile_, NULL, PAGE_READWRITE, 0, static_cast<DWORD>(size_), name_.c_str());
- checkAndThrow(hMapFile_ != NULL, L"Unable to create file mapping object.");
-
- lpBase_ = MapViewOfFile(hMapFile_, FILE_MAP_ALL_ACCESS, 0, 0, size_);
- checkAndThrow(lpBase_ != NULL, L"Unable to map view of file.");
-
- hEvent_ = CreateEventW(NULL, TRUE, FALSE, (name_ + L"_Event").c_str());
- checkAndThrow(hEvent_ != NULL, L"Unable to create event object.");
-
- return true;
- }
-
- // 打开现有的文件映射对象和事件对象
- bool SharedMemory::open() {
- hMapFile_ = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, name_.c_str());
- checkAndThrow(hMapFile_ != NULL, L"Unable to open file mapping object.");
-
- lpBase_ = MapViewOfFile(hMapFile_, FILE_MAP_ALL_ACCESS, 0, 0, size_);
- checkAndThrow(lpBase_ != NULL, L"Unable to map view of file.");
-
- hEvent_ = OpenEventW(EVENT_ALL_ACCESS, FALSE, (name_ + L"_Event").c_str());
- checkAndThrow(hEvent_ != NULL, L"Unable to open event object.");
-
- return true;
- }
-
- // 写入数据到映射内存
- void SharedMemory::write(const std::wstring& data) {
- if (lpBase_ != NULL) {
- memcpy(lpBase_, data.c_str(), (data.size() + 1) * sizeof(wchar_t)); // 包括终止符
- signal(); // 通知另一个进程数据已写入
- }
- }
-
- // 读取数据从映射内存
- std::wstring SharedMemory::read() {
- if (lpBase_ != NULL) {
- return std::wstring(static_cast<wchar_t*>(lpBase_));
- }
- return L"";
- }
-
- // 关闭文件映射和事件对象
- void SharedMemory::close() {
- cleanup();
- }
-
- // 用于通知另一个进程数据已写入
- void SharedMemory::signal() {
- if (hEvent_ != NULL) {
- SetEvent(hEvent_);
- }
- }
-
- // 用于等待另一个进程写入数据
- void SharedMemory::wait() {
- if (hEvent_ != NULL) {
- WaitForSingleObject(hEvent_, INFINITE);
- }
- }
-
- void SharedMemory::cleanup() {
- if (lpBase_ != NULL) {
- UnmapViewOfFile(lpBase_);
- lpBase_ = NULL;
- }
- if (hMapFile_ != NULL) {
- CloseHandle(hMapFile_);
- hMapFile_ = NULL;
- }
- if (hFile_ != NULL) {
- CloseHandle(hFile_);
- hFile_ = NULL;
- }
- if (hEvent_ != NULL) {
- CloseHandle(hEvent_);
- hEvent_ = NULL;
- }
- }
-
- void SharedMemory::checkAndThrow(bool condition, const std::wstring& errorMessage) {
- if (!condition) {
- DWORD errorCode = GetLastError();
- throw std::runtime_error(std::string(errorMessage.begin(), errorMessage.end()) + " Error code: " + std::to_string(errorCode));
- }
- }
父进程:
- #include <windows.h>
- #include <iostream>
- #include <string>
- #include "sharedMemoryW.h"
-
- void CreateChildProcess(const std::wstring& sharedMemoryName, size_t sharedMemorySize) {
- STARTUPINFOW si;
- PROCESS_INFORMATION pi;
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
- ZeroMemory(&pi, sizeof(pi));
-
- std::wstring commandLine = L"ChildProcess.exe " + sharedMemoryName + L" " + std::to_wstring(sharedMemorySize);
-
- if (!CreateProcessW(NULL, &commandLine[0], NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
- std::wcerr << L"CreateProcess failed (" << GetLastError() << L")." << std::endl;
- return;
- }
-
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
- }
-
- int main() {
- const std::wstring sharedMemoryName = L"SharedMemoryExample";
- const size_t sharedMemorySize = 1024;
-
- SharedMemory sharedMemory(sharedMemoryName, sharedMemorySize);
-
- try {
- sharedMemory.create();
- }
- catch (const std::exception& e) {
- std::cerr << "Error: " << e.what() << std::endl;
- return 1;
- }
-
- CreateChildProcess(sharedMemoryName, sharedMemorySize);
-
- std::wstring message = L"Hello from Parent Process";
- sharedMemory.write(message);
-
- std::wcout << L"Parent process waiting for child process to read the message..." << std::endl;
- sharedMemory.wait(); // 等待子进程读取数据
-
- std::wcout << L"Parent process read: " << sharedMemory.read() << std::endl;
-
- sharedMemory.close();
- system("pause");
- return 0;
- }
子进程:
- #include <windows.h>
- #include <iostream>
- #include <string>
- #include "sharedMemoryW.h" // 假设SharedMemory类的代码放在这个头文件中
-
- int wmain(int argc, wchar_t* argv[]) {
- if (argc != 3) {
- std::wcerr << L"Usage: ChildProcess <SharedMemoryName> <SharedMemorySize>" << std::endl;
- return 1;
- }
-
- std::wstring sharedMemoryName = argv[1];
- size_t sharedMemorySize = std::stoull(argv[2]);
-
- SharedMemory sharedMemory(sharedMemoryName, sharedMemorySize);
-
- try {
- sharedMemory.open();
- }
- catch (const std::exception& e) {
- std::cerr << "Error: " << e.what() << std::endl;
- return 1;
- }
-
- std::wcout << L"Child process read: " << sharedMemory.read() << std::endl;
-
- std::wstring response = L"Hello from Child Process";
- sharedMemory.write(response);
-
- std::wcout << L"Child process waiting for parent process to read the message..." << std::endl;
- sharedMemory.signal(); // 通知父进程数据已写入
-
- sharedMemory.close();
-
- system("pause");
- return 0;
- }
更多代码请访问我的GitHub:
GitHub - bowenliu1996/SharedMemoryW: Windows file mapping communication, including demo
复杂的同步机制:共享内存本身不提供同步机制,需要使用额外的同步手段(如互斥锁、事件等)来确保数据读写的正确性和一致性。这增加了开发的复杂性,容易引入竞态条件(Race Conditions)。
深刻分析:同步问题是共享内存使用中的主要挑战之一。没有正确处理同步,可能导致数据竞争、死锁、饿死等问题。这些问题不仅难以调试,而且可能导致数据损坏或程序崩溃。
内存管理难度:需要显式地管理共享内存的分配和释放,容易导致内存泄漏或内存碎片化。
深刻分析:内存管理错误是程序员常犯的错误之一。在共享内存的场景中,内存泄漏不仅影响一个进程,还会影响到所有使用该共享内存的进程,可能导致系统资源耗尽。
安全性问题:共享内存区域可以被所有拥有权限的进程访问,存在潜在的安全风险。如果没有严格的访问控制,可能导致敏感数据泄露或被恶意篡改。
深刻分析:安全性问题尤其在多用户环境中显得突出。恶意进程可以利用共享内存中的数据进行攻击或篡改,这需要额外的措施来保护数据的完整性和机密性。
平台依赖性:共享内存的实现通常依赖于操作系统的底层机制,不同操作系统(如Windows和Unix)的实现细节不同,导致代码的可移植性差。
深刻分析:跨平台开发时,共享内存的实现需要针对不同平台进行适配。这增加了开发和维护成本,同时也可能导致在不同平台上出现难以预见的问题。
调试困难:共享内存调试相对困难,因为多个进程同时操作同一内存区域,调试工具和技术支持较少。
深刻分析:调试共享内存中的问题往往需要了解多个进程的状态和行为,这增加了调试的难度和复杂性。开发人员需要具备更高的调试技巧和经验。
共享内存通信在高效数据传输方面有明显优势,但其复杂的同步机制、内存管理、安全性问题、平台依赖性和调试困难都是使用过程中必须慎重考虑的缺点。这些缺点不仅增加了开发和维护的难度,还可能带来潜在的系统稳定性和安全性风险。因此,在使用共享内存时,需要综合权衡其优缺点,选择适合具体应用场景的通信机制。
根据复杂的同步机制、内存管理难度、平台依赖性、安全性问题、调试困难等问题。
我们优化代码:sharedMemoryW.h
- #include <windows.h>
- #include <iostream>
- #include <string>
- #include <stdexcept>
- #include <memory>
-
- class SharedMemory {
- public:
- SharedMemory(const std::wstring& name, size_t size);
- ~SharedMemory();
-
- bool create();
- bool open();
- void write(const std::wstring& data);
- std::wstring read();
- void close();
- void signal(); // 用于通知另一个进程数据已写入
- void wait(); // 用于等待另一个进程写入数据
-
- private:
- std::wstring name_;
- size_t size_;
- HANDLE hFile_;
- HANDLE hMapFile_;
- LPVOID lpBase_;
- HANDLE hEvent_;
- HANDLE hMutex_; // 新增的互斥锁
-
- void cleanup();
- void checkAndThrow(bool condition, const std::wstring& errorMessage);
- };
sharedMemoryW.cpp:
- #include "sharedMemoryW.h"
-
- // 构造函数
- SharedMemory::SharedMemory(const std::wstring& name, size_t size)
- : name_(name), size_(size), hFile_(NULL), hMapFile_(NULL), lpBase_(NULL), hEvent_(NULL), hMutex_(NULL) {}
-
- // 析构函数
- SharedMemory::~SharedMemory() {
- close();
- }
-
- // 创建文件映射对象和事件对象
- bool SharedMemory::create() {
- SECURITY_ATTRIBUTES sa;
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.bInheritHandle = FALSE;
- sa.lpSecurityDescriptor = NULL; // 可以自定义安全描述符
-
- hFile_ = CreateFileW(name_.c_str(), GENERIC_READ | GENERIC_WRITE, 0, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- checkAndThrow(hFile_ != INVALID_HANDLE_VALUE, L"Unable to create file.");
-
- hMapFile_ = CreateFileMappingW(hFile_, NULL, PAGE_READWRITE, 0, static_cast<DWORD>(size_), name_.c_str());
- checkAndThrow(hMapFile_ != NULL, L"Unable to create file mapping object.");
-
- lpBase_ = MapViewOfFile(hMapFile_, FILE_MAP_ALL_ACCESS, 0, 0, size_);
- checkAndThrow(lpBase_ != NULL, L"Unable to map view of file.");
-
- hEvent_ = CreateEventW(&sa, TRUE, FALSE, (name_ + L"_Event").c_str());
- checkAndThrow(hEvent_ != NULL, L"Unable to create event object.");
-
- hMutex_ = CreateMutexW(&sa, FALSE, (name_ + L"_Mutex").c_str());
- checkAndThrow(hMutex_ != NULL, L"Unable to create mutex object.");
-
- return true;
- }
-
- // 打开现有的文件映射对象和事件对象
- bool SharedMemory::open() {
- hMapFile_ = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, name_.c_str());
- checkAndThrow(hMapFile_ != NULL, L"Unable to open file mapping object.");
-
- lpBase_ = MapViewOfFile(hMapFile_, FILE_MAP_ALL_ACCESS, 0, 0, size_);
- checkAndThrow(lpBase_ != NULL, L"Unable to map view of file.");
-
- hEvent_ = OpenEventW(EVENT_ALL_ACCESS, FALSE, (name_ + L"_Event").c_str());
- checkAndThrow(hEvent_ != NULL, L"Unable to open event object.");
-
- hMutex_ = OpenMutexW(MUTEX_ALL_ACCESS, FALSE, (name_ + L"_Mutex").c_str());
- checkAndThrow(hMutex_ != NULL, L"Unable to open mutex object.");
-
- return true;
- }
-
- // 写入数据到映射内存
- void SharedMemory::write(const std::wstring& data) {
- WaitForSingleObject(hMutex_, INFINITE); // 加锁
- if (lpBase_ != NULL) {
- memcpy(lpBase_, data.c_str(), (data.size() + 1) * sizeof(wchar_t)); // 包括终止符
- signal(); // 通知另一个进程数据已写入
- std::wcout << L"Data written: " << data << std::endl; // 日志记录
- }
- ReleaseMutex(hMutex_); // 解锁
- }
-
- // 读取数据从映射内存
- std::wstring SharedMemory::read() {
- WaitForSingleObject(hMutex_, INFINITE); // 加锁
- std::wstring result;
- if (lpBase_ != NULL) {
- result = std::wstring(static_cast<wchar_t*>(lpBase_));
- std::wcout << L"Data read: " << result << std::endl; // 日志记录
- }
- ReleaseMutex(hMutex_); // 解锁
- return result;
- }
-
- // 关闭文件映射和事件对象
- void SharedMemory::close() {
- cleanup();
- }
-
- // 用于通知另一个进程数据已写入
- void SharedMemory::signal() {
- if (hEvent_ != NULL) {
- SetEvent(hEvent_);
- ResetEvent(hEvent_); // 重置事件
- }
- }
-
- // 用于等待另一个进程写入数据
- void SharedMemory::wait() {
- if (hEvent_ != NULL) {
- WaitForSingleObject(hEvent_, INFINITE);
- }
- }
-
- void SharedMemory::cleanup() {
- if (lpBase_ != NULL) {
- UnmapViewOfFile(lpBase_);
- lpBase_ = NULL;
- }
- if (hMapFile_ != NULL) {
- CloseHandle(hMapFile_);
- hMapFile_ = NULL;
- }
- if (hFile_ != NULL) {
- CloseHandle(hFile_);
- hFile_ = NULL;
- }
- if (hEvent_ != NULL) {
- CloseHandle(hEvent_);
- hEvent_ = NULL;
- }
- if (hMutex_ != NULL) {
- CloseHandle(hMutex_);
- hMutex_ = NULL;
- }
- }
-
- void SharedMemory::checkAndThrow(bool condition, const std::wstring& errorMessage) {
- if (!condition) {
- DWORD errorCode = GetLastError();
- throw std::runtime_error(std::string(errorMessage.begin(), errorMessage.end()) + " Error code: " + std::to_string(errorCode));
- }
- }
这样改进优化,代码似乎安全了些。。。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。