Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

TrayIcon Source

81 views
Skip to first unread message

JD

unread,
Jun 15, 2005, 7:07:02 AM6/15/05
to

You are free to use the source in whole or in part for what
ever purpose you desire without acknolagement except you may
*not* create a component with it *and/or* sell it or ask for
donations. It's free - period. Any bugs/fixes, please report
them here.

It's an improved version from what I previousely posted in that
not only does it support tray animation and playing wave files,
but now it also supports Balloon Tips and it automatically
reinstalls itself when the TaskBar is recreated after a crash
by Explorer.

The DoBalloonTip method is OS version safe and it has 3 new
events related to this method: OnBalloonShow, OnBalloonClick,
and OnBalloonDismiss. It also supports optionally specifying
a default icon which can be any of the standard MessageBox icons
or your own custom icon which can be up to 32 BPP (OS version
specific).

The following is a simple class that you can allocate at
runtime but the code is ready for any one to wrap into a
component.

//--------------------------------------------------------------
#ifndef AnimatedTrayIconH
#define AnimatedTrayIconH
//--------------------------------------------------------------
#include <Classes.hpp>
#include <vector>
//--------------------------------------------------------------
// M$ says this should be 0x0500 for shellapi >= 5.0
// but cpp needs it to be 0x0501 or 0x0600
#undef _WIN32_IE
#define _WIN32_IE 0x0501
#include <shellapi.h>
#include <shlwapi.h>
#include <mmsystem.h>
//--------------------------------------------------------------
#include "TrayThread.h"
//--------------------------------------------------------------
enum TBalloonIconType
{
itNone = 0,
itInformation,
itWarning,
itError,
itQuestion,
itNoSound,
itUser
};
//--------------------------------------------------------------
class TAnimatedTrayIcon : public TComponent
{
private:
#define NIIF_QUESTION 0x07
#define NIIF_USER 0x14
typedef TComponent inherited;
LPVOID MinimizeWave, RestoreWave;
DWORD MinimizeSize, RestoreSize;
unsigned int ClickTimer;
unsigned int CM_TRAYNOTIFY;
unsigned int CM_TRAYCREATED;
unsigned int CM_TASKBARCREATED;
std::vector<HWND>vZOrder;
std::vector<TForm*>vForms;

HWND FHandle;
TForm *FParentForm;
TRect BoundsRect, TrayRect;
TAnimatedTrayIconThread *FThread;
bool FMinimized, FHooked, FInstalled, FAnimating, FCanBalloon;

bool FLoopSound;
bool FUseTray;
int FDelay;
int FStaticIndex;
bool FActive;
int FTrayID;
int FFromIndex;
int FToIndex;
TThreadPriority FPriority;
AnsiString FStaticHint;
AnsiString FAnimationHint;
AnsiString FAnimateWave;
TImageList *FImageList;
TPopupMenu *FPopupMenu;
HIMAGELIST hImageList;

AnsiString FBalloonCaption;
AnsiString FBalloonText;
TBalloonIconType FBalloonIconType;
UINT FBalloonIcon;
UINT FBalloonTimeout;

TMouseEvent FOnMouseUp;
TMouseEvent FOnMouseDown;
TNotifyEvent FOnDblClick;
TNotifyEvent FOnBalloonShow;
TNotifyEvent FOnBalloonClick;
TNotifyEvent FOnBalloonDismiss;

void __fastcall LoadSound( AnsiString ID, DWORD &Size, LPVOID &hMemWave );
void __fastcall SetClickTimer( bool Enable );
void __fastcall ModifyTray();
void __fastcall DetermineShellVersion();
void __fastcall GetSysTrayRect();

// setter methods
void __fastcall SetActive( bool State );
void __fastcall SetStaticIndex( int Index );
void __fastcall SetStaticHint( AnsiString Hint );
void __fastcall SetImageList( TImageList* );
void __fastcall SetPopupMenu( TPopupMenu* );
protected:
virtual void __fastcall Loaded();
virtual void __fastcall Notification( TComponent *AComponent, TOperation Operation );
virtual void __fastcall WndProc( TMessage &Message );
void __fastcall MouseDown(TMouseButton Button, TShiftState Shift );
void __fastcall MouseUp(TMouseButton Button, TShiftState Shift );
bool __fastcall AppHook( TMessage &Message );
public:
void __fastcall StartAnimation();
void __fastcall StopAnimation();
bool __fastcall Minimize();
bool __fastcall Restore();
void __fastcall DoBalloonTip();
__fastcall TAnimatedTrayIcon(TComponent* Owner);
__fastcall TAnimatedTrayIcon::~TAnimatedTrayIcon();
__published:
__property TMouseEvent OnMouseUp = { read = FOnMouseUp, write = FOnMouseUp };
__property TMouseEvent OnMouseDown = { read = FOnMouseDown, write = FOnMouseDown };
__property TNotifyEvent OnDblClick = { read = FOnDblClick, write = FOnDblClick };
__property TNotifyEvent OnBalloonShow = { read = FOnBalloonShow, write = FOnBalloonShow };
__property TNotifyEvent OnBalloonClick = { read = FOnBalloonClick, write = FOnBalloonClick };
__property TNotifyEvent OnBalloonDismiss = { read = FOnBalloonDismiss, write = FOnBalloonDismiss };
__property int AnimationDelay = { read = FDelay, write = FDelay, default = 50 };
__property int TrayID = { read = FTrayID, write = FTrayID, default = 1643 };
__property int AnimateIndexStart = { read = FFromIndex, write = FFromIndex };
__property int AnimateIndexEnd = { read = FToIndex, write = FToIndex };
__property AnsiString AnimationHint = { read = FAnimationHint, write = FAnimationHint };
__property AnsiString AnimateWaveSound = { read = FAnimateWave, write = FAnimateWave };
__property TThreadPriority AnimationPriority = { read = FPriority, write = FPriority, default = tpNormal };
__property TImageList *ImageList = { read = FImageList, write = SetImageList };
__property TPopupMenu *PopupMenu = { read = FPopupMenu, write = SetPopupMenu };
__property bool LoopAnimateSound = { read = FLoopSound, write = FLoopSound, default = true };
__property bool Active = { read = FActive, write = SetActive, default = false };
__property int StaticIndex = { read = FStaticIndex, write = SetStaticIndex };
__property AnsiString StaticHint = { read = FStaticHint, write = SetStaticHint };
__property bool MinimizeToTray = { read = FUseTray, write = FUseTray, default = true };
__property AnsiString BalloonCaption = { read = FBalloonCaption, write = FBalloonCaption };
__property AnsiString BalloonText = { read = FBalloonText, write = FBalloonText };
__property TBalloonIconType BalloonIconType = { read = FBalloonIconType, write = FBalloonIconType, default = itInformation };
// HICON is not an allowed type so I just used UINT and cast it when it's used
__property UINT BalloonIcon = { read = FBalloonIcon, write = FBalloonIcon };
__property UINT BalloonTimeout = { read = FBalloonTimeout, write = FBalloonTimeout, default = 1500 };
};
//--------------------------------------------------------------
#endif


//--------------------------------------------------------------
#include <vcl.h>
//--------------------------------------------------------------
#pragma hdrstop
//--------------------------------------------------------------
#include "AnimatedTrayIcon.h"
//--------------------------------------------------------------
// Tray.res is not included with the sample.
// All it is [was] is the sound resources.
//#pragma resource "Tray.res"
//--------------------------------------------------------------
#pragma package(smart_init)

// Used to ensure only a single instance of this object type application wide
TAnimatedTrayIcon *ThisInstance = NULL;
//--------------------------------------------------------------
__fastcall TAnimatedTrayIcon::TAnimatedTrayIcon( TComponent *Owner ) : TComponent(Owner)
{
if( ThisInstance ) throw Exception("Only one instance of TTrayIcon is allowed per application.");
if( !Owner ) throw Exception("You must assign an Owner.");
FParentForm = dynamic_cast<TForm*>(Owner);
if( !FParentForm ) throw Exception("The Owner must be a TForm.");
ThisInstance = this;

FThread = NULL;
ClickTimer = NULL;
RestoreWave = NULL;
MinimizeWave = NULL;
FBalloonIcon = NULL;
RestoreSize = 0;
MinimizeSize = 0;
FInstalled = false;
FAnimating = false;
FHooked = false;

if( !ComponentState.Contains(csDesigning) )
{
GetSysTrayRect();
DetermineShellVersion();

LoadSound( "MINIMIZE", MinimizeSize, MinimizeWave );
LoadSound( "RESTORE", RestoreSize, RestoreWave );

CM_TRAYNOTIFY = ::RegisterWindowMessage( "TAnimatedTrayIconNotifyMessage" );
CM_TRAYCREATED = ::RegisterWindowMessage( "TAnimatedTrayIconCreatedMessage" );
CM_TASKBARCREATED = ::RegisterWindowMessage( "TaskbarCreated" );

Application->HookMainWindow( AppHook );
FHooked = true;

FHandle = AllocateHWnd( WndProc );

// PostMessage is used because at this point Application::MainForm is still NULL
::PostMessage( Application->Handle, CM_TRAYCREATED, 0, 0 );
}
}
//--------------------------------------------------------------
__fastcall TAnimatedTrayIcon::~TAnimatedTrayIcon()
{
SetActive( false );
if( ClickTimer ) ::KillTimer( Application->MainForm->Handle, ClickTimer );
DeallocateHWnd( FHandle );
if( FHooked ) Application->UnhookMainWindow( AppHook );
if( MinimizeWave ) ::VirtualFree( MinimizeWave, MinimizeSize, MEM_FREE );
if( RestoreWave ) ::VirtualFree( RestoreWave, RestoreSize, MEM_FREE );
ThisInstance = NULL;
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::Notification( TComponent *AComponent, TOperation Operation )
{
inherited::Notification( AComponent, Operation );
if( Operation == opRemove )
{
if( AComponent == FImageList ) SetImageList( NULL );
else if( AComponent == FPopupMenu ) SetPopupMenu( NULL );
}
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::Loaded()
{
inherited::Loaded();
if( FActive ) ModifyTray();
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::GetSysTrayRect()
{
::GetWindowRect( ::FindWindowEx(::FindWindow("Shell_TrayWnd", NULL), NULL, "TrayNotifyWnd", NULL), &TrayRect );
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::DetermineShellVersion()
{
// Thanks to Gambit for this one - even if I had to google it up
WORD Major = 0;
HINSTANCE hShell = ::GetModuleHandle( "SHELL32" );
if( hShell )
{
DLLGETVERSIONPROC lpDllGetVersion = (DLLGETVERSIONPROC) ::GetProcAddress( hShell, "DllGetVersion" );
if( lpDllGetVersion )
{
DLLVERSIONINFO dvi = { sizeof(DLLVERSIONINFO), 0 };
if SUCCEEDED(lpDllGetVersion(&dvi)) Major = dvi.dwMajorVersion;
}
}
if( Major < 5 ) FCanBalloon = false;
else FCanBalloon = true;
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::LoadSound( AnsiString ID, DWORD &Size, LPVOID &MemoryWave )
{
HRSRC SoundResource = ::FindResource( HInstance, ID.c_str(), "WAVE" );
if( SoundResource )
{
Size = ::SizeofResource( HInstance, SoundResource );
if( Size )
{
HGLOBAL SoundLoad = ::LoadResource( HInstance, SoundResource );
if( SoundLoad )
{
LPVOID SoundPointer = ::LockResource( SoundLoad );
if( SoundPointer )
{
MemoryWave = ::VirtualAlloc( NULL, Size, MEM_COMMIT, PAGE_READWRITE );
if( MemoryWave ) ::CopyMemory( MemoryWave, SoundPointer, Size );
}
}
}
}
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::ModifyTray()
{
NOTIFYICONDATA IconData = { 0 };
IconData.cbSize = sizeof( NOTIFYICONDATA );
IconData.hWnd = FHandle;
IconData.uID = FTrayID;
if( ComponentState.Contains(csDestroying) )
{
if( FInstalled ) ::Shell_NotifyIcon( NIM_DELETE, &IconData );
}
else if( !ComponentState.Contains(csLoading) && !ComponentState.Contains(csDesigning) )
{
IconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
IconData.uCallbackMessage = CM_TRAYNOTIFY;
IconData.hIcon = NULL;
StrLCopy( IconData.szTip, FStaticHint.c_str(), sizeof(IconData.szTip) - 1 );
if( FActive )
{
if( !FImageList )
{
FActive = false;
throw Exception("TAnimatedTrayIcon : ImageList not assigned.");
}
if( FStaticIndex >= FImageList->Count )
{
FActive = false;
throw Exception("TAnimatedTrayIcon : Index range error.");
}
IconData.hIcon = ::ImageList_GetIcon( hImageList, FStaticIndex, ILD_TRANSPARENT );
if( !FInstalled )
{
::Shell_NotifyIcon( NIM_ADD, &IconData );
FInstalled = true;
}
else ::Shell_NotifyIcon( NIM_MODIFY, &IconData );
::DestroyIcon( IconData.hIcon );
}
else if( FInstalled )
{
::Shell_NotifyIcon( NIM_DELETE, &IconData );
FInstalled = false;
}
}
}
//--------------------------------------------------------------
//---
//--- M M OOO U U SSSS EEEEE
//--- MM MM O O U U S E
//--- M M M O O U U SSS EEEE
//--- M M O O U U S E
//--- M M OOO UUU SSSS EEEEE
//---
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::MouseDown( TMouseButton Button, TShiftState Shift )
{
if( FOnMouseDown )
{
POINT P;
::GetCursorPos( &P );
FOnMouseDown( this, Button, Shift, P.x, P.y );
}
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::MouseUp( TMouseButton Button, TShiftState Shift )
{
POINT P;
::GetCursorPos( &P );
if( Button == mbRight )
{
if( FPopupMenu )
{
::SetForegroundWindow( Application->MainForm->Handle );
FPopupMenu->PopupComponent = this;
FPopupMenu->Popup( P.x, P.y );
::PostMessage( Application->MainForm->Handle, WM_NULL, 0, 0 );
}
}
else if( Button == mbLeft ) Restore();
if( FOnMouseUp ) FOnMouseUp( this, Button, Shift, P.x, P.y );
}
//--------------------------------------------------------------
//---
//--- H H OOO OOO K K SSSS
//--- H H O O O O K K S
//--- HHHHH O O O O K K SSS
//--- H H O O O O K K S
//--- H H OOO OOO K K SSSS
//---
//--------------------------------------------------------------
bool __fastcall TAnimatedTrayIcon::AppHook( TMessage &Message )
{
if( Message.Msg == WM_SYSCOMMAND )
{
switch( Message.WParam )
{
case SC_RESTORE:
case SC_MAXIMIZE: return Restore();
case SC_MINIMIZE: return Minimize();
}
}
else if( Message.Msg == CM_TRAYCREATED )
{
if( FParentForm != Application->MainForm )
{
MessageDlg( "TAnimatedTrayIcon can only be placed on the Main Form.", mtError, TMsgDlgButtons() << mbOK, 0 );
Application->Terminate();
}
else
{
if( Application->MainForm->WindowState == wsMinimized ) FMinimized = true;
else FMinimized = false;
BoundsRect = Application->MainForm->BoundsRect;
}
}
return false;
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::WndProc( TMessage &Message )
{ /*
Adding mouse events presented a problem because of the way that windows
generates the WM_ messages. In response to a double click, Windows actually
generate 4 messsages: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, and
WM_LBUTTONUP again. The problem this creates is being able to distinguish
between a single mouse click and the first click of a double click. In
addition, the final WM_LBUTTONUP message signals another click.

How I handled this was to use a timer which is enabled on the first
WM_LBUTTONUP and disabled on the WM_LBUTTONDBLCLK. If a WM_LBUTTONDBLCLK is
not detected within the specified system time for a double click, the timer
activates and MouseUp is executed. If a WM_LBUTTONDBLCLK is detected, the
timer is disabled, causing the first WM_LBUTTONUP to be ignored, and the
double click is processed.

The last problem was to deal with the final WM_LBUTTONUP message. I handled
this by making the calls to SetClickTimer (in a fashion) nested. This way,
when WM_LBUTTONDBLCLK is processed, by disabling the timer a second time,
the next call to enable it does nothing - which is exactly what needs to
happen when that final WM_LBUTTONUP is detected. */

static TShiftState LeftClickShift;
if( Message.Msg == CM_TRAYNOTIFY )
{
TShiftState Shift = KeysToShiftState( Message.WParam );
switch( Message.LParam )
{
case WM_LBUTTONUP: LeftClickShift = Shift;
SetClickTimer( true );
break;
case WM_MBUTTONUP: MouseUp ( mbMiddle, Shift ); break;
case WM_RBUTTONUP: MouseUp ( mbRight, Shift ); break;
case WM_LBUTTONDOWN: MouseDown( mbLeft, Shift ); break;
case WM_MBUTTONDOWN: MouseDown( mbMiddle, Shift ); break;
case WM_RBUTTONDOWN: MouseDown( mbRight, Shift ); break;
case WM_LBUTTONDBLCLK: SetClickTimer( false );
SetClickTimer( false );
Restore();
if( FOnDblClick ) FOnDblClick( this );
break;
case NIN_BALLOONSHOW: if( FOnBalloonShow ) FOnBalloonShow( this ); break;
case NIN_BALLOONHIDE: // hide is not currently use shell32 v6 but might be in the future
case NIN_BALLOONTIMEOUT: // timeout is sent also when close clicked. if you want a timeout event, you have to count it yourself
if( FOnBalloonDismiss ) FOnBalloonDismiss( this ); break;
case NIN_BALLOONUSERCLICK: if( FOnBalloonClick ) FOnBalloonClick( this ); break;
}
}
else if( Message.Msg == WM_TIMER && (unsigned)Message.WParam == ClickTimer )
{
SetClickTimer( false );
MouseUp( mbLeft, LeftClickShift );
}
else if( Message.Msg == CM_TASKBARCREATED && CM_TASKBARCREATED != 0 )
{
GetSysTrayRect();
if( FInstalled )
{
if( FLoopSound ) ::PlaySound( NULL, NULL, NULL );
if( FAnimating ) StopAnimation();
FInstalled = false;
ModifyTray();
}
}
else Message.Result = DefWindowProc( FHandle, Message.Msg, Message.WParam, Message.LParam );
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::SetClickTimer( bool Enable )
{
static int Count = 0;
if( Enable )
{
if( Count == 0 )
{
// CM_TRAYCREATED is only used a single time which is to install
// a hook so instead of defining another variable, it's reused here
ClickTimer = ::SetTimer( FHandle, CM_TRAYCREATED, ::GetDoubleClickTime() + 10, NULL );
}
++Count;
}
else
{
if( ClickTimer )
{
::KillTimer( Application->MainForm->Handle, ClickTimer );
ClickTimer = NULL;
}
--Count;
}
}
//--------------------------------------------------------------
//---
//--- SSSS EEEEE TTTTT TTTTT EEEEE RRRR SSSS
//--- S E T T E R R S
//--- SSS EEEE T T EEEE RRRR SSS
//--- S E T T E R R S
//--- SSSS EEEEE T T EEEEE R R SSSS
//---
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::SetActive( bool State )
{
if( FActive != State )
{
FActive = State;
ModifyTray();
}
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::SetPopupMenu( TPopupMenu *PopupMenu )
{
if( FPopupMenu != PopupMenu )
{
FPopupMenu = PopupMenu;
if( FPopupMenu ) FPopupMenu->FreeNotification( this );
}
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::SetStaticIndex( int Index )
{
if( FStaticIndex != Index )
{
FStaticIndex = Index;
ModifyTray();
}
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::SetStaticHint( AnsiString Hint )
{
if( FStaticHint != Hint )
{
FStaticHint = Hint;
ModifyTray();
}
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::SetImageList( TImageList *ImageList )
{
if( FImageList != ImageList )
{
bool WasActive = FActive;
if( FAnimating ) StopAnimation();
FImageList = ImageList;
if( FInstalled ) SetActive( false );
if( FImageList )
{
hImageList = (HIMAGELIST)FImageList->Handle;
FImageList->FreeNotification( this );
if( FImageList->Count > 0 )
{
FStaticIndex = 0;
if( FImageList->Count > 1 )
{
FFromIndex = 1;
FToIndex = FImageList->Count - 1;
}
else
{
FFromIndex = 0;
FToIndex = 0;
}
if( WasActive ) SetActive( true );
}
else
{
FStaticIndex = -1;
FFromIndex = -1;
FToIndex = -1;
}
}
else hImageList = NULL;
}
}
//--------------------------------------------------------------
//---
//--- PPPP U U BBBB L IIIII CCCC
//--- P P U U B H L I C
//--- PPPP U U BBBB L I C
//--- P U U B B L I C
//--- P UUU BBBB LLLLL IIIII CCCC
//---
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::StartAnimation()
{
if( !FThread )
{
if( !FImageList ) throw Exception("TAnimatedTrayIcon : ImageList not assigned.");
if( FFromIndex < 0 || FToIndex < 0 || FFromIndex >= FImageList->Count || FToIndex >= FImageList->Count || FFromIndex > FToIndex ) throw Exception("TAnimatedTrayIcon : Index range error.");
if( FDelay < 1 ) throw Exception("TAnimatedTrayIcon : Invalid Delay factor.");

// Play sound directly from resource
unsigned int Flags = SND_ASYNC | SND_NODEFAULT | SND_NOWAIT;
if( FLoopSound ) Flags |= SND_LOOP;
::PlaySound( FAnimateWave.c_str(), HInstance, Flags );

FThread = new TAnimatedTrayIconThread( // current tray info
FInstalled,
FStaticIndex,
FStaticHint,
FTrayID,
hImageList,
FHandle,
CM_TRAYNOTIFY,
// new tray info
FFromIndex,
FToIndex,
FAnimationHint,
// thread info
FPriority,
FDelay );
FAnimating = true;
}
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::StopAnimation()
{
if( FThread )
{
::PlaySound( NULL, NULL, NULL );
FThread->Terminate();
FThread->WaitFor();
delete FThread;
FThread = NULL;
FAnimating = false;
}
}
//--------------------------------------------------------------
bool __fastcall TAnimatedTrayIcon::Minimize()
{
FMinimized = true;
if( FUseTray && FActive )
{
if( !FAnimating || !FLoopSound ) ::PlaySound( (LPCSTR)MinimizeWave, NULL, SND_MEMORY | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT );
BoundsRect = Application->MainForm->BoundsRect;
::DrawAnimatedRects(Application->MainForm->Handle, IDANI_CAPTION, &BoundsRect, &TrayRect );
if( Application->MainForm->FormStyle != fsMDIForm )
{
for( int x = 0; x < Screen->FormCount; ++x )
{
if( Screen->Forms[x]->Visible ) vForms.push_back( Screen->Forms[x] );
}
HWND hWnd = ::GetTopWindow( Application->MainForm->Handle );
while( hWnd )
{
vZOrder.push_back( hWnd );
hWnd = ::GetNextWindow( hWnd, GW_HWNDNEXT );
}
for( unsigned int x = 0; x < vForms.size(); ++x ) vForms[x]->Visible = false;
}
else Application->MainForm->Visible = false;
Application->ShowMainForm = false;
::ShowWindow( Application->Handle, SW_HIDE );
::SetWindowLong( Application->Handle, GWL_STYLE, ::GetWindowLong(Application->Handle, GWL_STYLE) | WS_MINIMIZE );
return true;
}
return false;
}
//--------------------------------------------------------------
bool __fastcall TAnimatedTrayIcon::Restore()
{
bool Result = false;
if( FUseTray && FActive && FMinimized )
{
if( !FAnimating || !FLoopSound ) ::PlaySound( (LPCSTR)RestoreWave, NULL, SND_MEMORY | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT );
::DrawAnimatedRects(Application->MainForm->Handle, IDANI_CAPTION, &TrayRect, &BoundsRect );
if( Application->MainForm->FormStyle != fsMDIForm )
{
for( int x = vForms.size() - 1; x > -1; --x ) vForms[x]->Visible = true;
for( int x = vZOrder.size() - 1; x > -1; --x ) ::ShowWindow( vZOrder[x], SW_SHOW );
vZOrder.clear();
vForms.clear();
}
else
{
Application->MainForm->Visible = true;
Application->MainForm->ArrangeIcons();
}
Application->ShowMainForm = true;
::ShowWindow( Application->Handle, SW_SHOW );
Application->Restore();
Application->BringToFront();
Result = true;
}
FMinimized = false;
return Result;
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIcon::DoBalloonTip()
{
if( FCanBalloon && FActive )
{
NOTIFYICONDATA IconData = { 0 };
IconData.cbSize = sizeof( IconData );
IconData.hWnd = FHandle;
IconData.uID = FTrayID;
IconData.uTimeout = FBalloonTimeout;
IconData.uFlags = NIF_INFO;
StrLCopy( IconData.szInfo, FBalloonText.c_str(), 255 );
StrLCopy( IconData.szInfoTitle, FBalloonCaption.c_str(), 63 );

switch( FBalloonIconType )
{
case itNoSound: IconData.dwInfoFlags = NIIF_NOSOUND; break;
case itError: IconData.dwInfoFlags = NIIF_ERROR; break;
case itWarning: IconData.dwInfoFlags = NIIF_WARNING; break;
case itQuestion: IconData.dwInfoFlags = NIIF_QUESTION; break;
case itInformation: IconData.dwInfoFlags = NIIF_INFO; break;
case itUser: if( FBalloonIcon )
{
IconData.dwInfoFlags = NIIF_USER;
IconData.uFlags |= NIF_ICON;
IconData.hIcon = (HICON) FBalloonIcon;
}
else IconData.dwInfoFlags = NIIF_NONE;
break;
default: IconData.dwInfoFlags = NIIF_NONE;
}
Shell_NotifyIcon( NIM_MODIFY, &IconData );
}
}
//--------------------------------------------------------------

//--------------------------------------------------------------
#ifndef TrayThreadH
#define TrayThreadH
//--------------------------------------------------------------
#include <Classes.hpp>
#include <ImgList.hpp>
//--------------------------------------------------------------
class TAnimatedTrayIconThread : public TThread
{
private:
bool Installed;
int StaticIndex;
AnsiString StaticHint;
int TrayID;
HIMAGELIST hImageList;
HWND hWnd;
unsigned int CM_TRAYNOTIFY;
int FromIndex;
int ToIndex;
AnsiString AnimateHint;
int Delay;
protected:
void __fastcall Execute();
public:
__fastcall TAnimatedTrayIconThread( bool, int, const AnsiString&, int, HIMAGELIST, HWND, unsigned int, int, int, const AnsiString&, TThreadPriority, int );
};
//--------------------------------------------------------------
#endif

//--------------------------------------------------------------
#pragma hdrstop
//--------------------------------------------------------------
#include "TrayThread.h"
//--------------------------------------------------------------
#pragma package(smart_init)
//--------------------------------------------------------------
__fastcall TAnimatedTrayIconThread::TAnimatedTrayIconThread( bool IsInstalled,
int CurrentIndex,
const AnsiString &SHint,
int ID,
HIMAGELIST hList,
HWND hwnd,
unsigned int TRAY_MESSAGE,
int FIndex,
int TIndex,
const AnsiString &AHint,
TThreadPriority APriority,
int Count )
: TThread( true )
{
Installed = IsInstalled;
StaticIndex = CurrentIndex;
StaticHint = SHint;
TrayID = ID;
hImageList = hList;
hWnd = hwnd;
CM_TRAYNOTIFY = TRAY_MESSAGE;
FromIndex = FIndex;
ToIndex = TIndex;
AnimateHint = AHint;
Priority = APriority;
Delay = Count;
Resume();
}
//--------------------------------------------------------------
void __fastcall TAnimatedTrayIconThread::Execute()
{
NOTIFYICONDATA IconData = { 0 };
IconData.cbSize = sizeof( NOTIFYICONDATA );
IconData.hWnd = hWnd;
IconData.uID = TrayID;
IconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
IconData.uCallbackMessage = CM_TRAYNOTIFY;
IconData.hIcon = NULL;
StrLCopy( IconData.szTip, AnimateHint.c_str(), sizeof(IconData.szTip) - 1 );

if( !Installed )
{
IconData.hIcon = ::ImageList_GetIcon( hImageList, FromIndex, ILD_TRANSPARENT );
::Shell_NotifyIcon( NIM_ADD, &IconData );
}

while( !Terminated )
{
for( int x = FromIndex; x <= ToIndex && !Terminated; ++x )
{
::DestroyIcon( IconData.hIcon );
IconData.hIcon = ::ImageList_GetIcon( hImageList, x, ILD_TRANSPARENT );
::Shell_NotifyIcon( NIM_MODIFY, &IconData );
::Sleep( Delay );
}
}

if( !Installed ) ::Shell_NotifyIcon( NIM_DELETE, &IconData );
else
{
::DestroyIcon( IconData.hIcon );
IconData.hIcon = ::ImageList_GetIcon( hImageList, StaticIndex, ILD_TRANSPARENT );
StrLCopy( IconData.szTip, StaticHint.c_str(), sizeof(IconData.szTip) - 1 );
::Shell_NotifyIcon( NIM_MODIFY, &IconData );
}
::DestroyIcon( IconData.hIcon );
}
//--------------------------------------------------------------

~ JD

Vladimir Stefanovic

unread,
Jun 15, 2005, 7:57:16 AM6/15/05
to
Thanks. I just wanted to ask you if you can post the most
recent and complete code you have about TrayIcon...

--
Best regards,
Vladimir Stefanovic
"JD" <nos...@nospam.com> wrote in message
news:42b00bd6$1...@newsgroups.borland.com...

JD

unread,
Jun 15, 2005, 8:15:01 AM6/15/05
to

"Vladimir Stefanovic" <anti...@po.sbb.co.yu> wrote:
>

Shame shame. You didn't trim that rather lengthly post.

> I just wanted to ask you if you can post the most
> recent and complete code you have about TrayIcon...

Just now? I just did! ;-). Didn't you already have code
that did the same? Your name popped up all over my googles.

~ JD

Vladimir Stefanovic

unread,
Jun 15, 2005, 8:30:04 AM6/15/05
to
> Shame shame. You didn't trim that rather lengthly post.

For such useful piece of code - it's worth while ;)

>> I just wanted to ask you if you can post the most
>> recent and complete code you have about TrayIcon...
>
> Just now? I just did! ;-).

Well, I knew that you already had the most complete Tray
code that can be found for BCB on the net...

Then I watched the thread with Danila & you (a couple of
posts below), and at one moment I got tired and wanted to
ask if you can make one-final-last-ultimate-the best version that
everyone can download and learn from it... I had in my archive
maybe 15 (uncomplete) versions of Tray icon, but I wanted
only *one* with everything I need. And this is it!

> Didn't you already have code that did the same? Your name
> popped up all over my googles.

Yes, I developed mine code (with help of this NG) and it works
fine for now. But I was not sattisfied with the way it's implemented.
For start it's not independent module - it's inside main form, etc...

Further I added functionalities as I needed them (on fly), so *my*
code probably have many unneeded parts which I have to check
and delete, or just rearange. You now...

In any case this is great! Let me now for new versions ;)

qyte

unread,
Jun 15, 2005, 9:38:54 AM6/15/05
to


i cannot find the file TrayThread.h anywhere on my pc.
I don't know if it should be anywhere. can you send it's code???

Remy Lebeau (TeamB)

unread,
Jun 15, 2005, 1:18:16 PM6/15/05
to

"JD" <nos...@nospam.com> wrote in message
news:42b00bd6$1...@newsgroups.borland.com...

> You are free to use the source
<snip>

JD, you should know better. Such a posting belonged in the .thirdpartytools
newsgroup instead.


Gambit


Danila Vershinin

unread,
Jun 15, 2005, 2:36:36 PM6/15/05
to
"JD" <nos...@nospam.com> wrote in message
news:42b00bd6$1...@newsgroups.borland.com...
[...]

Not breaking my word and not posting to the other thread.

<As for your demo, OnBalloonHide does nothing but that's no surprise because
that message is never sent under any condition.
In my program, yes, under no condition. :)
(as for other bugs in the program, I don't really have time to update the
program on the server, but things are fixed.)

Back to the OnBalloonHide.
I believe you said that in the context of not my program only, right? :)
because..

< case NIN_BALLOONHIDE: // hide is not currently use shell32 v6 but
might be in the future

Future? what future? am I missing somethinng?

the message IS sent - period, lol

Cheers

JD

unread,
Jun 15, 2005, 3:17:15 PM6/15/05
to

qyte <gy...@vivodinet.gr> wrote:
>
> i cannot find the file TrayThread.h anywhere on my pc.

It's a second class at the bottom of the TAnimatedTrayIcon
class. Just put the 2 classes into seperate units and headers.

~ JD

JD

unread,
Jun 15, 2005, 6:31:35 PM6/15/05
to

"Remy Lebeau \(TeamB\)" <no....@no.spam.com> wrote:
>
> JD, you should know better. Such a posting belonged in
> the .thirdpartytools newsgroup instead.

I don't use a reader and I couldn't for the life of me
remember how I translated the links to get to the web
interface.

~ JD

JD

unread,
Jun 15, 2005, 6:38:53 PM6/15/05
to

"Vladimir Stefanovic" <anti...@po.sbb.co.yu> wrote:
>
> [...] Let me now for new versions ;)

There isn't much more that can be done. One could add an
option to play wave file directly from disk and then there's
different font's and colors (saw it with a tool tip so maybe)
but after that, the only other thing that I can think of is
some method for storing multiple icon out side of a TImageList
so you can get around TImageList's color depth limitations.
Wanna do it?

~ JD

JD

unread,
Jun 15, 2005, 7:03:46 PM6/15/05
to

"Danila Vershinin" <c...@pnz.ru> wrote:
>
> [...] not posting to the other thread.

Here, there, it matters not where but that fact that you did.

>> As for your demo, OnBalloonHide does nothing but that's no
>> surprise because that message is never sent under any
>> condition.

> In my program, yes, under no condition. :)

Here you agree that that message is never sent.

> the message IS sent - period, lol

Here you disagree that the message is never sent. Did you take
your meds today?

> [...] I don't really have time to update the program on the


> server, but things are fixed.

Well that's a brilliant way to inspire confidence in your work;
post links to demo's that you know are broken.

> Back to the OnBalloonHide. I believe you said that in the
> context of not my program only, right? :)

Wrong. I never implemented OnBalloonHide but you did and it
does nothing.

> because..
>
>> case NIN_BALLOONHIDE: // hide is not currently use shell32 v6 but
>might be in the future
>
>Future? what future?

Future as in the next version of shell32.dll.

> am I missing somethinng?

Yes, and I would suspect it's the nature of a case statement.
The current version of shell32 does not send NIN_BALLOONHIDE
but in a future release of shell32, it should eventually be
implemented. For when that day comes, I encapsulated hide, timeout and close into one event: OnBalloonDismiss and I did it by understanding the behavior of a simple case statement
instead of coding multiple calls to the same event.

~ JD

Vladimir Stefanovic

unread,
Jun 16, 2005, 12:07:07 AM6/16/05
to
OK, I'll check that part ...

--
Best regards,
Vladimir Stefanovic

"JD" <nos...@nospam.com> wrote in message

news:42b0adfd$1...@newsgroups.borland.com...

Danila Vershinin

unread,
Jun 16, 2005, 2:02:52 AM6/16/05
to
"JD" <nos...@nospam.com> wrote in message
news:42b0b3d2$1...@newsgroups.borland.com...

> Here you disagree that the message is never sent. Did you take
> your meds today?

That's what you get you when you're trying to help people. Did you take
yours?

> Wrong. I never implemented OnBalloonHide but you did and it
> does nothing.

Once again. It doesn't work in my program only. There are NO situations in
my program that might cause it to be sent. But in other progams there MIGHT
BE and I know exactly what kind of situations.

> Future as in the next version of shell32.dll.

Wrong. wrong. wrong.

> The current version of shell32 does not send NIN_BALLOONHIDE

Wrong again. :)
Don't get mad when I say something, becasue I see you do, get mad, and now
you don't have actual reason for that. If I said that it is sent, then I
obviously had my reasons to say that. If you're absolutely, 100% sure that
it is not sent anywhere in Windows, lol, then ok, think whatever you want :)

> but in a future release of shell32, it should eventually be

and it eventually is, it has been already implemented.


> instead of coding multiple calls to the same event.

thanks, I didn't ask you to explain me your code. I've just copied it, to
put attention to this comment, look
<quote> // hide is not currently use shell32 v6 but..[..] </quote>

once again, the message IS sent - period :)

Cheers


Danila Vershinin

unread,
Jun 16, 2005, 2:07:13 AM6/16/05
to
"JD" <nos...@nospam.com> wrote in message
news:42b0adfd$1...@newsgroups.borland.com...
> option to play wave file directly from disk [...]

I sincerely hope that you know what this registry key is for:
HKEY_CURRENT_USER\AppEvents\Schemes\Apps

Cheers


JD

unread,
Jun 16, 2005, 6:26:15 AM6/16/05
to

No you don't. If you did, you'd have said something like...

Take a look at this Key, it's for ....

That's what this group is about ... the free exchange of idea's,
concepts and knowledge. If you don't have anything of value to
add, post it somewhere else.

That post was directed at Vladimir and I'm quite sure that he
understood me to mean your own custom generated wave files
that you don't want to include in a resource file because it
increases the size of the exe.

~ JD

JD

unread,
Jun 16, 2005, 6:30:16 AM6/16/05
to

"Vladimir Stefanovic" <anti...@po.sbb.co.yu> wrote:
>
> OK, I'll check that part ...

And when you're done, maybe we can get someone to do the help
for it and convince Gambit to convert it to Delphi and submit
it to Borland for v9!!

~ JD


JD

unread,
Jun 16, 2005, 6:17:00 AM6/16/05
to

"Danila Vershinin" <c...@pnz.ru> wrote:
>
> [...] Did you take yours?

I'm not the one talking out of both sides of my mouth.

>> Wrong. I never implemented OnBalloonHide but you did and it
>> does nothing.

> Once again. It doesn't work in my program only. There are NO
> situations in my program that might cause it to be sent. But
> in other progams there MIGHT BE and I know exactly what kind
> of situations.

Prove it.

>> Future as in the next version of shell32.dll.

>Wrong. wrong. wrong.

How could you possible say that I'm wrong when it comes to
explaining what I mean?

>> The current version of shell32 does not send NIN_BALLOONHIDE

>Wrong again. :)

Prove it.

> Don't get mad when I say something, [...]

It more like irritated, like when a child is at that phase
where everything is "mine". You ignore the facts and offer
wild statements with out substaintiating them and then throw
in personal comments like this one. This is not one of those
groups where it's generally accepted. Around here, it's put up
or shut up.

>> but in a future release of shell32, it should eventually be

>and it eventually is, it has been already implemented.

Prove it.

>> instead of coding multiple calls to the same event.

> thanks, I didn't ask you to explain me your code.

You obviousely need that explaination because you clearly
thought that I had implemented OnHide.

> once again, the message IS sent - period :)

Prove it.

~ JD

Danila Vershinin

unread,
Jun 16, 2005, 9:04:13 AM6/16/05
to
"JD" <nos...@nospam.com> wrote in message
news:42b1519c$1...@newsgroups.borland.com...
> Prove it.

"qyte" <gy...@vivodinet.gr> wrote in message
news:42a8...@newsgroups.borland.com...
> Is it possible using windows sdk in conjunction with the TTrayIcon
> provided with CBuilder 6 to show a balloon help???

You wrote:
>>No and do not use that component. It's very buggy.
Prove *that*.:)
I did prove that you are wrong. I gave the code that works. I never post
anything that is not based on actual code that works, but I guess you never
noticed that.

> I'm not the one talking out of both sides of my mouth.

Read what you wrote. That's exactly what you are doing.


> You ignore the facts and offer
> wild statements with out substaintiating them and then throw
> in personal comments like this one. This is not one of those
> groups where it's generally accepted. Around here, it's put up
> or shut up.

Please, if you have any actual facts that prove that the message is never
sent, provide me with those. As long as I can see you can't. I can and I
will prove it in this post.

In particular, what you are doing is ignoring that message, completely.
Well, in *that* CASE, this is a brand new level of incapsulation. I call it
*in-deapth*incapsulation, LOL.

>>> Future as in the next version of shell32.dll.

And the future is now. I am not concerned about your code. I am concerned
about people reading such comments like the one mentioned:


<quote> // hide is not currently use shell32 v6 but..[..] </quote>

Some of them might be really disoriented in time, what's good about that?
What did make you think that way, anyway? :)

> The current version of shell32 does not send NIN_BALLOONHIDE

Prove that.

> You obviousely need that explaination because you clearly
> thought that I had implemented OnHide.

I didn't think that way, on contra, I thought you hadn't.

The NIN_BALLOONHIDE message is sent every time when the balloon tooltip
dissapears. It is *not sent* if you clicked the balloon, or if it did
timeout, and nor if the user dismissed it by clicking that little X in the
balloon itself.
One of the situations when it is sent, is when you hide the icon itself,
or..
delete it from the notification area (which is the same thing). This is
quite a simple thing for understanding:
You delete the icon (balloon is being displayed) -> The message is sent.
You hide the icon (balloon is being diplayed)(which is the same as
delete) -> The message is sent.

How do I prove that?
I am not sure if your class has Visible property and I didn't look through
all the source above, but imagine this here situation that the user wants to
hide the icon....
like this way:
Visible = false;
Imagine also that the balloon tooltip is present at that time. => The
message is sent.
Shortly, while balloon is active Shell_NotifyIcon(&PData, NIM_DELETE) => the
message
is sent. Isn't that simple?
Whenever you do Shell_NotifyIcon(NIM_DELETE, &PData ), IF the balloon is
displayed at the moment => The message is sent.

And finally quote from MSDN:
<quote>
a.. NIN_BALLOONHIDE - Sent when the balloon disappears-when the icon is
deleted, for example. This message is not sent if the balloon is dismissed
because of a timeout or mouse click by the user.
</quote>
Simple again...


HTH, Danilka


Danila Vershinin

unread,
Jun 16, 2005, 9:00:50 AM6/16/05
to
"JD" <nos...@nospam.com> wrote in message
news:42b153c7$1...@newsgroups.borland.com...
> No you don't. If you did, you'd have said something like...[...]

Yes, I do
Why would I want to write things like:


> Take a look at this Key, it's for ....

..if you maybe already know that?
So wouldn't it be more *simple* for you to say: <No, I don't know, please
elaborate. What is it for>
I am here to share and help, just like you. The key actually contains sound
schemes for applications, here is example:
HKEY_CURRENT_USER\AppEvents\Schemes\Apps\YPager\Close
This key contains more subkeys which define which sounds to use on
application events, like... Restore, Minimize, etc...

HKEY_CURRENT_USER\AppEvents\Schemes\Apps\YPager\Close\old al0 says tha in
sound scheme "old al0" when the YPager application is being closed, the
sound file which is defined in Default string value of this key is used.
There is one great thing about using sound schemes. The end user can
easily customize his current scheme, so as accordingly, the sounds for a
program, via standard Windows interface, like...
Right click on the "Volume" icon in the icon notification area, select
Adjust Audio Properties, then go to the Sounds tab


Cheers

Vladimir Stefanovic

unread,
Jun 16, 2005, 9:39:28 AM6/16/05
to
> And when you're done, maybe we can get someone to do
> the help for it and convince Gambit to convert it to Delphi
> and submit it to Borland for v9!!

Nice! First to convince Remy ;)
I have some dead-lines to finish (some cinology software) until
next week, and after that I'll try what I can do with Tray component...

JD

unread,
Jun 18, 2005, 8:09:55 AM6/18/05
to

"Danila Vershinin" <c...@pnz.ru> wrote:
>
>>> I sincerely hope that you know [...]

>> No you don't. If you did, you'd have said something like...

> Yes, I do Why would I want to write things like:

>> Take a look at this Key, it's for ....

> if you maybe already know that?

If you assumed that I already knew about what you were posting,
then what's the point of the post in the first place?

> So wouldn't it be more *simple* for you to say: <No, I don't
> know, please elaborate. What is it for>

No it wouldn't. Why make some one have to make an additional
post and wait x-number of additional hours or days for an
answer when that information could have been included in your
original reply?

> The key actually contains sound schemes for applications,

> here is example: [...]

That's interesting and it might be useful but if you examine
the code, you'll see that I keep the wave in memory. I did that
because I didn't like the delay when read from disk *every*
time it played.

I think that it's worth considering but my initial thoughts
are that all you gain is a way for the user to use Windows
to change the sounds when most users would simply copy their
own waves into the installed folder. On the down side, if the
component loads the wave into memory, I have to wonder about
conflicts or 'double' playing of the wave because Windows
wants to do it's own thing.

~ JD

JD

unread,
Jun 18, 2005, 8:09:47 AM6/18/05
to

"Danila Vershinin" <c...@pnz.ru> wrote:
>
> You wrote:
> No and do not use that component. It's very buggy.
>
> Prove *that*.:)

In all honesty, I never considered making it work with
TTrayIcon BECAUSE TTrayIcon is useless and I did prove
that but you chose to ignore it:

http://tinyurl.com/bkgd8

<quote>
As for TTrayIcon being unreliable, it took me about 10 minutes
to find a fatal bug with it. If the underlying form's HWND is
recreated, the HWND associated with the TTaryIcon is no longer
valid.
</quote>

> I did prove that you are wrong. I gave the code that works.
> I never post anything that is not based on actual code that
> works, but I guess you never noticed that.

Oh I noticed but that code is unreliable. From the above link:

<quote>


> IconData.cbSize = sizeof( NOTIFYICONDATA );

This is unreliable. The cbSize member needs to be set
according to the current version of the shell32.dll
which, if less than 5.0 the cbSize member needs to be
set to NOTIFYICONDATA_V1_SIZE.

> IconData.uID = (UINT) TrayIcon1; // <---- this identifies which icon to operate with

This defeats the purpose of this member which is to allow for
multiple icons to be associated with the same HWND. The only
reason this works is because the uID member is programmer
defined and you cast the object to an UINT to meet the type
requirements.
</quote>

> Please, if you have any actual facts that prove that the
> message is never sent, provide me with those.

It's impossible to prove a negative and it wouldn't be the
first time that M$ failed to implement something correctly.

> In particular, what you are doing is ignoring that message,
> completely. Well, in *that* CASE, this is a brand new level
> of incapsulation. I call it *in-deapth*incapsulation, LOL.

You're mistaken so I would suggest that you look at the code
again. As the code stands, if Windows sends that message,
OnBalloonDismiss is raised. I wouldn't characterize that as
ignoring that message in any sense of the word.

> [...] I am concerned about people reading such comments like


> the one mentioned:
> <quote>
> // hide is not currently use shell32 v6 but..[..]
> </quote>
> Some of them might be really disoriented in time, what's
> good about that?

If you knew the circumstances under which it was sent *and*
you were *really* concerned about people being confused, why would you wait several days to post that information instead of posting it right away?

How you went about it sounds suspiciously close to "I know
something you don't know" and it was like pulling teeth to get
you to post something useful.

> The NIN_BALLOONHIDE message is sent [...] when you delete it
> from the notification area

Finally some clearity. I tested for every condition that I, as
a user, not programmer, could throw at it. This explains why I
never detected that message and since it requires a programmer
action to raise that message, it's rather useless.

> imagine this here situation that the user wants to hide the
> icon.... like this way:
> Visible = false;
> Imagine also that the balloon tooltip is present at that
> time. => The message is sent.

Perhaps you give an example of how this might be of benifit
because I don't see a use for it. If the programmer deletes
the icon from the tray, what good would it be to know if the
tip was active?

~ JD

Danila Vershinin

unread,
Jun 19, 2005, 4:00:53 PM6/19/05
to
"JD" <nos...@nospam.com> wrote in message
news:42b4...@newsgroups.borland.com...

> If you assumed that I already knew about what you were posting,
> then what's the point of the post in the first place?

Either you say "I don't like your manner of posting. Don't post, please no
more" :)...
or if you don't mind I will ignore things like:


>. Why make some one have to make an additional post and wait x-number of
>additional hours or days for an answer when that information could have
>been included in your original reply?

> That's interesting and it might be useful but if you examine


> the code, you'll see that I keep the wave in memory. I did that
> because I didn't like the delay when read from disk *every*
> time it played.

That's a nice approach. Anyway, I am glad that sound schemes were of a good
interest to you.

HTH, Danilka

Danila Vershinin

unread,
Jun 19, 2005, 3:50:56 PM6/19/05
to
"JD" <nos...@nospam.com> wrote in message
news:42b40f0b$1...@newsgroups.borland.com...

> If you knew the circumstances under which it was sent *and*
> you were *really* concerned about people being confused, why would you
> wait several days to post that information instead of posting it right
> away?
I *was* concerned, otherwise, if I wouldn't be, I wouldn't post at all. As
for waiting a few days, well, you were so sure that it is never sent.... :)

> How you went about it sounds suspiciously close to "I know
> something you don't know" and it was like pulling teeth to get
> you to post something useful.

Well, maybe :) But your posts sounded like "Don't even say anything at all,
you know I am right, so you better shut up" :)
Wasn't that useful anyway? :)

As for situations when that message might be useful, I am sure there are
such situations.
Back to the situation with "TaskbarCreated" message....
Imagine this here situation... (sorry for speaking in terms of 'imagine'
word) that the balloon is currently being displayed. Imagine you kill the
explorer.exe. => The icon is back on the taskbar as it was supposed to,
what's with balloon? - should be redisplayed, *especially* when it gives an
information of a great importance to the user, you can never implement
redisplaying of a balloon if you don't use the message we are talking
about.(balloonhide).

Hope to talk later, after I pass another exam..
HTH, Danilka

0 new messages