花差花差

像写情书一样写代码

费照东ID:fzd999
163956次访问,排名442好友3人,关注者28
物格而后知致,知致而后身修~
fzd999的文章
原创 46 篇
翻译 0 篇
转载 0 篇
评论 767 篇
花差花差的公告

这里全部是我的原创,一点一滴积累下来的文字。
闲时,总喜欢把玩自己写的小玩艺,细细读网友的评论,然后再看一遍。
如果你是我的朋友,很开心你能来这里做客,如果你是匆匆过客,也希望小坐一会儿,留下几字评论。

最近评论
gongmingwind:思考中!
carren1218:很伤感。。。
fzd999:楼上是???
nkckk:这么就走了?你好像还拿着我的一个录音机呢
wxrs:离开南京?去上海?
文章分类
收藏
    相册
    值得纪念的一切
    我的朋友们
    ee——左边风景
    团团的饭团
    大东——东大传说
    大雨仔
    我们的婉如同学
    我心如水
    流风轩主——颜鹏
    默默——心绪缥缈
    友情链接
    Dicky'Blog
    sugi的暗黑木屋
    南京程序员之家
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 一个完整的共享內存类收藏

    新一篇: 剑宗和气宗 | 旧一篇: 城市精神——我经历过的六座城市

    /******************************************************************
     ++  File Name :   FFMClass.h
     ++  Description: 共享內存類
     ---------------------------------------------------------------
     ++  Author:  Fei ZhaoDong
     ++  Create time: 2004/3/25 上午 10:00:00
     ++  Version:     1.1
     ++  Modifier:  
     ++  Activities:   
     ++  Update List: 2004/3/30 下午 02:59:45
    *******************************************************************/

    // FFMClass.h: interface for the CFFMClass.
    //
    //////////////////////////////////////////////////////////////////////

    #ifndef FZD_FFMCLASS_H
    #define FZD_FFMCLASS_H

    #include <aclapi.h>

    //////////////////////////////////////////////////////////////////////
    // Macro definition

    // 以下為共享內存定義

    #define DEFAULT_FILENAME NULL    // 默認的文件名
    #define DEFAULT_MAPNAME  "_FZD_MAP_"   // 默認的共享內存名
    #define DEFAULT_MAPSIZE  (0xFFFF + 1)  // 默認的共享內存大小

    const DWORD NETRGUSER_CFM_CODE = 0x1211DBFF; // 校驗碼, 用於命令數據
    const DWORD NETRGUSER_CMD_NONE = 0;   // 初始化指令碼, 無指令

    // 以下為錯誤碼定義

    #define ERROR_LEN    256    // 錯誤描述長度

    #define ERROR_INVALID_CMDCODE 0xE00001FF  // 已經存在完全一樣的共享內存
    #define ERROR_NO_MAPFILE             0xE00002FF  // 未分配共享內存文件
    #define ERROR_INVALID_CFMCODE 0xE00003FF  // 校驗碼不匹配

    //////////////////////////////////////////////////////////////////////
    // 內存文件格式定義

    #pragma pack(1)

    // 用於存儲命令數據的內存文件格式
    typedef struct _tagDATA_HEADER
    {
     DWORD dwConfirmCode; // 校驗碼
     DWORD nCommandCode;  // 指令識別碼
     DWORD dwDataSize;  // 數據的大小

     BYTE  dwReserved[19]; // 保留
     BYTE  bInfo[1];   // 數據起始地址

     _tagDATA_HEADER()
     {
      dwConfirmCode = NETRGUSER_CFM_CODE;
      nCommandCode = NETRGUSER_CMD_NONE;
      dwDataSize = 0;

      ZeroMemory(dwReserved, 19);
      ZeroMemory(bInfo, 1);
     }
    }DATA_HEADER, *LPDATA_HEADER;

    typedef DWORD (WINAPI *PSetEntriesInAcl)(ULONG, PEXPLICIT_ACCESS, PACL, PACL*);

    // 用於存儲應答數據的共享內存文件格式 (暫不用)
    typedef struct _tagANS_HEADER
    {
    }ANS_HEADER, *LPANS_HEADER;

    #pragma pack()

    //////////////////////////////////////////////////////////////////////
    // 類定義,共享內存服務端
    class CFFMServer 
    {
    public:
     CFFMServer();
     virtual ~CFFMServer();
     CFFMServer(char *szFileName, char *szMapName, DWORD dwSize);

    protected:
     PSetEntriesInAcl m_fnpSetEntriesInAcl;
     HANDLE m_hFile;   // 映射文件句柄
     HANDLE m_hFileMap;   // 內存文件句柄
     LPVOID m_lpFileMapBuffer; // 緩衝區指針

     char *m_pFileName;  // 映射文件名
     char *m_pMapName;  // 內存文件名
     DWORD m_dwSize;   // 緩衝區大小

     BOOL m_bCreateFlag;  // 是否已創建共享內存
     DWORD   m_dwLastError;  // 錯誤代碼

    private:
     void _Init();    // 初始化參數
     BOOL _IsWinNTLater();  // 判斷當前操作系統

    public:
     BOOL Create(char *szFileName = DEFAULT_FILENAME,
      char *szMapName = DEFAULT_MAPNAME,
      DWORD dwSize = DEFAULT_MAPSIZE); // 新建共享內存
     LPVOID GetBuffer();      // 獲取內存文件指針
     DWORD GetSize();      // 獲取內存文件大小
     void Destory();       // 銷毀已有的共享內存

     BOOL WriteCmdData(      // 寫入命令數據
      DWORD nCommandCode,
      DWORD dwDataSize,
      const LPVOID pBuf);
    };

    //////////////////////////////////////////////////////////////////////
    // 類定義,共享內存客戶端
    class CFFMClient 
    {
    public:
     CFFMClient();
     virtual ~CFFMClient();
     CFFMClient(DWORD dwAccess, char *szMapName, DWORD dwSize);
     
    protected:
     HANDLE m_hFileMap;   // 內存文件句柄
     LPVOID m_lpFileMapBuffer; // 內存文件指針
     char *m_pMapName;  // 內存文件名

     BOOL m_bOpenFlag;  // 是否已經打開了一個內存文件
     DWORD   m_dwLastError;  // 錯誤代碼
     
    private:
     void _Init();    // 初始化參數
     
    public:
     BOOL Open(DWORD dwAccess = FILE_MAP_READ,
      char *szMapName = DEFAULT_MAPNAME,
      DWORD dwSize = 0);      // 打開一個內存文件
     LPVOID GetBuffer();       // 獲取當前內存文件的指針
     void Destory();        // 關閉當前對內存文件的訪問

     BOOL GetCmdDataSize(DWORD *pDataSize);  // 讀取命令數據大小
     BOOL ReadCmdData(       // 讀取命令數據
      DWORD dwCommandCode,
      DWORD dwBufSize,
      LPVOID pOutBuf);
    };

    #endif // FZD_FFMCLASS_H

    /******************************************************************
     ++  File Name : FFMClass.cpp
     ++  Description: 共享內存類
     ---------------------------------------------------------------
     ++  Author:  Fei ZhaoDong
     ++  Create time: 2004/3/25 上午 10:00:00
     ++  Version:     1.0
     ++  Modifier:  
     ++   Activities:   
     ++  Update List: 2004/3/29 下午 02:59:45
    *******************************************************************/

    // FFMClass.cpp: implementation of the CFFMClass.
    //
    //////////////////////////////////////////////////////////////////////

    #include "stdafx.h"
    #include "FFMClass.h"
    #include <aclapi.h>

    //////////////////////////////////////////////////////////////////////
    // CFFMServer
    //////////////////////////////////////////////////////////////////////

    CFFMServer::CFFMServer()
    {
     m_dwLastError = 0;
     m_fnpSetEntriesInAcl = NULL;
     _Init();
    }

    CFFMServer::~CFFMServer()
    {
     Destory();
    }

    CFFMServer::CFFMServer(char *szFileName, char *szMapName, DWORD dwSize)
    {
     // 以自定義設置創建共享內存塊
     _Init();
     Create(szFileName, szMapName, dwSize);
    }

    // 初始化各個參數
    void CFFMServer::_Init()
    {
     m_hFile = NULL;
     m_hFileMap = NULL;
     m_lpFileMapBuffer = NULL;

     m_pFileName = NULL;
     m_pMapName = NULL;
     m_dwSize = 0;

     m_bCreateFlag = FALSE;
    }

    // 判斷是否NT4.0以上操作系統
    BOOL CFFMServer::_IsWinNTLater()
    {
     OSVERSIONINFO Ver;
     BOOL bAbleVersion = FALSE;
     Ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
     
     if (GetVersionEx(&Ver))
     {
      if (Ver.dwPlatformId == VER_PLATFORM_WIN32_NT
       && Ver.dwMajorVersion >= 4)
      {
       bAbleVersion = TRUE;
      }
     }
     else
     {
      m_dwLastError = GetLastError();
     }

     return bAbleVersion;
    }

    // 釋放當前共享內存,並重新初始化參數
    void CFFMServer::Destory()
    {
     if (m_lpFileMapBuffer != NULL)
     {
      UnmapViewOfFile(m_lpFileMapBuffer);
      m_lpFileMapBuffer = NULL;
     }
     
     if (m_hFileMap != NULL)
     {
      CloseHandle(m_hFileMap);
      m_hFileMap = NULL;
     }
     
     if (m_hFile && m_hFile != INVALID_HANDLE_VALUE)
     {
      CloseHandle(m_hFile);
      m_hFile = NULL;
     }

     if (m_pFileName != NULL)
     {
      free(m_pFileName);
      m_pFileName = NULL;
     }

     if (m_pMapName != NULL)
     {
      free(m_pMapName);
      m_pMapName = NULL;
     }

     _Init();
    }


    // 創建共享內存塊
    BOOL CFFMServer::Create(char *szFileName, char *szMapName, DWORD dwSize)
    {
     // 釋放已有的共享內存塊
     if (m_bCreateFlag)
     {
      Destory();
     }

     // 拷貝各個參數
     if (szFileName)
     {
      m_pFileName = _strdup(szFileName);
     }

     if (szMapName)
     {
      m_pMapName = _strdup(szMapName);
     }
     else
     {
      m_pMapName = _strdup(DEFAULT_MAPNAME);
     }

     if (dwSize > 0)
     {
      m_dwSize = dwSize;
     }
     else
     {
      m_dwSize = DEFAULT_MAPSIZE;
     }

     // 以下創建共享內存
     if (m_pFileName)
     {
      m_hFile = CreateFile(
       m_pFileName,
       GENERIC_READ|GENERIC_WRITE,
       FILE_SHARE_READ|FILE_SHARE_WRITE,
       NULL,
       OPEN_ALWAYS,
       FILE_ATTRIBUTE_NORMAL,
       NULL
       );
     }
     else
     {
      // 默認情況下,在頁面文件中創建共享內存
      m_hFile = INVALID_HANDLE_VALUE;
     }
     
     if (_IsWinNTLater())
     {
      // Set DACL

      const int NUM_ACES = 2;   // number if ACEs int DACL
              // evryone -- read
              // creator -- full access
      
      // 初始化參數
      PSID pEveryoneSID        = NULL; // everyone群組SID
      PSID pCreatorSID   = NULL; // creator群組SID
      PACL pFileMapACL         = NULL; // 準備新內存文件的DACL
      PSECURITY_DESCRIPTOR pSD = NULL; // 內存文件的SD
      SECURITY_ATTRIBUTES   saFileMap; // 內存文件的SA
      EXPLICIT_ACCESS    ea[NUM_ACES]; // 外部訪問結構 

      BOOL bHasErr   = FALSE; // 返回值
      
      // 以下創建SID
      SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
      SID_IDENTIFIER_AUTHORITY SIDAuthCreator = SECURITY_CREATOR_SID_AUTHORITY;
      
      // Evryone
      if (!AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID,
       0, 0, 0, 0, 0, 0, 0, &pEveryoneSID))
      {
       bHasErr = TRUE;
       goto Finish;
      }
      
      // Creator
      if (!AllocateAndInitializeSid(&SIDAuthCreator, 1, SECURITY_CREATOR_OWNER_RID,
       0, 0, 0, 0, 0, 0, 0, &pCreatorSID))
      {
       bHasErr = TRUE;
       goto Finish;
      }
      
      // 填充ACE
      ZeroMemory(&ea, NUM_ACES * sizeof(EXPLICIT_ACCESS));
      
      // S-1-1-0 evryone, 唯讀權限
      ea[0].grfAccessPermissions = GENERIC_READ | GENERIC_WRITE;
      ea[0].grfAccessMode = SET_ACCESS;
      ea[0].grfInheritance= NO_INHERITANCE;
      ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
      ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
      ea[0].Trustee.ptstrName  = (LPTSTR) pEveryoneSID;
      
      // S-1-3-0 creator owner, 完全權限
      ea[1].grfAccessPermissions = STANDARD_RIGHTS_ALL;
      ea[1].grfAccessMode = SET_ACCESS;
      ea[1].grfInheritance= NO_INHERITANCE;
      ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
      ea[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
      ea[1].Trustee.ptstrName  = (LPTSTR) pCreatorSID;
      
      // 創建並填充ACL
      if(NULL == m_fnpSetEntriesInAcl)
      {
       HINSTANCE hLib = ::LoadLibrary("Advapi32.dll");
       if(NULL != hLib)
       {
        m_fnpSetEntriesInAcl = (PSetEntriesInAcl)GetProcAddress(hLib,"SetEntriesInAclA");
        ::FreeLibrary(hLib);
        hLib = NULL;
       }

      }
      if (ERROR_SUCCESS != m_fnpSetEntriesInAcl(NUM_ACES, ea, NULL, &pFileMapACL))
      {
       bHasErr = TRUE;
       goto Finish;
      }
      
      // 創建並初始化SD
      pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
      if (NULL == pSD)
      {
       bHasErr = TRUE;
       goto Finish;
      }
      if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
      {
       bHasErr = TRUE;
       goto Finish;
      }
      
      // 添加ACL到SD中去
      if (!SetSecurityDescriptorDacl(pSD,
       TRUE,     // fDaclPresent flag  
       pFileMapACL,
       FALSE))   // not a default DACL
      {
       bHasErr = TRUE;
       goto Finish;
      }
      
      // 設置SA
      saFileMap.nLength = sizeof(SECURITY_ATTRIBUTES);
      saFileMap.bInheritHandle = FALSE;
      saFileMap.lpSecurityDescriptor = pSD;
      
      // 創建共享內存文件
      if (m_hFile != NULL)
      {
       m_hFileMap = CreateFileMapping(
        m_hFile,
        &saFileMap,
        PAGE_READWRITE,
        0,
        m_dwSize,
        m_pMapName);
       if (NULL == m_hFileMap)
       {
        m_hFileMap = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE,
         TRUE, m_pMapName);
        if (NULL == m_hFileMap)
        {
         m_dwLastError = GetLastError(); 
         Destory();
         goto Finish;
        }
       }
      }
      
    Finish:
      if (pSD != NULL)
      {
       LocalFree(pSD);
      }
      if (pFileMapACL != NULL)
      {
       LocalFree(pFileMapACL);
      }
      if (pEveryoneSID != NULL)
      {
       FreeSid(pEveryoneSID);
      }
      if (pCreatorSID != NULL)
      {
       FreeSid(pCreatorSID);
      }

      if (bHasErr) 
      {
       m_dwLastError = GetLastError();
       return FALSE;
      }
     }
     else
     {
      // 創建共享內存文件
      if (m_hFile)
      {
       m_hFileMap = CreateFileMapping(
        m_hFile,
        NULL,
        PAGE_READWRITE,
        0,
        m_dwSize,
        m_pMapName);
       if (NULL == m_hFileMap)
       {
        m_dwLastError = GetLastError();
        Destory();
        return FALSE;
       }
      }
     }

     // 映射文件指針到用戶
     if (m_hFileMap)
     {
      m_lpFileMapBuffer = MapViewOfFile(
       m_hFileMap,
       FILE_MAP_ALL_ACCESS,
       0,
       0,
       m_dwSize);
      if (NULL == m_lpFileMapBuffer)
      {
       m_dwLastError = GetLastError();
       Destory();
       return FALSE;
      }
     }

     m_bCreateFlag = TRUE;
     return TRUE;
    }

    // 獲取內存文件指針
    LPVOID CFFMServer::GetBuffer()
    {
     return (m_lpFileMapBuffer)?(m_lpFileMapBuffer):(NULL);
    }

    // 獲取內存文件大小
    DWORD CFFMServer::GetSize()
    {
     return m_dwSize;
    }

    BOOL CFFMServer::WriteCmdData(DWORD nCommandCode, DWORD dwDataSize, const LPVOID pBuf)
    {
     // 檢驗數據的合理性
     if (NULL == GetBuffer())
     {
      m_dwLastError = ERROR_NO_MAPFILE;
      SetLastError(ERROR_NO_MAPFILE);
      return FALSE;
     }
     if (NETRGUSER_CMD_NONE == nCommandCode)
     {
      m_dwLastError = ERROR_INVALID_CMDCODE;
      SetLastError(ERROR_INVALID_CMDCODE);
      return FALSE;
     }
     if (dwDataSize > 0 && pBuf == NULL)
     {
      m_dwLastError = ERROR_INVALID_USER_BUFFER;
      SetLastError(ERROR_INVALID_USER_BUFFER);
      return FALSE;
     }
     if (dwDataSize + sizeof(DATA_HEADER) > GetSize())
     {
      m_dwLastError = ERROR_BUFFER_OVERFLOW;
      SetLastError(ERROR_BUFFER_OVERFLOW);
      return FALSE;
     }

     // 填寫數據結構

     // 文件頭
     DATA_HEADER dataHeader;
     dataHeader.nCommandCode = nCommandCode;
     dataHeader.dwDataSize = dwDataSize;
     ZeroMemory(GetBuffer(), GetSize());
     memcpy(GetBuffer(), &dataHeader, sizeof(DATA_HEADER));

     // 數據塊
     LPDATA_HEADER pData = (LPDATA_HEADER)GetBuffer();
     memcpy(pData->bInfo, pBuf, dwDataSize);

     return TRUE;
    }

    //////////////////////////////////////////////////////////////////////
    // CFFMClient
    //////////////////////////////////////////////////////////////////////

    CFFMClient::CFFMClient()
    {
     m_dwLastError = 0;
     _Init();
    }

    CFFMClient::~CFFMClient()
    {
     Destory();
    }

    CFFMClient::CFFMClient(DWORD dwAccess, char *szMapName, DWORD dwSize)
    {
     _Init();

     if (!Open(dwAccess, szMapName, dwSize))
     {
      Destory();
     }
    }

    // 初始化參數
    void CFFMClient::_Init()
    {
     m_hFileMap = NULL;
     m_lpFileMapBuffer = NULL;

     m_pMapName = NULL;

     m_bOpenFlag = FALSE;
    }

    // 關閉當前對內存文件的訪問
    void CFFMClient::Destory()
    {
     if (m_lpFileMapBuffer)
     {
      UnmapViewOfFile(m_lpFileMapBuffer);
      m_lpFileMapBuffer = NULL;
     }
     
     if (m_hFileMap)
     {
      CloseHandle(m_hFileMap);
      m_hFileMap = NULL;
     }

     if (m_pMapName)
     {
      free(m_pMapName);
      m_pMapName = NULL;
     }

     _Init();
    }

    // 打開一個內存文件
    BOOL CFFMClient::Open(DWORD dwAccess, char *szMapName, DWORD dwSize)
    {
     if (m_bOpenFlag)
     {
      Destory();
     }
     
     if (szMapName != NULL)
     {
      m_pMapName = _strdup(szMapName);
     }
     else
     {
      m_pMapName = _strdup(DEFAULT_MAPNAME);
     }
     
     m_hFileMap = OpenFileMapping(dwAccess, TRUE, m_pMapName);
     if (NULL == m_hFileMap)
     {
      m_dwLastError = GetLastError();

      Destory();
      return FALSE;
     }
     
     m_lpFileMapBuffer = MapViewOfFile(m_hFileMap, dwAccess, 0, 0, dwSize);
     if (NULL == m_lpFileMapBuffer)
     {
      m_dwLastError = GetLastError();

      Destory();
      return FALSE;
     }

     m_bOpenFlag = TRUE;
     return TRUE;
    }

    // 獲取當前內存文件的指針
    LPVOID CFFMClient::GetBuffer()
    {
     return (m_lpFileMapBuffer)?(m_lpFileMapBuffer):(NULL);
    }

    // 讀取命令數據大小
    BOOL CFFMClient::GetCmdDataSize(DWORD *pDataSize)
    {
     ASSERT(pDataSize != NULL);
     *pDataSize = 0;

     LPDATA_HEADER pHeader = (LPDATA_HEADER)GetBuffer();
     if (NULL == pHeader)
     {
      m_dwLastError = ERROR_NO_MAPFILE;
      SetLastError(ERROR_NO_MAPFILE);
      return FALSE;
     }
     if (NETRGUSER_CFM_CODE != pHeader->dwConfirmCode)
     {
      m_dwLastError = ERROR_INVALID_CFMCODE;
      SetLastError(ERROR_INVALID_CFMCODE);
      return FALSE;
     }
     if (NETRGUSER_CMD_NONE == pHeader->nCommandCode)
     {
      m_dwLastError = ERROR_INVALID_CMDCODE;
      SetLastError(ERROR_INVALID_CMDCODE);
      return FALSE;
     }

     *pDataSize = pHeader->dwDataSize;
     return TRUE;
    }

    // 讀取命令數據
    BOOL CFFMClient::ReadCmdData(DWORD dwCommandCode, DWORD dwBufSize, LPVOID pOutBuf)
    {
     ASSERT (pOutBuf != NULL);

     LPDATA_HEADER pHeader = (LPDATA_HEADER)GetBuffer();
     if (NULL == pHeader)
     {
      m_dwLastError = ERROR_NO_MAPFILE;
      SetLastError(ERROR_NO_MAPFILE);
      return FALSE;
     }
     if (NETRGUSER_CFM_CODE != pHeader->dwConfirmCode)
     {
      m_dwLastError = ERROR_INVALID_CFMCODE;
      SetLastError(ERROR_INVALID_CFMCODE);
      return FALSE;
     }
     if (NETRGUSER_CMD_NONE == pHeader->nCommandCode)
     {
      m_dwLastError = ERROR_INVALID_CMDCODE;
      SetLastError(ERROR_INVALID_CMDCODE);
      return FALSE;
     }
     if (pHeader->dwDataSize > dwBufSize)
     {
      m_dwLastError = ERROR_BUFFER_OVERFLOW;
      SetLastError(ERROR_BUFFER_OVERFLOW);
      return FALSE;
     }
     if (pHeader->nCommandCode != dwCommandCode)
     {
      m_dwLastError = ERROR_INVALID_CMDCODE;
      SetLastError(ERROR_INVALID_CMDCODE);
      return FALSE;
     }

     ZeroMemory(pOutBuf, dwBufSize);

     // 拷貝數據到緩衝區
     memcpy(pOutBuf, pHeader->bInfo, pHeader->dwDataSize);
     return TRUE;
    }

    发表于 @ 2004年10月19日 17:38:00|评论(loading...)|编辑

    新一篇: 剑宗和气宗 | 旧一篇: 城市精神——我经历过的六座城市

    评论

    #DoCoMo 发表于2004-10-21 07:58:00  IP: 219.166.161.*
    厉害,佩服
    #Nick 发表于2004-11-18 17:58:00  IP: 218.62.24.*
    很不错,谢谢
    #fiveinone 发表于2004-11-29 03:09:00  IP: 222.95.54.*
    谢谢了!
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © 花差花差