Figure 2   CRACK OLE Control

CALLBCTL.H

 // callbctl.h : Declaration of the CCallBackCtrl OLE control class.

// CCallBackCtrl : See callbctl.cpp for implementation.

class CCallBackCtrl : public COleControl
{
       DECLARE_DYNCREATE(CCallBackCtrl)
// Constructor
public:
       CCallBackCtrl();

       CWordArray m_msglist;  // List of registered messages

// Overrides
       // We want first crack at the user messages!
       virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);

       // Drawing function
       virtual void OnDraw(CDC* pdc, const CRect& rcBounds, 
                           const CRect& rcInvalid);

       // Persistence
       virtual void DoPropExchange(CPropExchange* pPX);

       // Reset control state
       virtual void OnResetState();

// Implementation
protected:
       ~CCallBackCtrl();

       DECLARE_OLECREATE_EX(CCallBackCtrl)    // Class factory and guid
       DECLARE_OLETYPELIB(CCallBackCtrl)      // GetTypeInfo
       DECLARE_PROPPAGEIDS(CCallBackCtrl)     // Property page IDs
       DECLARE_OLECTLTYPE(CCallBackCtrl)      // Type name and misc status

// Message maps
       //{{AFX_MSG(CCallBackCtrl)
              // NOTE - ClassWizard will add and remove member functions here.
              // DO NOT EDIT what you see in these blocks of generated code !
       //}}AFX_MSG
       DECLARE_MESSAGE_MAP()

// Dispatch maps
       //{{AFX_DISPATCH(CCallBackCtrl)
       afx_msg short WatchMsg(short msg);
       afx_msg long PtrValL(OLE_HANDLE lpPtr);
       afx_msg short PtrValI(OLE_HANDLE lpPtr);
       //}}AFX_DISPATCH
       DECLARE_DISPATCH_MAP()

       afx_msg void AboutBox();

// Event maps
       //{{AFX_EVENT(CCallBackCtrl)
       void FireCallback(short msg, long wParam, long lParam)
              {FireEvent(eventidCallback,EVENT_PARAM(VTS_I2  VTS_I4  VTS_I4), msg, wParam, lParam);}
       //}}AFX_EVENT
       DECLARE_EVENT_MAP()

// Dispatch and event IDs
public:
       enum {
       //{{AFX_DISP_ID(CCallBackCtrl)
       dispidWatchMsg = 1L,
       dispidPtrValL = 2L,
       dispidPtrValI = 4L,
       eventidCallback = 1L,
       //}}AFX_DISP_ID
       };
};

CALLBCTL.CPP

 // callbctl.cpp : Implementation of the CCallBackCtrl OLE control class.

#include "stdafx.h"
#include "cback.h"
#include "callbctl.h"
#include "callbppg.h"
#include "memory.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif


IMPLEMENT_DYNCREATE(CCallBackCtrl, COleControl)

// Message map

BEGIN_MESSAGE_MAP(CCallBackCtrl, COleControl)
       //{{AFX_MSG_MAP(CCallBackCtrl)
       // NOTE - ClassWizard will add and remove message map entries
       //    DO NOT EDIT what you see in these blocks of generated code !
       //}}AFX_MSG_MAP
       ON_OLEVERB(AFX_IDS_VERB_EDIT, OnEdit)
       ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()

// Dispatch map

BEGIN_DISPATCH_MAP(CCallBackCtrl, COleControl)
       //{{AFX_DISPATCH_MAP(CCallBackCtrl)
       DISP_FUNCTION(CCallBackCtrl, "WatchMsg", WatchMsg, VT_I2, VTS_I2)
       DISP_FUNCTION(CCallBackCtrl, "PtrValL", PtrValL, VT_I4, VTS_HANDLE)
       DISP_FUNCTION(CCallBackCtrl, "PtrValI", PtrValI, VT_I2, VTS_HANDLE)
       DISP_STOCKPROP_HWND()
       //}}AFX_DISPATCH_MAP
       DISP_FUNCTION_ID(CCallBackCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
END_DISPATCH_MAP()

// Event map

BEGIN_EVENT_MAP(CCallBackCtrl, COleControl)
       //{{AFX_EVENT_MAP(CCallBackCtrl)
       EVENT_CUSTOM("Callback", FireCallback, VTS_I2  VTS_I4  VTS_I4)
       //}}AFX_EVENT_MAP
END_EVENT_MAP()

// Property pages

// TODO: Add more property pages as needed. Remember to increase the count!
BEGIN_PROPPAGEIDS(CCallBackCtrl, 1)
       PROPPAGEID(CCallBackPropPage::guid)
END_PROPPAGEIDS(CCallBackCtrl)


// Initialize class factory and guid

IMPLEMENT_OLECREATE_EX(CCallBackCtrl, "MSJ.Callback.Control",
       0x3d76aaa0, 0x17aa, 0x11cf, 0xa0, 0x18, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0)

// Type library ID and version

IMPLEMENT_OLETYPELIB(CCallBackCtrl, _tlid, _wVerMajor, _wVerMinor)


// Interface IDs

const IID BASED_CODE IID_DCallBack =
              { 0x3d76aaa1, 0x17aa, 0x11cf, { 0xa0, 0x18, 0x44, 0x45, 0x53, 
                                              0x54, 0x0, 0x0 } };
const IID BASED_CODE IID_DCallBackEvents =
              { 0x3d76aaa2, 0x17aa, 0x11cf, { 0xa0, 0x18, 0x44, 0x45, 0x53, 
                                              0x54, 0x0, 0x0 } };

// Control type information

static const DWORD BASED_CODE _dwCallBackOleMisc =
       OLEMISC_ACTIVATEWHENVISIBLE |
       OLEMISC_SETCLIENTSITEFIRST |
       OLEMISC_INSIDEOUT |
       OLEMISC_CANTLINKINSIDE |
       OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE(CCallBackCtrl, IDS_CALLBACK, _dwCallBackOleMisc)


// CCallBackCtrl::CCallBackCtrlFactory::UpdateRegistry -
// Adds or removes system registry entries for CCallBackCtrl

BOOL CCallBackCtrl::CCallBackCtrlFactory::UpdateRegistry(BOOL bRegister)
{
       if (bRegister)
              return AfxOleRegisterControlClass(
                     AfxGetInstanceHandle(),
                     m_clsid,  m_lpszProgID,
                     IDS_CALLBACK, IDB_CALLBACK,
                     TRUE,                       //  Insertable
                     _dwCallBackOleMisc,
                     _tlid,  _wVerMajor,
                     _wVerMinor);
       else
              return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}


// CCallBackCtrl::CCallBackCtrl - Constructor

CCallBackCtrl::CCallBackCtrl()
{
       InitializeIIDs(&IID_DCallBack, &IID_DCallBackEvents);
}

// CCallBackCtrl::~CCallBackCtrl - Destructor

CCallBackCtrl::~CCallBackCtrl()
{
}

// CCallBackCtrl::OnDraw - Drawing function

void CCallBackCtrl::OnDraw(
                     CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
    // Always hide the window - we need a handle, but not a displayed
    // window.

    if (m_hWnd != NULL)
              ::ShowWindow(m_hWnd, SW_HIDE);

       pdc->Rectangle(rcBounds);
}

// CCallBackCtrl::DoPropExchange - Persistence support

void CCallBackCtrl::DoPropExchange(CPropExchange* pPX)
{
       ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
       COleControl::DoPropExchange(pPX);
}

// CCallBackCtrl::OnResetState - Reset control to default state

void CCallBackCtrl::OnResetState()
{
       COleControl::OnResetState();  // Resets defaults found in DoPropExchange
}

// CCallBackCtrl::AboutBox - Display an "About" box to the user

void CCallBackCtrl::AboutBox()
{
       CDialog dlgAbout(IDD_ABOUTBOX_CALLBACK);
       dlgAbout.DoModal();
}

// CCallBackCtrl message handlers

short CCallBackCtrl::WatchMsg(short msg) 
{
    // Control method - the user can add a message for the control
    // to watch for.

    m_msglist.Add(msg);

       return msg;
}

// When we get a registered message, call FireCallback(msg, wParam, lParam)

LRESULT CCallBackCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
       for (int m=0; m < m_msglist.GetSize(); m++)
       {
              if (m_msglist[m] == message)
                     FireCallback(message, wParam, lParam);
       }

       return COleControl::WindowProc(message, wParam, lParam);
}

// Special bonus for people who actually read these code samples!
// The following functions take a long int pointer value and return
// the long integer or short integer it points to. These can be
// useful depending on the information the Callback function sends
// back to wParam and lParam.

long CCallBackCtrl::PtrValL(OLE_HANDLE lpPtr) 
{
       return *((LPLONG) lpPtr);
}

short CCallBackCtrl::PtrValI(OLE_HANDLE lpPtr) 
{
       return *((LPINT) lpPtr);
}

Figure 3   VBTRAY

VBTRAY.FRM

                                      .
                                     .  
                                     .
'====================================================
' When the user clicks on the Create button, do this

Private Sub btnCreate_Click()
    Dim tnd As NOTIFYICONDATA ' The Shell_NotifyIcon data structure

     ' Alternate between Create and Delete handling
    If btnCreate.Caption = "Create" Then
          ' Fill in tnd with appropriate values
        tnd.szTip = edtTip.Text & Chr$(0)
     ' Flags: the message, icon, and tip are valid and should be
     ' paid attention to.
        tnd.uFlags = NIF_MESSAGE + NIF_ICON + NIF_TIP
        tnd.uID = 100
        tnd.cbSize = Len(tnd)
     ' The window handle of our callback control
        tnd.hwnd = CBWnd.hwnd
     ' The message CBWnd will receive when there's an icon event
        tnd.uCallbackMessage = WM_USER + 1
        tnd.hIcon = picIcon.Picture
     ' Make the callback window wait for our defined message
        CBWnd.WatchMsg (WM_USER + 1)
     ' Add the icon to the taskbar tray
        rc = Shell_NotifyIcon(NIM_ADD, tnd)
     ' Flip the button's name
        btnCreate.Caption = "Remove"
    ElseIf btnCreate.Caption = "Remove" Then
     ' On remove, we only have to give enough information for Windows
     ' to locate the icon, then tell the system to delete it.
        tnd.uID = 100
        tnd.cbSize = Len(tnd)
        tnd.hwnd = CBWnd.hwnd
        tnd.uCallbackMessage = WM_USER + 1
        rc = Shell_NotifyIcon(NIM_DELETE, tnd)
     ' Ready to create a new one!
        btnCreate.Caption = "Create"
    End If
End Sub


'=========================================
' btnIcon changes the icon in the tray

Private Sub btnIcon_Click()
    Dim tnd As NOTIFYICONDATA

     ' Fill the data structure with necessary information, including
     ' the icon we get from the form's picture box
    tnd.uFlags = NIF_ICON
    tnd.uID = 100
    tnd.cbSize = Len(tnd)
    tnd.hwnd = CBWnd.hwnd
    tnd.uCallbackMessage = WM_USER + 1
    tnd.hIcon = picIcon.Picture

     ' Call the modify part of the function to change the elements indicated
     ' by the uFlags Type member above - in this case, just the icon.
    rc = Shell_NotifyIcon(NIM_MODIFY, tnd)
End Sub


'=========================================
' btnLoad shows the Open common dialog, then retrieves the chosen filename
' and tries to load a picture from it. This can be an icon or an appropriately
' bitmap.

Private Sub btnLoad_Click()
    ComDlg.ShowOpen
    picIcon.Picture = LoadPicture(ComDlg.filename)
End Sub

'=========================================
' btnTip changes the Tip property of the icon, similar to the btnIcon
' changing the icon.

Private Sub btnTip_Click()
    Dim tnd As NOTIFYICONDATA

     ' The tip is going to be important
    tnd.uFlags = NIF_TIP
    tnd.uID = 100
    tnd.cbSize = Len(tnd)
    tnd.hwnd = CBWnd.hwnd
    tnd.uCallbackMessage = WM_USER + 1

     ' Get the new tip from the onscreen edit box. This has to have a null
     ' character appended to it or the tip will appear as a string with as
     ' many trailing spaces as there are in the fixed-length string.

    tnd.szTip = edtTip.Text & Chr$(0)

    rc = Shell_NotifyIcon(NIM_MODIFY, tnd)
End Sub

'=========================================
' CBWnd_CallBack is called by the Cback control any time it receives
' a window message specified by a previous WatchMsg call to it. It
' provides the VB programmer the original msg/wParam/lParam intact. (These
' may at times be pointers to values instead of actual values; it is up to
' the programmer to know when this will occur and adjust his code accordingly.

Private Sub CBWnd_CallBack(ByVal msg As Integer, ByVal wParam As Long, ByVal lParam As Long)
     ' If the user has pressed the mouse button on the icon, pop up a message box
    If (lParam = WM_LBUTTONDOWN) Then
        MsgBox "You clicked on the tray icon!", vbOKOnly, "Shell_NotifyIcon callback"
    End If
End Sub

'============================================================
' The basic Form_Load - this provides a default icon and string
' for the VB program to set the tray icon.

Private Sub Form_Load()
    edtTip.Text = "Generic tip string."
    picIcon.Picture = Me.Icon
End Sub

VBTRAY.BAS

 Attribute VB_Name = "Module1"
Public Const WM_USER = &H400

Public Const NIF_ICON = &H2
Public Const NIF_MESSAGE = &H1
Public Const NIF_TIP = &H4

Public Const NIM_ADD = &H0
Public Const NIM_DELETE = &H2
Public Const NIM_MODIFY = &H1

Public Const WM_MOUSEMOVE = &H200
Public Const WM_LBUTTONUP = &H202
Public Const WM_LBUTTONDOWN = &H201
Public Const WM_LBUTTONDBLCLK = &H203

Type NOTIFYICONDATA
        cbSize As Long
        hwnd As Long
        uID As Long
        uFlags As Long
        uCallbackMessage As Long
        hIcon As Long
        szTip As String * 64
End Type

Declare Function Shell_NotifyIcon Lib "shell32.dll" Alias "Shell_NotifyIconA" (ByVal dwMessage As Long, lpData As NOTIFYICONDATA) As Long