Windows sdk编程笔记

windows 编程 入门



前言

入门了C语言之后,学完数据结构,学完算法,还是写不出想要的那种程序,而面向对象的编程又好像是另一个语言,除了函数结构写法差不多之外,与C语言似乎根本不搭边,一直再寻找C语言做UI的路径,试过许多图形库之后,也尝试过QT、MFC等等,都不友好。直到学会了SDK编程


一、操作系统原理

阿基米德说过,给他一个支点,他就能翘起地球。在学习一个新技能,新语言的时候,往往也需要这样一个支点,来构建我们对于新技能、新语言的一个整体框架的理解。
在《计算机原理》之类的书籍,会告诉我们现在的主流操作是分时操作系统,会告诉我们是流转时间片来实现的。
但是具体的实现过程,却一头雾水。对于硬件我们一头雾水,但至少知道了cpu时刻向内存中读取数据。而读取过程,是CPU向内存发送一个地址,然后内存向CPU返回这个地址的值。
而在CPU上电之后,会默认指向一个内存地址,比如0xfffe,内存就会将这个地址的值返回给cpu,这个内存地址存放的是一个特殊的值,它用来告诉cpu上电之后要从哪个地址开始运行程序。除了上电之外,cpu还会有其他需要,来读取这样存放特殊值的内存地址,这些存放特殊值的内存地址,成为向量表。
假设一个cpu上电后指向的地址是0xfffe(这个地址是硬件电路来实现指向的),如果内存返回的值是0x0000,那么cpu会将自己的程序计数器的值设为0x0000,它将读取内存中0x0000的指令。
除了内存之外,cpu还需要跟许多硬件打交道,比如显卡,比如声卡,比如键盘,比如鼠标,如果cpu只活在自己的世界,不管外部,就像一个专注自己事情的人,如果我们要使用鼠标告诉它要运行哪个程序,这是鼠标就要给cpu发送一个中断请求,差不多就是拍一下cpu的肩膀,这时cpu就会回过头来跟鼠标对话,鼠标是个低级的家伙,它只会告诉cpu,我左移1像素、我右移1像素、我的左键被点下了、我的右键被点下了,cpu在被鼠标拍了一下肩膀的时候,就开始完成了许多工作,包括放下手中的笔(保存现场,实际上是将它的寄存器的值存放到某块内存)然后向内存的中断向量表找鼠标的响应程序的地址,一旦拿到响应程序的地址,就会跳转到那个地址去读指令,这是cpu就会询问鼠标都有啥要说的,鼠标就会告诉cpu,我的左键被点下了,但鼠标不会记忆自己在啥位置,响应程序就需要记录鼠标在桌面上是啥位置,然后进行更新,然后判断是不是点下了菜单按钮。当响应程序执行完了,就需要向cpu发送一个return,cpu收到就知道已经处理完了,就会从刚才保存寄存器的那块内存读回保存的寄存器的值,这样就回到了中断前的状态。

这些跳转,都是cpu的硬件电路来实现的,操作系统,就是基于这种中断机制,设定一个定时器,定时器在一个时间后,就会产生一个中断,cpu就会去向量表读定时器的响应程序,只要给这个定时器的中断向量填入操作系统内核程序的地址,cpu就会跑去内核运行,内核就会实现调度程序,管理硬件等等。

二、操作系统桌面与程序的关系

在dos时代,用户与电脑之间的交互,主要是黑色背景下的命令行,用户输入一个指令,电脑把执行后的结果主要通过字符的形式输出到屏幕上。
而桌面操作系统面世后,用户与电脑之间的交互主要依靠与图形界面,对于图形界面的支持,linux和windows的做法不太一样,linux把图形界面作为用户层的程序,而windows为了快速响应用户的操作,把图形界面放在内核层。
一说到windows程序设计,就会被告知是基于消息机制的,一说到消息机制,又会说好莱坞规则:don’t call us, we’ll call you。从这个地方入门,没点毅力,就会从入门到放弃。

1.进程时如何切换的

先来看进程间的切换是怎么实现的,假设系统有2个程序,p1和p2,p1在执行,现在它的时间片到点了,cpu跳转到了内核,内核把p1运行时寄存器的值都给保存到一个进程控制的内存块里,然后把p2进程运行时的寄存器的值返回给cpu,这样就实现了进程的切换,如果此时p2执行完了,那么就会return,p2就会从进程列表里被内核给销毁,连带p2占用的内存空间也会被回收,为了让p2继续运行,p2得有一个循环,以便把自己一直卡在进程表里。
但是如果此时p1需要读取用户敲了键盘的值,p1如何得知呢,在实际过程中,我们敲下键盘的瞬间,比如qq聊天窗口,在系统里,就被切换到了迅雷下载的进程去,如何保证我们输入的键盘,不被错误的读到迅雷里去,形成神秘代码呢。这就需要信号量。
前面说过,当鼠标被点击,就会给cpu一个中断请求,cpu就会去跑到鼠标响应程序,让它问鼠标咋地啦。键盘也是一样的机制,但是当我们敲下键盘的时候,如何才能知道应该告诉哪个程序去响应。这就需要一个信号量机制,当p1需要获得一个键盘输入时,p1就会设置一个阻塞,让自己处于阻塞态,以便内核不会把自己再次放入cpu执行,直到等到用户键盘得输入时,内核发现了,就会将p1进程切换为就绪态,这是p1就能去读取键盘输入的值了。

2.系统如何管理图形界面

但是在图形界面下,如果图形界面全部由程序自己来维护,效率低切开发难度高。操作系统就提供模板,由操作系统来绘制,不但使开发难度降低,还能提升刷新的效率。但是用户程序如何获知用户点击了按钮或者移动鼠标等等呢,于是就有了消息机制。由操作系统来告诉用户程序,用户点击了按钮,用户程序只需要不停的去获取属于自己的消息,然后按照消息的类型来响应就行。

在windows中,用户程序用来获取消息的部分,叫消息循环。消息循环在主函数部分,这样就保证了用户进程能够卡在进程列表里,不被销毁。

	MSG msg;
	while(GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessageW(&msg);
	}

而用以响应消息的部分,叫窗口过程。

LRESULT	CALLBACK WinProc(HWND,UINT,WPARAM,LPARAM);

可以看到,这个函数由CALLBACK来修饰,前面我们说到了中断向量表,发生特定中断时,cpu会从特定地址读取一个值,来跳转到特定的内存地址去读指令(也就是跳转到该内存地址继续运行),借鉴这样的机制,操作系统里也会有类似的机制,只是这种机制由软件来实现,而cpu的中断则是由硬件来实现,CALLBACK修饰的函数,就会在系统的某个向量表添加自己的地址,如果有需要响应的消息,操作系统就会调用这个函数。

经过这样的改造之后,内核与用户进程之间的关系,就不再是实模式下那种平等,大家都是进程,也不是保护模式下那种内核是内部人员,可以使用特权指令。

3.影视公司与演员的自我修养

在windows下,系统与用户程序的关系,更像是影视制作公司与演员的关系,影视公司包揽了大多的事,包揽各种杂活,用户界面就像是一个个演员,他们按照导演的安排,各就各位。
当用户点击了一个按钮之后,导演就会告诉演员,用户让你哭,导演不会替演员哭,所以响应按钮点击的消息,需要在窗口过程中由程序员来写,这就是演员的自我修养,如果演员没有哭的技能,就要卡在那里,为了不卡在那里,演员没有的技能,导演就会把这个剧情处理掉

return DefWindowProc(hwnd,message,wParam,lParam);

但是如果演员会哭,只是他酝酿感情需要2-3天,程序真的就会卡在那里,这就有了任务管理器界面上看到的【未响应】

总结

所以,windows程序的框架是这样的

#include <windows.h>
LRESULT	CALLBACK WinProc(HWND,UINT,WPARAM,LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance,LPSTR pCmdLine,int nCmdShow)
{
	MSG msg;
	while(GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessageW(&msg);
	}
	return msg.wParam;
}

LRESULT	CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	switch(message)
	{
		case WM_CREATE:
		{
			return 0;
		}
	return DefWindowProc(hwnd,message,wParam,lParam);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值