• [置顶] 《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不仅会告诉你这个函数怎么用,还会告诉你消息循环是什么之类的,在此我就不仔细展开说明了。
  • 相关阅读:
    ORACLE中dba,user,v$等开头的常用表和视图
    CentOS最基本的20个常用命令
    Spring IOC原理解读 面试必读
    Nginx Web服务应用
    Linux系统SSH免密登录
    Zabbix+Grafana打造高逼格监控系统
    Ansible入门
    你应该知道的 5 个 Docker 工具
    关于 Docker Hub 上不能注册 Docker ID 的问题
    Linux下终端录制工具-asciinema
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3236946.html
Copyright © 2020-2023  润新知