标题:All about windows programming
只看楼主
kai
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:52
帖 子:3450
专家分:59
注 册:2004-4-25
结帖率:100%
 问题点数:0 回复次数:67 
All about windows programming

下面就让我们开始,请朋友们不要贴任何非技术性跟贴。

今天,让我们从 windows program 的基本框架开始。在这里所有程序的编译环境为VC 6.0 ,这里也不涉及 MFC 的讨论。 让我们用纯粹的 win32 Api 来编写 windows 应用程序。

首先打开 VC, -> File -> New... -> 选择Projects 选项 -> 加亮 Win32 Application -> 输入你想输入的Project name, 比如我们这里输入WindowsDemo -> 选择 Create new workspace (通常已经选好 )-> Platforms:选择win32 (通常已经选好 )-> 按下 ok 按钮 -> 在接下来的对话框为Win32 Application - Step 1 of 1, 我们选择 an empty project -> 按下 finish 按钮 -> 弹出新的对话框 New Project Information, 我们按下 ok 按钮

再次回到菜单栏,按下File -> New... -> 在Files 下,加亮 C++ Source File -> 在File name: 下输入你想要的文件名,比如我们这里输入 WindowsDemo , 如果你不人为确定文件格式,它将默认为C++ 文件,即 cpp 文件,如果你一定想让文件为C 文件,就需要人为输入文件结尾 .C, 我们这里采用 C++ 文件格式,因为C++ 兼容C, 而C并不兼容C++ 。请注意,add to project 旁边的那个打勾已经勾上了,如果没有,请勾上。-> 按下 ok 按钮

这样,我们看到了3个区域,右边最大的那个区域为工作区域,那儿,我们将输入我们的代码,右边那个区域我称它为文件区域,最下面的为信息区域,将显示一些编译的信息。

下面我们来将代码输入到工作区域。

以下为代码:

#include <windows.h>

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

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nShowCmd) { HWND hwnd; MSG Msg; WNDCLASS wndclass; char lpszClassName [] = "Windows"; char lpszTitle [] = "Windows Demo";

wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hInstance = hInstance; wndclass.lpfnWndProc = WndProc; wndclass.lpszClassName = lpszClassName; wndclass.lpszMenuName = NULL; wndclass.style = 0;

if(!RegisterClass(&wndclass)) { return 0; }

hwnd = CreateWindow(lpszClassName, lpszTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, nShowCmd); 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) { switch(message) { case WM_DESTROY: PostQuitMessage(0); default: return DefWindowProc(hwnd, message, wParam, lParam); } return 0; }

Ctrl+F7 编译

F7 生成 exe 文件

Ctrl+F5 运行程序

你将看到我们的第一个简单的 windows program

搜索更多相关主题的帖子: programming windows All 
2004-08-25 07:10
live41
Rank: 10Rank: 10Rank: 10
等 级:贵宾
威 望:67
帖 子:12442
专家分:0
注 册:2004-7-22
得分:0 

error C2065: 'nShowCmd' : undeclared identifier

以上是我编译时的error,不知是否我VC装少了库,不会用API,不过我会去查函数表。 我不想灌水,只是有句不吐不快:

这个是我见过的最有意义的帖子了,不是纯意义教程也不冗长,还可以参与其中,希望楼主继续,我相信会有很多人跟帖的!支持!

PS:最近一个月在搞mfc,傻了不想住,希望先学好API,请楼主也坚持下去啊!

改一下就可以了,nShowCmd -> nCmdShow,不知为什么,我用楼主的方法就可以直接通过,如果我中途在“step 1 of 1”里选择“a simple Win32 application”,然后双击打开“Globals”下的WinMain函数,再把楼主的代码复制进“// TOD Place code here.”这里就不出现我上面说的错误,而且这样做的不同就是“#include "stdafx.h"”和“int APIENTRY WinMain”,而楼主的方法创建的是“#include <windows.h>”和“int WINAPI WinMain”,为什么?

我菜啊,请楼主和大家不耻下答我的愚昧的问题!

[此贴子已经被作者于2004-08-26 01:38:52编辑过]

2004-08-25 15:30
live41
Rank: 10Rank: 10Rank: 10
等 级:贵宾
威 望:67
帖 子:12442
专家分:0
注 册:2004-7-22
得分:0 

先提供两个个好东西about Windows API:

API函数表(txt版) [attach]661[/attach]

WinMain函数介绍:   WinMain是Windows程序的入口点函数,和Dos程序的入口点函数main的作用相同,当WinMain函数结束或返回时,Windows应用程序结束。WinMain函数的原型如下:

int WINAPI WinMain( // :: API = Application Programming Interface -> 应用编程接口 HINSTANCE hInstance, // handle to current instance :: instance -> 实例 HINSTANCE hPrevInstance, // handle to previous instance :: previous -> 前一个 LPSTR lpCmdLine, // pointer to command line :: Cmd = command -> 命令 int nCmdShow // show state of window );

  该函数接受四个参数,这些参数都是系统调用WinMain函数时,传递给应用程序的。

  第一个参数hInstance表示该程序的当前运行的实例句柄。同一应用程序在同一计算机上可运行多份实例,每启动一个这样的实例,操作系统都要给该实例分配一个标识号,即实例句柄,随后系统调用程序中的WinMain函数,并将该实例句柄传递给参数hInstance。

  第二个参数hPrevInstance表示当前实例的上一个正在运行的,由同一个应用程序所产生的实例的句柄,即当前实例的"哥哥"的句柄。如果该值为NULL,则表示当前实例是该程序正在运行的第一份实例,是“长子”,是“老大”。如果该值不为NULL,只能表示当前实例不是该程序正在运行的第一份实例,不是“长子”,不是“老大”,但到底是“老几”,就无从得知了。这个参数到底有什么作用呢?如果想让我们的程序只能有一份实例运行,不能同时有多份实例运行,我们可以在WinMain函数的开始部分加上如下代码实现。

if(hPrevInstance) return 0; // :: -> if(hPrevInstance!=NULL)

  我们再来看看if(hPrevInstance) return 0;的作用,如果hPrevInstance为NULL(即0),说明当前运行的实例是程序的第一个实例,WinMain函数将不返回,程序正常向下运行。只要hPrevInstance不为NULL,说明已经有同样程序的实例在运行,WinMain函数将返回,当前实例启动后立马结束,这样就保证了只有程序的一个实例可以运行。

  第三个参数lpCmdLine是一个字符串,里面包含有传递给应用程序的参数串,如:双击C盘下的1.txt文件方式启动notepad.exe程序,传递给notepad.exe程序的参数串即"c:\1.txt",不包含应用程序名本身。要在VC开发环境中给应用程序传递参数,请选择菜单Project->Settings...,在弹出的Project Settings对话框中选择Debug标签,在该标签页的Program arguments编辑框中输入你想传递给应用程序的参数。我们在WinMain函数的入口点设置一运行断点,以调试方式启动程序运行至该断点处,将鼠标移动到参数lpCmdLine上,在弹出的黄色小浮框中便能观察到该变量的值。在我们的程序调试中,经常要用到这种方法查看变量的值和状态。

  第四个参数nCmdShow指定的程序的窗口应该如何显示,如最大化,最小化,隐藏等。

  WinMain函数前的修饰符WINAPI的解释,我们使用goto definition功能,发现WINAPI其实就是__stdcall。

//// :: std = standard -> 标准

  __stdcall与__cdecl是两种不同的函数调用习惯,定义了参数的传递顺序、堆栈清除等。关于它们的详细信息请参看msdn。由于除了那些可变参数的API函数外,其余的API函数都是__stdcall习惯。由于VC++程序默认的编译选项是__cdecl,所以在VC++中调用这些__stdcall习惯的API函数,必须在声明这些函数的原型时加上__stdcall修饰符,以便对该函数的调用使用__stdcall习惯。我们曾有这样的经验,在Delphi(默认的编译选项是__stdcall)中编写的dll中的函数,在VC++中被调用时,总是造成程序崩溃,在函数的原型声明中加上__stdcall修饰符,便解决了这个问题。回调函数也必须是__stdcall调用习惯,在这里是用CALLBACK来标识的,否则,在NT4.0环境,程序将崩溃,但win98和win2000却没有这种现象。

  Winmain函数的程序代码按功能划分主要有两部分:1.产生并显示程序的主窗口。窗口创建并显示后,用户便可以在窗口上进行各种操作了,用户的操作及程序状态的变化都以消息的形式放到了应用程序的消息队列中。2.从消息队列循环取走消息,并将消息派发到窗口过程函数中去处理。当消息循环取到一条WM_QUIT消息时,将结束循环,WinMain函数返回,结束整个程序的运行。如果WinMain在消息循环之前返回,程序没有正常运行,返回值为0。如果在消息循环之后返回,返回值为WM_QIUT消息的wParam参数。

[此贴子已经被作者于2004-08-27 11:12:30编辑过]

2004-08-25 21:05
kuangjingbo
Rank: 1
等 级:新手上路
帖 子:312
专家分:0
注 册:2004-4-24
得分:0 

WINAPI 和APIENTRY都是FAR PASCAL call,都是用typedef定义的。以及CALLBACK

还有,我觉的应该开一个专门的windows sdk版或者windows编程之类的版。毕竟这些跟c++没有太大的关系。c++不是受限于某一个系统,windows可以用c++,linux也可以用c++,其他的操作系统也可以用c++来描述。而且,sdk本身跟c的关系更密切一些!


永不放弃!
2004-08-26 20:11
kuangjingbo
Rank: 1
等 级:新手上路
帖 子:312
专家分:0
注 册:2004-4-24
得分:0 

我感觉,在

case WM_DESTROY: PostQuitMessage(0);

后面,应该加上break;语句。

经典的windows入门程序,把windows程序的框架很好的展示!


永不放弃!
2004-08-26 20:16
kai
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:52
帖 子:3450
专家分:59
注 册:2004-4-25
得分:0 

live41, 以下回答你2楼的问题:nShowCmd 是 WinMain 的一个形参变量,这个变量在 ShowWindow(hwnd, nShowCmd); 中将被用到,只要保持一致就可以了。如果你在函数中使用nCmdShow, 而在WinMain 函数中定义nShowCmd, 这样就出现前后不一致,所以出现,错误信息,说你有变量没有定义。

至于你说的用其他模式,我觉得没必要,现在就这样按部就班的作吧。

我不打算,一次搞太多,这样很可能就会有朋友没有耐心跟着做了。我打算每次只是让大家往前走一小步,这样大家会有浓厚的兴趣的。

live41, 你放心,我会继续下去的,每星期我都会给出一个完整的代码,最终我们来做实际的项目。

第一段程序只是 windows 程序的框架程序,大家什么也没看到,不过以后在此基础上,慢慢增加代码,就可实现月来越多的内容。

第二个程序代码将在周六贴出。


自由,民主,平等,博爱,进步.
中华民国,我的祖国,中华民国万岁!中华民国加油!
本人自愿加入中国国民党,为人的自由性,独立性和平等性而奋斗!
2004-08-27 02:10
kai
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:52
帖 子:3450
专家分:59
注 册:2004-4-25
得分:0 

kuangjingbo,

你5楼意见我认为可取,这是显而易见的,由于本程序就一个case, 另外一个为default case, 所以不会有任何不正常情况出现。


自由,民主,平等,博爱,进步.
中华民国,我的祖国,中华民国万岁!中华民国加油!
本人自愿加入中国国民党,为人的自由性,独立性和平等性而奋斗!
2004-08-27 02:17
live41
Rank: 10Rank: 10Rank: 10
等 级:贵宾
威 望:67
帖 子:12442
专家分:0
注 册:2004-7-22
得分:0 

谢谢你的解答,我在3楼给了一些相关资料,希望对大家有帮助。我也支持你一个星期一次的做法,其实间隔再长我也会候着你的。我也继续问问题:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nShowCmd) 函数里面的HINSTANCE和LPSTR是类还是结构,还是被typedef了的基本类型?

呵呵,谢谢楼下的回答我的问题,由于不想灌水占地方,所以惟有修改此帖了。

[此贴子已经被作者于2004-08-27 15:51:18编辑过]

2004-08-27 11:11
Knocker
Rank: 8Rank: 8
等 级:贵宾
威 望:47
帖 子:10454
专家分:603
注 册:2004-6-1
得分:0 

HINSTANCE 是实例句柄

LPSTR L 长 P 指针 STR 字符串 一个指向字符串的长指针 这个是16位windows定义的类型,在32位中与PSTR是一样的吧


九洲方除百尺冰,映秀又遭蛮牛耕。汽笛嘶鸣国旗半,哀伤尽处是重生。     -老K
治国就是治吏。礼义廉耻,国之四维。四维不张,国之不国。   -毛泽东
2004-08-27 14:50
live41
Rank: 10Rank: 10Rank: 10
等 级:贵宾
威 望:67
帖 子:12442
专家分:0
注 册:2004-7-22
得分:0 
All about windows programming

感谢楼上,就楼上的“句柄”一词,我把一个通俗的解释贴一下。

关于句柄

  在Windows编程中我们时刻接触到一个称为句柄(HANDLE)的东西。可以这样去理解句柄,Windows程序中产生的任何资源(要占用某一块或大或小的内存),如图标,光标,窗口,应用程序的实例(已加载到内存运行中的程序)。操作系统每产生一个这样的资源时,都要将它们放入相应的内存,并为这些内存指定一个唯一的标识号,这个标识号即该资源的句柄。

  操作系统要管理和操作这些资源,都是通过句柄来找到对应的资源的。按资源的类型,又可将句柄细分成图标句柄(HICON),光标句柄(HCURSOR),窗口句柄(HWND),应用程序实例句柄(HINSTANCE),等等各种类型的句柄。操作系统给每一个窗口指定的一个唯一的标识号即窗口句柄。

2004-08-27 20:50



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-4546-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.674357 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved