CE600

    技术2025-07-22  10

    #pragma once#include <iostream>#include <Imaging.h>/******************************************************************** file name :  g:/工具源码/Old/TestP4302/20110128/CE600/CE600.h author  : Clark created  : 27:1:2011   16:09 purpose  : *********************************************************************/

    //___________________ a2w: Clark 2011/01/27 ________________________class a2w{public: explicit a2w(); explicit a2w(const char* str); ~a2w(); void operator =(const char* str); operator const wchar_t*();private: wchar_t* buffer;};//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

     

    ___________________ w2a: Clark 2011/01/27 ________________________class w2a {public: explicit w2a(); explicit w2a(const wchar_t* str); ~w2a(); void operator =(const wchar_t* str); operator const char*();private: char* buffer;};~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

     

    //___________________ CutTime: Clark 2011/01/27 ________________________class CutTime{public: CutTime(); ~CutTime(); void init(); unsigned long overTime();private: HANDLE    m_hMutex;    unsigned long  m_lStartTime;};//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

     

    //___________________ ThreadEx: Clark 2011/01/27 ________________________class ThreadEx{public: ThreadEx(HANDLE& o_hCloseEvent, LPTHREAD_START_ROUTINE lpFun, LPVOID lpvThreadParam); ~ThreadEx();

    private: HANDLE    m_hEventThread;     DWORD    m_dwEventThreadID;    HANDLE    m_hEventCloseEvent;   };

    class WorkThreadEx{public: WorkThreadEx(HANDLE& o_hCloseEvent); ~WorkThreadEx(); void SetWorkFun(LPTHREAD_START_ROUTINE lpFun, LPVOID lpPar); bool IsWorking();

    private: static DWORD WINAPI  WorkThread(LPVOID i_lparam); ThreadEx*    m_pThread; LPTHREAD_START_ROUTINE m_pFun; LPVOID     m_pPar; CRITICAL_SECTION  m_csLineBusy; HANDLE     m_hCloseEvent; bool     m_bIsWorking;};//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

     

    //___________________ Clark: Clark 2011/01/27 ________________________class HINSTANCEUserEx{public: explicit HINSTANCEUserEx(); ~HINSTANCEUserEx(); BOOL Load(TCHAR *szPath); HBITMAP GetBmpResource(UINT ResID); operator const HINSTANCE();private: HINSTANCE m_hHINSTANCE;};//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

     

    //___________________ CE600: Clark 2011/01/28 ________________________std::wstring string2wstring(std::string str);std::string wstring2string(std::wstring wstr);std::string readUnicodeTxt(char *szPath);void showTaskBar(int iTaskBarStatus);BOOL getCurDirPath(TCHAR *szPath);BOOL AppExist(TCHAR tcsName[MAX_PATH]);void DoEvent(); //让当前函数中断且让系统去执行消息函数,执行完所有消息函数再回来。void KeyBoard(bool bShowKeyBoard);//BOOL RaiseSip() ;//BOOL LowerSip();void ShowExplorer(TCHAR strPath[MAX_PATH] = _T("//App"));COLORREF getRGB(const float fMin, const float fMax, const float fValue);DWORD GetDiskSpaceInfo();// 函数名: CopyDirectory// 参数1: RegularExpression 正则表达式// 参数2: SourceDirectory 源目录// 参数3: DestinationDirectory 目标目录// 参数4: logfp log文件指针// 功能: 把源目录中符合正则表达式的文件按照相同的结构复制到目标目录// 例: 要把 /Storage Card 中的所有文件复制到 /NAND FLASH 中// CopyDirectory(L"//*",L"//Storage Card",L"//NAND FLASH",logfp);void CopyDirectory(LPCTSTR RegularExpression, LPCTSTR SourceDirectory, LPCTSTR DestinationDirectory,        FILE *logfp, WORD& nfolder, WORD& nunnecessary, WORD& nFailcount, DWORD& error,       WORD& nfile, DWORD& nSize,HANDLE* pMutex);void GetIconDirectly(HICON& hIcon,LPCTSTR lpszPath, bool bIsFile);HBITMAP LoadImageFromFile(TCHAR * pFileImage);//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

     

     

     

     

    #include "StdAfx.h"#include <assert.h>#include <tchar.h>#include "CE600.h"#include <fstream>#include "AFX.h"#include "sipapi.h"//#include <shellsdk.h>//#pragma comment(lib,"aygshell.lib")

     

    //___________________ a2w: Clark 2011/01/27 ________________________a2w::a2w():buffer(NULL){}a2w::a2w( const char* str ):buffer(NULL){ *this = str; }a2w::~a2w(){ delete[] buffer; }void a2w::operator=( const char* str ){ if( NULL != buffer)  delete[] buffer; if(NULL != str) {  int n = ::MultiByteToWideChar(CP_ACP,0,str,-1,NULL,0);  buffer = new wchar_t[n+1];  memset(buffer,0,(n+1)*sizeof(wchar_t));    ::MultiByteToWideChar(CP_ACP,0,str,-1,buffer,n);  buffer[n] = 0; }}a2w::operator const wchar_t*(){ return buffer; }//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

     

     

    ___________________ w2a: Clark 2011/01/27 ________________________w2a::w2a():buffer(NULL){}w2a::w2a( const wchar_t* str ):buffer(NULL){ *this = str; }w2a::~w2a(){ delete[] buffer; }void w2a::operator=( const wchar_t* str ){ if( NULL != buffer)  delete[] buffer; if(NULL != str) {  int nLen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);  buffer = new char[nLen+1];  WideCharToMultiByte (CP_ACP, 0,str, -1,buffer , nLen, NULL,NULL); }}w2a::operator const char*(){ return buffer; }~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

     

    //___________________ CutTime: Clark 2011/01/27 ________________________CutTime::CutTime(){ TCHAR szTemp[MAX_PATH]; _stprintf(szTemp,_T("MUTEX_FOR_CUTTIME_%x"),this); m_hMutex = CreateMutex(NULL,FALSE,szTemp); init();}

    CutTime::~CutTime(){ m_lStartTime = GetTickCount(); if( WAIT_OBJECT_0 == WaitForSingleObject(m_hMutex,5000)) {  ReleaseMutex(m_hMutex); } CloseHandle(m_hMutex);}

    void CutTime::init(){ if( WAIT_OBJECT_0 == WaitForSingleObject(m_hMutex,INFINITE)) {  m_lStartTime = GetTickCount();  ReleaseMutex(m_hMutex); }}

    unsigned long CutTime::overTime(){ int iOverT = 0; if( WAIT_OBJECT_0 == WaitForSingleObject(m_hMutex,INFINITE)) {  int iCurT = GetTickCount();  iOverT = iCurT-m_lStartTime;  ReleaseMutex(m_hMutex); } return iOverT;}//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

     

    //___________________ ThreadEx: Clark 2011/01/27 ________________________ThreadEx::ThreadEx(HANDLE& o_hCloseEvent, LPTHREAD_START_ROUTINE lpFun,LPVOID lpvThreadParam){ m_hEventThread = CreateThread(NULL,0,lpFun,lpvThreadParam,0,&m_dwEventThreadID); TCHAR szEvent[MAX_PATH]; _stprintf(szEvent,_T("EventThread_%x_%0x"),m_hEventThread,m_dwEventThreadID); m_hEventCloseEvent = CreateEvent(NULL,FALSE,FALSE,szEvent); o_hCloseEvent = m_hEventCloseEvent; printf("[Start Thread] HANDLE->%x ID->%0x/n",m_hEventThread,m_dwEventThreadID);}

    ThreadEx::~ThreadEx(){ SetEvent(m_hEventCloseEvent); if( WAIT_TIMEOUT == WaitForSingleObject(m_hEventThread,3000)) {  printf("~Thread WAIT_TIMEOUT/n");  TerminateThread(m_hEventThread,0); } CloseHandle(m_hEventCloseEvent); printf("[End Thread] HANDLE->%x ID->%0x/n",m_hEventThread,m_dwEventThreadID); m_hEventThread = NULL;}

    DWORD WorkThreadEx::WorkThread(LPVOID i_lparam){ WorkThreadEx*  pWorkThreadEx = (WorkThreadEx*)i_lparam; while( TRUE) {  if( WAIT_OBJECT_0 == WaitForSingleObject(pWorkThreadEx->m_hCloseEvent,100))  {   break;  }  EnterCriticalSection(&(pWorkThreadEx->m_csLineBusy));  pWorkThreadEx->m_bIsWorking = true;  if( NULL != pWorkThreadEx->m_pFun)  {   pWorkThreadEx->m_pFun(pWorkThreadEx->m_pPar);  }  pWorkThreadEx->m_bIsWorking = false;  LeaveCriticalSection(&(pWorkThreadEx->m_csLineBusy)); } pWorkThreadEx = NULL; return 0;}

    WorkThreadEx::WorkThreadEx(HANDLE& o_hCloseEvent){ m_bIsWorking = false; InitializeCriticalSection(&m_csLineBusy); SetWorkFun(NULL,NULL); m_pThread = new ThreadEx(m_hCloseEvent,WorkThread,this);}

    WorkThreadEx::~WorkThreadEx(){ DeleteCriticalSection(&m_csLineBusy); if( NULL != m_pThread)  delete m_pThread; m_pThread = NULL;}

    void WorkThreadEx::SetWorkFun(LPTHREAD_START_ROUTINE lpFun, LPVOID lpPar){ EnterCriticalSection(&m_csLineBusy); m_pFun = lpFun; m_pPar = lpPar; LeaveCriticalSection(&m_csLineBusy);}

    bool WorkThreadEx::IsWorking(){ return m_bIsWorking;}//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

     

    //___________________ Clark: Clark 2011/01/27 ________________________HINSTANCEUserEx::HINSTANCEUserEx():m_hHINSTANCE(NULL){}HINSTANCEUserEx::~HINSTANCEUserEx(){ if( NULL != m_hHINSTANCE) {  FreeLibrary(m_hHINSTANCE);  m_hHINSTANCE = NULL; }}

    BOOL HINSTANCEUserEx::Load( TCHAR *szPath ){ if( NULL != m_hHINSTANCE) {  FreeLibrary(m_hHINSTANCE);  m_hHINSTANCE = NULL; }

     m_hHINSTANCE = LoadLibraryEx(szPath , NULL , LOAD_LIBRARY_AS_DATAFILE ); if( NULL != m_hHINSTANCE )  return TRUE; return FALSE;}

    HINSTANCEUserEx::operator const HINSTANCE(){ return m_hHINSTANCE;}

    HBITMAP HINSTANCEUserEx::GetBmpResource( UINT ResID){ if( NULL == m_hHINSTANCE) {  return NULL; } return (HBITMAP)LoadImage(m_hHINSTANCE , MAKEINTRESOURCE(ResID) , IMAGE_BITMAP , 0 , 0 , 0);//NULL indicates failure}//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

     

     

    //___________________ CE600: Clark 2011/01/28 ________________________std::wstring string2wstring(std::string str)   {    std::wstring result;    //获取缓冲区大小,并申请空间,缓冲区大小按字符计算    int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0);    TCHAR* buffer = new TCHAR[len + 1];    //多字节编码转换成宽字节编码    MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len);    buffer[len] = '/0';             //添加字符串结尾    //删除缓冲区并返回值    result.append(buffer);    delete[] buffer;    return result;   }  

    std::string wstring2string(std::wstring wstr)   {    std::string result;    //获取缓冲区大小,并申请空间,缓冲区大小事按字节计算的    int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), NULL, 0, NULL, NULL);    char* buffer = new char[len + 1];    //宽字节编码转换成多字节编码    WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer, len, NULL, NULL);    buffer[len] = '/0';    //删除缓冲区并返回值    result.append(buffer);    delete[] buffer;    return result;   }

    void showTaskBar( int iTaskBarStatus ){ //隐藏状态栏 HWND lpClassName; lpClassName = ::FindWindow(TEXT("HHTaskBar"), NULL); if(lpClassName != NULL)  ::ShowWindow(lpClassName, iTaskBarStatus);}

    BOOL getCurDirPath(TCHAR *szPath){ TCHAR szCurPath[MAX_PATH+1]; memset(szCurPath , 0 ,MAX_PATH+1); if( 0 == GetModuleFileName(NULL , szCurPath , MAX_PATH) ) {  return FALSE; } (_tcsrchr(szCurPath, _T('//')))[1] = 0; _tcscpy(szPath,szCurPath); return TRUE;}

    std::string readUnicodeTxt( char *szPath ){ std::ifstream readTxt;  readTxt.open(szPath, std::ios::binary);  size_t index = 2;  std::wstring str; if (readTxt.is_open()) {  while (!readTxt.eof())   {    readTxt.seekg(index, std::ios::beg);    wchar_t wch = '/0';   readTxt.read((char *)(&wch), 2);   str.append(1, wch);   index += 2;  } } readTxt.close(); std::string strRet = wstring2string(str); return strRet;}

    BOOL AppExist(TCHAR tcsName[MAX_PATH]){ return (::FindWindow(tcsName , NULL) != NULL);}

    void DoEvent(){ //让当前函数中断且让系统去执行消息函数,执行完所有消息函数再回来。 MSG msg; while (PeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE) )//判断是否有消息 {  TranslateMessage(&msg);  DispatchMessage(&msg); }}

    void KeyBoard( bool bShowKeyBoard ){ bShowKeyBoard ? SipShowIM(SIPF_OFF) : SipShowIM(SIPF_ON); SIPINFO SipInfo; memset(&SipInfo,0,sizeof(SipInfo)); SipInfo.cbSize=sizeof(SIPINFO); BOOL bRes = SipGetInfo(&SipInfo); if ( bRes ) {  if ( bShowKeyBoard )  {   SipInfo.fdwFlags |= SIPF_ON;  }  else  {   SipInfo.fdwFlags = SIPF_OFF;  }  bRes = SipSetInfo(&SipInfo); }}

    ////BOOL RaiseSip() //{ // BOOL fRes = FALSE; // SIPINFO si; // memset( &si, 0, sizeof( si ) ); // si.cbSize = sizeof( si ); // if( SHSipInfo( SPI_GETSIPINFO, 0, &si, 0 ) ) // { //  si.fdwFlags |= SIPF_ON; //  fRes = SHSipInfo( SPI_SETSIPINFO, 0, &si, 0 ); // } // return fRes; //} ////BOOL LowerSip()//{// BOOL fRes = FALSE;// SIPINFO si;// memset(&si,0,sizeof(si));// si.cbSize = sizeof(si);// if(SHSipInfo(SPI_GETSIPINFO,0,&si,0))// {//  si.fdwFlags &=~SIPF_ON;//  fRes = SHSipInfo(SPI_SETSIPINFO,0,&si,0);// }// return fRes;// return TRUE;//}

    void ShowExplorer( TCHAR strPath[MAX_PATH] /*= L"//App"*/ ){ PROCESS_INFORMATION  pi; if( L"" != strPath)  CreateProcess(L"Explorer.exe",strPath, NULL, NULL,FALSE, 0, NULL, NULL, NULL, &pi); else  CreateProcess(L"Explorer.exe",NULL, NULL, NULL,FALSE, 0, NULL, NULL, NULL, &pi);}

    COLORREF getRGB(const float fMin, const float fMax, const float fValue){ float fRate = (float)(fValue-fMin)/(fMax-fMin); fRate = (fRate<1)? fRate: 1; fRate = (fRate>0)? fRate: 0; int R,G,B; if( fRate >= 0.75) {  fRate -= 0.75;  R = 255;  G = 255-fRate/0.25*255;  B = 0; } else if( fRate >= 0.5) {  fRate -= 0.5;  R = fRate/0.25*255;  G = 255;  B = 0; } else if( fRate >= 0.25) {  fRate -= 0.25;  R = 0;  G = 255;  B = 255-fRate/0.25*255; } else if( fRate >= 0) {  R = 0;  G = fRate/0.25*255;  B = 255; } else {  R = 0;  G = 0;  B = 0; } return RGB(R,G,B);}

    DWORD GetDiskSpaceInfo(){ ULARGE_INTEGER nTotalBytes, nTotalFreeBytes, nTotalAvailable; if(::GetDiskFreeSpaceEx(L"//PocketMory//Vol:", &nTotalAvailable, &nTotalBytes, &nTotalFreeBytes)) {  return (int)(nTotalBytes.QuadPart/1024/1024); } return 0;}

    // 函数名: CopyDirectory// 参数1: RegularExpression 正则表达式// 参数2: SourceDirectory 源目录// 参数3: DestinationDirectory 目标目录// 参数4: logfp log文件指针// 功能: 把源目录中符合正则表达式的文件按照相同的结构复制到目标目录// 例: 要把 /Storage Card 中的所有文件复制到 /NAND FLASH 中// CopyDirectory(L"//*",L"//Storage Card",L"//NAND FLASH",logfp);void CopyDirectory(LPCTSTR RegularExpression, LPCTSTR SourceDirectory, LPCTSTR DestinationDirectory,        FILE *logfp, WORD& nfolder, WORD& nunnecessary, WORD& nFailcount, DWORD& error,       WORD& nfile, DWORD& nSize,HANDLE* pMutex){ WIN32_FIND_DATA wfd = {0}; HANDLE hFindFile = NULL; TCHAR *FileName = (TCHAR *)malloc( MAX_PATH ); wcscpy(FileName,SourceDirectory); wcscat(FileName,RegularExpression);

     SECURITY_ATTRIBUTES attribute; attribute.nLength = sizeof(attribute); attribute.lpSecurityDescriptor = NULL; attribute.bInheritHandle = FALSE; if(CreateDirectory(DestinationDirectory,&attribute)) {  if( WAIT_OBJECT_0 == WaitForSingleObject(*pMutex,INFINITE))  {   nfolder++;   ReleaseMutex(*pMutex);  } }

     hFindFile = ::FindFirstFile(FileName,&wfd); free(FileName); if(INVALID_HANDLE_VALUE!=hFindFile) {  do  {   if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)   {    if(wcscmp(wfd.cFileName,L".")&&wcscmp(wfd.cFileName,L".."))    {     TCHAR *NextSourceDirectory = (TCHAR *)malloc( MAX_PATH );     wcscpy(NextSourceDirectory,SourceDirectory);     wcscat(NextSourceDirectory,L"//");     wcscat(NextSourceDirectory,wfd.cFileName);

         TCHAR *NextDestinationDirectory = (TCHAR *)malloc( MAX_PATH );     wcscpy(NextDestinationDirectory,DestinationDirectory);     wcscat(NextDestinationDirectory,L"//");     wcscat(NextDestinationDirectory,wfd.cFileName);

         CopyDirectory(RegularExpression,NextSourceDirectory,NextDestinationDirectory,logfp,      nfolder,nunnecessary,nFailcount,error,nfile,nSize, pMutex);

         free(NextSourceDirectory);     free(NextDestinationDirectory);    }   }   else   {    TCHAR *SourceFile = (TCHAR *)malloc( MAX_PATH );    wcscpy(SourceFile,SourceDirectory);    wcscat(SourceFile,L"//");    wcscat(SourceFile,wfd.cFileName);

        TCHAR *DestinationFile = (TCHAR *)malloc( MAX_PATH );    wcscpy(DestinationFile,DestinationDirectory);    wcscat(DestinationFile,L"//");    wcscat(DestinationFile,wfd.cFileName);

        if( 0)    {     FILETIME lpCreationTime,lpLastAccessTime,lpLastWriteTime;     HANDLE hFile = CreateFile(DestinationFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);     if(hFile!=INVALID_HANDLE_VALUE)     {      if(GetFileTime(hFile, &lpCreationTime, &lpLastAccessTime, &lpLastWriteTime))      {       CloseHandle(hFile);       if(lpLastWriteTime.dwHighDateTime==wfd.ftLastWriteTime.dwHighDateTime&&lpLastWriteTime.dwLowDateTime==wfd.ftLastWriteTime.dwLowDateTime)       {        if( WAIT_OBJECT_0 == WaitForSingleObject(*pMutex,INFINITE))        {         nunnecessary++;         ReleaseMutex(*pMutex);        }        wcscat(DestinationFile,L" is unnecessary/r/n");        if(logfp != NULL)         _ftprintf(logfp, _T("%s"), DestinationFile);        continue;       }      }      CloseHandle(hFile);     }    }    else    {     DeleteFile(DestinationFile);    }

        if(!CopyFile(SourceFile,DestinationFile,0))    {     if( WAIT_OBJECT_0 == WaitForSingleObject(*pMutex,INFINITE))     {      nFailcount ++;      if(!error) error = GetLastError();      ReleaseMutex(*pMutex);     }

         wcscat(DestinationFile,L" Copy Fail/r/n");     if(logfp != NULL)      _ftprintf(logfp, _T("%s"), DestinationFile);    }    else    {     if( WAIT_OBJECT_0 == WaitForSingleObject(*pMutex,INFINITE))     {      nfile++;      nSize+=wfd.nFileSizeLow;      ReleaseMutex(*pMutex);     }

         wcscat(DestinationFile,L" Copy OK/r/n");     if(logfp != NULL)      _ftprintf(logfp, _T("%s"), DestinationFile);    }    free(SourceFile);    free(DestinationFile);   }  }while(::FindNextFile(hFindFile,&wfd));  ::FindClose(hFindFile); }}

    void GetIconDirectly(HICON& hIcon,LPCTSTR lpszPath, bool bIsFile){ SHFILEINFO sfi; memset( &sfi, 0, sizeof(sfi) );

     DWORD dwType = FILE_ATTRIBUTE_NORMAL; if ( !bIsFile ) {  // 文件夹类型单独使用  dwType = FILE_ATTRIBUTE_DIRECTORY; }

     //SHGetFileInfo(lpszPath, dwType, &sfi, sizeof(sfi), //    SHGFI_SMALLICON | SHGFI_ICON | SHGFI_USEFILEATTRIBUTES ); SHGetFileInfo(lpszPath, dwType, &sfi, sizeof(sfi),  SHGFI_ICON | SHGFI_ICON | SHGFI_USEFILEATTRIBUTES );

     hIcon = sfi.hIcon;

     //#if 0 //直接提取图标 //ExtractIconEx(lpszPath, 0, &hMaxIcon, &hMinIcon, 1); //#endif}

    HBITMAP LoadImageFromFile(TCHAR * pFileImage){ return SHLoadDIBitmap(pFileImage);}//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    最新回复(0)