张硕(CathyEagle)的专栏

      ——朝闻道,夕死可矣。

用户操作
[即时聊天] [发私信] [加为好友]
张硕ID:CathyEagle
208976次访问,排名366,好友0人,关注者9人。
CathyEagle的文章
原创 57 篇
翻译 0 篇
转载 0 篇
评论 329 篇
CathyEagle的公告
eagleboost@21cn.com

声明:本专栏之文章及照片,除特别注明外均为本人原创,如有转载,敬请注明出处。若需商业用途,请与本人联系。

Google

最近评论
CathyEagle:如果你用的是CHtmlView的话,可以这样写

IWebBrowser2* CMyView::GetActiveWebBrowserPtr(void)
{
if ( m_pBrowserApp )
return m_pBrowserApp;
else
return NULL;
}
renhit:实在惭愧,没明白这里:GetActiveWebBrowserPtr返回活动的浏览器IWebBrowser2接口指针

GetActiveWebBrowserPtr这个函数该怎么实现?不是微软提供的吧?

谢谢
wangzivc2004:非常感谢楼主, 帮了我大忙了.
由于自己不才, 没有看过Hook方面的知识, 虽然知道MFC也是利用Hook模拟模态对话框的, 但是自己就是不知咋办. 现在老大让我用WTL做东西, 发现那里面模态对话框恶心的连键盘消息都无法响应, 最终还是无意间发现这篇经典的文章.

再次感谢
CathyEagle:看了老兄的溢美之词,汗流浃背in……
sunhui:昨天聊到深夜,决定今天来拜读大作,果然精彩!非常佩服你的精细,期待你的MiExplorer早日面世……,很羡慕你的文档写作能力。
文章分类
收藏
    相册
    恋之风景
    我的生活
    C++
    C++ Templates 中文
    Effective STL 中文
    周星星之Blog
    Delphi
    Delphi窑洞
    Torry.net
    大富翁论坛
    源码空间
    绝好的Delphi Tips
    Java
    !Java
    Misc
    SourceForge.org
    Think in Patterns 中文
    ZoCSoft.com
    阿甘的家
    友情链接
    Stanley_Xu 的专栏
    编程手札
    综合
    CodeGuru
    The Code Project
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 具有自动恢复功能的通知栏图标控件收藏

    新一篇: 看男篮对战西班牙——置疑“银狐”的执教水平?还是球员? | 旧一篇: Windows通知栏图标高级编程概述

    任务栏(Taskbar)是微软公司在Windows 95中引入的一种特殊的桌面工具条,它为用户快速访问计算机资源提供了极大的方便,而状态栏(以下称通知栏)无疑是任务栏上较为特殊的一个窗口。编程人员可以调用API函数Shell_NotifyIcon向通知栏发送消息来添加、删除或修改图标,当在图标上发生鼠标或键盘事件时,系统会向应用程序发送编程时预先定义的消息,通知栏处理回调函数就会被自动调用以做出相应的处理。实现上述功能的相关文章俯仰即拾,此处不再赘述。本文将讨论两个较为深入的问题及其在Delphi中的实现方法。
      1、Windows发生错误导致外壳Explorer.exe重启时通知栏图标的自动恢复
      2、将自动恢复功能封装在控件中以便其它程序中调用。

    关键词:通知栏、窗口过程


    1 外壳Explorer重启时通知栏图标的自动恢复
    相信很多Windows用户都碰到过这种情况:运行某个程序时出现意外错误,导致外壳程序Explorer.exe崩溃而发生重启(即Explorer.exe被关闭后重新运行),任务栏也在消失后重新生成,但应用程序在通知栏添加的图标消失了,虽然这些程序仍在运行,但再也无法通过通知栏图标与用户交互。为避免这种情况出现,Windows提供了相应的机制。
    在安装了Internet Explorer 4.0及以上版本的Windows操作系统中,当任务栏建立后,外壳会向所有顶层的应用程序发出通知消息,该消息是外壳以字符串"TaskbarCreated"为参数向系统注册获得的,应用程序窗口接收到该消息后就应该重新添加的通知栏图标。
    在Delphi中实现过程如下:
    1). 定义一个整型变量MsgTaskbarRestart,用以保存任务栏重建的消息。
    2). 在主程序的initialization部分或者是在OnCreate事件中以"TaskbarCreated"为参数向系统注册消息(也即是询问"TaskbarCreated"是哪条消息,因为以相同的参数注册会得到相同的消息,而"TaskbarCreated"在Windows启动的时候就已经被外壳注册)。

    initialization
      MsgTaskbarRestart := RegisterWindowMessage('TaskbarCreated');

    3). 重载主窗口的消息处理过程,拦截任务栏重建消息,进行重新添加图标的操作。

    procedure TMainForm.WndProc(var Message: TMessage);
    begin
      ……
      if Message.Msg = MsgTaskbarRestart then
      begin
        TrayIcon.Active := False;      //删除通知栏图标
        TrayIcon.Active := True;       //添加通知栏图标
      end;
      ……
      inherited WndProc(Message);
    end; //end of WndProc

    2 自动恢复功能的封装
    由于外壳只向所有顶层的应用程序发送通知,这为封装自动恢复功能带来了一定的困难。因为通知栏图标的回调函数只能接收WM_XBUTTONDOWN、WM_XBUTTONUP等有限的几个消息,并不能接收所有的窗口消息。本节介绍的方法将使得在控件中能够接收窗口消息,从而实现自动恢复功能的封装。
    解决问题的关键是SetWindowLong函数,向它传入GWL_WNDPROC参数,可以改变一个窗口的窗口过程。只需在创建控件时将应用程序窗口的窗口过程指针保存起来,并指向为控件中的某个新的窗口处理过程,在控件中就能够响应所有的窗口消息了(包括任务栏重建的消息);当控件销毁的时候再将保存的原始窗口过程指针恢复即可。实现代码如下(其中"……"的地方略去容易实现的添加、删除通知栏图标等函数及过程):

      TEoCSysTray = class(TComponent)
      Private
        ……
        FActive: boolean;
        FParentWindow: TWinControl;     //父窗口
        FNewWndProc: Pointer;     //新的父窗口过程指针
        FPrevWndProc: Pointer;     //原先的父窗口过程指针
        FTaskBarCreated: TNotifyEvent;     //任务栏重建事件
        ……
        procedure SetActive(Value: boolean);   //设置控件是否起作用
        procedure HookParentForm;     //替换父窗口的窗口过程
        procedure UnHookParentForm;     //还原父窗口的窗口过程
        procedure HookWndProc(var AMsg: TMessage);  //新的父窗口过程
      protected
        procedure DoTaskBarCreated; dynamic;   //触发任务栏重建事件
      public
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;
        property Active: boolean read FActive write SetActive;
        property OnTaskBarCreated: TNotifyEvent read FTaskBarCreated
          write FTaskBarCreated;

    implementation

    type
      THack = class(TWinControl);   //用以访问位于父窗口保护域的默认窗口处理过程

    var
      MsgTaskbarCreated  : Integer;   //由系统注册的任务栏重建消息

    constructor TEoCSysTray.Create(AOwner: TComponent);
    begin
      inherited Create(AOwner);
      ……
      FActive := false;
      FNewWndProc := MakeObjectInstance(HookWndProc);//建立新的窗口过程指针
      FPrevWndProc := nil;
      if (AOwner <> nil) and (AOwner is TForm) then  //获得父窗口
        FParentWindow := TWinControl(AOwner)
      else
        FParentWindow := Application.MainForm;
      ……
    end;//end of Contructor

    destructor TEoCSysTray.Destroy;
    begin
      ……
      FDestroying := True;
      FParentWindow := nil;
      FreeObjectInstance(FNewWndProc);
      FNewWndProc := nil;
      ……
      inherited Destroy;
    end; //end of destructor

    procedure TEoCSysTray.SetActive(Value: boolean);
    begin
      if Value <> FActive then
      begin
        FActive := Value;
        if not (csDesigning in ComponentState) then //控件未处于设计状态
          case Value of
            True:
              begin
                ……
                HookParentForm;     //替换父窗口的窗口过程
                ……
              end;
            False:
              begin
                ……
                UnHookParentForm;     //还原父窗口的窗口过程
                ……
              end;
          end;
      end;
    end; //end of procedure SetActive

    procedure TEoCSysTray.HookParentForm;    //替换父窗口的窗口过程
    var
      P                                     : Pointer;
    begin
      if Assigned(FParentWindow) and
        not ((csDesigning in FParentWindow.ComponentState) or
        (csDestroying in FParentWindow.ComponentState) or FDestroying) then
      begin
        FParentWindow.HandleNeeded;
        P := Pointer(GetWindowLong(FParentWindow.Handle, GWL_WNDPROC));
        if (P <> FNewWndProc) then
        begin
          FPrevWndProc := P;
          SetWindowLong(FParentWindow.Handle,
            GWL_WNDPROC, LongInt(FNewWndProc));  //替换父窗口的窗口过程
        end;
      end;
    end; //end of procedure HookParentForm

    procedure TEoCSysTray.UnHookParentForm;   //还原父窗口的窗口过程
    begin
      if Assigned(FParentWindow) then
      begin
        if Assigned(FPrevWndProc) and FParentWindow.HandleAllocated and
          (Pointer(GetWindowLong(FParentWindow.Handle, GWL_WNDPROC)) = FNewWndProc) then
          SetWindowLong(FParentWindow.Handle,
            GWL_WNDPROC, LongInt(FPrevWndProc));  //还原父窗口的窗口过程
      end;
      FPrevWndProc := nil;
    end; //end of procedure UnHookParentForm

    procedure TEoCSysTray.HookWndProc(var AMsg: TMessage);
    begin
      if Assigned(FParentWindow) then
      begin
        with AMsg do
        begin
          if Msg = MsgTaskbarCreated then    //接收到任务栏重建消息
            DoTaskBarCreated;     //触发任务栏重建事件
          if Assigned(FPrevWndProc) then     //调用原窗口的窗口过程
            Result := CallWindowProc(FPrevWndProc, FParentWindow.Handle,
              Msg, WParam, LParam)
          else
            Result := CallWindowProc(THack(FParentWindow).DefWndProc,
              FParentWindow.Handle, Msg, WParam, LParam);
          if Msg = WM_DESTROY then     //窗口正被销毁
            UnHookParentForm;     //还原父窗口的窗口过程
        end;
      end;
    end; //end of procedure HookWndProc

    procedure TEoCSysTray.DoTaskBarCreated;
    begin
      ……    //在这里重新添加通知栏图标
      if Assigned(FTaskBarCreated) then
        FTaskBarCreated(Self);
    end; //end of procedure DoTaskBarCreated

    initialization
      //注册询问任务栏重建的消息
      MsgTaskbarCreated := RegisterWindowMessage('TaskbarCreated');

    end.

    引用地址具有自动恢复功能的通知栏图标控件

    发表于 @ 2004年08月09日 20:59:00|评论(loading...)|编辑

    新一篇: 看男篮对战西班牙——置疑“银狐”的执教水平?还是球员? | 旧一篇: Windows通知栏图标高级编程概述

    评论

    #yellow pages main 发表于2006-04-02 06:12:00  IP: 216.237.126.*
    TrackBack来自《yellow pages main》

    <a href='http://www.yahoo.com'></a>Welcome! http://www.dirare.com/India/ <a href='http://www.dirare.com'>business yellowpages</a>. <a href="http://www.dirare.com ">international directory</a>: MY yellowpages, SMART Yellow Pages, About DIRare. Also [url]http://www.dirare.com/China/[/url] and [link=http://www.dirare.com]companies of the world[/link] from yellow pages .
    #天蝎蝴蝶 发表于2004-08-10 07:39:00  IP: 219.130.215.*
    C#也可以的,原理一样,处理好系统消息就行
    #CathyEagle 发表于2004-08-10 09:29:00  IP: 222.18.4.*
    天蝎蝴蝶说得对。
    #仪表 发表于2004-08-09 23:01:00  IP: 219.131.242.*
    一直希望解决的问题,希望有C#的解决方案
    #lzhidm 发表于2004-09-20 20:51:00  IP: 220.174.209.*
    up
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © CathyEagle