var
  FlxpTrayIcon: TlxpTrayIcon;

{ TlxpTrayIcon }

constructor TlxpTrayIcon.Create(AOwner: TComponent);
begin     
  inherited Create(AOwner);
  FlxpTrayIcon := Self;
  ……
end

procedure SetAnimatedIcon(Wnd: HWND; Msg, idEvent: UINT; dwTime: DWORD); stdcall;
begin
  if Msg = WM_TIMER then with FlxpTrayIcon.NotifyIconData do
  begin
    if hIcon = 0 then hIcon := FlxpTrayIcon.FTrayIcon.Handle
    else hIcon := 0;
    Shell_NotifyIcon(NIM_MODIFY, @FlxpTrayIcon.NotifyIconData);
  end;
end;
………
TimerHandle := SetTimer(0, 0, FInterval, @SetAnimatedIcon)
……..

最近在看一本《delphi 精要》的书,其中实现了一个TRAYICON的原代码,其中定时器是用SetTimer实现的,

我把他改写为以下代码:

void CALLBACK SetAnimatedIcon(HWND Wnd,UINT Msg,UINT idEvent,DWORD dwTime)
{
        if(Msg == WM_TIMER)
        {
                if(NotifyIconData.hIcon==NULL)
                {
                        NotifyIconData.hIcon = FTrayIcon->Handle;
                }
                else
                        NotifyIconData.hIcon = NULL;
                Shell_NotifyIcon(NIM_MODIFY,&NotifyIconData);
        }
}
//—————————————————————————

问题1:NotifyIconData是类中的私有变量,他是如何可以在外部函数中可以直接使用的?
问题2:如何在组件实现单元中声明一个实例让他指向自己?
如果有空,最好帮我改写一下DELPHI的实现代码?
BCB中的原码实现TRAYICON我看了的,它没有使用的是SETTIMER,而是用的定时器.

1. 友元(friendly)
2. (没明白意思)

SetAnimatedIcon写成类的成员函数不就可以了?

将外部的某个类声明为friend,外部类就可以访问自己的私有变量和方法了。
SetTimer跟定时器没有什么区别

如果不用回调函数:

C/C++ code
#include <vcl.h> #pragma hdrstop #include "Unit1.h" //————————————————————————— #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; void __fastcall TForm1::WndProc(Messages::TMessage &Message) //重载WM_TIMER消息,楼主也可以用消息映射宏来做 { TForm::WndProc(Message); if(Message.Msg==WM_TIMER && Message.wParam==1) { ShowMessage("AA");// } } //————————————————————————— __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //————————————————————————— void __fastcall TForm1::Button1Click(TObject *Sender) { ::SetTimer(Handle,1,1000,NULL);// } //————————————————————————— void __fastcall TForm1::Button2Click(TObject *Sender) { ::KillTimer(Handle,1);// } //—————————————————————————

SetTimer要求有一个函数指针,执行自定义流程
我在API中是这样调用的:
SetTimer(NULL,NULL,FInterval,(TIMERPROC)SetAnimatedIcon)

就是我定义的:
void CALLBACK SetAnimatedIcon(HWND Wnd,UINT Msg,UINT idEvent,DWORD dwTime)

但这个函数不在类中,却要用到私有变量,
请注意DELPHI中的FlxpTrayIcon对象,这个对象在类外部定义,
var
FlxpTrayIcon: TlxpTrayIcon;

但在DELPHI的函数中却能引用私有变量,不知道它是怎么实现的?

引用 6 楼 jaffy 的回复:
SetTimer要求有一个函数指针,执行自定义流程
我在API中是这样调用的:
SetTimer(NULL,NULL,FInterval,(TIMERPROC)SetAnimatedIcon)

就是我定义的:
void CALLBACK SetAnimatedIcon(HWND Wnd,UINT Msg,UINT idEvent,DWORD dwTime)

但这个函数不在类中,却要用到私有变量,
请注意DELPHI中的FlxpTrayIcon对象,这个对象在类外部定义,
var
FlxpTrayIcon: TlxpTrayIcon;

但在DELPHI的函数中却能引用私有变…


SetTimer是基于WM_TIMER消息的:
引用An application can process WM_TIMER messages by including a WM_TIMER case statement in the window procedure or by specifying a TimerProc callback function when creating the timer. When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER.

The wParam parameter of the WM_TIMER message contains the value of the nIDEvent parameter.

The timer identifier, nIDEvent, is specific to the associated window. Another window can have its own timer which has the same identifier as a timer owned by another window. The timers are distinct.

SetTimer can reuse timer IDs in the case where hWnd is NULL.

如果需要传递一个附加数据到该过程当中,个人建议使用多媒体定时器

关于多媒体定时器,可以参考下面的贴子当中的代码:http://topic.csdn.net/u/20070806/23/43870f4d-0e26-4320-9d0a-2623e3d0d6a1.html

引用 3 楼 wewaa 的回复:
SetAnimatedIcon写成类的成员函数不就可以了?

如果写成成员函数就无法作为函数指针带进去了,多了个_closure
下面是TimerProc的原型

VOID CALLBACK TimerProc(

    HWND hwnd, // handle of window for timer messages
    UINT uMsg, // WM_TIMER message
    UINT idEvent, // timer identifier
    DWORD dwTime // current system time
  );

路过,学习……

自己搞定了

是要用到友员,将SetAnimatedIcon设为一个友员函数
friend void CALLBACK SetAnimatedIcon(HWND Wnd,unsigned int Msg,unsigned int idEvent,unsigned long dwTime);

然后在组件实现单元,申明一个指针,
TLZWTrayIcon *FLZWTrayIcon;

在构造函数中指向自己,FLZWTrayIcon = this;

然后就可以在函数中用到自己的私有变量了:

void CALLBACK SetAnimatedIcon(HWND Wnd,UINT Msg,UINT idEvent,DWORD dwTime)
{
        if(Msg == WM_TIMER)
        {
                if(FLZWTrayIcon->NotifyIconData.hIcon==NULL)
                {
                        FLZWTrayIcon->NotifyIconData.hIcon = FLZWTrayIcon->FTrayIcon->Handle;
                }
                else
                        FLZWTrayIcon->NotifyIconData.hIcon = NULL;
                Shell_NotifyIcon(NIM_MODIFY,&FLZWTrayIcon->NotifyIconData);
        }
}
//—————————————————————————

这样调用SETTIMER时,就没有问题了。谢谢僵哥,你的多媒体定时器,我有时间再来研究。
谢谢各位,结帖了。