分享
 
 
 

内存文件映射用户类的修改

王朝other·作者佚名  2006-01-10
窄屏简体版  字體: |||超大  

// filemapping.h: interface for the UC_FILEMAPPING class.

//

//////////////////////////////////////////////////////////////////////

#if !defined(AFX_UC_FILEMAPPING_H__72FE31B2_7B02_442F_A754_66427E1C5946__INCLUDED_)

#define AFX_UC_FILEMAPPING_H__72FE31B2_7B02_442F_A754_66427E1C5946__INCLUDED_

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

//////////////////////////////////////////////////

// 模块: 内存映射文件用户类

// 作者: 张旻

// 创建: 2002.01.16

// 说明:

// 利用内存映射文件进行进程之间的内存共享,

// 目前的32位应用程序寻址范围4GB, 不需要高位

//////////////////////////////////////////////////

//#include "uc_log.h"

#include "windows.h"

#include <stdlib.h>

//自定义返回值

//RET_BADARG 参数非法 ret bad arg

#define RET_USER 0

#define RET_FILEOPENNED RET_USER + 1 //文件已经打开 file openned

#define RET_FILENOTOPENNED RET_USER + 2 //文件未打开 file not openned

#define RET_BUFFERTOOBIG RET_USER + 3 //缓冲区过大 buffer too big

#define RET_BUFFEROVERFLOW RET_USER + 4 //缓冲区溢出 buffer over flow

#define RET_FILEPROCESSING RET_USER + 5 //文件正在操作 file processing

#define RET_OFFSETOVERFLOW RET_USER + 6 //偏移量溢出 off set overflow

#define RET_BADARG RET_USER + 7 //参数非法 ret bad arg=未定义

#define RET_FILEERR RET_USER + 8 //文件操作失败 file err=未定义

#define RET_OK RET_USER + 9 //操作成功 ok=未定义

//共享内存的预留长度信息结构预定义

typedef struct tagMapInfo

{

DWORD dwSizeHigh; //高位文件大小

DWORD dwSizeLow; //低位文件大小

char szMappingName[_MAX_PATH]; //映射名称

int count; //用来计述有多少个文件映射对象打开了同一个文件

//tagMapInfo()

//{

// dwSizeHigh = dwSizeLow = 0;

// memset( szMappingName, 0, _MAX_PATH );

//}

} US_MAPINFO, * PUS_MAPINFO;

//分页门限

#define HIGH_MAX 0xFFFFFFFE //高位最大值 high max

#define LOW_MAX 0xFFFFFFFF - sizeof(US_MAPINFO) //低位最大值 low max

#define INFO_LEN sizeof(US_MAPINFO) //头信息长度 info len

#define NOPHYSICALFILE 0xFFFFFFFF //不需要物理文件 no physical file

class FileMapping //: public UC_LOG //uc file mapping

{

public:

DWORD GetSize();

//////////////////////////////////////////////////

// 作者: 张旻

// 创建: 2002.01.16

// 功能: 写入映射文件

// 参数:

// [in] lpBuf 缓冲区

// [in] nSize 缓冲区大小

// [in] dwOffsetLow 偏移地址地位

// 修改 [in] isAppend=TRUE 如果isAppend为TRUE直接加到映射文件的尾部,参数dwOffsetLow表示的偏移地址不起作用

// 返回:

// RET_BADARG 参数非法 ret bad arg

// RET_BUFFERTOBIG 缓存区过大 ret buffer to big

// RET_BUFFEROVERFLOW 缓冲区溢出 ret buffer overflow

// RET_FILENOTOPENNED 文件未打开 file not openned

// RET_FILEPROCESSING 文件正在操作 file processing

// RET_FILEERR 文件操作失败 file err

// RET_OK 操作成功 ok

//////////////////////////////////////////////////

DWORD Write( LPVOID lpBuf, UINT &nSize, DWORD dwOffsetLow=0, BOOL isAppend=TRUE );

//////////////////////////////////////////////////

// 作者: 张旻

// 创建: 2002.01.16

// 功能: 读取映射文件

// 参数:

// [in] lpBuf 缓冲区

// [in] nSize 缓冲区大小

// [in] dwOffsetLow 偏移地址地位

// 返回:

// RET_BADARG 参数非法

// RET_BUFFERTOBIG 缓存区过大

// RET_BUFFEROVERFLOW 缓冲区溢出

// RET_FILENOTOPENNED 文件未打开

// RET_FILEPROCESSING 文件正在操作

// RET_FILEERR 文件操作失败

// RET_OK 操作成功

//////////////////////////////////////////////////

DWORD Read( LPVOID lpszBuf, UINT &nSize, DWORD dwOffsetLow=0 );

//////////////////////////////////////////////////

// 作者: 张旻

// 创建: 2002.01.16

// 功能: 关闭映射文件

// 参数:

// [in] wantDump 需要导出

// 返回:

// RET_FILENOTOPENNED 文件未打开

// RET_FILEERR 文件操作失败

// RET_OK 操作成功

//////////////////////////////////////////////////

DWORD Close( BOOL wantDump=TRUE );

//////////////////////////////////////////////////

// 作者: 张旻

// 创建: 2002.01.16

// 功能: 打开映射文件

// 参数:

// [in] lpszMappingName 映射内存命名

// 返回:

// RET_BADARG 参数非法

// RET_FILEOPENNED 文件已经打开

// RET_FILEERR 文件操作失败

// RET_OK 操作成功

//////////////////////////////////////////////////

DWORD Open( LPCTSTR lpszMappingName );

//////////////////////////////////////////////////

// 作者: 张旻

// 创建: 2002.01.16

// 功能: 打开映射文件

// 参数:

// [in] lpszFilePath 物理文件路径

// [in] lpszMappingName 映射内存命名

// [in] dwSizeLow 低位空间大小

// 返回:

// RET_BADARG 参数非法

// RET_FILEOPENNED 文件已经打开

// RET_FILEERR 文件操作失败

// RET_OK 操作成功

//////////////////////////////////////////////////

DWORD Open( LPCTSTR lpszFilePath, LPCTSTR lpszMappingName, DWORD dwSizeLow=0 );

//////////////////////////////////////////////////

// 作者: 张旻

// 创建: 2002.01.16

// 功能: 构造函数

//////////////////////////////////////////////////

FileMapping();

//////////////////////////////////////////////////

// 作者: 张旻

// 创建: 2002.01.16

// 功能: 析构函数

//////////////////////////////////////////////////

virtual ~FileMapping();

LPVOID getlpAddress()

{

return m_lpAddress;

}

protected:

HANDLE m_hPhysicsFile; //物理文件句柄

HANDLE m_hMappingFile; //映射文件句柄

HANDLE m_hFileOP; //文件操作互斥量

HANDLE m_hMutex;

LPVOID m_lpCursor; //映射游标地址指针

LPVOID m_lpAddress; //映射文件地址指针

PUS_MAPINFO m_pusMapInfo; //映射内存头信息

BOOL m_isFileLoaded; //工作状态标志

BOOL m_isMyHandle; //是否是自己创建的文件映射

DWORD m_dwSysAlloc; //系统分配内存的最小单位

private:

int count; //用来计述有多少个文件映射对象打开了同一个文件

DWORD FlushView();

DWORD GetErrorMessage();

//////////////////////////////////////////////////

// 作者: 张旻

// 创建: 2002.01.16

// 功能: 格式化大小和偏移量

// 参数:

// [in] dwOffsetLow 低位偏移量

// 返回:

// RET_BADARG 参数非法

// RET_FILENOTOPENNED 文件未打开

// RET_FILEPROCESSING 文件正在操作

// RET_OK 操作成功

//////////////////////////////////////////////////

//////////////////////////////////////////////////

// 作者: 张旻

// 创建: 2002.01.16

// 功能: 移动映射文件指针

// 参数:

// [in] dwOffsetLow 低位偏移量

// 返回:

// RET_BADARG 参数非法

// RET_FILENOTOPENNED 文件未打开

// RET_FILEPROCESSING 文件正在操作

// RET_OK 操作成功

//////////////////////////////////////////////////

};

#endif // !defined(AFX_UC_FILEMAPPING_H__72FE31B2_7B02_442F_A754_66427E1C5946__INCLUDED_)

// filemapping.cpp: implementation of the UC_FILEMAPPING class.

//

//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include "filemapping.h"

#ifdef _DEBUG

#undef THIS_FILE

static char THIS_FILE[]=__FILE__;

//#define new DEBUG_NEW

#endif

//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////

//构造函数

FileMapping::FileMapping() //

{

m_hMutex = CreateMutex( NULL, FALSE, "map" );

//没有类似上面的指令创建互斥对象,下面指令怎么可以使用呢?

//推断在UC_FILEMAPPING的UC_LOG类中的构造函数中一定调用函数类似

//m_hMutex= CreateMutex( NULL, FALSE, szMutex );//szMutex为一互斥对象的名字

WaitForSingleObject( m_hMutex, INFINITE ); //应该是m_hFileOP吧 m_hMutex找不到定义

//初始化句柄

m_hPhysicsFile = NULL; //物理文件句柄

m_hMappingFile = NULL; //映射文件句柄

m_hFileOP = NULL; //文件操作互斥量

//初始化标志

m_isFileLoaded = FALSE; //工作状态标志

m_isMyHandle = FALSE; //是否是自己创建的文件映射

//初始化文件成员变量

m_pusMapInfo = NULL; //映射内存头信息

m_lpAddress = NULL; //映射文件地址指针

m_lpCursor = NULL; //映射游标地址指针

//得到系统的最小内存单位

SYSTEM_INFO SysInfo;

GetSystemInfo( &SysInfo );

m_dwSysAlloc = SysInfo.dwAllocationGranularity; //系统分配内存的最小单位

ReleaseMutex( m_hMutex );

}

//析构函数

FileMapping::~FileMapping()

{

m_hMutex = CreateMutex( NULL, FALSE, "map" );

WaitForSingleObject( m_hMutex, INFINITE );

//文件处理互斥操作

WaitForSingleObject( m_hFileOP, INFINITE );

//关闭映射内存头信息指针

if ( m_pusMapInfo )

delete m_pusMapInfo;

//关闭句柄

ReleaseMutex( m_hFileOP );

//只有创建者才有权关闭句柄

if ( m_isMyHandle ){

CloseHandle( m_hPhysicsFile );

CloseHandle( m_hMappingFile );

CloseHandle( m_hFileOP );

}

ReleaseMutex( m_hMutex );

}

//新建文件

//////////////////////////////////////////////////

// 作者: 张旻

// 创建: 2002.01.16

// 功能: 打开映射文件

// 参数:

// [in] lpszFilePath 物理文件路径

// [in] lpszMappingName 映射内存命名

// [in] dwSizeLow 低位空间大小

// 返回:

// RET_BADARG 参数非法

// RET_FILEOPENNED 文件已经打开

// RET_FILEERR 文件操作失败

// RET_OK 操作成功

//////////////////////////////////////////////////

DWORD FileMapping::Open(LPCTSTR lpszFilePath, LPCTSTR lpszMappingName, DWORD dwSizeLow)

{

//状态监测

if ( m_isFileLoaded )//初始值为FALSE

return RET_FILEOPENNED;

//参数监测

if ( lpszMappingName==NULL )

return RET_BADARG;

DWORD dwRet = RET_OK;

//创建文件操作互斥句柄

char szMutex[_MAX_PATH];

memset( szMutex, 0, _MAX_PATH );//字符数组中的元素全部置0

sprintf( szMutex, "%s_MUTEX", lpszMappingName );//以映射名称作为互斥对象名称,来确保在指定时刻只有

//一个线程在访问文件映射

m_hFileOP = CreateMutex( NULL, FALSE, szMutex );

WaitForSingleObject( m_hFileOP, INFINITE );

//创建对应的物理文件

if ( lpszFilePath!=NULL )

{

//新建文件

m_hPhysicsFile = CreateFile( lpszFilePath, GENERIC_READ|GENERIC_WRITE, 0, //generic

NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );

//如果文件存在, 打开现有文件,如果上面指令调用CreateFile函数的返回值为INVALID_HANDLE_VALUE说明指定的文件存在

if ( m_hPhysicsFile==INVALID_HANDLE_VALUE )

{

GetErrorMessage();

m_hPhysicsFile = CreateFile( lpszFilePath, GENERIC_READ|GENERIC_WRITE, 0,

NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );

}//参数中一个是CREATE_NEW表示新建,一个是OPEN_EXISTING表示打开一个已有的文件。

if(dwSizeLow==0 && m_hPhysicsFile!=INVALID_HANDLE_VALUE)

{

dwSizeLow=GetFileSize(m_hPhysicsFile,NULL );

}

}

if ( m_hPhysicsFile==INVALID_HANDLE_VALUE )

{

GetErrorMessage();

m_hPhysicsFile = NULL;

dwRet = RET_FILEERR;//line 271

}

else{

//创建映射文件(实际长度比申请长度多头信息的长度)

if ( dwRet==RET_OK ){

if ( m_hPhysicsFile==NULL ){

m_hMappingFile = CreateFileMapping( (HANDLE)NOPHYSICALFILE, NULL, PAGE_READWRITE,

0, dwSizeLow, lpszMappingName );

}

else{

m_hMappingFile = CreateFileMapping( m_hPhysicsFile, NULL, PAGE_READWRITE,

0, dwSizeLow + INFO_LEN, lpszMappingName );

}

if ( m_hMappingFile==NULL ){

GetErrorMessage();

CloseHandle( m_hPhysicsFile );

m_hPhysicsFile = NULL;

dwRet = RET_FILEERR;

}

else{

//获得对应的映射地址

m_lpAddress = MapViewOfFile( m_hMappingFile, FILE_MAP_ALL_ACCESS,

0, 0, 0 );

if ( m_lpAddress==NULL ){

dwRet = RET_FILEERR;

}

else{

//保存映射内存头信息

if ( m_pusMapInfo==NULL )

m_pusMapInfo =new US_MAPINFO; //US_MAPINFO

//PUS_MAPINFO m_pusMapInfo;

m_pusMapInfo->count=1;

m_pusMapInfo->dwSizeLow = dwSizeLow + INFO_LEN;//????头信息长度 info len

//上一句基本看懂了,dwSizeLow 是指映射文件的长度,INFO_LEN指映射文件对象自身信息的

//长度,加起来的长度是映射文件,在头部加了自身信息后的总长度,这些信息存放到文件映射头部

memset( m_pusMapInfo->szMappingName, 0, _MAX_PATH );

memcpy( m_pusMapInfo->szMappingName, lpszMappingName, strlen(lpszMappingName) );

memmove((LPBYTE) m_lpAddress+ INFO_LEN,(LPBYTE) m_lpAddress, dwSizeLow );

memcpy( m_lpAddress, m_pusMapInfo, INFO_LEN ); //映射文件地址指针m_lpAddress

//如果原来映射中有数据的话,是否会被覆盖。

//保存申请获得的开始地址和初始化游标信息

//这里其实真正的其实地址因为包含了头部信

//息, 为此需要移动到空白部分

m_lpAddress =m_lpCursor= (LPVOID)( (LPBYTE)m_lpAddress + INFO_LEN );

//设置打开标志信息

m_isFileLoaded = TRUE;

m_isMyHandle = TRUE;

}

}

}

}

ReleaseMutex( m_hFileOP );

if ( dwRet!=RET_OK )

CloseHandle( m_hFileOP );

return dwRet;

}

//打开一个已有命名内存映射文件

DWORD FileMapping::Open(LPCTSTR lpszMappingName)

{

//状态监测

if ( m_isFileLoaded || m_hFileOP )

return RET_FILEOPENNED;

//参数监测

if ( lpszMappingName==NULL )

return RET_BADARG;

DWORD dwRet = RET_OK;

//创建文件操作互斥句柄

char szMutex[_MAX_PATH];

memset( szMutex, 0, _MAX_PATH );

sprintf( szMutex, "%s_MUTEX", lpszMappingName );

m_hFileOP = OpenMutex( MUTEX_ALL_ACCESS, FALSE, szMutex );

if ( m_hFileOP==NULL ){

return RET_FILENOTOPENNED;

}

WaitForSingleObject( m_hFileOP, INFINITE );

//打开映射文件

m_hMappingFile = OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, lpszMappingName );

if ( m_hMappingFile==NULL ){

dwRet = RET_FILEERR;

}

else{

//获得对应的映射地址

m_lpAddress = MapViewOfFile( m_hMappingFile, FILE_MAP_ALL_ACCESS,

0, 0, 0 );

if ( m_lpAddress==NULL ){

dwRet = RET_FILEERR;

}

else{

//获得映射内存头信息

if ( m_pusMapInfo==NULL )

m_pusMapInfo = new US_MAPINFO;

memcpy( m_pusMapInfo, m_lpAddress, INFO_LEN );

m_pusMapInfo->count++; //表示打开的文件映射数增加了一。

memcpy( m_lpAddress, m_pusMapInfo, INFO_LEN ); //把增加后的信息写回到文件映射的头部

//保存地址和游标

//同创建时候的原理

m_lpAddress = m_lpCursor = (LPVOID)( (LPBYTE)m_lpAddress + INFO_LEN );

//设置打开标志信息

m_isFileLoaded = TRUE;

m_isMyHandle = TRUE;

}

}

ReleaseMutex( m_hFileOP );

return dwRet;

}

//关闭文件

DWORD FileMapping::Close(BOOL wantDump)

{

//状态监测

if ( m_isFileLoaded==FALSE ) //工作状态标志

return RET_FILENOTOPENNED;

DWORD dwRet = RET_OK;

WaitForSingleObject( m_hFileOP, INFINITE );

m_pusMapInfo->count--;

if( m_pusMapInfo->count==0 )

{

memmove((LPBYTE) m_lpAddress- INFO_LEN,(LPBYTE) m_lpAddress, m_pusMapInfo->dwSizeLow-INFO_LEN );

}

if ( wantDump )

FlushView();

delete m_pusMapInfo;

m_pusMapInfo = NULL; //映射内存头信息

m_isFileLoaded = FALSE; //工作状态标志

ReleaseMutex( m_hFileOP );

//只有创建者才有权利关闭句柄

if ( m_isMyHandle==FALSE ){ //是否是自己创建的文件映射

CloseHandle( m_hPhysicsFile );

CloseHandle( m_hMappingFile );

CloseHandle( m_hFileOP );

}

return dwRet;

}

//读取映射文件

//////////////////////////////////////////////////

// 作者: 张旻

// 创建: 2002.01.16

// 功能: 读取映射文件

// 参数:

// [in] lpBuf 缓冲区

// [in] nSize 缓冲区大小

// [in] dwOffsetLow 偏移地址地位

// 返回:

// RET_BADARG 参数非法

// RET_BUFFERTOBIG 缓存区过大

// RET_BUFFEROVERFLOW 缓冲区溢出

// RET_FILENOTOPENNED 文件未打开

// RET_FILEPROCESSING 文件正在操作

// RET_FILEERR 文件操作失败

// RET_OK 操作成功

//////////////////////////////////////////////////

DWORD FileMapping::Read(LPVOID lpBuf, UINT &nSize, DWORD dwOffsetLow )

{

//状态监测

if ( m_isFileLoaded==FALSE ) //工作状态标志

return RET_FILENOTOPENNED;

//参数监测

if ( lpBuf==NULL || nSize==0 )

return RET_BADARG;

DWORD dwRet = RET_OK;

WaitForSingleObject( m_hFileOP, INFINITE );

//计算内容是否溢出

UINT nSizeUsed = (UINT)( LPBYTE(m_lpCursor) - LPBYTE(m_lpAddress) );

if ( nSize<nSizeUsed ){

dwRet = RET_BUFFEROVERFLOW;

}

else{

//读出信息

//nSize = nSizeUsed;

memcpy( lpBuf, (LPVOID)( (LPBYTE)m_lpAddress + dwOffsetLow ), nSize );

}

ReleaseMutex( m_hFileOP );

return dwRet;

}

//写入映射文件

DWORD FileMapping::Write(LPVOID lpBuf, UINT &nSize, DWORD dwOffsetLow, BOOL isAppend )

{

//状态监测

if ( m_isFileLoaded==FALSE ) //工作状态标志

return RET_FILENOTOPENNED;

//参数监测

if ( lpBuf==NULL || nSize==0 )

return RET_BADARG;

DWORD dwRet = RET_OK;

WaitForSingleObject( m_hFileOP, INFINITE );

//计算内容是否溢出

UINT nLeftSize = (UINT)m_pusMapInfo->dwSizeLow - (UINT)( LPBYTE(m_lpCursor) - LPBYTE(m_lpAddress) )

- INFO_LEN;

if ( nLeftSize<nSize ){

dwRet = RET_BUFFEROVERFLOW;

}

else{

//根据模式移动游标

if ( isAppend==FALSE ){

m_lpCursor = (LPVOID)( (LPBYTE)m_lpAddress + dwOffsetLow );

}

//写入信息

memcpy( m_lpCursor, lpBuf, nSize );

//移动游标

if ( isAppend )

m_lpCursor = (LPVOID)( (LPBYTE)m_lpCursor + nSize );

}

ReleaseMutex( m_hFileOP );

return dwRet;

}

//获得错误信息

DWORD FileMapping::GetErrorMessage()

{

DWORD dwRet = GetLastError();

LPVOID lpMsgBuf;

FormatMessage(

FORMAT_MESSAGE_ALLOCATE_BUFFER |

FORMAT_MESSAGE_FROM_SYSTEM |

FORMAT_MESSAGE_IGNORE_INSERTS,

NULL,

dwRet,

MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language

(LPTSTR) &lpMsgBuf,

0,

NULL

);

// Process any inserts in lpMsgBuf.

// ...

// Display the string.

//MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );

//TRACE( "0x%08X: %s\n", dwRet, lpMsgBuf );

// Free the buffer.

LocalFree( lpMsgBuf );

return dwRet;

}

//得到映射文件大小

DWORD FileMapping::GetSize()

{

if ( m_isFileLoaded==FALSE )

return RET_FILENOTOPENNED;

if ( m_pusMapInfo )

return m_pusMapInfo->dwSizeLow - INFO_LEN;

else

return -1;

}

//输出内容

DWORD FileMapping::FlushView()

{

//状态监测

if ( m_isFileLoaded )

{

if ( m_lpCursor > m_lpAddress && m_hPhysicsFile )

{

SIZE_T nSize = (SIZE_T)( (LPBYTE)m_lpCursor - (LPBYTE)m_lpAddress );

if ( FlushViewOfFile( m_lpAddress, nSize ) )

return RET_OK;

else

return RET_FILEERR;

}

return RET_OK;

}

else{

return RET_FILENOTOPENNED;

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有