绪言:
这是一篇很肤浅的文章,严格意义上来讲不能算是一篇技术型的文章,只能说是自己在学习direct编程时的一点心得,不过里面还是包含了不少的win32编程和direct编程的基础知识,拿到这里来献丑也是为了希望为正在从事direct编程的朋友尽一点绵力,这篇文章主要是讲了我利用direct编程实现一个图像的裁减的过程,其效果图如下:
裁减前:
裁减后:
如果朋友们在里面发现了bug请告诉我,如果朋友们有什么更好的意见和指教也请告诉我^_^。
第一回:初窥门径
windows的编程是有一定流程的,其实也就是最开始我们必须创建一个主函数,而这个主函数就应该是一个大的消息循环,这个主函数的大致流程如下图:
首先我们必须做一个最基本的事情就是创建一个窗体,并注册,再基于这个窗体上我们才能干更多的事,就好比先有一张画布,然后我们可以在画布中绘图。
//************************************************************
//函数:WinMain( )
//功能:Windows程序入口函数。创建主窗口,处理消息循环
//************************************************************
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg; //消息结构
InitWindow(hInstance,nCmdShow); //初始化窗体
while(1) //消息循环
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message==WM_QUIT) //退出消息循环
break;
TranslateMessage(&msg); //得到消息,处理回调函数
DispatchMessage(&msg);
}
}
return msg.wParam;
}
在讲本程序的消息循环之前,我想先谈一下Dos与Windows驱动机制的区别:
DOS程序主要使用顺序的,过程驱动的程序设计方法。顺序的,过程驱动的程序有一个明显的开始,明显的过程及一个明显的结束,因此程序能直接控制程序事件或过程的顺序。虽然在顺序的过程驱动的程序中也有很多处理异常的方法,但这样的异常处理也仍然是顺序的,过程驱动的结构。
而Windows的驱动方式是事件驱动,就是不由事件的顺序来控制,而是由事件的发生来控制,所有的事件是无序的,所为一个程序员,在你编写程序时,你并不知道用户先按哪个按纽,也不知道程序先触发哪个消息。你的任务就是对正在开发的应用程序要发出或要接收的消息进行排序和管理。事件驱动程序设计是密切围绕消息的产生与处理而展开的,一条消息是关于发生的事件的消息。
WinMain( )函数的原型如下:
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
第一个参数hInstance是标识该应用程序的句柄。不过句柄又是什么呢?其实就是一个指向该程序所占据的内存区域的指针,它唯一地代表了该应用程序,Windows使用它管理内存中的各种对象。
第二个参数是hPrevInstance,应用程序的前一个实例句柄,别管它,对于Win32位而言,它一般是NULL.
第三个参数是lpCmdLine,是指向应用程序命令行参数字符串的指针。比如说我们运行"test hello",则此参数指向的字符串为"hello"。
最后一个参数是nCmdShow,是一个用来指定窗口显示方式的整数。它告诉应用程序如何初始化窗口,如最大化,最小化等状态。关于窗口显示方式的其他种类,将在下图说明。
然后我们要初始化窗体,并且注册它,然后我们才能使用它。
//************************************************************
//函数:InitWindow( )
//功能:创建窗口
//************************************************************
static BOOL InitWindow( HINSTANCE hInstance, int nCmdShow )
{
WNDCLASS wc;
wc.style = NULL; //窗口类风格
wc.lpfnWndProc = (WNDPROC)WinProc; //指向窗口过程函数的指针
wc.cbClsExtra = 0; //窗口类附加数据
wc.cbWndExtra = 0; //窗口类附加数据
wc.hInstance = hInstance; //拥有窗口类的实例句柄
wc.hIcon = NULL; //最小窗口图标
wc.hCursor = NULL; //窗口内使用的光标
wc.hbrBackground = NULL; //用来着色窗口背景的刷子
wc.lpszMenuName = NULL; //指向菜单资源名的指针
wc.lpszClassName = "menpao_RPG_DEMO"; // 指向窗口类名的指针
RegisterClass(&wc); //注册窗口
hwnd = CreateWindow("menpao_RPG_DEMO","menpao_RPG_DEMO",WS_POPUP|WS_MAXIMIZE,0,0,GetSystemMetrics( SM_CXSCREEN ),GetSystemMetrics( SM_CYSCREEN ), NULL,NULL,hInstance,NULL);
if( !hwnd ) return FALSE;
ShowWindow(hwnd,nCmdShow); //显示窗口
UpdateWindow(hwnd); //刷新窗口
return TRUE;
}
(1)第一个参数:成员style控制窗口样式的某些重要特性,在WINDOWS.H中定义了一些前缀为CS的常量,在程序中可组合使用这些常量.其他还有以下的一些特性:
(2)第二个参数:lpfnWndProc,给它消息处理函数的函数名称即可,必要时应该进行强制类型转换,将其转换成WNDPROC型。
(3)第三,四个参数:cbWndExtra域指定用本窗口类建立的所有窗口结构分配的额外字节数。当有两个以上的窗口属于同一窗口类时,如果想将不同的数据和每个窗口分别相对应。则使用该域很有用。这般来讲,你只要把它们设为0就行了,不必过多考虑。
(4)第五个参数:hInstance成员,给它的值是窗口所对应的应用程序的句柄,表明该窗口与此应用程序是相关联的。
(5)第六个参数:成员hIcon被设置成应用程序所使用图标的句柄,图标是将应用程序最小化时出现在任务栏里的的图标,用以表示程序仍驻留在内存中。Windows提供了一些默认图标,我们也可定义自己的图标,VC里面专有一个制作图标的工具。
(6)第七个参数: hCursor域定义该窗口产生的光标形状。LoadCursor可返回固有光标句柄或者应用程序定义的光标句柄。IDC_ARROW表示箭头光标.
(7)第八个参数:hbrBackground成员用来定义窗口的背景色。这里设为NULL。
(8)第九个参数:lpszMenuName用来指定菜单名,本程序中没有定义菜单,所以为NULL。
(9)第十个参数:lpszClassName指定了本窗口的类名。本程序命名为“menpao_RPG_DEMO”。
当对WNDCLASS结构域一一赋值后,就可注册窗口类了,在创建窗口之前,是必须要注册窗口类的,注册窗口类用的API函数是RegisterClass,注册失败的话,就会出现一个对话框如程序所示,函数RegisterClass返回0值,也只能返回0值,因为注册不成功,程序已经不能再进行下去了。
注册完了以后,就是创建该窗体,一般我们一时调用API函数中的CreatWindows()函数完成的
以上面注册的这个窗体为例
hwnd = CreateWindow(
"menpao_RPG_DEMO", //创建的这个窗体类的名称
"menpao_RPG_DEMO", //窗口标题
WS_POPUP|WS_MAXIMIZE, //窗口风格,全部风格见后表
0, //窗口位置x坐标
0, //窗口位置y坐标
GetSystemMetrics(SM_CXSCREEN ), //窗口高度,这里是全屏
GetSystemMetrics( SM_CYSCREEN ), //窗口高度,这里是全屏
NULL, //父窗口句柄
NULL, //菜单句柄
hInstance, //应用程序句柄
NULL); //最后一个参数是附加数据,一般都是0
参数1:登记的窗口类名,这个类名刚才咱们在注册窗口时已经定义过了。
参数2:用来表明窗口的标题。可以和第一个参数一样。
参数3: 用来表明窗口的风格,如有无最大化,最小化按纽啊什么的。 具体其他风格见下图所示
在DirectX编程中,我们一般使用的是WS_POPUP | WS_MAXIMIZE,用这个标志创建的窗口没有标题栏和系统菜单且窗口为最大化,可以充分满足DirectX编程的需要。
参数4,5: 用来表明程序运行后窗口在屏幕中的坐标值。
参数6,7: 用来表明窗口初始化时(即程序初运行时)窗口的大小,即长度与宽度。
参数8: 在创建窗口时可以指定其父窗口,这里没有父窗口则参数值为0。
参数9: 用以指明窗口的菜单,菜单以后会讲,这里暂时为0。
最后一个参数是附加数据,一般都是0。
如果窗口创建成功,CreateWindow( )返回新窗口的句柄,否则返回NULL。
不要以为创建和注册完了以后就大功告成,这样的话你是在屏幕上什么也看不见,我们必须要调用另外一个API函数才能看见窗体就是ShowWindow,他的原型是:
ShowWindow (hwnd, iCmdShow)
其第一个参数是窗口句柄,告诉ShowWindow()显示哪一个窗口,而第二个参数则告诉它如何显示这个窗口,还有很多其他样式。
WinMain()调用完ShowWindow后,还需要调用函数UpdateWindow,最终把窗口显示了出来。调用函数UpdateWindow将产生一个WM_PAINT消息,这个消息将使窗口重画,即使窗口得到更新.
然后就是最重要的消息循环和回调函数了,这就是windows编程的灵魂了,不过该死的寝室要停电了,预听后事如何,且带下回分解J。