走进windows编程的世界-----窗口的注册及创建

来源:互联网 发布:java ioc框架 编辑:程序博客网 时间:2024/06/10 07:26

1   窗口注册和创建

1.1WIN32 窗口程序创建步骤

1、WinMain入口函数的定义

2、WindowProc函数的定义

3、注册窗口类

RegisterClass、RegisterClassEX

4、创建窗口

CreateWindow、CreateWindowEx

HWND CreateWindow(    

    LPCTSTRlpClassName,//指向已注册的窗口类的名称的指针

    LPCTSTRlpWindowName,//指向窗口名称的指针

    DWORDdwStyle,//窗口的风格

    intx,//窗口位置的X坐标

    inty,//窗口位置的Y坐标

    intnWidth,//窗口的宽度

    intnHeight,//窗口的高度

    HWNDhWndParent,//父窗口的句柄

    HMENUhMenu,//窗口菜单句柄

    HINSTANCEhInstance,//应用程序使用句柄

    LPVOIDlpParam//应用程序数据区句柄

);

参数:

lpClassName

一个指向以零结尾的字符串的指针,或者指向以前由RegisterClassRegisterClassEx条用创建的原子的指针。这个原子必须是次参数的低位,高位必须是0。如果是一个字符串,它指定窗口类的名称。类名可以是用RegisterClassRegisterClassEx注册过的任何名称,providedthat themodule that registers the class is also the module thatcreates the window.类名称也可以是任何预定义的系统类名称。

lpWindowName

指向指定窗口名称的以零结尾的字符串的指针。如果窗口的风格指定了一个标题栏,则它将会显示在标题栏上。当使用CreateWindow创建控件时,此参数指定控件的文字。当用SS_ICON风格创建static控件时,此参数指定图标的名称或者标识符。要指定一个标识符,使用”#num”语法。

dwStyle

指定要创建窗口的风格。可以是窗口风格的组合,加上控件的风格的组合。

x

指定窗口的初始水平位置。对于overlapped或者弹出式窗口,x参数是初始的x坐标相当窗口的左上角,在屏幕坐标系上。Fora childwindow, x is the x-coordinate of the upper-left corner ofthe window relative tothe upper-left corner of the parent window'sclientarea.如果参数值被设置为CW_USEDEFAULT,系统为窗口左上角选择默认的位置并忽略y参数。CW_USEDEFAULT仅对overlapped窗口有效,如果它在弹出窗口或者自窗口上被指定,则xy参数被设置为零。

y

指定窗口的初始化垂直位置。对于交叠式窗口或者弹出式窗口,y参数是在屏幕坐标上初始的窗口左上角的y坐标。对于子窗口,y是和父窗口客户区左上角相关的初始子窗口左上角的y坐标。对于listbox控件,y是和父窗口客户区左上角相关的listbox客户区初始的左上角的y坐标。如果用WS_VISIBLE风格创建一个overlapped窗口并且x参数设置为CW_USEDEFAULT,系统忽略y参数。

nWidth

用设备单位指定窗口的宽度。对于overlapped窗口,nWidth参数既可以是在屏幕坐标上窗口的宽度,也可以是CW_USEDEFAULT.如果nWidthCW_USEDEFAULT,系统选择一个默认的宽度和高度,这个默认的宽度从初始的x坐标到屏幕的右边缘,默认的高度从y坐标到图标区的顶端。CW_USEDEFAULT仅对overlapped窗口可用,如果对子窗口或者弹出窗口设置了CW_USEDEFAULT,则nWidthnHeight被设置为0

nHeight

指定窗口的高度用设备单位。对于overlapped窗口,nHeight是在屏幕坐标上窗口的高度。如果nWidth被设置为CW_USEDEFAULT,系统忽略nHeight

 

hWndParent

指向被创建窗口的父窗口或者所有者窗口的句柄。要创建一个子窗口或者一个被所有的窗口,提供一个有效的窗口句柄。这个参数对于弹出式窗口是可选的。

hMenu

菜单句柄,或者指定一个依靠窗口风格的子窗口标识符。对于overlapped窗口或者弹出式窗口,hMenu识别窗口要使用的菜单。可以是NULL如果使用类的菜单。对于子窗口,hMenu指定自窗口的标识符,一个用来通知父窗口对话框控件的事件的整数。程序决定子窗口的标识,他对于相同父窗口的所有子窗口必须是唯一的。

hInstance

Windows95/98/Me: 和这个窗口有关系的模块的实例句柄。

WindowsNT/2000/XP: 此值被忽略。

lpParam

[in]Pointer to a value to be passed to the window through theCREATESTRUCT structurepassed in the lpParam parameter theWM_CREATE message. 如果一个程序通过调用CreateWindow创建多文档界面的客户窗口。lpParam必须指向一个CLIENTCREATESTRUCT结构。


5、窗口的显示和刷新

ShowWindow、 UpdateWindow

6、消息处理

GetMessage、 DispatchMessage

7、窗口退出

WM_DESTROY、

1.2窗口的注册

1.2.1窗口类的分类

1、  系统全局窗口类,比如按钮(BUTTOn),文本编辑框(EDITed)等

2、  应用程序的全局窗口类。可以在一个应用程序中EXE、DLL等所有模块中使用的窗口类。

3、  局部窗口类。只能在本模块中使用的窗口类。

1.2.2实现窗口类的注册

1、  系统全局的窗口类,无需注册直接使用

使用CreateWindow函数,在CLASSNAME中指定系统已经定义好的窗口类型名称即可。

下面创建一个BUtton或者EDIt窗口

/*File : botton.cpp *Auth : sjin *Date : 20140618 *Mail : 413977243@qq.com *//*窗口的创建的练习*/#include <Windows.h>#include <WinNT.h>HINSTANCE g_hInst = NULL; /*窗口处理函数*/LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg,WPARAM wParam,LPARAM iParam){return DefWindowProc(hWnd,nMsg,wParam,iParam);}/*创建BUTTON*/HWND CreateButton(){/*BUTTOn */#if 0HWND hWnd = CreateWindow("BUTTON","My first button test",WS_OVERLAPPEDWINDOW,0,0,100,150,NULL,NULL,g_hInst,NULL);#elseHWND hWnd = CreateWindow("EDIT","My first button test",WS_OVERLAPPEDWINDOW,0,0,100,150,NULL,NULL,g_hInst,NULL);#endifreturn hWnd;}/*注册*/BOOL RegisterWnd(LPSTR pszClassName){WNDCLASSEX hWnd = {'\0'};hWnd.cbSize = sizeof(hWnd);hWnd.style  = CS_VREDRAW | CS_HREDRAW;hWnd.lpfnWndProc = WndProc;hWnd.cbClsExtra = 0;hWnd.cbWndExtra = 0;hWnd.hCursor = NULL;hWnd.hIcon = NULL;hWnd.hbrBackground = HBRUSH(COLOR_BTNFACE +1);hWnd.lpszClassName = pszClassName;hWnd.hInstance = g_hInst;ATOM  nAtom = RegisterClassEx(&hWnd);if( 0 == nAtom) {return FALSE;}return TRUE;}/*显示窗口*/void DisplayButton(HWND hwnd){ShowWindow(hwnd,SW_SHOW);UpdateWindow(hwnd);}void Message(){MSG msg = {0};while(GetMessage(&msg,NULL,0,0)){/*文本框可输入*/TranslateMessage(&msg);DispatchMessage(&msg);}}/*入口函数*/int WINAPI WinMain(HINSTANCE hInst,HINSTANCE  hPrevInst,LPSTR  pszCmcLine,int nShowCmd){g_hInst = hInst;HWND hwnd = CreateButton();RegisterWnd("");DisplayButton(hwnd);Message();return 0;}


2、  应用程序全局窗口类,需要用代码实现注册,在注册时需要增加CS_CLOBALCLASS(各个模块中都能够使用的)定义的实现方式:

WNDCLASS wc = {'\0'};

 

wc.style          = CS_CLOBALCLASS |CS_HREARAW;

RegisterClass(&wc);

下面的例子基本都是一样的

3、  局部窗口类,不是增加CS_CLOBALCLASS定义

使用RegisterClass、RegisterClassEX来注册

/*File : winreg.cpp *Auth : sjin *Date : 20140619 *Mail : 413977243@qq.com *//*窗口的创建的练习*/#include <Windows.h>#include <WinNT.h>HINSTANCE g_hInst = NULL; /*窗口处理函数*/LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg,WPARAM wParam,LPARAM iParam){return DefWindowProc(hWnd,nMsg,wParam,iParam);}/*创建window*/HWND Createwindow(LPSTR pszClassName){HWND hWnd = CreateWindow(pszClassName,"My first wondow test",WS_OVERLAPPEDWINDOW,0,0,100,150,NULL,NULL,g_hInst,NULL);return hWnd;}/*注册*/BOOL RegisterWnd(LPSTR pszClassName){WNDCLASSEX hWnd = {'\0'};hWnd.cbSize = sizeof(hWnd);hWnd.style  = CS_VREDRAW | CS_HREDRAW;hWnd.lpfnWndProc = WndProc;hWnd.cbClsExtra = 0;hWnd.cbWndExtra = 0;hWnd.hCursor = NULL;hWnd.hIcon = NULL;hWnd.hbrBackground = HBRUSH(COLOR_BTNFACE +1);hWnd.lpszClassName = pszClassName;hWnd.hInstance = g_hInst;ATOM  nAtom = RegisterClassEx(&hWnd);if( 0 == nAtom) {return FALSE;}return TRUE;}/*显示窗口*/void DisplayWnd(HWND hwnd){ShowWindow(hwnd,SW_SHOW);UpdateWindow(hwnd);}void Message(){MSG msg = {0};while(GetMessage(&msg,NULL,0,0)){/*文本框可输入*/TranslateMessage(&msg);DispatchMessage(&msg);}}/*入口函数*/int WINAPI WinMain(HINSTANCE hInst,HINSTANCE  hPrevInst,LPSTR  pszCmcLine,int nShowCmd){g_hInst = hInst;RegisterWnd("MYWIN");HWND hwnd = Createwindow("MYWIN");DisplayWnd(hwnd);Message();return 0;}

注:上面程序中存在一个问题,就是程序关闭后,并没有完全退出,还在后台运行,问了解决这个问题,需要在窗口处理函数做以下的修改:

/*窗口处理函数*/LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg,WPARAM wParam,LPARAM iParam){switch(nMsg){case WM_DESTROY:/*增加这个程序可以正常的退出*/PostQuitMessage(0);break;}return DefWindowProc(hWnd,nMsg,wParam,iParam);}

1.1.1窗口类风格

CS_HREDRAW 窗口水平变化,重新绘制窗口。

CS_VREDRAW 窗口垂直变化,重新绘制窗口。

CS_DBCLICK 窗口可以接收鼠标双击消息

CS_GLOBALCLASS 创建应用程序全局窗口类。

CS_BYTEALIGNWINDOW 窗口对齐方式,以8的倍数对齐

CS_BYTEALIGNCLIENT 窗口客户区对齐方式,以8的倍数对齐

 CS_CLASSDC 所有这种类型的窗口使用同一个DC(设备描述表,绘图使用)

 CS_OWNDC 每个窗口拥有自己的DC

CS_PARENTDC 使用父窗口的DC

            CS_SAVEBITS是用位图保存窗口界面,可以提高窗口界面的刷新性能CS_NOCLOSE 禁止关闭命令

1.1.2窗口类的附加数据 cbClsExtra

在窗口类的数据信息中可以添加自己的信息

cbClsExtra 用于添加信息的内存的大小。

SetClassLong 将信息保存到内存中

GetClassLong 将信息从内存中取出

1.1.3窗口附加数据cbWndExtra

在窗口的数据信息中可以添加自己的信息

cbWndExtra 用于添加信息的内存的大小。

SetWindowLong 将信息保存到内存中

GetWindowLong 将信息从内存中取出

下面代码示例:

/*File : winreg.cpp *Auth : sjin *Date : 20140619 *Mail : 413977243@qq.com *//*窗口的创建的练习*/#include <Windows.h>#include <WinNT.h>#include <stdio.h>HINSTANCE g_hInst = NULL; /*窗口处理函数*/LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg,WPARAM wParam,LPARAM iParam){switch(nMsg){case WM_DESTROY:/*增加这个程序可以正常的退出*/PostQuitMessage(0);break;}return DefWindowProc(hWnd,nMsg,wParam,iParam);}/*创建window*/HWND Createwindow(LPSTR pszClassName){HWND hWnd = CreateWindow(pszClassName,"My first wondow test",WS_OVERLAPPEDWINDOW,0,0,100,150,NULL,NULL,g_hInst,NULL);return hWnd;}/*注册*/BOOL RegisterWnd(LPSTR pszClassName){WNDCLASSEX hWnd = {'\0'};hWnd.cbSize = sizeof(hWnd);/*     *      *CS_HREDRAW 窗口水平变化,重新绘制窗口。     *CS_VREDRAW 窗口垂直变化,重新绘制窗口。     *CS_DBCLICK 窗口可以接收鼠标双击消息     *CS_GLOBALCLASS 创建应用程序全局窗口类。     *CS_BYTEALIGNWINDOW 窗口对齐方式,以8的倍数对齐     *CS_BYTEALIGNCLIENT 窗口客户区对齐方式,以8的倍数对齐     *CS_CLASSDC 所有这种类型的窗口使用同一个DC(设备描述表,绘图使用) *CS_OWNDC 每个窗口拥有自己的DC     *CS_PARENTDC 使用父窗口的DC     *CS_SAVEBITS 是用位图保存窗口界面,可以提高窗口界面的刷新性能     *CS_NOCLOSE 禁止关闭命令. */hWnd.style  = CS_VREDRAW | CS_HREDRAW;hWnd.lpfnWndProc = WndProc;hWnd.cbClsExtra = 100;hWnd.cbWndExtra = 100;hWnd.hCursor = NULL;hWnd.hIcon = NULL;hWnd.hbrBackground = HBRUSH(COLOR_BTNFACE +1);hWnd.lpszClassName = pszClassName;hWnd.hInstance = g_hInst;ATOM  nAtom = RegisterClassEx(&hWnd);if( 0 == nAtom) {return FALSE;}return TRUE;}/*显示窗口*/void DisplayWnd(HWND hwnd){ShowWindow(hwnd,SW_SHOW);UpdateWindow(hwnd);}void Message(){MSG msg = {0};while(GetMessage(&msg,NULL,0,0)){/*文本框可输入*/TranslateMessage(&msg);DispatchMessage(&msg);}}/*设置附加数据*/void SetExtra(HWND hWnd){SetClassLong(hWnd,1,100);SetWindowLong(hWnd,1,200);}/*获取附加数据*/void GetExtra(HWND hWnd){DWORD nClass = GetClassLong(hWnd,1);DWORD nWnd =  GetWindowLong(hWnd,1);char szText[256]= {0};sprintf(szText,"CLS:%d WND:%d",nClass,nWnd);MessageBox(NULL,szText,"EXTRA",MB_OK);}/*入口函数*/int WINAPI WinMain(HINSTANCE hInst,HINSTANCE  hPrevInst,LPSTR  pszCmcLine,int nShowCmd){g_hInst = hInst;RegisterWnd("MYWIN");HWND hwnd = Createwindow("MYWIN");HWND hwnd2 = Createwindow("MYWIN");SetExtra(hwnd);GetExtra(hwnd);GetExtra(hwnd2);DisplayWnd(hwnd);Message();return 0;}


1.1创建窗口

1.1.1窗口创建函数

CreateWindow/CreateWindowEx

      HWND CreateWindowEx(

                  DWORD dwExStyle,//窗口的扩展样式

                  LPCTSTR lpClassName,  // pointer to registered class name

                  LPCTSTR lpWindowName, //pointer to window name

                  DWORD dwStyle,        // window style

                  int x,                // horizontal position ofwindow

                  int y,                // vertical position of window

                  int nWidth,           // window width

                  int nHeight,          // window height

                  HWND hWndParent,      // handle to parent or owner window

                  HMENU hMenu,          // handle to menu, or child-windowidentifier

                  HINSTANCE hInstance,  // handle to application instance

                  LPVOID lpParam );     // pointer to window-creation data

1.1.2窗口的风格及扩展风格

 窗口风格: WS_XXXX定义的风格,是窗口的基本风格.

 扩展风格:WS_EX_XXXXX 定义的风格,是窗口的扩展风格.比如: ToolWindow窗口等等。

 在CreateWindow可以使用基本窗口风格,扩展的窗口风格,需要使用CreateWindowEx设置.    
 WS_OVERLAPPED窗口,层叠式窗口
   WS_POPUP窗口,弹出式窗口
   WS_CHILD窗口,子窗口

1.1.3子窗口和父窗口

CreateWindow时,指定父窗口

将窗口的风格增加WS_CHILD      

可以使用SetParent和GetParent函数设置和获取指定窗口的父窗口.

其他: MoveWindow 移动窗口

下面是关于父子窗口的示例

/* File : createWindow.cpp * Auth : sjin * Date : 20140623 * Mail : 413977243@qq.com */#include <Windows.h>#include <stdio.h>HINSTANCE g_hInst = NULL;/*父窗口处理函数*/LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg,                          WPARAM wParam, LPARAM lParam){    switch(nMsg) {    case WM_DESTROY: PostQuitMessage(0);        return 0;    }    return DefWindowProc(hWnd, nMsg, wParam, lParam);}/*子窗口处理函数*/LRESULT CALLBACK ChildProc(HWND hWnd, UINT nMsg,                          WPARAM wParam, LPARAM lParam){    return DefWindowProc(hWnd, nMsg, wParam, lParam);}/*注册窗口*/BOOL RegisterWnd(LPSTR pszClassName,WNDPROC proc,int nBrush){    WNDCLASSEX wce = {0};    wce.cbSize = sizeof(wce);    wce.style = CS_VREDRAW|CS_HREDRAW;    wce.lpfnWndProc = proc;    wce.cbClsExtra = 100;    wce.cbWndExtra = 100;    wce.hCursor = NULL;    wce.hIcon = NULL;    wce.hbrBackground = HBRUSH(nBrush);    wce.lpszClassName = pszClassName;    wce.lpszMenuName = NULL;    wce.hInstance = g_hInst;    ATOM nAtom = RegisterClassEx(&wce);    if(0 == nAtom)    {        MessageBox(NULL, "registerError", "Error", MB_OK);        return FALSE;    }    return TRUE;}/*创建窗口*/HWND CreateWnd(LPSTR pszClassName,HWND hParent,DWORD dwStyle){HWND hWnd = CreateWindowEx(0,                    /*窗口扩展风格*///WS_EX_TOOLWINDOW,   /*没有扩大和隐藏按钮*///WS_EX_CLIENTEDGE | WS_EX_CONTEXTHELP,//WS_EX_PALETTEWINDOW,/**/pszClassName,        "My Wnd",dwStyle, CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,        hParent, NULL, g_hInst, NULL);    return hWnd;}/*显示窗口*/void DisplayWnd(HWND hWnd){    ShowWindow(hWnd, SW_SHOW);    UpdateWindow(hWnd);}/*消息*/void Message(){    MSG msg = {0};    while(GetMessage(&msg, NULL, 0, 0))    {        TranslateMessage(&msg);        DispatchMessage(&msg);    }}int WINAPI WinMain(HINSTANCE hInst,                   HINSTANCE hPrevInt,                   LPSTR lpCmdLine,                   int nShowCmd){    g_hInst = hInst;/*注册父窗口*/RegisterWnd("parent",WndProc,COLOR_BTNFACE + 1); /*注册子窗口*/RegisterWnd("Child",ChildProc,COLOR_WINDOW);/*注册子窗口*/RegisterWnd("Child1",ChildProc,COLOR_WINDOW);/*创建父窗口  * 注意 窗口类的名称必须和注册时的名字一样,否则显示不了窗口 */HWND hMyWnd1 = CreateWnd("parent",NULL,WS_OVERLAPPEDWINDOW);/*创建子窗口*/HWND hChild = CreateWnd("Child",hMyWnd1,WS_CHILD| WS_VISIBLE|WS_BORDER|WS_THICKFRAME|WS_CAPTION|WS_SYSMENU);HWND hChild1 = CreateWnd("Child1",hMyWnd1,WS_CHILD| WS_VISIBLE|WS_BORDER|WS_THICKFRAME|WS_CAPTION|WS_SYSMENU);/*移动窗口*/MoveWindow(hChild,100,100,100,100,TRUE);/*移动窗口*/MoveWindow(hChild1,100,200,100,100,TRUE);    DisplayWnd(hMyWnd1);    Message();    return 0;}

MDI 窗口创建

/* File : mdiWindows.c * Auth : sjin * Date : 20140625 * Mail : 413977243@qq.com */#include <Windows.h>#include <stdio.h>HINSTANCE g_hInst = NULL;HWND g_hMDIClient = NULL;/*主窗口处理函数*/LRESULT CALLBACK MainProc(HWND hWnd,UINT nMsg,WPARAM wParam,LPARAM lParam){switch(nMsg){case WM_DESTROY:PostQuitMessage(0);return 0;}return DefFrameProc(hWnd,g_hMDIClient,nMsg,wParam,lParam);}/*子窗口处理函数*/LRESULT CALLBACK ChildProc(HWND hWnd,UINT nMsg,WPARAM wParam,LPARAM lParam){return DefMDIChildProc(hWnd,nMsg,wParam,lParam);}/*窗口注册函数*/BOOL RegisterWnd(LPSTR pszClassname,WNDPROC Proc,int nBrush){WNDCLASSEX wce = {0};    wce.cbSize = sizeof(wce);    wce.style = CS_VREDRAW|CS_HREDRAW;    wce.lpfnWndProc = Proc;    wce.cbClsExtra = 100;    wce.cbWndExtra = 100;    wce.hCursor = NULL;    wce.hIcon = NULL;    wce.hbrBackground = HBRUSH(nBrush);    wce.lpszClassName = pszClassname;    wce.lpszMenuName = NULL;    wce.hInstance = g_hInst;wce.hIconSm = NULL;    ATOM nAtom = RegisterClassEx(&wce);    if(0 == nAtom)    {        MessageBox(NULL, "registerError", "Error", MB_OK);        return FALSE;    }    return TRUE;}/*创建主窗口*/HWND createMainWnd(LPSTR pszClassName){HWND hWnd = CreateWindowEx(0,pszClassName,"MainWnd",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,g_hInst,NULL);return hWnd;}/*创建MDICLIENT窗口*/HWND createMdiClient(HWND hParent){/*创建时附件的数据 * MDICLIENT时必须的 */CLIENTCREATESTRUCT cs = {'\0'};cs.idFirstChild = 1000;/*ID号*/HWND hWnd = CreateWindowEx(0,"MDICLIENT","MainWnd",WS_CHILD|WS_VISIBLE,0,0,500,500,hParent,NULL,g_hInst,&cs);return hWnd;}/**/HWND createChildWnd(HWND hParent,LPSTR pszClassName){HWND hWnd = CreateWindowEx(WS_EX_MDICHILD,pszClassName,"ChildWnd",WS_CHILD|WS_VISIBLE,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,hParent,NULL,g_hInst,NULL);return hWnd;}/*显示窗口*/void DisplayWnd(HWND hWnd){ShowWindow(hWnd,SW_SHOW);UpdateWindow(hWnd);}/*消息处理*/void Message(){MSG msg = {'\0'};while(GetMessage(&msg,NULL,0,0)){DispatchMessage(&msg);}}/*main*/int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE  hPrevINstance,LPSTR lpCmdLine,int ShowCmd){/*注册窗口*/RegisterWnd("MainWnd",MainProc,COLOR_BTNFACE + 1);RegisterWnd("ChildWnd",ChildProc,COLOR_WINDOW);/*创建MDI主窗口*/HWND hMain = createMainWnd("MainWnd");/*创建MDICLIENT窗口*/HWND hMdiClient = createMdiClient(hMain);//MoveWindow(hMdiClient,0,0,500,500,TRUE);/*创建MDI子窗口*/HWND hChild =  createChildWnd(hMdiClient,"ChildWnd");/*显示和消息处理*/DisplayWnd(hMain);Message();return 0;}


3 0