第03章 Windows编程基础.ppt

上传人:qwe****56 文档编号:70009848 上传时间:2023-01-14 格式:PPT 页数:29 大小:724KB
返回 下载 相关 举报
第03章 Windows编程基础.ppt_第1页
第1页 / 共29页
第03章 Windows编程基础.ppt_第2页
第2页 / 共29页
点击查看更多>>
资源描述

《第03章 Windows编程基础.ppt》由会员分享,可在线阅读,更多相关《第03章 Windows编程基础.ppt(29页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、第三章第三章 Windows 编程基础编程基础 Windows 编程基础知识编程基础知识 Windows 应用程序常用消息应用程序常用消息 Windows 中的事件驱动程序设计中的事件驱动程序设计 Windows 应用程序的基本结构应用程序的基本结构跨平台开发原则跨平台开发原则跨平台应用程序的开发跨平台应用程序的开发 Windows Windows 操作平台:操作平台:Windows 3.X Windows 3.X 是一个是一个1616位的操作平台。位的操作平台。Windows Windows 95/98/NT/200095/98/NT/2000是是一一个个3232位位的的操操作作平平台。台。

2、NT/2000NT/2000是一个全是一个全3232位的操作系统,而位的操作系统,而95/9895/98是是1616位和位和32 32 位的混合物。位的混合物。Windows APIWindows API(Win16 APIWin16 API和和Win32APIWin32API)Win16(Windows 3.x)Win32S(Windows3.xWin16(Windows 3.x)Win32S(Windows3.x的的3232接口接口)Win32)Win32(Windows95/98/NTWindows95/98/NT)跨平台应用程序的开发原则:跨平台应用程序的开发原则:1 1、应用程序中要

3、检测版本、应用程序中要检测版本 2 2、注意数据类型的变化、注意数据类型的变化 3 3、尽量使用通用的、尽量使用通用的APIAPI函数函数 4 4、注意各个版本的区别和支持、注意各个版本的区别和支持/不支持的功不支持的功能能5 5、注意一些函数语法和语义上的改变、注意一些函数语法和语义上的改变Win32Win32平台开发工具包平台开发工具包 Win32Win32平台的常用开发工具平台的常用开发工具1 1、微软提供的软件开发包(、微软提供的软件开发包(SDKSDK)Win32 SDKWin32 SDK、OLE SDKOLE SDK、ODBC SDKODBC SDK等。等。2 2、微软提供的可视化

4、集成开发工具、微软提供的可视化集成开发工具 Visual StudioVisual Studio系列产品系列产品 Visual Visual C+(MFC)C+(MFC)、Visual Visual BasicBasic、Visual Visual J+J+3 3、Borland Borland 公司的一些开发工具公司的一些开发工具 Borland C+(OWL)Borland C+(OWL)、C+BuilderC+Builder、DelphiDelphi4 4、其他的其他的 WatcomWatcom C+C+、PowerBuilderPowerBuilder 窗口窗口 窗口是窗口是Windo

5、ws 应用程序基本的操作应用程序基本的操作单元,是应用程序和用户之间交互的接单元,是应用程序和用户之间交互的接口环境,也是系统管理应用程序的基本口环境,也是系统管理应用程序的基本单位。单位。事件、句柄事件、句柄 事件驱动事件驱动 WindowsWindows是消息驱动(或事件驱动)的是消息驱动(或事件驱动)的操作系统。操作系统。句柄和句柄和Windows 消息消息 1、句柄、句柄 句柄是整个句柄是整个Windows编程的基础,一个编程的基础,一个句柄是指句柄是指Windows使用的一个惟一的整数使用的一个惟一的整数值(值(long),),用于标识应用程序中不同的用于标识应用程序中不同的对象和同

6、类对象中不同的实例,例如,一对象和同类对象中不同的实例,例如,一个窗口、文件等。个窗口、文件等。常用的句柄类型常用的句柄类型一些常用的句柄类型:一些常用的句柄类型:(表表3-1)3-1)HWND HBITMAPHINSTANCE HICONHCURSOR HMENUHFONT HFILEHPEN HDC HBRUSH消息结构定义消息结构定义2、消息、消息 消息是消息是Windows应用程序之间及应用程应用程序之间及应用程序与序与Windows操作系统之间进行通信的机操作系统之间进行通信的机制。消息是一个整数值,可以携带两个参制。消息是一个整数值,可以携带两个参数,一个是数,一个是wParam,

7、另一个是另一个是lParam。根据消息的不同,参数所表示的含义也不根据消息的不同,参数所表示的含义也不同。同。在在Windows API中为了方便的使用消息,中为了方便的使用消息,通常用通常用MSG结构来封装消息。结构来封装消息。MSGMSG结构的定义:结构的定义:typedeftypedef structstruct tagMSGtagMSG HWND HWND hwndhwnd;/;/检索消息的窗口检索消息的窗口 UINTUINT message;/message;/消息类型消息类型 WPARAM WPARAM wParamwParam;/;/消息附加信息,如键值消息附加信息,如键值 LP

8、ARAM LPARAM lParamlParam;DWORD DWORD time;time;POINT POINT pt;pt;MSG;MSG;消息的分类消息的分类 消息的分类消息的分类 系统定义的消息系统定义的消息消息消息 内部的消息内部的消息 用户自定义的消息用户自定义的消息 外部的消息外部的消息系统定义的消息的取值范围:系统定义的消息的取值范围:0 x0000 0 x0000 0 x03FF 0 x03FF、0 x8000 0 x8000 0 xBFFF 0 xBFFF用户自定义的内部消息的取值范围:用户自定义的内部消息的取值范围:0 x0400 0 x0400 0 x7FF 0 x7

9、FF用户自定义的外部消息的取值范围:用户自定义的外部消息的取值范围:0 xC000 0 xC000 0 xFFFF 0 xFFFF系统定义的消息系统定义的消息系统定义的消息系统定义的消息 WindowsWindows使用系统定义的消息和应用程序使用系统定义的消息和应用程序进行通信、控制应用程序。每个系统定义进行通信、控制应用程序。每个系统定义的消息都有一个唯一的数值标识符和相应的消息都有一个唯一的数值标识符和相应的宏,例如,按下鼠标左键为:的宏,例如,按下鼠标左键为:WM_LBUTTONDOWN 0 x0201WM_LBUTTONDOWN 0 x0201按下鼠标右键为:按下鼠标右键为:WM_R

10、BUTTONDOWN 0 x0204WM_RBUTTONDOWN 0 x0204用户定义的消息(用户定义的消息(1 1)用户定义的消息用户定义的消息 除系统定义的消息外,用户也可以定义除系统定义的消息外,用户也可以定义自己的消息。用户自定义的消息分为:用自己的消息。用户自定义的消息分为:用户自定义的内部消息和用户自定义的外部户自定义的内部消息和用户自定义的外部消息两类。消息两类。用户自定义的内部消息一般用于本应用用户自定义的内部消息一般用于本应用程序内的通信,其他的外部程序不认识该程序内的通信,其他的外部程序不认识该消息。使用用户自定义的内部消息时应注消息。使用用户自定义的内部消息时应注意,定

11、义的内部消息值应大于意,定义的内部消息值应大于0 x0400。Windows定义了一个宏:定义了一个宏:#define WM_USER 0 x0400用户定义的消息(用户定义的消息(2 2)用户自定义的外部消息一般用于不同应用户自定义的外部消息一般用于不同应用程序之间的通信,其他的外部程序可以用程序之间的通信,其他的外部程序可以认识该消息。认识该消息。使用用户自定义的外部消息必须通过使用用户自定义的外部消息必须通过 RegisterWindowMessage()API函数在函数在Windows系统中进行注册,成系统中进行注册,成功后,将返回一个功后,将返回一个0 xC0000 xFFFF之间的

12、之间的值。值。常用消息(常用消息(1)WM_LBUTTONDOWN 单击鼠标左键时产生该消息,其附加的单击鼠标左键时产生该消息,其附加的参数参数wParam中包含了标识鼠标键的按下状中包含了标识鼠标键的按下状态;态;lParam的低位字节包含了当前光标的的低位字节包含了当前光标的X坐标,高位字节包含了当前光标的坐标,高位字节包含了当前光标的Y坐标。坐标。MK_LBUTTONMK_LBUTTON鼠标键状态参数及其说明鼠标键状态参数及其说明(表表3-3)MK_MBUTTONMK_MBUTTONMK_RBUTTONMK_RBUTTON按下了鼠标左键按下了鼠标左键按下了鼠标中键按下了鼠标中键按下了鼠标

13、右键按下了鼠标右键常用消息(常用消息(2)和和WM_LBUTTONDOWN相似的消息有:相似的消息有:WM_LBUTTONUPWM_RBUTTONDOWNWM_RBUTTONUPWM_MBUTTONDOWNWM_MBUTTONUP常用消息(常用消息(3)WM_KEYDOWN WM_CHAR WM_CREATE WM_CLOSE WM_DESTROY WM_QUIT WM_PAINT事件驱动程序设计(事件驱动程序设计(1)基于基于DOS的应用程序主要使用顺序的、的应用程序主要使用顺序的、过程驱动的程序设计方法。顺序的、过程过程驱动的程序设计方法。顺序的、过程驱动的程序有一个明显的开始和结束,因驱

14、动的程序有一个明显的开始和结束,因此,程序能直接控制事件或过程的顺序。此,程序能直接控制事件或过程的顺序。基于基于Windows的应用程序的设计方法与的应用程序的设计方法与基于基于DOS的程序设计方法的主要不同在于的程序设计方法的主要不同在于Windows程序是事件驱动的,事件驱动的程序是事件驱动的,事件驱动的程序的执行顺序不是由程序控制的,而是程序的执行顺序不是由程序控制的,而是由事件的发生来控制的。由事件的发生来控制的。事件驱动程序设计(事件驱动程序设计(2)过程驱动程序与事件驱动程序的区别过程驱动程序与事件驱动程序的区别 例如,求一个学生的平均成绩的程序例如,求一个学生的平均成绩的程序开

15、始开始输入学生的姓名输入学生的姓名输入第一次成绩输入第一次成绩输入第二次成绩输入第二次成绩输入第三次成绩输入第三次成绩结束结束计算平均成绩计算平均成绩过程驱动设计过程驱动设计事件驱动程序设计(事件驱动程序设计(3)过程驱动程序与事件驱动程序的区别过程驱动程序与事件驱动程序的区别 例如,求一个学生的平均成绩的程序例如,求一个学生的平均成绩的程序开始开始结束结束消息循环消息循环输入学生的姓名输入学生的姓名输入第一次成绩输入第一次成绩输入第二次成绩输入第二次成绩输入第三次成绩输入第三次成绩计算平均成绩计算平均成绩事件驱动设计事件驱动设计Windows Windows 应用程序的基本流程应用程序的基本

16、流程开始初始化应用程序和窗口进入消息循环并检索消息是退出消息?退出程序是否处理该消息?由Windows进行默认处理 处理消息是否是否Windows 应用程序的文件组成应用程序的文件组成 Windows 应用程序的组成应用程序的组成 .CPP或或.C文件文件 .H文件文件 .DEF文件文件/模块属性,可省略模块属性,可省略 .RC文件文件 .MAK文件文件/工程文件工程文件源程序文件源程序文件/建建立立project project win32 win32 applicationapplication,然然后后建建立立新新文文件件输输入入#include#include windows.hwin

17、dows.h LRESULT LRESULT CALLBACK CALLBACK WndProc(HWND,UINT,WPARAM,LPARAMWndProc(HWND,UINT,WPARAM,LPARAM););HINSTANCE HINSTANCE ghInstghInst;char char szAppNameszAppName=WinSDKWinSDK;char char szAppTitleszAppTitle=A Windows SDK Application;=A Windows SDK Application;intint WINAPI WINAPI WinMainWinMai

18、n(HINSTANCE HINSTANCE hInstancehInstance,HINSTANCE HINSTANCE hPrevInstancehPrevInstance,LPSTR LPSTR lpCmdLinelpCmdLine,intint nShowCmdnShowCmd /初初始始窗口显示方式窗口显示方式 )HWND HWND hWndMainhWndMain;MSG Message;MSG Message;WNDCLASS WNDCLASS wcwc;wc.stylewc.style=CS_HREDRAW|CS_VREDRAW;=CS_HREDRAW|CS_VREDRAW;wc

19、.lpfnWndProcwc.lpfnWndProc =WndProcWndProc;/;/窗窗口口消消息息处处理理函函数数 wc.cbClsExtrawc.cbClsExtra =0;/=0;/类扩展内存类扩展内存 wc.cbWndExtrawc.cbWndExtra =0;/=0;/窗口扩展内存窗口扩展内存 wc.hInstancewc.hInstance =hInstancehInstance;/;/当前实例句柄当前实例句柄 wc.hIconwc.hIcon=LoadIcon(NULL,IDI_APPLICATIONLoadIcon(NULL,IDI_APPLICATION););wc.

20、hCursorwc.hCursor=LoadCursor(NULL,IDC_ARROWLoadCursor(NULL,IDC_ARROW););wc.hbrBackgroundwc.hbrBackground =(=(HBRUSH)GetStockObject(WHITE_BRUSHHBRUSH)GetStockObject(WHITE_BRUSH););wc.lpszMenuNamewc.lpszMenuName =NULL;=NULL;wc.lpszClassNamewc.lpszClassName =szAppNameszAppName;/;/给给定定义义的的类类一个名字一个名字/1./

21、1.注册窗口类注册窗口类 RegisterClass(&wcRegisterClass(&wc););/2./2.创建窗口创建窗口 hWndMainhWndMain=CreateWindowCreateWindow(szAppName,/lpClassNameszAppName,/lpClassNameszAppTitle,/lpWindowNameszAppTitle,/lpWindowNameWS_OVERLAPPEDWINDOW,/WS_OVERLAPPEDWINDOW,/dwStyledwStyleCW_USEDEFAULT,/xCW_USEDEFAULT,/xCW_USEDEFAUL

22、T,/xCW_USEDEFAULT,/xCW_USEDEFAULT,/CW_USEDEFAULT,/nWidthnWidthCW_USEDEFAULT,/CW_USEDEFAULT,/nHeightnHeightNULL,/NULL,/hWndParenthWndParentNULL,/NULL,/hMenuhMenuhInstancehInstance,/,/程序句柄程序句柄NULL);/NULL);/lpParamlpParam/3./3.显示窗口显示窗口 ShowWindow(hWndMain,SW_SHOWMAXIMIZEDShowWindow(hWndMain,SW_SHOWMAXI

23、MIZED););/4./4.绘制客户区绘制客户区 UpdateWindow(hWndMainUpdateWindow(hWndMain););/5./5.消息循环消息循环 while(GetMessage(&Message,NULL,0,0)while(GetMessage(&Message,NULL,0,0)TranslateMessage(&MessageTranslateMessage(&Message););DispatchMessage(&MessageDispatchMessage(&Message););/6./6.消息循环结束消息循环结束 return return Mess

24、age.wParamMessage.wParam;LRESULT LRESULT CALLBACK CALLBACK WndProc(HWNDWndProc(HWND hWnd,UINThWnd,UINT message,WPARAMmessage,WPARAM wParam,LPARAMwParam,LPARAM lParamlParam)switch(messageswitch(message)case WM_DESTROY:case WM_DESTROY:PostQuitMessage(0);PostQuitMessage(0);default:default:return return

25、 DefWindowProc(hWnd,message,wParam,lParamDefWindowProc(hWnd,message,wParam,lParam););return 0;return 0;程序分析程序分析(1)程序入口点程序入口点 用用C C语言编写的语言编写的DOSDOS程序的入口点是程序的入口点是main()main()函数,函数,WindowsWindows程序也需要入口点,称为程序也需要入口点,称为WinMainWinMain()()。通通常在常在WinMainWinMain函数中完成程序的初始化、创建窗口函数中完成程序的初始化、创建窗口和进行消息循环。和进行消息循环

26、。WinMainWinMain函数的原型:函数的原型:intint FAR PASCAL FAR PASCAL WinMainWinMain(HINSTANCE HINSTANCE hInstancehInstance,HINSTANCE HINSTANCE hPrevInstancehPrevInstance,LPSTR LPSTR lpCmdLinelpCmdLine,intint nCmdShownCmdShow)在在Win32Win32平平台台下下,hPrevInstancehPrevInstance 的的值值总总是是为为NULLNULL!WinMain的另一种形式:的另一种形式:in

27、t WINAPI WinMain()程序分析程序分析(2)(2)类初始化类初始化 每个应用程序的窗口都有窗口类,应用程序的每个应用程序的窗口都有窗口类,应用程序的窗口类必须由窗口类必须由WindowsWindows初始化和注册一次。窗口初始化和注册一次。窗口类由类由WNDCLASSWNDCLASS结构定义,通过结构定义,通过RegisterClassRegisterClass APIAPI函数。函数。WNDCLASSWNDCLASS结构定义如下:结构定义如下:typedeftypedef structstruct _WNDCLASS _WNDCLASS UINT style;UINT styl

28、e;WNDPROC WNDPROC lpfnWndProclpfnWndProc;intint cbClsExtracbClsExtra;intint cbWndExtracbWndExtra;HANDLE HANDLE hInstancehInstance;HICON HICON hIconhIcon;HCURSOR HCURSOR hCursorhCursor;HBRUSH HBRUSH hbrBackgroundhbrBackground;LPCTSTR LPCTSTR lpszMenuNamelpszMenuName;LPCTSTR LPCTSTR lpszClassNamelpszC

29、lassName;WNDCLASS;WNDCLASS;程序分析程序分析(3)(3)RegisterClass 函数定义函数定义注册窗口类是为注册窗口类是为CreateWindowCreateWindow做准备做准备 ATOM ATOM RegisterClassRegisterClass(CONST WNDCLASS*CONST WNDCLASS*lpWndClasslpWndClass)如如果果该该函函数数执执行行成成功功,将将返返回回一一个个唯唯一一的的类标识,失败时,返回类标识,失败时,返回NULLNULL。除除使使用用WNDCLASSWNDCLASS和和RegisterClassReg

30、isterClass定定义义和和注注册册类类外外,在在Win32Win32平平台台下下,还还可可以以使使用用WNDCLASSEXWNDCLASSEX和和RegisterClassExRegisterClassEx定义和注册。定义和注册。ATOM:ATOM:字符串表中的字符串表中的16bit16bit的标志符号的标志符号程序分析程序分析(4)(4)创建应用程序窗口创建应用程序窗口 通过通过CreateWindowCreateWindow API API函数创建窗口;通过函数创建窗口;通过ShowWindowShowWindow和和UpdateWindowUpdateWindow显示窗口。显示窗口

31、。CreateWindowCreateWindow函数定义如下:函数定义如下:HWND HWND CreateWindowCreateWindow(LPCTSTR LPCTSTR lpClassNamelpClassName,LPCTSTR LPCTSTR lpWindowNamelpWindowName,intint x x,intint y y,intint nWidthnWidth,intint nHeightnHeight,HWND HWND hWndParenthWndParent,HMENU HMENU hMenuhMenu,HANDLE HANDLE hInstancehInst

32、ance,LPVOID LPVOID lpParamlpParam ););ShowWindowShowWindow只只完完成成了了创创建建窗窗口口显显示示的的一一部部分分工工作作,它它主主要要负负责责建建立立窗窗口口框框架架、标标题题栏栏、菜菜单单栏栏等等窗窗口口的的边边界界元元素素,而而不不负负责责创创建建窗窗口口的的客客户户区,区,这这部分工作通部分工作通过过UpdateWindowUpdateWindow函数完成。函数完成。程序分析程序分析(5)-(5)-消息循环消息循环while(GetMessage(&Message,NULL,0,0)while(GetMessage(&Messa

33、ge,NULL,0,0)TranslateMessage(&MessageTranslateMessage(&Message););DispatchMessage(&MessageDispatchMessage(&Message););通通过过调调用用GetMessageGetMessage APIAPI函函数数从从应应用用程程序序的的消消息息队队列列中中得得到到消消息息,然然后后将将消消息息传传递递给给TranslateMessageTranslateMessage函函数数,该该 函函 数数 执执 行行 键键 盘盘 消消 息息 的的 翻翻 译译 工工 作作,最最 后后 通通 过过Dispat

34、chMessageDispatchMessage函函数数将将消消息息分分派派到到指指定定的的窗窗口口,由由窗窗口口处理函数对消息进行处理。处理函数对消息进行处理。GetMessageGetMessage函数定义为:函数定义为:BOOL BOOL GetMessageGetMessage(LPMSG LPMSG lpMsglpMsg,HWND HWND hWndhWnd,/,/发出消息窗口发出消息窗口 UINT UINT wMsgFilterMinwMsgFilterMin,/,/消息值是一个整数消息值是一个整数 UINT UINT wMsgFilterMaxwMsgFilterMax)/)/用

35、此设定上下限用此设定上下限 该该函函数数由由四四个个参参数数,通通常常只只用用第第一一个个,其其他他的的为为NULLNULL和和0 0。程序分析程序分析(6)(6)窗口过程窗口过程 窗窗口口过过程程是是消消息息处处理理中中心心,一一般般都都包包含含一一个个很很大大的的switchswitch语语句句,用用于于对消息进行分类处理。窗口过程通过对消息进行分类处理。窗口过程通过WNDCLASSWNDCLASS结构中的结构中的lpfnWndProclpfnWndProc成成 员员 和和 窗窗 口口 建建 立立 联联 系系,即即 发发 向向 该该 窗窗 口口 的的 消消 息息 将将 由由lpfnWndP

36、roclpfnWndProc成员指定的函数(窗口过程)进行处理。成员指定的函数(窗口过程)进行处理。窗口过程的定义格式为:窗口过程的定义格式为:LRESULT LRESULT CALLBACK CALLBACK WndProc(HWNDWndProc(HWND hWnd,UINThWnd,UINT message,WPARAMmessage,WPARAM wParam,LPARAMwParam,LPARAM lParamlParam)switch(messageswitch(message)case WM_DESTROY:case WM_DESTROY:PostQuitMessage(0);P

37、ostQuitMessage(0);default:default:return return DefWindowProc(hWnd,message,wParam,lParamDefWindowProc(hWnd,message,wParam,lParam););return 0;return 0;程序分析程序分析(7)(7)窗口过程窗口过程 LRESULT CALLBACK LRESULT CALLBACK WndProcWndProc(HWND HWND hWndMainhWndMain,/,/消息所指向的窗口消息所指向的窗口 UINT Message,/UINT Message,/消息值

38、消息值 WPARAM WPARAM wParamwParam,/,/消息参数消息参数 LPARAM LPARAM lParamlParam /消息参数消息参数 )对窗口过程中没有处理的消息,要调用对窗口过程中没有处理的消息,要调用DefWindowProcDefWindowProc 函函数数让让WindowsWindows进进行行缺缺省省处处理。理。返回返回消息机制消息机制应用程序1窗口函数WndProc消息映射默认窗口函数DefWndowProcApp1消息队列 App2消息队列 App3消息队列 系统队列输入消息系统消息postpostMessageMessageSendSendMessa

39、geMessage消息机制消息机制退出消息退出消息当用户选择 File 菜单的退出 菜单项时,windows 会产生一系列消息,如键盘或鼠标消息,WM_SYSCOMMAND 消息,WM_CLOSE 消息。WM_CLOSE 是一条进队消息,被放入应用程序消息队列中。GetMessage 函数从消息队列中取得 WM_CLOSE 消息,由 DispatchMessage 派送给窗口函数,若窗口函数中没有对 WM_CLOSE 处理的代码,转由缺省窗口函数处理。缺省窗口函数调用 DestroyWindow 函数撤销窗口,并将不进队消息 WM_DESTROY 直接发送给窗口函数,窗口函数处理 WM_DESTROY 时调用函数 void PostQuitMessage(int nExitCode);并产生 WM_QUIT 消息放入消息队列中,其中参数 nExitCode 是应用程序退出代码。GetMessage 函数取得 WM_QUIT 消息后,返回 FALSE,结束消息循环,此时 msg.wParam 中存放的是调用 PostQuitMessage 时的参数,应用程序执行下面语句返回此参数并退出程序。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 其他杂项

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁