在这篇文章里我们先用 windows API 制作一个窗口出来,以后再用 DirectX API 渲染的东西就会显示在这里,控制台那黑白的画面肯定是没法用的。

每次的代码都会更新到Github

首先贴出来目前为止的文件结构图,由上到下表示#include“XXXXX”关系

系统头文件的调用不包含在内

由于.h和.cpp都是对应出现的,我就不写的那么详细了

Main.cpp 是调用 SoftwareClass 类的主函数。

那么我们从上往下开始吧。

Main.cpp

由于只用调用接下来的类成员函数就行,所以这个代码非常简单。

 ////////////////
// Main.cpp //
////////////////
#include"SoftwareClass.h" /*********************************
这里是整个程序的入口函数
WinMain
仅适用于Win32编程
**********************************/ int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR pScmdline,int nCmdshow)
{
//新建类指针
SoftwareClass *Software;
//new一个类出来
Software = new SoftwareClass;
//初始化、运行、结束该程序
if (Software->Initialize())
{
Software->Run();
}
Software->Shutdown();
//删除并清理类指针
delete Software;
Software = NULL;
return ;
}

SoftwareClass

接下来就是重点的主要类SoftwareClass,它管理着这个程序的生杀大权,并调用InputClass(记录输入的类)和GraphicsClass(渲染图形的类)来完成更高级的操作。

首先是他的header

SoftwareClass.h

 ////////////////////////
// SoftwareClass.h //
/////////////////////// /*******************************
该类包含整个程序运行所需的功能
********************************/ #ifndef _SOFTWARECLASS_H_
#define _SOFTWARECLASS_H_ //////////////
// include //
//////////////
#include<Windows.h> //////////////////
// File include //
//////////////////
#include"InputClass.h"
#include"GraphicsClass.h" /////////////////////////
// Class Declaration //
/////////////////////////
class SoftwareClass
{
public:
//默认构造,复制,析构函数
SoftwareClass();
SoftwareClass(const SoftwareClass&);
~SoftwareClass(); bool Initialize();//初始化
void Shutdown();//关闭
void Run();//运行 //主要消息处理函数
//系统级消息丢给另外的一个WndProc
//比如窗口的关闭等消息
LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM); //以下为私有成员函数
private:
bool Frame();
//创建窗口最重要的函数
void InitializeWindows(int&, int&);
void ShutdownWindows();
//以下为私有数据成员
private:
//创建窗口程序需要的参数,无需过度关心
LPCWSTR m_SoftwareName;
HINSTANCE m_hinstance;
HWND m_hwnd; //m_* 代表成员数据
InputClass *m_Input;
GraphicsClass *m_Graphics;
}; ////////////////////////
// Static Function //
/////////////////////// //次要消息处理函数
//用于处理系统级消息
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); /////////////
// Global //
///////////// //用于消息处理函数的调用
//因为我们有两个
//所以需要这个静态变量指向该类
static SoftwareClass *SoftwareHandle = NULL; #endif

SoftwareClass.cpp

接着是他的.cpp

 ///////////////////////////
// SoftwareClass.cpp //
//////////////////////////
#include "SoftwareClass.h" //////////////////////////////////////////////////////////
SoftwareClass::SoftwareClass()
{
m_hinstance = NULL;
m_hwnd = NULL;
m_SoftwareName = NULL; m_Input = NULL;
}
SoftwareClass::SoftwareClass(const SoftwareClass &other)
{
}
SoftwareClass::~SoftwareClass()
{
}
////////////////////////////////////////////////////////// bool SoftwareClass::Initialize()
{
int screenWidth, screenHeight;
bool result; screenHeight = ;
screenWidth = ;
InitializeWindows(screenWidth, screenHeight); //new一个输入处理类
m_Input = new InputClass;
if (!m_Input)
{
return false;
}
m_Input->Initialize(); //new一个图形处理类
m_Graphics = new GraphicsClass;
if (!m_Graphics)
{
return false;
} //由于图形类涉及到窗口的创建
//容易失败
//因此测试一下new是否成功
result = m_Graphics->Initialize(screenWidth, screenHeight, m_hwnd);
if (!result)
{
return false;
} return true;
} //先清除输入类和图形类
//再关闭窗口程序
void SoftwareClass::Shutdown()
{
if (m_Graphics)
{
m_Graphics->Shutdown();
delete m_Graphics;
m_Graphics = NULL;
} if (m_Input)
{
delete m_Input;
m_Input = NULL;
} ShutdownWindows();
} //消息的翻译分配在此
void SoftwareClass::Run()
{
MSG msg;
bool done, result;
done = false; ZeroMemory(&msg, sizeof(MSG)); //程序的最主要循环
//不停地渲染、输出画面
while (!done)
{
//消息队列的查找
if (PeekMessage(&msg, NULL, , , PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} //这说明PostQuitMessage被调用了
if (msg.message == WM_QUIT)
{
done = true;
}
else
{
result = Frame();
if (!result)
{
done = true;
}
}
}
} LRESULT SoftwareClass::MessageHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_KEYDOWN:
m_Input->KeyDown((unsigned int)wParam); //当ESC被按下时,退出程序
if (wParam == VK_ESCAPE)
{
PostQuitMessage();
}
return ;
case WM_KEYUP:
m_Input->KeyUp((unsigned int)wParam);
return ;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
} bool SoftwareClass::Frame()
{
bool result; result = m_Graphics->Frame();
if (!result)
{
return false;
}
return true;
} //窗口程序的创建,注册,显示
void SoftwareClass::InitializeWindows(int &screenWidth, int &screenHeight)
{
WNDCLASSEX wc = {};
DEVMODE dmScreenSettings;
int posX, posY; //赋值那个静态变量
//指向该类
SoftwareHandle = this;
//别管
m_hinstance = GetModuleHandle(NULL);
//由于Unicode的原因
//所有字符串要用 TEXT() 括起来
m_SoftwareName = TEXT("MyShabbyEngine"); //填写对象wc的有关信息
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
//该窗口的消息处理函数
wc.lpfnWndProc = WndProc;
//以下全部不用管
wc.cbClsExtra = ;
wc.cbWndExtra = ;
wc.hInstance = m_hinstance;
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.hCursor = NULL;
wc.lpszMenuName = NULL;
//设置程序窗口背景
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
//类名,意义不明
wc.lpszClassName = m_SoftwareName;
//这步绝不能漏了
wc.cbSize = sizeof(WNDCLASSEX); //向系统注册该窗口
RegisterClassEx(&wc); //从系统得到显示的分辨率
screenWidth = GetSystemMetrics(SM_CXSCREEN);
screenHeight = GetSystemMetrics(SM_CYSCREEN); //如果GraphicsClass文件里设置为全屏
if (FULL_SCREEN)
{
memset(&dmScreenSettings, , sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = (unsigned long)screenWidth;
dmScreenSettings.dmPelsHeight = (unsigned long)screenHeight;
dmScreenSettings.dmBitsPerPel = ;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN); posX = posY = ;
}
else
{
screenWidth = ;
screenHeight = ; posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth) / ;
posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight) / ;
} //在显示屏创建窗口
//无边框
m_hwnd = CreateWindowEx(WS_EX_APPWINDOW,
m_SoftwareName, m_SoftwareName,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
posX, posY, screenWidth, screenHeight,
NULL, NULL, m_hinstance, NULL); //将窗口显示出来
ShowWindow(m_hwnd, SW_SHOW);
SetFocus(m_hwnd); ShowCursor(false);
} void SoftwareClass::ShutdownWindows()
{
//显示鼠标指针
ShowCursor(true); if (FULL_SCREEN)
{
ChangeDisplaySettings(NULL, );
} DestroyWindow(m_hwnd);
m_hwnd = NULL; UnregisterClass(m_SoftwareName, m_hinstance);
m_hinstance = NULL; SoftwareHandle = NULL;
} LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_DESTROY:
case WM_CLOSE:
PostQuitMessage();
return ;
default:
return SoftwareHandle->MessageHandler(hWnd, Msg, wParam, lParam);
}
}

InputClass

该类监控并记录哪些键被按下

InputClass.h

 ////////////////////
// InputClass.h //
/////////////////// /******************************
该类包含记录输入按键的功能
******************************/ #ifndef _INPUTCLASS_H_
#define _INPUTCLASS_H_ /////////////////////////
// Class Declaration //
/////////////////////////
class InputClass
{
public:
//默认构造、复制、析构函数
InputClass();
~InputClass();
InputClass(const InputClass&);
//初始化
void Initialize();
//当按键被按下或抬起时调用
void KeyDown(unsigned int);
void KeyUp(unsigned int);
//检测某键是否被按下
bool IsKeyDown(unsigned int);
private:
//储存哪些键被按下
//true表示正被按下
bool m_keys[];
}; #endif

Input.cpp

 ////////////////////
// InputClass.cpp //
///////////////////
#include "InputClass.h" InputClass::InputClass()
{
}
InputClass::~InputClass()
{
}
InputClass::InputClass(const InputClass &other)
{
} //初始化按键表
void InputClass::Initialize()
{
int i;
for (i = ; i < ; i++)
{
m_keys[i] = false;
}
} void InputClass::KeyDown(unsigned int input)
{
//将该键设为true
m_keys[input] = true;
} void InputClass::KeyUp(unsigned int input)
{
//将该键设为false
m_keys[input] = false;
} bool InputClass::IsKeyDown(unsigned int key)
{
return m_keys[key];
}

GraphicsClass

最后是GraphicsClass,由于目前只做了窗口的显示,其实还并未涉及到任何 DirectX 的代码,所以这个类基本上是空的。

GraphicsClass.h

 /////////////////////////
// GraphicsClass.h //
/////////////////////// /***********************
该类处理图像
********************/ #ifndef _GRAPHICSCLASS_H_
#define _GRAPHICSCLASS_H_ //////////////
// include //
//////////////
#include<Windows.h> /////////////
// Global //
///////////// //是否全屏显示
const bool FULL_SCREEN = false;
//是否垂直同步
const bool VSYNC_ENABLED = true;
//场景相关数据
const float SCREEN_DEPTH = 1000.0;
const float SCREEN_NEAR = 0.1f; /////////////////////////
// Class Declaration //
////////////////////////
class GraphicsClass
{
public:
GraphicsClass();
GraphicsClass(const GraphicsClass&);
~GraphicsClass(); bool Initialize(int, int, HWND);
void Shutdown();
bool Frame();
private:
bool Render();
}; #endif

GraphicsClass.cpp

 ///////////////////////////
// GraphicsClass.cpp //
//////////////////////////
#include "GraphicsClass.h" GraphicsClass::GraphicsClass()
{
} GraphicsClass::GraphicsClass(const GraphicsClass &other)
{
} GraphicsClass::~GraphicsClass()
{
} bool GraphicsClass::Initialize(int screenWidth, int screenHeight, HWND hWnd)
{
return true;
} void GraphicsClass::Shutdown()
{
} bool GraphicsClass::Frame()
{
return true;
} bool GraphicsClass::Render()
{
return true;
}

最后程序正确运行后,会在屏幕中间产生一个黑色的矩形,没有边框,也没有鼠标指针。按ESC可退出。

我知道。。。光贴代码屁用没有。。。。。日后补上注释

DirectX API 编程起步 #02 窗口的诞生的更多相关文章

  1. DirectX API 编程起步 #01 项目设置

    =========================================================== 目录: DirectX API 编程起步 #02 窗口的诞生 DirectX A ...

  2. Flink Program Guide (2) -- 综述 (DataStream API编程指导 -- For Java)

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...

  3. Mysql C语言API编程入门讲解

    原文:Mysql C语言API编程入门讲解 软件开发中我们经常要访问数据库,存取数据,之前已经有网友提出让鸡啄米讲讲数据库编程的知识,本文就详细讲解如何使用Mysql的C语言API进行数据库编程.   ...

  4. ASP.NET Web API编程——路由

    路由过程大致分为三个阶段: 1)请求URI匹配已存在路由模板 2)选择控制器 3)选择操作 1匹配已存在的路由模板 路由模板 在WebApiConfig.Register方法中定义路由,例如模板默认生 ...

  5. 黑客编程教程(二)Win API编程简介

    第二节 Win API编程简介 下面介绍一下WIN API. 我们需要自己编写一个工具时,必然会用到很多操作windows和控制windows的函数,这些函数就是windows API. API是Ap ...

  6. 浅谈Windows API编程

    WinSDK是编程中的传统难点,个人写的WinAPI程序也不少了,其实之所以难就难在每个调用的API都包含着Windows这个操作系统的潜规则或者是windows内部的运行机制…… WinSDK是编程 ...

  7. Maya API编程快速入门

    一.Maya API编程简介 Autodesk® Maya® is an open product. This means that anyone outside of Autodesk can ch ...

  8. 第23 章 : Kubernetes API 编程范式

    Kubernetes API 编程范式 需求来源 首先我们先来看一下 API 编程范式的需求来源. 在 Kubernetes 里面, API 编程范式也就是 Custom Resources Defi ...

  9. Team Foundation API - 编程访问 WorkItem

    Team Foundation Server (TFS)工具的亮点之一是管理日常工作项, 工作项如Bug, Task,Task Case等. 使用TFS API编程访问TFS服务器中的工作项, 步骤如 ...

随机推荐

  1. c#开发工具软件集合

    visual studio 2015(自带Nuget) Resharper de4dot dnspy ILMergeGui Git 大漠插件3.1233 天使插件v4.019 Navicat_Prem ...

  2. sql server:compare data from two tables

    --Comparing data between two tables in SQL Server --Create two Tables-- CREATE TABLE TableA(ID Int, ...

  3. [PHP] 自定义错误处理

    关闭掉默认的错误提示,注册自己的错误提示 Application.php <?php class Application{ public static function main(){ head ...

  4. javascript 之正则匹配HTML

    正则表达式 <(\S*?) [^>]*>.*?</\1>|<.*? /> 匹配 <html>hello</html>|<a> ...

  5. Hibernate的缓存技术详解

    转载注明出处:http://www.cnblogs.com/xiaoming0601/p/5882980.html 一.什么是缓存: 并不是指计算机的内存或者CPU的一二级缓存:缓存是指为了降低应用程 ...

  6. Android开发中的问题及相应解决(持续更新)

    最近博客写的少了,以后还得经常更新才行. ------------------------------------------------------------ 1.特定业务需求下try cath ...

  7. [Design Pattern] Substitute Interface

    [Design Pattern] Substitute Interface 目的 将对象的成员建立为替身接口的成员,用来解耦对象之间的循环相依. 情景 假设开发人员接手一个系统,在系统里有订单对象.送 ...

  8. Eclipse反编译工具Jad及插件JadClipse配置

    Jad是一个Java的一个反编译工具,是用命令行执行,和通常JDK自带的java,javac命令是一样的.不过因为是控制台运行,所以用起来不太方便.不过幸好有一个eclipse的插件JadClipse ...

  9. 回车键和button按钮都绑定同一个事件,如何避免按回车的时候button重复点击

    保存一个全局变量,用来记录Button的焦点状态 <button onclick="login();" onfocus="window.buttonIsFocuse ...

  10. Sharepoint学习笔记—习题系列--70-573习题解析 -(Q104-Q106)

    Question 104You plan to create a workflow that has the following three activities: CreateTask OnTask ...