用到的几个windows API函数:
函数CreateFileMapping、MapViewOfFile声明如下:
WINBASEAPI
__out
HANDLE
WINAPI
CreateFileMappingA(
__in HANDLE hFile,
__in_opt LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
__in DWORD flProtect,
__in DWORD dwMaximumSizeHigh,
__in DWORD dwMaximumSizeLow,
__in_opt LPCSTR lpName
);
WINBASEAPI
__out
HANDLE
WINAPI
CreateFileMappingW(
__in HANDLE hFile,
__in_opt LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
__in DWORD flProtect,
__in DWORD dwMaximumSizeHigh,
__in DWORD dwMaximumSizeLow,
__in_opt LPCWSTR lpName
);
#ifdef UNICODE
#define CreateFileMapping CreateFileMappingW
#else
#define CreateFileMapping CreateFileMappingA
#endif // !UNICODE
WINBASEAPI
__out
LPVOID
WINAPI
MapViewOfFile(
__in HANDLE hFileMappingObject,
__in DWORD dwDesiredAccess,
__in DWORD dwFileOffsetHigh,
__in DWORD dwFileOffsetLow,
__in SIZE_T dwNumberOfBytesToMap
);
hFile是创建共享文件的句柄。
lpFileMappingAttributes是文件共享的属性。
flProtect是当文件映射时读写文件的属性。
dwMaximumSizeHigh是文件共享的大小高位字节。
dwMaximumSizeLow是文件共享的大小低位字节。
lpName是共享文件对象名称。
hFileMappingObject是共享文件对象。
dwDesiredAccess是文件共享属性。
dwFileOffsetHigh是文件共享区的偏移地址。
dwFileOffsetLow是文件共享区的偏移地址。
dwNumberOfBytesToMap是共享数据长度。
打开已经存在的命名的文件映射,函数原型如下:
HANDLE OpenFileMapping(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName);
参数:
dwDesiredAccess: 输入参数,Mapping对象的存取权限,参见CreateFileMapping函数的flProtect参数。
bInheritHandle: 输入参数,如果设置为TRUE,则可继承进程句柄,否则不能继承。一般设置为FALSE。
返回值:
返回HANDLE值,Mapping对象的句柄。如果返回NULL,则表示失败。可使用GetLastError函数获取错误信息。
取消文件映射,函数原型如下:
BOOL UnmapViewOfFile(
LPCVOID lpBaseAddress);
参数lpBaseAddress为需要取消映射的内存地址。
返回值:
返回值BOOL,表示是否成功。
/**********************************************************************************************************************************/
我们知道,在Windows中的每个进程都有自己独立的内存空间。该独立的内存空间包含了所有的可执行模块或DLL模块的代码和数据以及动态内存分配的空间。每个进程的内存空间只能被该进程访问,其他进程是不能访问的。
如果我们要想在进程间共享内存(也就是创建一块不同进程都能访问的内存),那就必须使用内核对象。因为内核对象由Windows系统内核所拥有,而不是由进程所拥有。
下面就用文件映射(File Mapping)和互斥量(Mutex)两中内核对象来实现简单的进程间内存共享。文件映射(File Mapping)用来开辟共享的内存空间,而互斥量(Mutex)则是用来使读写互斥。
在该例子里,实现了下面5个函数用来进行进程间的内存共享。可以把这5个函数放到一个DLL里面当成输出函数来用。在进程里加载该DLL并调用相应的函数就可实现进程间内存共享。
首先,定义返回值代码:
typedef
enum
{
LX_OK
=
0
,
//
正常返回
LX_SHAREDMEMORY_EXISTS
=
1
,
//
共享内存已经存在
LX_INVALID_SHAREDMEMORY
=
2
,
//
共享内存错误返回
LX_INVALID_SIZE
=
3
//
共享内存大小错误
}LX_RETURN_VALUE;
然后,是函数声明:
//
创建共享内存
LX_RETURN_VALUE CreateSharedMemory(UINT nSize);
//
释放共享内存
LX_RETURN_VALUE ReleaseSharedMemory();
//
得到共享内存大小
LX_RETURN_VALUE GetSharedMemorySize(UINT
&
nSize);
//
向共享内存写入数据
LX_RETURN_VALUE WriteToSharedMemory(
void
*
pData, UINT nSize);
//
从共享内存读取数据
LX_RETURN_VALUE ReadFromSharedMemory(
void
*
pData, UINT nSize);
下面是函数的实现:
//
自动Lock和Unlock互斥量
struct
CAutoMutex
{
CAutoMutex();
~
CAutoMutex();
//
互斥量
static
CMutex m_mutex;
};
CMutex CAutoMutex::m_mutex(FALSE,
"
StarLeeMutex
"
);
CAutoMutex::CAutoMutex()
{
m_mutex.Lock();
}
CAutoMutex::
~
CAutoMutex()
{
m_mutex.Unlock();
}
LX_RETURN_VALUE CreateSharedMemory(UINT nSize)
{
//
创建共享内存块
HANDLE hFileMapping
=
CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
0
, nSize,
"
StarLeeSharedMemory
"
);
//
创建错误
if
((hFileMapping
==
NULL)
||
(hFileMapping
==
INVALID_HANDLE_VALUE))
return
LX_INVALID_SHAREDMEMORY;
//
共享内存已经存在
if
(GetLastError()
==
ERROR_ALREADY_EXISTS)
return
LX_SHAREDMEMORY_EXISTS;
//
创建另外一块内存存放共享内存的大小
HANDLE hSize
=
CreateFileMapping(NULL, NULL, PAGE_READWRITE,
0
,
sizeof
(UINT),
"
StarLeeSharedMemorySize
"
);
if
((hSize
==
NULL)
||
(hSize
==
INVALID_HANDLE_VALUE)
||
(GetLastError()
==
ERROR_ALREADY_EXISTS))
return
LX_INVALID_SHAREDMEMORY;
//
得到存放共享内存大小的指针
UINT
*
pSize
=
(UINT
*
)MapViewOfFile(hSize, FILE_MAP_WRITE,
0
,
0
,
sizeof
(UINT));
if
(pSize
==
NULL)
return
LX_INVALID_SHAREDMEMORY;
//
写入共享内存的大小
memcpy(pSize,
&
nSize,
sizeof
(UINT));
UnmapViewOfFile(pSize);
return
LX_OK;
}
LX_RETURN_VALUE ReleaseSharedMemory()
{
CAutoMutex MutexLock;
//
打开共享内存
HANDLE hFileMapping
=
OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE,
"
StarLeeSharedMemory
"
);
//
关闭共享内存
if
(hFileMapping
!=
NULL)
CloseHandle(hFileMapping);
//
打开存放共享内存大小的文件映射
HANDLE hSize
=
OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE,
"
StarLeeSharedMemorySize
"
);
//
关闭存放共享内存大小的文件映射
if
(hSize
!=
NULL)
CloseHandle(hSize);
return
LX_OK;
}
LX_RETURN_VALUE GetSharedMemorySize(UINT
&
nSize)
{
CAutoMutex MutexLock;
HANDLE hSize
=
OpenFileMapping(FILE_MAP_READ, FALSE,
"
StarLeeSharedMemorySize
"
);
if
(hSize
==
NULL)
return
LX_INVALID_SHAREDMEMORY;
UINT
*
pSize
=
(UINT
*
)MapViewOfFile(hSize, FILE_MAP_READ,
0
,
0
,
sizeof
(UINT));
if
(pSize
==
NULL)
return
LX_INVALID_SHAREDMEMORY;
//
得到共享内存的大小
memcpy(
&
nSize, pSize,
sizeof
(UINT));
return
LX_OK;
}
LX_RETURN_VALUE WriteToSharedMemory(
void
*
pDate, UINT nSize)
{
UINT nSharedMemorySize
=
0
;
//
得到共享内存的大小
if
(GetSharedMemorySize(nSharedMemorySize)
!=
LX_OK)
return
LX_INVALID_SHAREDMEMORY;
//
检查共享内存的大小
if
(nSize
>
nSharedMemorySize)
return
LX_INVALID_SIZE;
CAutoMutex MutexLock;
HANDLE hFileMapping
=
OpenFileMapping(FILE_MAP_WRITE, FALSE,
"
StarLeeSharedMemory
"
);
if
(hFileMapping
==
NULL)
return
LX_INVALID_SHAREDMEMORY;
void
*
pMapView
=
MapViewOfFile(hFileMapping, FILE_MAP_WRITE,
0
,
0
, nSize);
if
(pMapView
==
NULL)
return
LX_INVALID_SHAREDMEMORY;
//
清空共享内存
memset(pMapView,
0
, nSharedMemorySize);
//
将数据写入共享内存
memcpy(pMapView, pDate, nSize);
UnmapViewOfFile(pMapView);
return
LX_OK;
}
LX_RETURN_VALUE ReadFromSharedMemory(
void
*
pData, UINT nSize)
{
UINT nSharedMemorySize
=
0
;
if
(GetSharedMemorySize(nSharedMemorySize)
!=
LX_OK)
return
LX_INVALID_SHAREDMEMORY;
if
(nSize
>
nSharedMemorySize)
return
LX_INVALID_SIZE;
CAutoMutex MutexLock;
HANDLE hFileMapping
=
OpenFileMapping(FILE_MAP_READ, FALSE,
"
StarLeeSharedMemory
"
);
if
(hFileMapping
==
NULL)
return
LX_INVALID_SHAREDMEMORY;
void
*
pMapView
=
MapViewOfFile(hFileMapping, FILE_MAP_READ,
0
,
0
, nSize);
if
(pMapView
==
NULL)
return
LX_INVALID_SHAREDMEMORY;
//
从共享内存读取数据
memcpy(pData, pMapView, nSize);
UnmapViewOfFile(pMapView);
return
LX_OK;
}
最后附记:栈是每个线程都有的,堆则是每个进程有的。