zoukankan      html  css  js  c++  java
  • [置顶] 《Windows编程零基础》__2 一个完整的程序

    Windows开发的常识

    1)窗口

    Windows中最基本的概念也许就是窗口了,每一个前台程序都至少有一个窗口,一个窗口也是你可以看到的部分,比如,QQ有如下的登录窗口
    基本上你在Windows中可见的都是一个窗口,窗口也是Windows中用于用户直接交互的基本元素(GUI程序)。

    2)句柄

    窗口、文件、socket、信号量、管道、邮槽(mailslot)……都是Windows平台中的基本对象,为了操作这些对象,我们需要一个能够引用这些对象的东西,这个引用这些对象的东西就是句柄(Handle)。句柄对于资源就像遥控器对于电视机,用遥控器能更好地操作电视机而不用关心内部实现的细节,句柄也是这样的,用句柄你能更好地操作Windows对象,而不需要关系其内部的实现细节。事实上,你想操作Windows对象也只能通过句柄操作。比如,你想操作一个线程,你看看SuspendThread的原型如下所示:(第一个参数就是一个线程句柄)
    Syntax
    DWORD WINAPI SuspendThread(
      __in  HANDLE hThread
    );
    
    又比如,你想读一个文件,其函数ReadFile的原型如下:( 第一个参数就是一个文件的句柄。)
    BOOL WINAPI ReadFile(
      __in         HANDLE hFile,
      __out        LPVOID lpBuffer,
      __in         DWORD nNumberOfBytesToRead,
      __out_opt    LPDWORD lpNumberOfBytesRead,
      __inout_opt  LPOVERLAPPED lpOverlapped
    );
    
    …………类似的例子还有很多,基本上想操作Windows对象都需要指向它们的句柄,句柄在语义上与C中的 指针一样,但是,语法上是完全不一样的。

    3)进程

    一些操作系统教材上对进程的定义为:进程是一个程序的一次运行过程。这个定义其实是对的,但是,也是错的,为什么呢?在Windows之前还有许多其它的操作系统,比如OS 360、UNIX……进程的概念提出来的时候Windows 还根本没出生呢。不过,在Windows中,进程的概念完全不是这样的,在Windows里面,进程是程序隔离的基本单元,每一个32位应用程序在自己的进程空间里面运行,进程只为这个程序提供4G的虚拟地址空间,并且,不同的进程之间互相不干扰(当然,后面会讲到,进程之间会通信)。

    4)线程

    在Windows里面,真正运行程序的其实是线程,线程在进程提供的4G虚拟地址空间里面运行,它执行PE文件的.text段。也就是说,线程才是真正的执行体。

    基本的正常的Windows程序

    代码

    创建一个工程,还是按照上次的方法,在上一节里面有,然后输入以下代码:
    #include <windows.h>
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
    {
        static TCHAR szAppName[] = TEXT ("BossJue");
        HWND         hwnd;
        MSG          msg;
        WNDCLASSEX   wndclassex = {0};
        wndclassex.cbSize        = sizeof(WNDCLASSEX);
        wndclassex.style         = CS_HREDRAW | CS_VREDRAW;
        wndclassex.lpfnWndProc   = WndProc;
        wndclassex.cbClsExtra    = 0;
        wndclassex.cbWndExtra    = 0;
        wndclassex.hInstance     = hInstance;
        wndclassex.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
        wndclassex.hCursor       = LoadCursor (NULL, IDC_ARROW);
        wndclassex.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
        wndclassex.lpszMenuName  = NULL;
        wndclassex.lpszClassName = szAppName;
        wndclassex.hIconSm       = wndclassex.hIcon;
    	
        if (!RegisterClassEx (&wndclassex))
        {
            MessageBox (NULL, TEXT ("RegisterClassEx failed!"), szAppName, MB_ICONERROR);
            return 0;
        }
        hwnd = CreateWindowEx (WS_EX_OVERLAPPEDWINDOW, 
    		                  szAppName, 
            		          TEXT ("WindowTitle"),
                    		  WS_OVERLAPPEDWINDOW,
    		                  CW_USEDEFAULT, 
            		          CW_USEDEFAULT, 
                    		  CW_USEDEFAULT, 
    		                  CW_USEDEFAULT, 
            		          NULL, 
                    		  NULL, 
    		                  hInstance,
            		          NULL); 
    						  
        ShowWindow (hwnd, iCmdShow);
        UpdateWindow (hwnd);
    	
        while (GetMessage (&msg, NULL, 0, 0))
        {
            TranslateMessage (&msg);
            DispatchMessage (&msg);
        }
        return msg.wParam;
    }
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	static const LPTSTR text = TEXT("Hello,World");
        HDC hdc;
        PAINTSTRUCT ps;
        switch (message)
        {
        case WM_CREATE:
            return (0);
    		
        case WM_PAINT:
            hdc = BeginPaint (hwnd, &ps);
            TextOut (hdc, 0, 0, text, lstrlen(text));
            EndPaint (hwnd, &ps);
            return (0);
    		
        case WM_DESTROY:
            PostQuitMessage (0);
            return (0);
        }
        return DefWindowProc (hwnd, message, wParam, lParam);
    }
    

    运行

    按下Ctrl + F5,你可能会碰到如下的链接错误:

    不要急,这个错误的设置是因为Windows把这个程序当作console程序,而console程序默认入口函数是main,而我们在这里面并没有定义main,而是定义了一个叫WinMain的入口函数,所以链接器不认,而我们希望的却是编译器认为我们这个程序是一个GUI程序,GUI程序的入口函数是WinMain(如果你用#pragma comment(linker…………)修改的话当然也是可以的,这种方法我在第一章里面就写到了。当然,我们还可以直接在Visual Studio IDE里面直接设置,方法是打开项目属性,然后如下设置:
    样设置之后,再按Ctrl + F5,有没有看到如下的一个窗口呢?
    ,就是这样,你看到的就是一个正常的Windows程序的编写。

    代码解释

    编写Windows程序的过程

    编写一个Windows程序,你需要做的是三步,第一步是注册一个窗口类,第二步是创建窗口,第三步是编写消息响应函数。其中第一步和第二步是基本固定的,除了个别的参数需要自己调整之外,最重要的是第三步,
    一个Windows程序中,代码量最大的基本都在第三步。在Windows应用程序里面,如果我们想要接收用户的输入、在窗口上面显示一些信息……我们都需要处理相关的消息,Windows把与这个程序相关的事件都以消息告诉程序,至于怎么处理这些消息,则是我们自己的事情。上面的RegisterClassEx (&wndclassex)其实就是注册窗口类CreateWindowEx (WS_EX_OVERLAPPEDWINDOW, 
                     szAppName, 
                     TEXT ("WindowTitle"),
                     WS_OVERLAPPEDWINDOW,
                     CW_USEDEFAULT, 
                     CW_USEDEFAULT, 
                     CW_USEDEFAULT, 
                     CW_USEDEFAULT, 
                     NULL, 
                     NULL, 
                     hInstance,
                     NULL); 
    其实就是创建窗口,LRESULT CALLBACK WndProc (HWND hwnd, UINT message,WPARAM wParam, LPARAM lParam)其实就是那个消息处理函数,只不过,这个消息处理函数不需要我们自己调用,当有消息的时候,Windows会自己调用这个函数来处理,我们只需要编写处理代码,但是,编写的代码不需要我们自己手动调用(这也许就是Callback函数的原因)。

    剩下的

    剩下的如果还有不懂的自己可以读msdn,比如,对CreateWindow不熟悉,可以直接在MSDN里面搜索CreateWindow,MSDN不仅会告诉你这个函数怎么用,还会告诉你消息循环是什么之类的,在此我就不仔细展开说明了。
  • 相关阅读:
    PHP 开发 APP 接口 学习笔记与总结
    Java实现 LeetCode 43 字符串相乘
    Java实现 LeetCode 43 字符串相乘
    Java实现 LeetCode 43 字符串相乘
    Java实现 LeetCode 42 接雨水
    Java实现 LeetCode 42 接雨水
    Java实现 LeetCode 42 接雨水
    Java实现 LeetCode 41 缺失的第一个正数
    Java实现 LeetCode 41 缺失的第一个正数
    Java实现 LeetCode 41 缺失的第一个正数
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3236946.html
Copyright © 2011-2022 走看看