Figure 1   Creating an IDispatch Pointer
 void CTestflexgridDlg::OnSelectbmp() 
 {
     IDispatch* pDisp = 0;
 
     PICTDESC pictDesc;
     memset(&pictDesc, 0, sizeof(pictDesc));
     pictDesc.cbSizeofstruct = sizeof(pictDesc);
     pictDesc.bmp.hpal = 0;
 
     UpdateData(TRUE);
     switch(m_nPicture)
     {
         case 0:
         {
             pictDesc.bmp.hbitmap = m_ctlYellow.GetBitmap();
             pictDesc.picType = PICTYPE_BITMAP;
 
             HRESULT hr;
             hr = OleCreatePictureIndirect(&pictDesc,
                                           IID_IDispatch, 
                                 FALSE, 
                             (void**)&pDisp);
             if(SUCCEEDED(hr))
             {
                 ExamineIPicture(pDisp);
 
                 m_flexgrid.SetRefCellPicture(pDisp);
                 pDisp->Release();
             } else
             {
                 AfxMessageBox("Couldn't create the/
                               Picture interface");
             }
         }
             break;
         case 1:
         {
             // Similar treatment for this bitmap
         }
             break;
         case 2:
         {
             // Similar treatment for this bitmap
         }
             break;
     default :
         break;
     }
 }

Figure 3   Displaying the Icon


 void CTestflexgridDlg::DoIcon()
 {
     HICON hIcon;
     hIcon = ::LoadIcon(AfxGetApp()->m_hInstance,
                                 MAKEINTRESOURCE(IDC_ANICON));
     if(hIcon)
     {
         pictDesc.icon.hicon = hIcon;
         pictDesc.picType = PICTYPE_ICON;
 
         HRESULT hr;
     hr = OleCreatePictureIndirect(&pictDesc, 
                                   IID_IDispatch, 
                                   FALSE, 
                                   (void**)&pDisp);
 
         if(SUCCEEDED(hr))
         {
         m_flexgrid.SetRefCellPicture(pDisp);
             pDisp->Release();
         } else
         {
         AfxMessageBox("Couldn't create the icon interface");
     }
 }

Figure 4   The PICTDESC Structure


 typedef struct tagPICTDESC 
 {
     UINT cbSizeOfStruct;
     UINT picType; 
     union
     {
         struct
         {
             HBITMAP hbitmap; 
             HPALETTE hpal;
         } bmp;
         struct
         { 
             HMETAFILE hmeta;
              int xExt;
              int yExt; 
         } wmf;
         struct
         {
             HICON hicon; 
         } icon;
         struct
         {
             HENHMETAFILE hemf; 
         } emf;
     }; 
 } PICTDESC;

Figure 6   The IPicture Interface


 IPicture : public IUnknown
 {
     HRESULT  get_Handle(OLE_HANDLE *pHandle) = 0;
     HRESULT  get_hPal(OLE_HANDLE *phPal) = 0;
     HRESULT  get_Type(SHORT *pType) = 0;
     HRESULT  get_Width(OLE_XSIZE_HIMETRIC *pWidth) = 0;
     HRESULT  get_Height(OLE_YSIZE_HIMETRIC *pHeight) = 0;
     HRESULT  Render(HDC hDC, LONG x, LONG y, 
                     LONG cx, LONG cy, 
                     OLE_XPOS_HIMETRIC xSrc, 
                     OLE_YPOS_HIMETRIC ySrc,
                     OLE_XSIZE_HIMETRIC cxSrc, 
                     OLE_YSIZE_HIMETRIC cySrc,
                     LPCRECT pRcWBounds) = 0;
     HRESULT  set_hPal(OLE_HANDLE hPal) = 0;
     HRESULT  get_CurDC(HDC *phDC) = 0;
     HRESULT  SelectPicture(HDC hDCIn, HDC *phDCOut, 
                            OLE_HANDLE *phBmpOut) = 0;
     HRESULT  get_KeepOriginalFormat(BOOL *pKeep) = 0;
     HRESULT  put_KeepOriginalFormat(BOOL keep) = 0;
     HRESULT  PictureChanged(void) = 0;
     HRESULT  SaveAsFile(LPSTREAM pStream, 
                         BOOL fSaveMemCopy,
                         LONG *pCbSize) = 0;
     HRESULT  get_Attributes(DWORD *pDwAttr) = 0;
 };

Figure 7   Connecting to the Property Notification Sink


 struct CPropertyNotifySinkImpl : public IPropertyNotifySink 
 {
     ULONG m_cRef;
 
     CPropertyNotifySinkImpl()
     {
         m_cRef = 0;
     }
 
     STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
     {
         if(riid == IID_IUnknown || 
            riid == IID_IPropertyNotifySink)
         {
             *ppv = static_cast<IPropertyNotifySink*>(this);
             ((IUnknown*)*ppv)->AddRef();
             return S_OK;
         } else
         {
             *ppv = 0;
             return E_NOINTERFACE;
         }
     }
 
     STDMETHODIMP_(ULONG) AddRef()
     {
         return m_cRef++;
     }
 
     STDMETHODIMP_(ULONG) Release()
     {
         m_cRef--;
 
         if(m_cRef == 0)
         {
             return 0;
         } else
         {
             return m_cRef;
         }
     }
 
     STDMETHODIMP OnChanged(DISPID dispid)
     {
         CString str;
 
         str.Format("Changed Property #%ld", dispid);
         AfxMessageBox(str);
         return S_OK;
     }
 
     STDMETHODIMP OnRequestEdit(DISPID dispid)
     {
         return S_FALSE;
     }
 };
 
 // Global instance of the property notification sink
 CPropertyNotifySinkImpl g_propNotifySink;
 IPropertyNotifySink* g_pPropNotifySink = 
     static_cast<IPropertyNotifySink*>(&g_propNotifySink);
 DWORD g_cookie;
 
 void SetupConnection(IUnknown* pUnk)
 {
     IConnectionPointContainer* pCPC = 0;
 
     HRESULT hr = pUnk->QueryInterface(&pCPC);
     if(SUCCEEDED(hr))
     {
         IEnumConnectionPoints* pECP = 0;
 
         IConnectionPoint* pCP = 0;
         hr = pCPC->FindConnectionPoint(IID_IPropertyNotifySink, 
                                        &pCP);
         if(SUCCEEDED(hr))
         {
             hr = pCP->Advise(g_pPropNotifySink, 
                              &g_cookie);
             pCP->Release();
         }
         pCPC->Release();
     }
 }
 
 void TeardownConnection(IUnknown* pUnk)
 {
     IConnectionPointContainer* pCPC = 0;
 
     HRESULT hr = pUnk->QueryInterface(&pCPC);
     if(SUCCEEDED(hr))
     {
         IConnectionPoint* pCP = 0;
         hr = pCPC->FindConnectionPoint(__uuidof(pCPC), 
                                        &pCP);
         if(SUCCEEDED(hr))
         {
             pCP->Unadvise(g_cookie);
             pCP->Release();
         }
         pCPC->Release();
     }
 }

Figure 8   Saving an Image to a Stream


 void SaveThePicture(IUnknown* pUnk)
 {
 IPicture* pPicture = 0;
 
     HRESULT hr = pUnk->QueryInterface(&pPicture);
 
     if(SUCCEEDED(hr))
     {
         IStorage* pStg = 0;
 
         hr = ::StgCreateDocfile(L"c:\\picttest", 
              STGM_SHARE_EXCLUSIVE | 
              STGM_CREATE | 
              STGM_READWRITE, 
              0, &pStg);
         if(SUCCEEDED(hr))
         {
             IStream* pStream = 0;
     
             hr = pStg->CreateStream(L"PICTURE", 
                  STGM_SHARE_EXCLUSIVE | 
                  STGM_CREATE | 
                  STGM_READWRITE, 
                  0, 0, &pStream);
             if(SUCCEEDED(hr))
             {
                 hr = pPicture->SaveAsFile(pStream, 
                      TRUE, // save mem copy
                      NULL);
                 pStream->Release();
             }
             pStg->Release();
         }
         pPicture->Release();
     }
 }

Figure 9   Loading an Image from a Stream


 void CTestflexgridDlg::OnLoadsavedbitmap() 
 {
     IStorage* pStg = 0;
 
     HRESULT hr;
     hr = ::StgOpenStorage(L"c:\\picttest", 
          NULL,
          STGM_SHARE_EXCLUSIVE | 
          STGM_READ, 
          NULL, 0, &pStg);
     if(SUCCEEDED(hr))
     {
         IStream* pStream = 0;
     
         hr = pStg->OpenStream(L"PICTURE", NULL, 
              STGM_SHARE_EXCLUSIVE | 
              STGM_READ, 
              0, &pStream);
         if(SUCCEEDED(hr))
         {
             IDispatch* pDispatch;
             hr = ::OleLoadPicture(pStream,
                  0, // read entire stream
                  TRUE, 
                  IID_IDispatch, 
                  (void**)&pDispatch);
             if(SUCCEEDED(hr))
             {
                 m_flexgrid.SetRefCellPicture(pDispatch);    
                 pDispatch->Release();
             }
             pStream->Release();
         }
         pStg->Release();
     }
 }