• Directx11 教程(1) 基本的windows应用程序框架(1)


           在vs2010中,建立一个新的win32工程,名字是: myTutorialD3D11, 注意:同时勾选Create directory for solution,我们同时建立一个solution,后面教程的所有的工程文件,我们都建立在这个solution中。

    image

    勾选 Emtpy project

    image

    增加source files->add new item->main.cpp

    image

    创建一个windows应用程序需要以下步骤:

    1、在入口Main函数中注册窗口类

    2、调用CreateWindowEx函数创建窗口

    3、处理调度消息循环

    4、编写回调函数,在回调函数中响应处理各种消息事件

    在main.cpp中,逐步增加以下的代码:

    首先增加

    #include <windows.h>

    这样,我们就能够使用windows中的API函数、structure,类对象等。

    //窗口类的名字
    LPCWSTR m_applicationName;
    //应用程序实例句柄
    HINSTANCE m_hinstance;

    定义一个全局的windows窗口句柄,这个句柄用来表示应用程序的主窗口句柄。
    //窗口句柄
    HWND m_hwnd;
    //用来判断是否按ESC键,按下ESC键,则退出程序
    bool bexit = false
    ;

    //初始化窗口类,创建应用程序窗口
    void InitializeWindows(int& screenWidth, int& screenHeight);
    //调用初始化窗口函数,以及其它的接口类的初始化函数
    bool Initialize();

    //处理消息循环
    void Run();

    //关闭窗口
    void ShutdownWindows();

    //这两个函数是窗口的回调函数
    static LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

    //判断是否全屏,全屏模式和窗口模式下使用不同的创建窗口参数

    const bool FULL_SCREEN = false;

         下面的函数WinMain,是windows应用程序的入口函数。

          四个参数简单提一下,HInstance表示当前应用程序的实例句柄,它实际上是一个内存基地址,系统将可执行程序的映像加载到进程地址空间中的这个位置

          HPrevInstance表示进程前一个实例句柄,比如对于同一个程序打开两次,出现两个窗口,第一次打开的窗口就是先前实例的窗口。该参数用于16位Windows系统,对于一个32位程序,该参数总为NULL,现在仍然保留该参数主要是为了和16位windows系统兼容。

          pSCmdLine是指向应用程序命令行的字符串的指针,不包括执行文件名。获得整个命令行,使用函数GetCommandLine。

          nCmdShow:指明窗口如何显示,比如SW_HIDE(隐藏),SW_MINIMIZE(最小化)等等,默认情况为SW_SHOW。

         

    //应用程序入口main函数
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow)
        {

        Initialize();
        Run();
        ShutdownWindows();
        return 0;
        }

    该函数首先调用初始化函数,初始化函数中将会设置窗口的高度、宽度,然后调用初始化窗口函数

    //调用窗口初始化函数和其它一些类的初始化函数
    //本例子中,只调用初始化窗口函数

    bool Initialize()
        {
        int screenWidth = 0, screenHeight = 0;

        // 初始化窗口
        InitializeWindows(screenWidth, screenHeight);

        return true;
        }

    void InitializeWindows(int& screenWidth, int& screenHeight)
        {
        WNDCLASSEX wc;
        DEVMODE dmScreenSettings;
        int posX, posY;


        // 得到应用程序实例句柄
        m_hinstance = GetModuleHandle(NULL);

        // 应用程序名字
        m_applicationName = L"Engine";

        // 设置窗口类参数.
        wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;

    指定回调函数后,windows会自动调用回调函数处理各种消息事件
        wc.lpfnWndProc   = WndProc; //指定回调函数
        wc.cbClsExtra    = 0;
        wc.cbWndExtra    = 0;
        wc.hInstance     = m_hinstance;
        wc.hIcon         = LoadIcon(NULL, IDI_WINLOGO);
        wc.hIconSm       = wc.hIcon;
        wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //默认黑色窗口黑色背景
        wc.lpszMenuName  = NULL;
        wc.lpszClassName = m_applicationName;
        wc.cbSize        = sizeof(WNDCLASSEX);

        // 注册窗口类
        RegisterClassEx(&wc);

        // 得到windows桌面分辨率
        screenWidth  = GetSystemMetrics(SM_CXSCREEN);
        screenHeight = GetSystemMetrics(SM_CYSCREEN);

        // 根据是否全屏设置不同的分辨率.
        if(FULL_SCREEN)
            {
            //全屏模式下,设置窗口大小为windows桌面分辨率.
            memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
            dmScreenSettings.dmSize       = sizeof(dmScreenSettings);
            dmScreenSettings.dmPelsWidth  = (unsigned long)screenWidth;
            dmScreenSettings.dmPelsHeight = (unsigned long)screenHeight;
            dmScreenSettings.dmBitsPerPel = 32;           
            dmScreenSettings.dmFields     = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

           // 临时设置显示设备为全屏模式,注意:应用程序退出时候,将恢复系统默认设置。
            ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);

            // 设置窗口的左上角坐标位置为(0,0).
            posX = posY = 0;
            }
        else
            {
            // 窗口模式:800*600.
            screenWidth  = 800;
            screenHeight = 600;

            // 窗口左上角坐标位置,posX, posY

            posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth)  / 2;
            posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight) / 2;
            }

        // 全屏和窗口使用不同的参数.
        if( FULL_SCREEN)
            {
            m_hwnd = CreateWindowEx(WS_EX_APPWINDOW, m_applicationName, m_applicationName,
                WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
                posX, posY, screenWidth, screenHeight, NULL, NULL, m_hinstance, NULL);
            }
        else
            {
            m_hwnd = CreateWindowEx(WS_EX_APPWINDOW, m_applicationName, m_applicationName,
                WS_OVERLAPPEDWINDOW,
                posX, posY, screenWidth, screenHeight, NULL, NULL, m_hinstance, NULL);
            }

        // 显示窗口并设置其为焦点.
        ShowWindow(m_hwnd, SW_SHOW);
        SetForegroundWindow(m_hwnd);
        SetFocus(m_hwnd);

        // 隐藏鼠标.
        //ShowCursor(false);

        return;
        }

    在Run函数中,我们响应调度windows消息以及调用我们的render函数。

    //处理消息
    void Run()
        {
        MSG msg;
        bool done, result = 1;


       // 初始化消息结构.
        ZeroMemory(&msg, sizeof(MSG));

        // 循环进行消息处理

        done = false;
        while(!done)
            {
           // 处理windows消息.
            if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
                }

           // 接收到WM_QUIT消息,退出程序.
            if(msg.message == WM_QUIT)
                {
                done = true;
                }
            else
                {
                result = bexit; //如果按了ESC,也退出程序

                //我们的渲染或者其它处理,可以放在这儿
                //....
                //.....
                if(result)
                    {
                    done = true;
                    }
                }

            }

        return;
        }

    WndProc函数为窗口回调函数,程序中的消息处理都在这个函数中

    LRESULT CALLBACK WndProc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
    {
    switch(umessage)
    {

    // 窗口销毁消息.
    case WM_DESTROY:
    {
    PostQuitMessage(0);
    return 0;
    }

    // 窗口关闭消息.
    case WM_CLOSE:
    {
    PostQuitMessage(0);
    return 0;
    }

    //MessageHandle过程处理其它所有消息.
    default:
    {
    return MessageHandler(hwnd, umessage, wparam, lparam);
    }
    }
    }


    LRESULT CALLBACK MessageHandler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
        {

        switch(umsg)
            {
           // 检测按键消息.
            case WM_KEYDOWN:
                if(wparam==VK_ESCAPE)
                    bexit = true;
                return 0;
           //任何其它消息发送到windows缺省处理.
        default:
            {
            return DefWindowProc(hwnd, umsg, wparam, lparam);
            }
            }
        }


    ShutdownWindows函数主要用来在程序结束后,释放一些资源。

    void ShutdownWindows()
        {
        //显示光标.
        //ShowCursor(true);

        // 恢复默认显示设置.
        if(FULL_SCREEN)
            {
            ChangeDisplaySettings(NULL, 0);
            }

        //释放窗口句柄.
        DestroyWindow(m_hwnd);
        m_hwnd = NULL;

        // 释放应用程序实例.
        UnregisterClass(m_applicationName, m_hinstance);
        m_hinstance = NULL;

        return;
        }

    程序执行后,界面如下,窗口是黑色,我们按下ESC,程序会退出:

    image

    完整的代码请参考:

    工程文件myTutorialD3D11

    代码下载:

    https://files.cnblogs.com/mikewolf2002/myTutorialD3D11.zip

  • 相关阅读:
    laravel底层源码解析:pipeline,db,console
    composer命令清单
    composer使用笔记
    git常见问题
    JS阻止冒泡和取消默认事件(默认行为)
    vue项目构建:vue-cli+webpack常用配置
    MVC和三层架构
    SSM框架初始配置
    Java对象间的关系
    Spring框架
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/2385827.html
Copyright © 2020-2023  润新知