Fork me on GitHub

MFC学习笔记

获取窗口句柄

  • FindWindow                根据窗口名获取
  • GetSafehWnd                取你程序所在窗口类的句柄
  • GetActiveWindow          取当前活动窗口句柄
  • AfxGetMainWnd            取主窗口句柄
  • GetForegroundWindow   取前台窗口句柄

窗口对象和CWnd对象,Attach和Detach函数

  CWnd对象实际上并没有把整个Windows对象都包装在其中,它只是有一个窗口句柄。(在MSDN上查看CWnd类的成员变量,确实只有一个HWND hWnd,成员函数有Attach()和Dettach()、Create()等)。这个窗口句柄如果指向一个实际存在的窗口对象,那么这个CWnd对象就是有效的;否则是空的。

  如果你还不明白,请回忆一下,当我们使用MFC创建一个窗口时,是分两步进行的:

  1. new一个CWnd对象,但其中的HWND还是非法的,因为对应的窗口对象还没有被创建出来;
  2. 调用CWnd的成员函数Create创建真正的窗口对象,同时,把先前创建的MFC的CWnd对象的HWND成员指向该窗口,这样才算创建完毕一个窗口。

  而如果你是用SDK方式,那么只要创建一个WNDCLASS结构,然后调用Create或者CreateEx就创建了一 个窗口。

  让一个有效窗口句柄和一个CWnd对象关联起来用Attach:就是让一个CWnd对象的HWND成员等于这个窗口句柄;Attach,通俗地说,就是切断一个CWnd对象和一个有效窗口的脐带。因为CWnd是C++的对象,C++的对象有一个生存期的概念,脱离了该对象的作用域,这个对象就要被销毁,但是窗口对象没有这个特点,当销毁 CWnd对象的时候,我们不一定希望WNDCLASS一起被销毁,那么在此之前,我们就先要把这个“脐带”剪断,以免“城门失火,殃及池鱼”。

不要在子线程中操作MFC控件  

  不要在线程函数体内操作MFC控件,因为每个线程都有自己的线程模块状态映射表,在一个线程中操作另一个线程中创建的MFC对象,会带来意想不到的问题。更不要在线程函数里,直接调用UpdataData()函数更新用户界面,这会导致程序直接crash。而应该通过发送消息给主线程的方式,在主线程的消息响应函数里操作控件

类之间的相互访问

  MFC中一个类要访问另外一个类的的对象的成员变量值,就需要获得原来那个类对象的指针,其实有好几种方法都可以实现。比如维护一个单例模式、设置静态变量等等。这里举个例子,实现多个类之间的相互访问。

(1)创建一个MFC对话框应用程序,命名为Visit工程,对话框本身有一个主界面(CVisitDlg对话框),我们再添加一个新界面CXXXDlg。

(2)在主界面CVisitDlg类的头文件中,添加一个static CVisitDlg *s_pDialog;指针。由于这个指针式静态的,需要在类外初始化,那么在CVisitDlg .cpp文件中,写上一行初始化代码,直接初始化为空,如下:

CVisitDlg *CVisitDlg::s_pDialog = NULL; //注意要写在类外,不要写在类实现函数里面

(3)然后需要在CVisitDlg主对话框生成的时候,给这个指针赋值为主对话框指针,在CVisitDlg 类的构造函数或者OnInitDialog()函数里面写上如下一句代码:

s_pDialog = this;

  现在只要在其他的类里面获得这个静态指针,就可以访问这个类里面的所有数据了。

(4)获得静态指针,如果在CXXXDlg类中访问CVisitDlg类的数据,如下代码即可实现:

CVisitDlg *pDia = CVisitDlg::s_pDialog 

注意: 

  初始化是赋一个初始值,而定义是分配内存。

  静态成员变量在类中仅仅是声明,没有定义,所以要在类的外面定义,实际上是给静态成员变量分配内存

  对于类来说,new一个类对象不仅会分配内存,同时会调用构造函数进行初始化,所以类对象的定义和初始化总是关联在一起。

解决MFC启动时隐藏的闪烁问题

(1)VC++ 6.0开发的单文档程序

  在BOOL CXXXXApp::InitInstance()方法中添加如下代码:

m_nCmdShow = SW_HIDE;

if (!ProcessShellCommand(cmdInfo))
    return FALSE;

  即在"if (!ProcessShellCommand(cmdInfo))”在这一句的上方加一句代码"m_nCmdShow = SW_HIDE;"即可

 (2)VC2010开发的单文档程序

  • 在InitInstance函数中ParseCommandLine(cmdInfo)语句之后添加语句m_bLoadWindowPlacement=FALSE
  • 在InitInstance函数中m_pMainWnd->ShowWindow(SW_SHOW)语句中的SW_SHOW改为SW_HIDE
  • 在mainframe中还要实现虚函数ActivateFrame,把参数m_nCmdShow置为SW_HIDE;

设置透明窗体

//透明窗体
SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0X80000);
HINSTANCE hInst = LoadLibrary("User32.DLL");
if(hInst)
{
    typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);
    MYFUNC fun = NULL;
    //取得SetLayeredWindowAttributes函数指针
    fun=(MYFUNC)GetProcAddress(hInst,"SetLayeredWindowAttributes");
    if(fun)
        fun(this->GetSafeHwnd(),0,128,2);
    FreeLibrary(hInst);
}

GetDeviceCaps获取与修改显示器属性

int pixelxperinch = dc.GetDeviceCaps(LOGPIXELSX);//每英寸水平逻辑像素数

int pixelyperinch = dc.GetDeviceCaps(LOGPIXELSY);//每英寸垂直逻辑像素数

int pixelx = dc.GetDeviceCaps(HORZRES);//水平像素总数

int pixely = dc.GetDeviceCaps(VERTRES);//垂直像素总数

int hmm = dc.GetDeviceCaps(HORZSIZE);//水平毫米数

int vmm = dc.GetDeviceCaps(VERTSIZE);//垂直毫米

  以上三者的关系通常满足:HORZSIZE = 25.4 * HORZRES / LOGPIXELSX

  获取和设置显示器属性的代码如下所示:

//创建显示设备上下文
HDC hdc = CreateDC(_T("display"), NULL, NULL, NULL);

//********** 获取显示器属性 **********
//颜色深度
int nBitsPerPixel=GetDeviceCaps(hdc, BITSPIXEL);

//水平分辨率
int nWidth = GetDeviceCaps(hdc, HORZRES);

//垂直分辨率
int nHeight = GetDeviceCaps(hdc, VERTRES);     

//刷新率
int nDisplayFrequency = GetDeviceCaps(hdc, VREFRESH);

 
//********** 设置显示器属性 **********
DEVMODE DevMode;

//颜色深度
DevMode.dmBitsPerPel = 16;

//分辨率
DevMode.dmPelsWidth = 800;
DevMode.dmPelsHeight = 600;

//刷新率
DevMode.dmDisplayFrequency = 60;

//设置显示属性
LONG nResult = ChangeDisplaySettings(&DevMode, 0);
if (nResult == DISP_CHANGE_SUCCESSFUL) 
{
    //用新的设置参数更新注册表
    ChangeDisplaySettings(&DevMode, CDS_UPDATEREGISTRY);
    AfxMessageBox(_T("设置显示属性成功。"));
}
else 
{
    //恢复默认设置
    ChangeDisplaySettings(NULL, 0);
    AfxMessageBox(_T("设置显示属性失败。"));
}

 
//设置显示器为省电模式
::SendMessage(m_hWnd, WM_SYSCOMMAND, SC_MONITORPOWER, 1);

//打开显示器
::SendMessage(m_hWnd, WM_SYSCOMMAND, SC_MONITORPOWER, -1);

//关闭显示器
::SendMessage(m_hWnd, WM_SYSCOMMAND, SC_MONITORPOWER, 2);

GetSystemMetrics

 1 int i;
 2 i = GetSystemMetrics(SM_CLEANBOOT);//启动方式 0
 3 i = GetSystemMetrics(SM_CMONITORS);//显示器数目 1
 4 i = GetSystemMetrics(SM_CMOUSEBUTTONS);//鼠标上按键的数目 3
 5 i = GetSystemMetrics(SM_CXBORDER);//窗口边框的宽度,3D外观下与SM_CXEDGE值相同 1
 6 i = GetSystemMetrics(SM_CXCURSOR);//光标的宽度 32
 7 i = GetSystemMetrics(SM_CXDLGFRAME);//与SM_CXFIXEDFRAME相同 3
 8 i = GetSystemMetrics(SM_CXDOUBLECLK);//鼠标在某个矩形内连击两次被认为是双击,该矩形的宽度 4
 9 i = GetSystemMetrics(SM_CXDRAG);//鼠标在某个矩形内单击移动被认为是拖曳,该矩形的宽度 4
10 i = GetSystemMetrics(SM_CXEDGE);//SM_CXBORDER在3D外观下的值 2
11 i = GetSystemMetrics(SM_CXFIXEDFRAME);//具有title bar和固定border的窗体的border的宽度 3
12 i = GetSystemMetrics(SM_CXFOCUSBORDER);//DrawFocusRect画出的矩形的左右边框的 1
13 i = GetSystemMetrics(SM_CXFRAME);//与SM_CXSIZEFRAME相同 4
14 i = GetSystemMetrics(SM_CXFULLSCREEN);//客户区(工作区)的宽度 1280
15 i = GetSystemMetrics(SM_CXHSCROLL);//水平滚动条上箭头位图的宽度 17
16 i = GetSystemMetrics(SM_CXHTHUMB);//水平滚动条滑块的宽度 17
17 i = GetSystemMetrics(SM_CXICON);//图标的默认宽度,LoadIcon只能载入该宽度和SM_CYICON指定高度的icon 32
18 i = GetSystemMetrics(SM_CXICONSPACING);//icon view中各icon的所占矩形的宽度,大于等于SM_CXICON 75
19 i = GetSystemMetrics(SM_CXMAXIMIZED);//最大化顶级窗口的宽度 1288
20 i = GetSystemMetrics(SM_CXMAXTRACK);//一个具有title bar和sizable的窗口所能达到的最大宽度 1292
21 i = GetSystemMetrics(SM_CXMENUCHECK);//菜单上位图的宽度 13
22 i = GetSystemMetrics(SM_CXMENUSIZE);//菜单条按钮的宽度,例如多文档中ChildFrame(最大化时)右上角的关闭按钮 19
23 i = GetSystemMetrics(SM_CXMIN);//窗体的最小宽度 123
24 i = GetSystemMetrics(SM_CXMINIMIZED);//最小化窗体的宽度 160
25 i = GetSystemMetrics(SM_CXMINSPACING);//各个最小化窗体所占的矩形的宽度,大于等于SM_MINIMIZED 160
26 i = GetSystemMetrics(SM_CXMINTRACK);//窗口能拖拽的最小宽度 123
27 i = GetSystemMetrics(SM_CXSCREEN);//屏幕宽度 1280
28 i = GetSystemMetrics(SM_CXSIZE);//title bar上按钮的宽度 25
29 i = GetSystemMetrics(SM_CXSIZEFRAME);//sizable窗体的横向border的宽度 4
30 i = GetSystemMetrics(SM_CXSMICON);//推荐的小图标(如title bar上的和icon view中的)的宽度 16
31 i = GetSystemMetrics(SM_CXSMSIZE);//caption中图标的宽度 17
32 i = GetSystemMetrics(SM_CXVIRTUALSCREEN);//virutal screen的宽度 1280
33 i = GetSystemMetrics(SM_CXVSCROLL);//垂直滚动条的宽度 17
34 i = GetSystemMetrics(SM_CYBORDER);// 1
35 i = GetSystemMetrics(SM_CYCAPTION);// 26
36 i = GetSystemMetrics(SM_CYCURSOR);// 32
37 i = GetSystemMetrics(SM_CYDLGFRAME);// 3
38 i = GetSystemMetrics(SM_CYDOUBLECLK);// 4
39 i = GetSystemMetrics(SM_CYDRAG);// 4
40 i = GetSystemMetrics(SM_CYEDGE);// 2
41 i = GetSystemMetrics(SM_CYFIXEDFRAME);// 3
42 i = GetSystemMetrics(SM_CYFOCUSBORDER);// 1
43 i = GetSystemMetrics(SM_CYFRAME);// 4
44 i = GetSystemMetrics(SM_CYFULLSCREEN);// 744
45 i = GetSystemMetrics(SM_CYHSCROLL);// 17
46 i = GetSystemMetrics(SM_CYICON);// 32
47 i = GetSystemMetrics(SM_CYICONSPACING);// 75
48 i = GetSystemMetrics(SM_CYMAXIMIZED);// 778
49 i = GetSystemMetrics(SM_CYMAXTRACK);// 812
50 i = GetSystemMetrics(SM_CYMENU);// 20
51 i = GetSystemMetrics(SM_CYMENUCHECK);// 13
52 i = GetSystemMetrics(SM_CYMIN);// 34=4+4+26
53 i = GetSystemMetrics(SM_CYMINIMIZED);// 31
54 i = GetSystemMetrics(SM_CYMINSPACING);// 31
55 i = GetSystemMetrics(SM_CYMINTRACK);// 34
56 i = GetSystemMetrics(SM_CYSCREEN);// 800
57 i = GetSystemMetrics(SM_CYSIZE);// 25
58 i = GetSystemMetrics(SM_CYSIZEFRAME);// 4
59 i = GetSystemMetrics(SM_CYSMCAPTION);// 18
60 i = GetSystemMetrics(SM_CYSMICON);// 16
61 i = GetSystemMetrics(SM_CYSMSIZE);// 17
62 i = GetSystemMetrics(SM_CYVIRTUALSCREEN);// 800
63 i = GetSystemMetrics(SM_CYVSCROLL);// 17
64 i = GetSystemMetrics(SM_CYVTHUMB);// 17
View Code

MFC坐标转换

  GetWindowRect是取得窗口在屏幕坐标系下的RECT坐标(包括客户区和非客户区),这样可以得到窗口的大小和相对屏幕左上角(0,0)的位置。

  GetClientRect取得窗口客户区(不包括非客户区)在客户区坐标系下的RECT坐标,可以得到窗口的大小,而不能得到相对屏幕的位置,因为这个矩阵是在客户区坐标系下(相对于窗口客户区的左上角)的。  

  ClientToScreen把客户区坐标系下的RECT坐标转换为屏幕坐标系下的RECT坐标。

  ScreenToClient把屏幕坐标系下的RECT坐标转换为客户区坐标系下的RECT坐标。

  我们对同一个窗口先GetWindowRect取得一个RECT,再用ScreenToClient转换到客户坐标系。然后 GetClientRect取得一个RECT,再用ClientToScreen转换到屏幕坐标系。显然,GetWindowRect取得的矩阵不小于 GetClientRect取得的矩阵。因为前者包含了非客户区,而后者包括了客户区。   

  • 对GetWindowRect取得的矩阵ScreenToClient后,矩阵的大小没有变小,(-3,-29)是窗口的左上角的坐标,相对窗口客户区左上角;   
  • 对GetClientRect取得的矩阵ClientToScreen后,矩阵也没有变大,新得到的矩阵是窗口客户区在屏幕坐标系上的RECT;

对话框全屏

//删除WS_CAPTION和WS_BORDER风格
ModifyStyle(WS_CAPTION, 0);
ModifyStyle(WS_BORDER, 0);

//获得屏幕长度和高度
int cx = GetSystemMetrics(SM_CXSCREEN);
int cy = GetSystemMetrics(SM_CYSCREEN);

//设置对话框位置和大小
SetWindowPos(NULL, 0, 0 , cx, cy, SWP_NOZORDER)

键盘消息

(1)组合按键

BOOL CMyDlg::PreTranslateMessage(MSG* pMsg)   
{
    if(pMsg->message == WM_KEYDOWN)
    {
        // 组合键响应keydown消息
        if( pMsg->wParam == VK_SPACE && (GetKeyState(VK_SHIFT) & 0x8000))
        {
            // 空格 + Shift
        }
    }
}

(2)屏蔽ESC键

BOOL CColorDlgDlg::PreTranslateMessage(MSG* pMsg)
{
    //屏蔽ESC关闭窗体/
    if(pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_ESCAPE ) return TRUE;
    //屏蔽回车关闭窗体,但会导致回车在窗体上失效.
    //if(pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_RETURN && pMsg->wParam) return TRUE;
    else
        return CDialog::PreTranslateMessage(pMsg);
}

(3)屏蔽Alt+F4

BOOL CTestApp::PreTranslateMessage(MSG* pMsg)
{
    // TODO: 在此添加专用代码和/或调用基类
    if(pMsg->message == WM_SYSKEYDOWN
        && pMsg->wParam == VK_F4)
        return TRUE;

    return CWinAppEx::PreTranslateMessage(pMsg);
}

添加ToolTip提示框

为窗口或其中的控件添加提示框,可以使用MFC的类CToolTipCtrl,使用方法如下:

(1)在窗口的类定义中添加变量说明:

class CTooltipTestDlg : public Cdialog
{
public:
    CToolTipCtrl m_tt;
}

(2)在对话框的OnInitDialog()函数中添加如下代码:

EnableToolTips(TRUE);
m_tt.Create(this);
m_tt.Activate(TRUE);
CWnd* pW=GetDlgItem(IDC_CHECK1);//得到控件的指针
m_tt.AddTool(pW,L"Check1lakjsfasfdasfd");//为此控件添加tip

(3)重载父窗口的 BOOL PreTranslateMessage(MSG* pMsg) ,在函数中调用 m_tt.RelayEvent(pMsg):

BOOL CTooltipTestDlg::PreTranslateMessage(MSG* pMsg)
{
    // TODO: Add your specialized code here and/or call the base class
    if (NULL != m_tt.GetSafeHwnd())
    {
        m_tt.RelayEvent(pMsg);
    }
    return CDialog::PreTranslateMessage(pMsg);
}

  这样就完成了为控件添加Tip。

  如果想修改已添加的tip的内容,可以使用UpdateTipText函数,如下

CWnd* pW=GetDlgItem(IDC_CHECK1);//得到已添加tip控件
m_tt.UpdateTipText(L"asdflasdf",pW);//更新tip的内容

  其他控制函数具体可查MSDN的CToolTipCtrl类。

  对于静态文本框,要把Notify的属性设为TRUE;而如果静态文本控件是动态创建的,必须给窗口风格添加SS_NOTIFY,如

m_StaticText.Create(_T("my static"), WS_CHILD|WS_VISIBLE|WS_BORDER|SS_NOTIFY,CRect(10,10,150,50),this);

鼠标经过控件时呈手形

//响应WM_SETCURSOR消息
BOOL CAboutDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
     // TODO: 在此添加消息处理程序代码和/或调用默认值

     //m_hCursor=AfxGetApp()->LoadCursor(IDC_HAND);
     //文本框IDC_STATIC_HOMEPAGE_LINK的Notify设为true
     if(pWnd==GetDlgItem(IDC_STATIC_HOMEPAGE_LINK))
     {
              SetCursor(LoadCursor(NULL,IDC_HAND));
              return true;//必须加上
     }
     return CDialogEx::OnSetCursor(pWnd, nHitTest, message);
}

Bmp图片显示

HBITMAP  hBitmap = (HBITMAP)LoadImage(
    NULL,
    _T(“xxx.bmp”),
    Image_Bitmap,
    0,0,
    Lr_CreateDibSection|Lr_DefaultSize|Lr_LoadFromFile);

PWnd->ModifyStytle(0,SS_BITMAP);
PWnd->SetBitmap(hBitmap);

对话框bmp背景图片显示

在对话框的OnEraseBkgnd(CDC *pDC) 函数中添加如下代码:

HBITMAP  hBitmap = (HBITMAP)Load Image(
    NULL,
    _T(“xxx.bmp”),
    Image_Bitmap,
    0,0,
    Lr_CreateDibSection|Lr_DefaultSize|Lr_LoadFromFile);

CBitmap bitmap;
bitmap.Attach(hBitmap); //关联位图对象

BITMAP bmp;
Bitmap.GetBitmap(&bmp); //获取位图信息

CDC compatibleDC;
compatibleDC.CreateCompatibleDC(pDC); //内存
compatibleDC. SelectObject(&bitmap); //选取位图对象

Crect rect;
GetClientRect(&rect);

pDC->StretchBlt(
    rect.left, rect.top, rect.right, rect.bottom,
    &compatibleDC,
    0, 0, bmp.bmWidth, bmp.bmHeight,
    SRCCOPY);

Return true;// 将OnEraseBkgnd(CDC *pDC) 函数中最后的return语句改为本句

解决StretchBlt()压缩图片失真

  StretchBlt函数缩放图片后图片失真严重,所以要用SetStretchBltMode函数来设置 StretchBlt(或StretchDIBits)函数的伸缩模式。具体用法是调用StretchBlt前调用:

SetStretchBltMode(pDC->m_hDC,STRETCH_HALFTONE);

  

GDI+加载透明png图片

(1)开始加入:

#include <comdef.h>//初始化一下com口

#include "GdiPlus.h"

using namespace Gdiplus;

#pragma comment(lib,"gdiplus.lib")

(2)添加成员变量

ULONG_PTR m_gdiplusToken;

(3)初始化时,启动GDI+

GdiplusStartupInput gdiplusStartupInput;

GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

(4)退出时,结束GDI+

GdiplusShutdown(m_gdiplusToken);

(5)在OnPaint或OnDraw函数中,显示图片

CClientDC *pDC = new CClientDC(GetDlgItem(IDC_STATIC_PIC));

CRect rect;
GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(&rect);

Image image(_T("1.png")); // Construct an image
//或 Image::FromFile(strPath);

Graphics graphics(pDC->m_hDC); // Create a GDI+ graphics object
graphics.DrawImage(&image, 0, 0, image.GetWidth(), image.GetHeight());

delete pDC;//或ReleaseDC

窗口重绘

  RedrawWindow函数引发重新绘制,使用flags参数控制。

  InvalidateRect直接无效某个区域,指定是否刷新背景。

  如果您的绘制变化较多,有时有闪烁,可以用LockWindowUpdate、UnlockWindowUpdate或者CWnd::SetRedraw控制,最后结束了,允许绘制,再无效待绘制区域Invalidate。

可视动画控件ActiveMovie

  可视动画控件ActiveMovie是Microsoft公司开发的ActiveX控件,从开始的1.0版、1.2版到现在的2.0版,功能上已经有了很大的改进。由于该控件内嵌了Microsoft MPEG音频解码器和Microsoft MPEG视频解码器,所以能够很好地支持音频文件和视频文件,用其播放的VCD效果就很好。另外,播放时若用鼠标右键单击画面,可以直接对画面的播放、暂停、停止等进行控制,读者还可以自行在"属性"栏中对影片播放进行控制设置,用起来非常方便。当前在Microsoft公司推出的Visual C++6.0中已经包含了ActiveMovie控件的2.0版。

    在Visual C++6.0中,一般情况都是在基于对话框的应用程序中使用ActiveMovie控件,可在菜单中依次选择"project- >Add To Project- >Components And Controls",在出现的"Components And Controls Gallery"对话框中打开"Registered Active Controls"文件夹,选中"ActiveMovie Control Object"选项,按"Insert"按钮后关闭该对话框,ActiveMovie控件便出现在程序编辑器的控件面板中。

     可是我按本法操作,却找不到此控件。

解决办法:

    打开"开始",运行 regsvr32 msdxm.ocx,有时候会发生注册失败的情况,这时必须关掉VS6及相关的音频播放软件,才能注册成功。

MFC operator new: 没有重载函数接受 3 个参数

  解决办法:在new前添加全局作用域::

程序打包

  在没有安装 VC 的计算机上运行VC程序时要从 VC 中把 mscomm32.ocx、 msvcrt.dll、 mfc42.dll 拷到 Windows 目录下的 System 子目录中(win2000 为 System32),对于还没有注册的控件,例如自己开发出来的控件,可以借助regsvr32.exe注册,具体做法是:开始菜单->运行->regsvr32.exe 控件文件名.ocx(或者是控件文件名.dll),注意控件文件名处需要用绝对路径,例如regsvr32.exe C:/progrm files/myActiveXControl.ocx;你也可以卸载已注册的控件(也即反注册),命令格式如下:regsvr32.exe/u 控件文件名.ocx(或者是控件文件名.dll)

  相关链接:http://blog.csdn.net/testcs_dn/article/details/26976555

posted @ 2016-07-29 14:23  晨光iABC  阅读(3060)  评论(0编辑  收藏  举报