• Windows编程入门程序详解


    引用:http://blog.csdn.net/jarvischu/article/details/8115390

    1.     程序

    1. /************************************************************************ 
    2.  * 名  称:Windows_Frist_Code.cpp 
    3.  * 功  能:Windows编程入门 
    4.  * 描  述:包含WinMain函数、WNDCLASS、消息循环等多种内容 
    5.            windows窗口程序的流程如下:【WinMain入口】-->创建和设计窗口类 
    6.         -->注册窗口类-->创建、显示和更新窗口-->消息循环-->【窗口过程函数】 
    7.  * 作  者:JarvisChu 
    8.  * 时  间:2012-10-24 
    9.  * 修  订:1. 2012-10-26,Jarvis. 完善代码和注释。 
    10.  ************************************************************************/  
    11. #include <windows.h>  
    12. #include <stdio.h>  
    13. #include "resource.h"  
    14.   
    15. //回调函数  
    16. LRESULT CALLBACK WinProc(  
    17.                             HWND hwnd,   
    18.                             UINT uMsg,   
    19.                             WPARAM wParam,   
    20.                             LPARAM lParam   
    21. );  
    22.   
    23. //入口函数 WinMain  
    24. int WINAPI WinMain(HINSTANCE hInstance,    //当前应用程序的句柄  
    25.                    HINSTANCE hPrevInstance,//先前应用程序的句柄,总是NULL  
    26.                    LPSTR lpCmdLine,        //不包含程序名的命令行,可通过GetCommandLine获取  
    27.                    int nShowCmd            //窗口显示方式  
    28.                 )  
    29. {  
    30. //-------------------创建和设计窗口类----------------------------------------------------  
    31.     WNDCLASS wndclass;      
    32.     wndclass.cbClsExtra =0;  
    33.     wndclass.cbWndExtra =0;  
    34.     wndclass.hbrBackground =(HBRUSH)GetStockObject(GRAY_BRUSH);  
    35.     wndclass.hCursor =LoadCursor(hInstance,MAKEINTRESOURCE(ID_MYCURSOR));   //LoadCursor(NULL,IDC_HELP);//  
    36.     wndclass.hIcon =LoadIcon(hInstance,MAKEINTRESOURCE(ID_MYICON));         //LoadIcon(NULL,IDI_APPLICATION);//  
    37.     wndclass.hInstance =hInstance;  
    38.     wndclass.lpfnWndProc =WinProc;  
    39.     wndclass.lpszClassName ="Jarvis";  
    40.     wndclass.lpszMenuName =NULL;  
    41.     wndclass.style =CS_HREDRAW | CS_VREDRAW;  
    42.   
    43. //-------------------注册窗口类----------------------------------------------------  
    44.     RegisterClass(&wndclass);  
    45.       
    46. //-------------------创建显示更新窗口----------------------------------------------------  
    47.     HWND hwnd;  
    48.     hwnd=CreateWindow("Jarvis","Jarvis",WS_OVERLAPPEDWINDOW|WS_HSCROLL|WS_MAXIMIZE,  
    49.         CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);  
    50.       
    51.     ShowWindow(hwnd,SW_SHOWNORMAL);  
    52.     UpdateWindow(hwnd);  
    53.   
    54. //-------------------消息循环----------------------------------------------------  
    55.     MSG msg;  
    56.     while(GetMessage(&msg,NULL,0,0))  
    57.     {  
    58.         TranslateMessage(&msg);  
    59.         DispatchMessage(&msg);  
    60.     }  
    61.     return 0;  
    62. }  
    63.   
    64.   
    65. //窗口过程函数实现  
    66. LRESULT CALLBACK WinProc(  
    67.                             HWND hwnd,   
    68.                             UINT uMsg,   
    69.                             WPARAM wParam,   
    70.                             LPARAM lParam   
    71.                             )  
    72. {  
    73.     switch(uMsg)  
    74.     {  
    75.   
    76.     case WM_LBUTTONDOWN:  
    77.         MessageBox(hwnd,"LeftButton Clicked!","Prompt",0);  
    78.         break;  
    79.     case WM_CLOSE:  
    80.         if(IDYES==MessageBox(hwnd,"Are you sure to quit?","Prompt",MB_YESNO))  
    81.         {  
    82.             DestroyWindow(hwnd);  
    83.         }  
    84.         break;  
    85.     case WM_DESTROY:  
    86.         PostQuitMessage(0);  
    87.         break;  
    88.     default:  
    89.         return DefWindowProc(hwnd,uMsg,wParam,lParam);  
    90.           
    91.     }  
    92.     return 0;  
    93. }  

    2.  WinMain函数解析

    2.1.   WinMain函数原型

    1. int WINAPI WinMain ( HINSTANCE hInstance,    //当前应用程序的句柄  
    2.                      HINSTANCE hPrevInstance,//先先前应用程序的句柄,总是NULL  
    3.                      LPSTR lpCmdLine,        //不含程序名的命令行,通过GetCommandLine获取  
    4.              int nShowCmd            //窗口显示方式  
    5.            );  

    2.2.   WinMain函数功能

    WinMain是一个函数,该函数的功能是被系统调用,作为一个32位应用程序的入口点WinMain函数应初始化应用程序,显示主窗口,进入一个消息接收-发送循环,这个循环是应用程序执行的其余部分的顶级控制结构。

    2.3.   窗口显示方式

    WinMain函数的nShowCmd参数指示了窗口的显示方式。显示方式可以是下表中的任何一种。

     

    表格 1 窗口显示方式

    SW_HIDE

    隐藏窗口并且激活另外一个窗口

    SW_RESTORE

    激活并显示窗口。如果窗口已经最小化或最大化,系统将以恢复到原来的尺寸和位置显示窗口(与SW_SHOWNORMAL相同)

    SW_SHOW

    激活一个窗口并以原来的尺寸和位置显示窗口

    SW_SHOWMAXIMIZED

    激活窗口并且将其最大化

    SW_SHOWMINIMIZED

    激活窗口并将其最小化(以图标显示)

    SW_SHOWMINNOACTIVE

    将一个窗口显示为图标。激活窗口维持活动状态

    SW_SHOWNA

    以窗口的当前状态显示窗口。激活窗口保持活动状态

    SW_SHOWNOACTIVATE:

    以窗口的最近一次的尺寸和位置显示窗口。激活窗口维持激活状态

    SW_SHOWNORMAL

    激活并显示窗口。如果窗口最大化或最小化,系统将其恢复到原来的尺寸和位置(与SW_RESTORE相同)

    SW_MINIMIZE

    最小化指定的窗口,并且激活在系统表中的顶层窗口

    3.     创建和设计窗口类

    3.1.   WNDCLASS结构体定义

    1. typedef struct {  
    2.             UINT style;              //窗口类型CS_HREDRAW|CS_VREDRAW  
    3.             WNDPROC lpfnWndProc;     //窗口回调函数  
    4.             int cbClsExtra;          //指定紧随在 WNDCLASS 后分配的字节数,初始化为零  
    5.             int cbWndExtra;          //指定紧随在窗口实例之后分配的字节数,初始化为零。  
    6.             HINSTANCE hInstance;     //指示该窗口类的回调函数所在实例的句柄,不为NULL  
    7.             HICON hIcon;             //窗口图标句柄,若为NULL,系统提供默认  
    8.             HCURSOR hCursor;         //光标资源句柄  
    9.             HBRUSH hbrBackground;    //背景画刷句柄  
    10.             LPCTSTR lpszMenuName;    //菜单资源名  
    11.             LPCTSTR lpszClassName;   //窗口对应的窗口类名  
    12.            } WNDCLASS, *PWNDCLASS; //  

    3.2.   窗口类型

    多种窗口类型可以使用 | 号叠加

    表格 2 窗口类型

    标识

    描述

    CS_BYTEALIGNCLIENT

    在字节边界上(在x方向上)定位窗口的用户区域的位置

    CS_BYTEALIGNWINDOW

    在字节边界上(在x方向上)定位窗口的位置

    CS_CLASSDC:

    窗口类的所有窗口实例都共享一个窗口类DC

    CS_DBLCLKS

    允许向窗口发送双击鼠标键的消息

    CS_GLOBALCLASS

    当调用CreateWindow 或 CreateWindowEx 函数来创建窗口时允许它的hInstance参数和注册窗口类时传递给RegisterClass 的 hInstance参数不同。如果不指定该风格,则这两个 hInstance 必须相同。

    CS_HREDRAW

    当水平长度改变或移动窗口时,重画整个窗口

    CS_NOCLOSE

    禁止系统菜单的关闭选项

    CS_OWNDC

    给予每个窗口实例它本身的DC。注意,尽管这样是很方便,但它必须慎重使用,因为每个DC大约要占800个字节的内存。

    CS_PARENTDC

    将子窗口的裁剪区域设置到父窗口的DC中去,这样子窗口便可以在父窗口上绘制自身。注意,这是子窗口还是从系统缓存中获取DC,而不是使用父窗口的DC。使用该风格可以提高系统性能。

    CS_SAVEBITS

    以位图形式保存被该窗口遮挡的屏幕部分,这样当给窗口移动以后,系统便可以用该保存的位图恢复屏幕移动的相应部分,从而系统不用向被该窗口遮挡的窗口发送 WM_PAINT 消息。该特性对于菜单类型的窗口比较合适,因为它通常是简短的显示一下之后便消失。设置该特性将增加显示该窗口的时间,因为它通常要先分配保存位图的内存。

    CS_VREDRAW

    当垂直长度改变或移动窗口时,重画整个窗口

    3.3.   窗口图标

    3.3.1. LoadIcon函数

    1. HICON  LoadIcon(  HINSTANCE Instance,   //应用程序的实例句柄  
    2.                     LPCTSTR lpIconName   //图标资源的字符串型ID  
    3. ) ;  

    3.3.2. 加载系统预定义图标

    1. LoadIcon(NULL, IDI_APPLICATION);  

     

    表格 3 系统图标资源

     

    IDI_APPLICATION

    Default application icon.

    IDI_ASTERISK

    Same as IDI_INFORMATION.

    IDI_ERROR

    Hand-shaped icon.

    IDI_EXCLAMATION

    Same as IDI_WARNING.

    IDI_HAND

    Same as IDI_ERROR.

    IDI_INFORMATION

    Asterisk icon.

    IDI_QUESTION

    Question mark icon.

    IDI_WARNING

    Exclamation point icon.

    IDI_WINLOGO

    Windows logo icon. Windows XP: Default application icon.

    IDI_SHIELD

    Security Shield icon.

    3.3.3. 加载自定义图标

    [1] 添加图标资源

          File-->New-->Files-->Icon File (Name it “My_Icon.ico” on the right)-->Draw the Icon

    [2] 添加资源文件

         File-->New-->Files-->Resource Script (Name it “My_Resource”)

         打开resource.h 文件,添加语句“#define ID_MYICON 1024”(1024 可以随意)

         用记事本打开My_Resource.rc文件,添加语句“ID_MYICON ICON My_Icon.ico”

    [3] 添加“resource.h”头文件的引用

          在主程序的.cpp文件中,引用头文件“#include “resource.h””

    [4] 使用自定义图标

    1. LoadIcon(hInstance,MAKEINTRESOURCE(ID_MYICON));  

    3.4.   光标资源

    光标资源的加载类似于图标资源

    3.4.1. LoadCursor函数

    1. HCURSOR  LoadCursor (  HINSTANCE Instance,   //应用程序的实例句柄  
    2.                     LPCTSTR lpCursorName      //光标资源的字符串型ID  
    3. ) ;    

    3.4.2. 加载系统预定义光标

    1. LoadCursor(NULL,IDC_CROSS);  

    IDC_APPSTARTING

    Standard arrow and small hourglass

    IDC_ARROW

    Standard arrow

    IDC_CROSS

    Crosshair

    IDC_HAND

    Windows 98/Me, Windows 2000/XP: Hand

    IDC_HELP

    Arrow and question mark

    IDC_IBEAM

    I-beam

    IDC_ICON

    Obsolete for applications marked version 4.0 or later.

    IDC_NO

    Slashed circle

    IDC_SIZE

    Obsolete for applications marked version 4.0 or later. Use IDC_SIZEALL.

    IDC_SIZEALL

    Four-pointed arrow pointing north, south, east, and west

    IDC_SIZENESW

    Double-pointed arrow pointing northeast and southwest

    IDC_SIZENS

    Double-pointed arrow pointing north and south

    IDC_SIZENWSE

    Double-pointed arrow pointing northwest and southeast

    IDC_SIZEWE

    Double-pointed arrow pointing west and east

    IDC_UPARROW

    Vertical arrow

    IDC_WAIT

    Hourglass

    3.4.3. 加载自定义光标

     具体步骤与图标相同(3.3.3

    [1]  resource.h

    [2] My_Resource.rc

    [3] main.cpp

    3.5.   背景画刷

    背景画刷就是用来设置窗口的背景。

    hbrBackground是画刷的句柄,它必须是用于绘制背景的物理刷子的句柄,或者是一个颜色的值。

    如果给出一个颜色的值,它必须是下面列出的标准系统颜色之一(系统将对所选颜色加1)。

    3.5.1. 使用标准系统颜色

    1. hbrBackground=(HBRUSH)(COLOR_ACTIVEBORDER+1);  

                                                                                                                        表格 4 标准系统颜色

    名称

    样式

    名称

    样式

    COLOR_ACTIVEBORDER

    COLOR_ACTIVECAPTION

    COLOR_CAPTIONTEXT

    COLOR_WINDOWTEXT

    COLOR_BTNTEXT

    COLOR_MENUTEXT

    COLOR_APPWORKSPACE

    COLOR_HIGHLIGHTTEXT

    COLOR_BACKGROUND

    COLOR_GRAYTEXT

    COLOR_HIGHLIGHT

    COLOR_INACTIVEBORDER

    COLOR_INACTIVECAPTION

    COLOR_BTNFACE

    COLOR_SCROLLBAR

    COLOR_WINDOWFRAME

    COLOR_MENU

    COLOR_BTNSHADOW

    COLOR_WINDOW

     

    3.5.2. 使用系统预定义的画刷

    1. hbrBackground =(HBRUSH)GetStockObject(BLACK_BRUSH);  

    BRUSH

    名称

    BLACK_BRUSH                                      

    黑色画刷

    DKGRAY_BRUSH

    暗灰色画刷

    DC_BRUSH

    (Win7中错误)

    GRAY_BRUSH 

    灰色画刷

    HOLLOW_BRUSH 

    空心刷(相当于NULL_BRUSH)

    LTGRAY_BRUSH         

    浅灰色画刷

    NULL_BRUSH           

    空心刷(即背景透明)

    WHITE_BRUSH             

    白色画刷

    3.5.3. GetStockObject()函数

    1. HGDIOBJ GetStockObject(int fnObject);  

    该函数检索预定义的备用笔、刷子、字体或者调色板的句柄。

    fnObject可以是: BLACK_BRUSH,WHITE_PEN,SYSTEM_FONT, DEFAULT_PALETTE

    4.     注册窗口类

    1. ATOM RegisterClass(CONST WNDCLASS *lpWndClass);  

    窗口只有在其对应的窗口类注册之后,才能使用CreateWindow或CreateWindowEx创建。

    5.     创建窗口

    1. HWND hwnd;  
    2. hwnd = CreateWindow("Jarvis","Jarvis",WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,  
    3. CW_USEDEFAULT,NULL,NULL,hInstance,NULL);  
    1. HWND CreateWindow(             
    2.      LPCTSTR            lpClassName,   // 对应的窗口类的名称  
    3.             LPCTSTR             lpWindowName, //窗口名称  
    4.             DWORD              dwStyle,       / /窗口类型/  
    5.          int                   x,            //初始水平位置  
    6.             int                   y,             //初始垂直位置   
    7.         int                   nWidth,        //窗口宽度  
    8.          int                   nHeight,       //窗口高度  
    9.          HWND               hWndParent,   //父窗口句柄  
    10.             HMENU              hMenu,        //菜单资源句柄  
    11.             HINSTANCE          hInstance,      //实例句柄  
    12.          LPVOID              lpParam       //传给WM_CREATE的值  
    13. );   

     Window_Style(可以组合)

    表格 5 Window_Style

    Style

    说明

    WS_BORDER

    创建一个单边框的窗口。

    WS_CAPTION

    创建一个有标题框的窗口(包括WS_BODER风格)。

    WS_CHILD

    创建一个子窗口。这个风格不能与WS_POPUP风格合用。

    WS_CHLDWINDOW

    与WS_CHILD相同。

    WS_CLIPCHILDREN

    当在父窗口内绘图时,排除子窗口区域。在创建父窗口时使用这个风格。

    WS_CLIPSIBLINGS

    排除子窗口之间的相对区域,也就是,当一个特定的窗口接收到WM_PAINT消息时,WS_CLIPSIBLINGS 风格将所有层叠窗口排除在绘图之外,只重绘指定的子窗口。如果未指定WS_CLIPSIBLINGS风格,并且子窗口是层叠的,则在重绘子窗口的客户区时,就会重绘邻近的子窗口。

    WS_DISABLED

    创建一个初始状态为禁止的子窗口。一个禁止状态的窗口不能接受来自用户的输入信息。

    WS_DLGFRAME

    创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条。

    WS_GROUP

    指定一组控制的第一个控制。这个控制组由第一个控制和随后定义的控制组成,自第二个控制开始每个控制,具有WS_GROUP风格,每个组的第一个控制带有WS_TABSTOP风格,从而使用户可以在组间移动。用户随后可以使用光标在组内的控制间改变键盘焦点。

    WS_HSCROLL

    创建一个有水平滚动条的窗口。

    WS_ICONIC

    创建一个初始状态为最小化状态的窗口。与WS_MINIMIZE风格相同。

    WS_MAXIMIZE

    创建一个初始状态为最大化状态的窗口。

    WS_MAXIMIZEBOX

    创建一个具有最大化按钮的窗口。该风格不能与WS_EX_CONTEXTHELP风格同时出现,同时必须指定WS_SYSMENU风格。

    WS_OVERLAPPED

    产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与WS_TILED风格相同。

    WS_OVERLAPPEDWINDOW

    创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXIMIZEBOX风格的层叠窗口,与WS_TILEDWINDOW风格相同。

    WS_POPUP

    创建一个弹出式窗口。该风格不能与WS_CHLD风格同时使用。

    WS_POPUPWINDOW

    创建一个具有WS_BORDER,WS_POPUP,WS_SYSMENU风格的窗口,WS_CAPTION和WS_POPUPWINDOW必须同时设定才能使窗口某单可见。

    WS_SIZEBOX

    创建一个可调边框的窗口,与WS_THICKFRAME风格相同。

    WS_SYSMENU

    创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格。

    WS_TABSTOP

    创建一个控制,这个控制在用户按下Tab键时可以获得键盘焦点。按下Tab键后使键盘焦点转移到下一具有WS_TABSTOP风格的控制。

    WS_THICKFRAME

    创建一个具有可调边框的窗口,与WS_SIZEBOX风格相同。

    WS_TILED

    产生一个层叠的窗口。一个层叠的窗口有一个标题和一个边框。与WS_OVERLAPPED风格相同。

    WS_TILEDWINDOW

    创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU, WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXMIZEBOX风格的层叠窗口。与WS_OVERLAPPEDWINDOW风格相同。

    WS_VISIBLE

    创建一个初始状态为可见的窗口。

    WS_VSCROLL

    创建一个有垂直滚动条的窗口。

    6.     显示窗口

    1. BOOL ShowWindow(HWND hWnd,     //窗口句柄  
    2.                  int nCmdShow   //显示方式  
    3.                 );  

    显示方式可以是下表中的任何一种。

    表格 6 窗口显示方式

    窗口显示方式

    说明

    SW_HIDE

    隐藏窗口并激活其他窗口。

    SW_MAXIMIZE

    最大化指定的窗口。

    SW_MINIMIZE

    最小化指定的窗口并且激活在Z序中的下一个顶层窗口。

    SW_RESTORE

    激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。在恢复最小化窗口时,应用程序应该指定这个标志。

    SW_SHOW

    在窗口原来的位置以原来的尺寸激活和显示窗口。

    SW_SHOWDEFAULT

    依据在STARTUPINFO结构中指定的SW_FLAG标志设定显示状态,STARTUPINFO 结构是由启动应用程序的程序传递给CreateProcess函数的。

    SW_SHOWMAXIMIZED

    激活窗口并将其最大化。

    SW_SHOWMINIMIZED

    激活窗口并将其最小化。

    SW_SHOWMINNOACTIVE

    窗口最小化,激活窗口仍然维持激活状态。

    SW_SHOWNA

    以窗口原来的状态显示窗口。激活窗口仍然维持激活状态。

    SW_SHOWNOACTIVATE

    以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态。

    SW_SHOWNORMAL

    激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小。应用程序在第一次显示窗口的时候应该指定此标志。

    7.     更新窗口

     如果窗口更新的区域不为空,UpdateWindow函数通过发送一个WM_PAINT消息来更新指定窗口的客户区。函数绕过应用程序的消息队列,直接发送WM_PAINT消息给指定窗口的窗口过程,如果更新区域为空,则不发送消息。

    8.     消息循环

    1. MSG msg;  
    2. while (GetMessage(&msg,NULL,0,0))     //从消息队列中取得一条消息  
    3. {  
    4.     TranslateMessage(&msg);       //将虚拟键消息转化成字符消息     
    5.     DispatchMessage(&msg);        //将消息发送给相应的窗口过程函数  
    6. }//  

    8.1.   MSG 结构体

    MSG结构体包含一条WindowMessage的全部信息

    1. typedef struct  tagMSG {                 //msg  
    2.                         HWND hwnd;       //接受消息循环的窗口句柄  
    3.             UINT message;    //消息类型  
    4.             WPARAM wParam;   //附加信息  
    5.             LPARAM lParam;   //附加信息  
    6.             DWORD time;      //投递到消息队列的时间  
    7.             POINT pt;        //鼠标的位置  
    8.                }MSG; //  

    8.2.   自定义MSG

    参见博文:MFC程序最小化到系统托盘区的一个简单实例

    9.     窗口过程

    窗口过程函数是一个应用程序定义的函数,用来处理发送到窗口的消息。WNDPROC类型定义了一个指向该回调函数的指针。WindowProc是用于应用程序定义函数的占位符,也就是说,程序员自己更改WindowProc这个名称,但是参数类型不变。

    一个Windows 程序可以包含多个窗口过程。一个窗口过程总是与调用RegisterClass注册的特定窗口类相关联。程序通常不直接调用窗口过程。窗口过程通常由 Windows 本身调用。通过调用 SendMessage 函数,程序能够直接调用它自己的窗口过程。

    9.1.   函数声明

    1. LRESULT CALLBACK WindowProc(        
    2.                          HWND   hwnd,   //指向窗口的句柄  
    3.              UINT   uMsg,   //指定消息类型  
    4.              WPARAM wParam, //指定其余的、消息特定的信息  
    5.                          LPARAM lParam  //指定其余的、消息特定的信息  
    6. );  

    9.2.   函数功能

    该函数主要是用来处理发送给窗口的各类MSG消息。

    窗口过程在处理消息时,必须返回0。

    窗口过程不予处理的所有消息应该被传给名为DefWindowProc() 函数。

    从 DefWindowProc 返回的值必须由窗口过程返回。

    本文部分内容来自MSDN和网络。

    转载请注明地址:

    JarvisChu的专栏

  • 相关阅读:
    2、Azure Devops之Azure Boards使用
    1、Azure Devops之什么是Azure DevOps
    MongoDB学习笔记
    首页面作成(二)
    首页面作成(一)
    统计报表的作成(一)
    外派人员责任险项目作成总结
    Hibernate对象的状态
    Javaweb权限管理设计思路
    Ajax详解
  • 原文地址:https://www.cnblogs.com/sode/p/3335315.html
Copyright © 2020-2023  润新知