关于主form和application的handle的区别!!!

netlib 2002-07-03 06:45:26
最近发现mainform.handle和application.handle不同,
请问
1、application.handle和主窗口的handle不一样,那么它的本质是什么?
2、系统创建这两个handle的时间?
...全文
489 58 打赏 收藏 转发到动态 举报
写回复
用AI写文章
58 条回复
切换为时间正序
请发表友善的回复…
发表回复
Borlandor 2002-07-04
  • 打赏
  • 举报
回复
不要争论了,看看Application.Handle的用法就明白了。

实例一

利用Delphi实现系统状态栏图标

[ 作者: 小逗逗 添加时间: 2001-9-25 9:19:58 ]


下面以一个具体的例子,详细介绍一下利用Delphi实现系统状态栏图标的步骤和方法。

1.创建一个应用程序,在主窗体上增加一个TpopupMenu组件。并为该弹出选单组件增加选单项Exit,标题为“退出”。

2.在Uses中添加ShellAPI,因为在系统状态栏中增加图标时需调用ShellAPI中的函数Shell_NotifyIconA。该函数需要两个参数,其中一个是TnotifyIconDataA结构,需在主窗体中增加TnotifyIconDataA类型的全局变量ntida。

3.定义消息mousemsg,并编写主窗体的mousemessage消息处理函数,此函数说明在图标上用鼠标左键单击时,会打开应用程序窗口;用鼠标右键单击时,会弹出一个选单。

下面给出步骤2和3的实现代码:

unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, Menus, shellapi;
const
mousemsg = wm_user + 1; //自定义消息,用于处理用户在图标上点击鼠标的事件
iid = 100; //用户自定义数值,在TnotifyIconDataA类型全局变量ntida中使用
type
TForm1 = class(TForm)
......
private
//自定义消息处理函数,处理鼠标点击图标事件
procedure mousemessage(var message: tmessage); message mousemsg;
public
{ Public declarations }
end;
var
Form1: TForm1;
ntida: TNotifyIcondataA;
//用于增加和删除系统状态图标
implementation
{$R .DFM}
procedure TForm1.mousemessage(var message: tmessage);
var
mousept: TPoint; //鼠标点击位置
begin
inherited;
if message.LParam = wm_rbuttonup then begin //用鼠标右键点击图标
getcursorpos(mousept); //获取光标位置
popupmenu1.popup(mousept.x, mousept.y);
//在光标位置弹出选单
end;
if message.LParam = wm_lbuttonup then begin //用鼠标左键点击图标
//显示应用程序窗口
ShowWindow(Handle, SW_SHOW);
//在任务栏上显示应用程序窗口
ShowWindow(Application.handle, SW_SHOW);
SetWindowLong(Application.Handle, GWL_EXSTYLE,
not (GetWindowLong(Application.handle, GWL_EXSTYLE)
or WS_EX_TOOLWINDOW AND NOT WS_EX_APPWINDOW));
end;
message.Result := 0;
end

4.编写FormCreate的代码如下:

procedure TForm1.FormCreate(Sender: TObject);
begin
ntida.cbSize := sizeof(tnotifyicondataa); //指定ntida的长度
ntida.Wnd := handle; //取应用程序主窗体的句柄
ntida.uID := iid; //用户自定义的一个数值,在uCallbackMessage参数指定的消息中使
ntida.uFlags := nif_icon + nif_tip + nif_message;//指定在该结构中uCallbackMessage、hIcon和szTip参数都有效
ntida.uCallbackMessage := mousemsg;
//指定的窗口消息
ntida.hIcon := Application.Icon.handle;
//指定系统状态栏显示应用程序的图标句柄
ntida.szTip := 'Icon';
//当鼠标停留在系统状态栏该图标上时,出现该提示信息
shell_notifyicona(NIM_ADD, @ntida);
//在系统状态栏增加一个新图标
end;

5.编写Tform1.OnClose的代码如下:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caNone; //不对窗体进行任何操作
ShowWindow(Handle, SW_HIDE); //隐藏主窗体
//隐藏应用程序窗口在任务栏上的显示
ShowWindow(Application.Handle, SW_HIDE);
SetWindowLong(Application.Handle, GWL_EXSTYLE,
GetWindowLong(Application.handle, GWL_EXSTYLE)
or WS_EX_TOOLWINDOW AND NOT WS_EX _APPWINDOW);
end;

6.编写Exit代码如下:

当用户点击Exit时实现完全退出应用程序。具体代码如下:

procedure TForm1.ExitClick(Sender: TObject);
begin
//为ntida赋值,指定各项参数
ntida.cbSize := sizeof(tnotifyicondataa);
ntida.wnd := handle;
ntida.uID := iid;
ntida.uFlags := nif_icon + nif_tip + nif_message;
ntida.uCallbackMessage := mousemsg;
ntida.hIcon := Application.Icon.handle;
ntida.szTip := 'Icon';
shell_notifyicona(NIM_DELETE, @ntida);
//删除已有的应用程序图标
Application.Terminate;
//中断应用程序运行,退出应用程序
end

通过以上步骤,我们即可用Delphi轻松实现系统状态栏图标。



实例二

全面禁止WINDOWS

许昭鹏
诸位朋友,你是否曾经有过全面禁止Windows的想法呢?就是诸如禁止Windows桌面、任务栏(包括工具栏的快速启动区域、右下角的通知区域、开始按钮、任务按钮等)、系统按键(包括“Ctrl+Alt+Del”、“Alt+Tab”、“Ctrl+Esc”、“Start-button”等等)、屏幕保护,还有最后的禁止关机。禁止就是不能对它们进行操作,你要是不愿意禁止,你还可以隐藏,把这些统统隐藏起来。

要禁止桌面、任务栏必须知道,当桌面的背景图片刚刚显现,注意这时的屏幕是没有桌面图标和任务栏的,也就是说,它们都是在系统启动后才装入系统的,并不是系统的核心部分。通过对系统当前所有窗体的搜索可以知道,它们都是窗体 (当然,并不是普通的窗体),且都拥有自己的句柄,这样,我们就可以用ShowWindow(Wnd, SW_HIDE)来隐藏它们,或者用EnableWindow(Wnd, False)来禁止它们,是不是很简单。关键是要获得它们的句柄,这可以用FindWindow获得,而用FindWindow必须知道所找窗体的类名。下面先列出我们要用到的类名:

Shell_TrayWnd 任务栏整条

TrayNotifyWnd 任务栏的右下角通知区域

Button 任务栏上的开始按钮

ReBarWindow32 任务栏的工具栏和任务按钮

TrayClockWClass 通知区域的小时钟

ShellDll_DefView 桌面图标

Progman 程序管理器

1. 禁止/隐藏整条任务栏
procedure TForm1.Button1Click(Sender: TObject);

Var Wnd: THandle;

begin

Wnd:= FindWindow('Shell_TrayWnd', nil);

//用下面这一句实现隐藏

if Wnd <> 0 then ShowWindow(Wnd, SW_HIDE);

//用下面这一句实现禁止

if Wnd <> 0 then EnableWindow(Wnd, False);

end;

禁止和隐藏最好只用一个,因为隐藏了,你无处去按,等于禁止;禁止了,失去了作用,藏不藏都无关紧要。最后别忘了恢复正常必须用ShowWindow(Wnd, SW_SHOW)和EnableWindow(Wnd, True)。

注:以下2~6只列出如何使用FindWindow

2. 隐藏任务栏的右下角通知区域
Wnd:= FindWindow('Shell_TrayWnd', nil);

Wnd:=FindWindowEx(Wnd, HWND(0),'TrayNotifyWnd', nil);

3. 禁止/隐藏任务栏上的开始按钮
Wnd:=FindWindow('Shell_TrayWnd', nil);

Wnd:=FindWindowEx(Wnd, HWND(0),'Button', nil);

4. 禁止/隐藏任务栏的工具栏和任务按钮
Wnd:=FindWindow('Shell_TrayWnd', nil);

Wnd:=FindWindowEx(Wnd, HWND(0), 'ReBarWindow32', nil);

5. 隐藏通知区域的小时钟
Wnd:=FindWindow('Shell_TrayWnd', nil);

Wnd:=FindWindowEx(Wnd, HWND(0), 'TrayNotifyWnd', nil);

Wnd:=FindWindowEx(Wnd, HWND(0),'TrayClockWClass', nil);

6. 禁止/隐藏桌面图标
Wnd:=FindWindow('Progman', nil);

Wnd:=FindWindowEx(Wnd, HWND(0), 'ShellDll_DefView', nil);

以上2~6可以直接代入1的Button1Click过程中,以实现相应的功能。并且注意2和5只能隐藏,不能禁止(不信?你可以试试,没有危险的,Hehe)。

7. 在任务栏中隐藏本程序的按钮
Var XWndLong: integer;

begin

XWndLong:= GetWindowLong(Application.Handle,GWL_EXSTYLE);

ShowWindow(Application.Handle,SW_HIDE); //必须先隐藏程序窗口

SetWindowLong(Application.Handle,GWL_EXSTYLE, XWndLong or WS_EX_TOOLWINDOW and not WS_EX_APPWINDOW or WS_EX_TOPMOST);

ShowWindow(Application.Handle, SW_SHOW); //设置按钮隐藏后再恢复窗口

end;

恢复按钮显示用SetWindowLong(Application.Handle,GWL_EXSTYLE, XWndLong);

并且仍然需要两个ShowWindow,将Application.Handle改成其它程序的句柄还可以隐藏其它程序。

8. 从关闭程序对话框(按“Ctrl+Alt+Del”时出现)中隐藏本程序:
先在程序中的implementation前加上这么一句

function RegisterServiceProcess(dwProcessID,dwType:integer):integer; stdcall;external 'KERNEL32.DLL'; //调用系统的外部API函数

然后隐藏用RegisterServiceProcess(GetCurrentProcessID, 1);

恢复显示用RegisterServiceProcess(GetCurrentProcessID, 0);

9. 禁止系统键(包括“Ctrl+Alt+Del”、“Alt+Tab”、“Ctrl+Esc”、“Start-button”等等)
procedure TForm1.Button1Click(Sender:TObject);

var pv: integer;

begin

SystemParametersInfo(SPI_SCREENSAVERRUNNING,1, @pv,0);

end

恢复用SystemParametersInfo(SPI_SCREENSAVERRUNNING,0, @pv,0);

10. 禁止屏幕保护
先增加一过程如下:

procedure TForm1.AppMessage(var msg:TMsg; var Handled: boolean);

begin

if(msg.message = wm_SysCommand)and(msg.wParam = sc_ScreenSave)then

begin

Handled:= True; //禁止屏幕保护

MessageBeep(0); //加入自己的处理

MessageDlg('Screen-saver is Disabled!', mtWarning,[mbOk],
darzui 2002-07-04
  • 打赏
  • 举报
回复
aaronzhang(风不息)的看法似乎有些问题,看下面tapplication.createhandle代码

procedure TApplication.CreateHandle;
var
TempClass: TWndClass;
SysMenu: HMenu;
begin
if not FHandleCreated and not IsConsole then
begin
FObjectInstance := MakeObjectInstance(WndProc);
if not GetClassInfo(HInstance, WindowClass.lpszClassName, TempClass) then
begin
WindowClass.hInstance := HInstance;
if Windows.RegisterClass(WindowClass) = 0 then
raise EOutOfResources.Create(SWindowClass);
end;
FHandle := CreateWindow(WindowClass.lpszClassName, PChar(FTitle),
WS_POPUP or WS_CAPTION or WS_CLIPSIBLINGS or WS_SYSMENU
or WS_MINIMIZEBOX,
GetSystemMetrics(SM_CXSCREEN) div 2,
GetSystemMetrics(SM_CYSCREEN) div 2,
0, 0, 0, 0, HInstance, nil);
FTitle := '';
FHandleCreated := True;
SetWindowLong(FHandle, GWL_WNDPROC, Longint(FObjectInstance));
if NewStyleControls then
begin
SendMessage(FHandle, WM_SETICON, 1, GetIconHandle);
SetClassLong(FHandle, GCL_HICON, GetIconHandle);
end;
SysMenu := GetSystemMenu(FHandle, False);
DeleteMenu(SysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
DeleteMenu(SysMenu, SC_SIZE, MF_BYCOMMAND);
if NewStyleControls then DeleteMenu(SysMenu, SC_MOVE, MF_BYCOMMAND);
end;
end;

在这一句里
FHandle := CreateWindow(WindowClass.lpszClassName, PChar(FTitle),
WS_POPUP or WS_CAPTION or WS_CLIPSIBLINGS or WS_SYSMENU
or WS_MINIMIZEBOX,
GetSystemMetrics(SM_CXSCREEN) div 2,
GetSystemMetrics(SM_CYSCREEN) div 2,
0, 0, 0, 0, HInstance, nil);
这说明,fhandle(就是application.handle属性所读写的字段)是由createwindow返回的,也就是说,它是窗口句柄而不是程序实例句柄,程序实例句柄是HInstance
还有这一句
SendMessage(FHandle, WM_SETICON, 1, GetIconHandle);
这说明程序窗口上的小图标是显示在application.handl窗口上的
tapplication.wndproc里有个子程序
procedure Default;
begin
with Message do
Result := DefWindowProc(FHandle, Msg, WParam, LParam);
end;
...
with Message do
case Msg of
WM_SYSCOMMAND:
case WParam and $FFF0 of
SC_MINIMIZE: Minimize;
SC_RESTORE: Restore;
else
Default;
end;
.....
说明处理消息的窗口是tapplication.handle的窗口

tform.handle是从twincontrol.handle里继承下来的Use the Handle when making Windows API function calls that requires a window handle.
同样是窗口句柄,到底和tappliction.hanle有什么不同,就不清楚了.

以上是本人一点愚见,请大家指正
netlib 2002-07-04
  • 打赏
  • 举报
回复
TO aaronzhang(风不息),我不清楚其中的本质,但有些人说的是错误的,这个我却知道。

请问刚才说application.handle就是任务栏上的那个窗体的handle,那么是不是在VC中写的时候也要创建两个呢(对不起,我对VC不熟:));

有人说application.handle是应该程序的handle,那么请问应用程序(也就是进程)怎么会有handle呢?

我是没有搞清楚才提问的?不会和大家开这种玩笑,:)
  • 打赏
  • 举报
回复
同意楼上的说法!
aaronzhang 2002-07-04
  • 打赏
  • 举报
回复
呵呵,不知道大家看过《Programming Windows》没有,这里面其实说得很清楚,我看的是中文版,呵呵,说说自己的理解吧。

大家在以前的Ms-dos方式下的C编程里肯定都知道Main这个入口函数,现在在Windows里面这个函数也仍然存在,不管是用Delphi还是VC或是VB,到了最后都会调用这个函数,在调用这个函数之前(我觉得应该是)Windows会自动为调用这个Winmain函数的程序分配一个好长好长的整型(呵呵,其实也不会太长),这个长整型数值一般用变量hInstance来表示,这个就是Program的句柄(其实就类似于一个名字,只不过要独一无二,而且Windows得能够解析)。

当启动了一个ProGram后,程序会创建一个Window,函数为CreateWindow,这个就是我们程序的某一个界面,用Delphi的话就是第一个Form,也可以称之为主Form,这个函数会返回一个hwnd,这个就是主Form的句柄。

因此,我觉得实际上句柄就是一个Windows对各个程序的命名,是它给自己的各个孩子(程序和程序中的Form和控件)起的名字。
由于CreateWindow运行时有一个参数为hInstance,这个就是Delphi中的Application.Handle,因此,很明显application.handle比主窗口的Handle早。具体时间应该是在Windows刚开始运行这个可执行文件时就马上给这个可执行文件分配hInstance(Application.Handle),然后调用Winmain函数,在这个函数里CreateWindow,从而产生楼主所说的mainform.Handle。

以上为我的理解,希望能有高手表示一下我这样描述是否正确。


另:不知道楼主netlib (河外孤星)是否对这个问题很清楚,不清楚的话为什么对别的评语似乎都很自信,似乎很了解事情的本质?清楚的话为什么发这个贴子呢?
  • 打赏
  • 举报
回复
偶也同意同意cpls(温柔一刀)的
我就不同意,
这不是子不子的问题,如果是的话,那么完全可以关了子Handle而父HANDLE还在

但我做不到,
我想

我也试过了,确实在Application.Initialize之前就有了,不知道怎么回事还是听到家的吧!

这可能是WIN给每个EXE的HANDLE,是不是每一次不一样呀??

用close有许多问题,不如application.teminate干净,
有好多文章这样说过,我想这也是两个HANDLE中间的差别

APPLICACION的HANDLE,是整个程序的,如前面加载了DLL,或COM而使COM的计数加1了,关APPLICATION也要反向做的,
不过,我们认为没有差别的原因是,
关上主FORM后,APPLICATION马上也关了,我们察不出有什么差别,
只有他们不同步的时候,我们才能看出有什么不同来,
如做一个死循环,用主FORM的HANDLE就不行了,就得用APP的,
是不是?

以上说的不一定对,请大家再指正呀



王集鹄 2002-07-04
  • 打赏
  • 举报
回复
Handle: 句柄; //描述的是系统资源的标识//用于区分不同的资源

系统的资源这就多了,有文件资源资源、图标资源、内存资源....
所有的资源都是通过Handle来处理和区分的

首先:
Application.Handle//这是运用程序资源的标识
Application.MainForm.Handle//这是窗体资源的标识
一种资源是窗体、另一中资源是运用程序
两种资源的类型都不同,可以说没有太大的可比性
Application.MainForm.Handle和Form2.Handle才是同一个类型
要知道 运用程序 不是一个Form,主窗体只是它的一个元素

procedure TApplication.CreateHandle;
var
TempClass: TWndClass;
SysMenu: HMenu;
begin
if not FHandleCreated and not IsConsole then
begin
FObjectInstance := MakeObjectInstance(WndProc);
if not GetClassInfo(HInstance, WindowClass.lpszClassName, TempClass) then
begin
WindowClass.hInstance := HInstance;
if Windows.RegisterClass(WindowClass) = 0 then
raise EOutOfResources.Create(SWindowClass);
end;
//-----------------------------------
FHandle := CreateWindow(WindowClass.lpszClassName, PChar(FTitle),
WS_POPUP or WS_CAPTION or WS_CLIPSIBLINGS or WS_SYSMENU
or WS_MINIMIZEBOX,
GetSystemMetrics(SM_CXSCREEN) div 2,
GetSystemMetrics(SM_CYSCREEN) div 2,
0, 0, 0, 0, HInstance, nil);
//-----------------------------------
FTitle := '';
FHandleCreated := True;
SetWindowLong(FHandle, GWL_WNDPROC, Longint(FObjectInstance));
if NewStyleControls then
begin
SendMessage(FHandle, WM_SETICON, 1, GetIconHandle);
SetClassLong(FHandle, GCL_HICON, GetIconHandle);
end;
SysMenu := GetSystemMenu(FHandle, False);
DeleteMenu(SysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
DeleteMenu(SysMenu, SC_SIZE, MF_BYCOMMAND);
if NewStyleControls then DeleteMenu(SysMenu, SC_MOVE, MF_BYCOMMAND);
end;
end;


procedure TWinControl.CreateWindowHandle(const Params: TCreateParams);
begin
with Params do
FHandle := CreateWindowEx(ExStyle, WinClassName, Caption, Style,
X, Y, Width, Height, WndParent, 0, WindowClass.hInstance, Param);
end;

  • 打赏
  • 举报
回复
打错了这么多,重来一遍!

这两者是不同的,因为WIN的资源不同,但在大都有FORM的程序下有什么不同呢?

在VC中
一个是APP,一个是WIN
但在DELPHI中,我看只是要用到canvas的时候不一样吧,
反正开Application的时候自动激活主FORM
关主FORM的时候,也会关上APPLICATION
是DELPHI把这个东西做在一起了,WIN也把这两个*消息*做在一起了,
为什么还要两个,
因为。。。。我想是不是开多线程是不一样的,或者是在释放某些DLL时是一不样的呢?或者是程序就错了,有了异常,你一定关不掉主FORM吧,
但WIN利用关掉APPLICATION就可以结束程序,
如果你的消息一直是对的,但在这两者之中再有什么动作,我就不知道了

我想这就是有的人用
close

application.teminate
的差别
前者发出了WM_quit的消息
而后者。。。。
我才试了一下,一下子就关上了,不管里面有没有文件没存,
大家能不能再测一测异常的时候,是不是关不掉主FORM,但能关上APP,
谢谢了,


对不起,打字有点问题,不,问题很大
  • 打赏
  • 举报
回复
我也乱说呀

这两者是不同的,因为WIN的资源不同,但在大者有FORM的程序下有什么不同呢

在VC中
一个是APP,一个是WIN
但在DELPHI中我看只是要用到canvas的时候不一样吧,
反正开Application的时候自动激活主FORM
关主FORM的时候,也会关上APPLICATION
是DELPHI把这个东西做在一起了,WIN也把这两个做在一起了,
为什么还要两个,
因为。。。。我想是不是开多线程是不一样的,或者是在释放某些DLL时是一不样的呢?或者是程序就错了,有了异常,你一定关不掉主FORM吧,
但WIN利用关掉APPLICATION就可以结束程序,
如果你的消息一直是对的,但在这两者之中再有什么动作,我就不知道了

我想这就是有的人用
close

application.teminate
的差别
前者发出了WM_quit的消息
而后者。。。。
我上回是一下子就关上了,不管里面有没有文件,
但有些时间了,
大家能不能再测一测,
谢谢了,

Blank_ 2002-07-04
  • 打赏
  • 举报
回复
Application.Handle就是工具条上的那个条条
Form.Handle就是窗体。
yansea 2002-07-04
  • 打赏
  • 举报
回复
阅读中~~~~~~~
kds 2002-07-04
  • 打赏
  • 举报
回复
每贴我都看了,但是不会,帮助提前
xzgyb 2002-07-04
  • 打赏
  • 举报
回复
Masting Delphi6的
var
OldStyle: Integer;
begin
OldStyle := GetWindowLong(Application.Handle, GWL_STYLE);
SetWindowLong(Application.Handle, GWL_STYLE, OldStyle or WS_THICKFRAME or WS_CAPTION);
SetWindowPos(Application.Handle, 0, 0, 200, 100, SWP_NOMOVE or SWP_NOZORDER);
end;

zhptj 2002-07-04
  • 打赏
  • 举报
回复
学习一下
netlib 2002-07-04
  • 打赏
  • 举报
回复
以上回答不让人满意,只有胡呵说的完全正确,但只是提出了大家的错误,
没有解决问题。
LXJ2001(lxj) 帖出的代码我已经看过了,但这能说明application.handle的创建时间和它的本质,还有,如果application本身是一个不让用户看到的窗口,那什么不直接使用mainfm.handle呢,请指教。谢谢!!!
aaronzhang 2002-07-04
  • 打赏
  • 举报
回复
To: netlib(河外孤星)

你觉得huhe(胡呵)再上面说的都对吗?我不这么认为,至少他认为Dll里面没有Application这个观点是肯定错的。我想可以看看Delphi里关于TApplication的帮助和它的Create过程的代码就知道了吧。
LXJ2001 2002-07-04
  • 打赏
  • 举报
回复
to huhe(胡呵):
你早应该出来说了,别老是搞总结发言拉。
Tapplication 中创建一个窗口,它的窗口消息处理函数是DefWindowProc
同时它作为所有窗口的父亲,其他窗口没处理的消息就发送给它,在DefWindowProc中进行处理。
darzui 2002-07-04
  • 打赏
  • 举报
回复
贴主所说的"很搞笑的话",我承认,因为我对这个本来就不很熟悉:)
Borlandor 2002-07-04
  • 打赏
  • 举报
回复
还没有搞明白,大家知道hPreInstance吗?没有用过的话,那你还年轻。
网上资源特别丰富,再灌一篇,让大家了解一下原始的未经包装的Windows程序是怎么写出来的。

但愿不要骂我!


  MFC应用程序的控制流程

  一般的Window应用程序基本流程

  WinMain()函数

  任何一个应用程序都有一个入口函数,在Window下,程序的入口函数根据应用程序的类型,有两种选择:控制台程序的入口函数是main(),一般的Window界面程序的入口函数是WinMain()。这里只探讨同我们下面的讨论有关的WinMain()函数。下面是该函数的原型:(Visuall C++中)

  int APIENTRY WinMain(

    HINSTANCE hInstance,

    HINSTANCE hPrevInstance,

    LPSTR lpCmdLine,

    int nCmdShow)

  其中:

  hInstance是标识当前进程的实例,它实际上是进程所占据的地址空间的首地址,在很多Window API中,都要将它作为一个参数传进去,所以,应用程序一般都会将它保存在一个全局量中。

  hPreInstance是应用程序前一个实例的实例句柄。这是16位Window的残留物,在Win32应用程序中,这个参数始终为NULL。所以,某些从16为移植到32位的应用程序,如果使用了hPreInstance,就应该对代码作相应的修改。

  lpCmdLine是命令行参数,这同main()中的argv[]类似。

  nCmdShow用来指明应用程序的主窗口的显示方式(最大化显示,最小化显示,一般化显示)。

  一个实例

  下面是一个显示”Hello, world”的程序的代码,它体现了一般的Window应用程序的基本流程。

  int APIENTRY WinMain(HINSTANCE hInstance,

      HINSTANCE hPrevInstance,

      LPSTR lpCmdLine,

      int nCmdShow)

  {

   MSG msg;

   file://注册窗口类

   WNDCLASSEX wcex;

   wcex.cbSize = sizeof(WNDCLASSEX);

   wcex.style = CS_HREDRAW | CS_VREDRAW;

   wcex.lpfnWndProc = (WNDPROC)WndProc;

   wcex.cbClsExtra = 0;

   wcex.cbWndExtra = 0;

   wcex.hInstance = hInstance;

   wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_HELLOWORLD);

   wcex.hCursor = LoadCursor(NULL, IDC_ARROW);

   wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

   wcex.lpszMenuName = (LPCSTR)IDC_HELLOWORLD;

   wcex.lpszClassName = szWindowClass;

   wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

   RegisterClassEx(&wcex);

   file://创建一个该类型的窗口

   HWND hWnd;

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,

   CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd) return FALSE;

    file://一nCmdShow所指定的方式显示窗口

    ShowWindow(hWnd, nCmdShow);

    UpdateWindow(hWnd);

    file://启动消息循环,将消息发送给相应的窗口函数

    while (GetMessage(&msg, NULL, 0, 0))

     {

      TranslateMessage(&msg);

      DispatchMessage(&msg);

      }

    return msg.wParam;

   }

   file://窗口函数

  LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

  {

   PAINTSTRUCT ps;

   HDC hdc;

   char* szHello = “Hello, world!”;

    switch (message)

    {

     case WM_PAINT:

      hdc = BeginPaint(hWnd, &ps);

      RECT rt;

      GetClientRect(hWnd, &rt);

      DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);

      EndPaint(hWnd, &ps);

      break;

     case WM_DESTROY:

      PostQuitMessage(0);

      break;

     default:

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

     }

    return 0;

    }

  上面程序的执行过程如下:

  1、注册一个窗口类

  这是为后面的创建窗口作准备,在使用CreateWindwo()和CreateWindowEx()创建窗口时,都必须提供一个标识窗口类的字符串。创建窗口类的主要意图是向操作系统提供窗口处理函数。

  2、创建窗口

     启动消息循环,分发并处理消息。

     其中的关键部分是消息循环:

     while (GetMessage(&msg, NULL, 0, 0))

     {

      TranslateMessage(&msg);

      DispatchMessage(&msg);

     }

调用GetMessage()从线程的消息队列中取出一条消息,将消息翻译后,再调用

DispatchMessage()将该消息分发至相应的窗口过程。(实际上DispatchMessage()是将该消息作为参数调用对应的窗口的窗口函数,这就是分发的实质),在后面我们会详细讨论MFC的消息环同上面的消息环的区别。




darzui 2002-07-04
  • 打赏
  • 举报
回复
to:huhe(胡呵)
"很多人在制造垃圾,搞得大家都没了看帖子和研究问题的兴致:"
这里是什么地方?论坛,所谓论坛就是大家讨论的地方,既然是讨论就难免有对有错.在论坛里说和论坛无关的话,抨击他人,我看这才是真正的垃圾.
"他们的目的是得分,我看应该让他们失分"
目的是得分,从何说起?有分当然更好,但200分的帖子这么多人回答,能有几个人得分?每个人又能得几分?而且本人自认才疏学浅,并不指望从诸位高手手上抢分,发表一下自己的看法,希望从中得到提高而已,我看你的目的才是得分,而且是用排挤他人,抬高自己的方式得分.按照你自己的说法,让自己失分罢!
"回答了这么多贴,没有解决多少实际问题,反倒引出了更多的谬误"
所谓在错误中前进,没有谬误何来真理?想必大虾你说的每句话肯定都是放之四海皆准的真理,既然如此,你已功德圆满,也没有到这里来的必要了.

声明一下:我本来就没说我说的东西都是对的,只是自己的一点看法而已,本人水平和诸位比起来有确实相当大的差距,我是抱着学习的目的来的,也希望有一个自由平等的环境让大家学习,进步.无论水平高低,说话的机会均等,学习的机会均等.
加载更多回复(38)
这几天没事做,研究了下Delphi的托盘编程 。现在很多程序都用这个,比如傲游,迅雷,==,很方便。要代码如下: uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ShellAPI, AppEvnts, StdCtrls, Menus; const WM_NID = WM_User + 1000; //声明一个常量 private { Private declarations } // 定义两个函数 procedure SysCommand(var SysMsg: TMessage); message WM_SYSCOMMAND; procedure WMNID(var msg:TMessage); message WM_NID; public end; var Form1: TForm1; NotifyIcon: TNotifyIconData; // 全局变量 implementation {$R *.dfm} procedure TForm1.WMNID(var msg:TMessage); var mousepos: TPoint; begin GetCursorPos(mousepos); //获取鼠标位置 case msg.LParam of WM_LBUTTONUP: // 在托盘区点击左键后 begin Form1.Visible := not Form1.Visible; // 显示窗体与否 Shell_NotifyIcon(NIM_DELETE, @NotifyIcon); // 显示窗体后删除托盘区的图标 SetWindowPos(Application.Handle, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW); // 在任务栏显示程序 end; WM_RBUTTONUP: PopupMenu1.Popup(mousepos.X, mousepos.Y); // 弹出菜单 end; end; procedure TForm1.FormDestroy(Sender: TObject); begin Shell_NotifyIcon(NIM_DELETE, @NotifyIcon); // 删除托盘图标 end; procedure TForm1.SysCommand(var SysMsg: TMessage); begin case SysMsg.WParam of SC_MINIMIZE: // 当最小化时 begin SetWindowPos(Application.Handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_HIDEWINDOW); Hide; // 在任务栏隐藏程序 // 在托盘区显示图标 with NotifyIcon do begin cbSize := SizeOf(TNotifyIconData); Wnd := Handle; uID := 1; uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP; uCallBackMessage := WM_NID; hIcon := Application.Icon.Handle; szTip := '托盘程序'; end; Shell_NotifyIcon(NIM_ADD, @NotifyIcon); // 在托盘区显示图标 end; else inherited; end; end; {以下三个函数为托盘右键菜单,可自行添加功能} procedure TForm1.N1Click(Sender: TObject); begin ShowMessage('Delphi托盘小程序,Code by Zero Zhang'); end; procedure TForm1.N2Click(Sender: TObject); begin Form1.Visible := true; // 显示窗体 SetWindowPos(Application.Handle, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW); Shell_NotifyIcon(NIM_DELETE, @NotifyIcon); // 删除托盘图标 end; procedure TForm1.N3Click(Sender: TObject); begin Shell_NotifyIcon(NIM_DELETE, @NotifyIcon); Application.Terminate; end; end.

5,388

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧