| Tenouk C & C++ | MFC Home | Uniform Data Transfer & OLE 1 | Uniform Data Transfer & OLE 3 | Download | Site Index |


 

 

 

 

 

 

Uniform Data Transfer:

Clipboard Transfer and OLE Drag and Drop 2

 

 

 

 

 

 

Program examples compiled using Visual C++ 6.0 compiler on Windows XP Pro machine with Service Pack 2. Topics and sub topics for this tutorial are listed below. Don’t forget to read Tenouk’s small disclaimer. The supplementary notes for this tutorial are cdib.h, cdib.cpp, formatetc and IDataObject.

  1. The MYMFC30A Example: A Data Object Clipboard

  2. The MYMFC30A Steps From Scratch

 

 

The MYMFC30A Example: A Data Object Clipboard

 

This example uses the CDib class from Module 21 (MYMFC26C). Here you'll be able to move and resize the DIB image with a tracker rectangle, and you'll be able to copy and paste the DIB to and from the clipboard using a COM data object. The example also includes functions for reading DIBs from and writing DIBs to BMP files. If you create such an example from scratch, use AppWizard to create MDI, without any ActiveX or Automation options and then add the following line in your StdAfx.h file:

 

 

#include <afxole.h>

 

Add the following call at the start of the application's InitInstance() function:

 

AfxOleInit();

 

To prepare MYMFC30A, open the Mymfc30a.dsw workspace and then build the project. Run the application, and paste a bitmap into the rectangle by choosing Paste From on the Edit menu. You'll see an MDI application similar to the one shown in Figure 2.

 

Figure 2: The MYMFC30A program in operation.

 

Figure 2: The MYMFC30A program in operation.

 

The MYMFC30A Steps From Scratch

 

The following are the steps to build MYMFC30A program from scratch. This is MDI without Automation and ActiveX support. The View base class is CScrollView.

 

Figure 3: MYMFC30A – Visual C++ new project dialog.

 

Figure 3: MYMFC30A – Visual C++ new project dialog.

 

Figure 4: MYMFC30A – AppWizard step 1 of 6, select Multiple documents option.

 

Figure 4: MYMFC30A – AppWizard step 1 of 6, select Multiple documents option.

 

Figure 5: MYMFC30A – AppWizard step 2 of 6.

 

Figure 5: MYMFC30A – AppWizard step 2 of 6.

 

For step 3 of 6, don’t forget to deselect the Automation and ActiveX Controls check boxes.

 

Figure 6: MYMFC30A – AppWizard step 3 of 6.

 

Figure 6: MYMFC30A – AppWizard step 3 of 6.

 

Figure 7: MYMFC30A – AppWizard step 4 of 6.

 

Figure 7: MYMFC30A – AppWizard step 4 of 6.

 

Figure 8: MYMFC30A – AppWizard step 5 of 6.

 

Figure 8: MYMFC30A – AppWizard step 5 of 6.

 

Change the CView to CScrollView base class for CMymfc30aView class.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Figure 9: MYMFC30A – AppWizard step 6 of 6.

 

Figure 9: MYMFC30A – AppWizard step 6 of 6.

 

Figure 10: MYMFC30A project summary.

 

Figure 10: MYMFC30A project summary.

 

Firstly, add the CDib class (device independent bitmap).

 

Figure 11: Adding new class to project.

 

Figure 11: Adding new class to project.

 

Figure 12: Adding an empty cdib.h, a header file to project.

 

Figure 12: Adding an empty cdib.h, a header file to project.

 

Copy and paste the cdib.h file content. Repeat the same step but select the C++ Source File for cdib.cpp. Here, we do not use the ClassWizard to add new class, so you won’t find the CDib class in ClassWizard, though the ClassWizard database file (CLW) can be rebuilt to include the class.

 

Figure 13: Adding cdib.cpp, a source file to project.

 

Figure 13: Adding cdib.cpp, a source file to project.

 

Add menu items under the Edit menu of the IDR_MYMFC3TYPE. Use the information in the following Table.

 

ID

Menu caption

Prompt

Separator

-

-

ID_EDIT_COPYTO

Copy T&o

Copy directly to a BMP file

ID_EDIT_PASTEFROM

P&aste From

Load a dib from a BMP file

ID_EDIT_CLEAR_ALL

Clear A&ll

-

 

Table 4.

 

Figure 14: Adding separator.

 

Figure 14: Adding separator.

 

Figure 15: Adding Copy To menu item.

 

Figure 15: Adding Copy To menu item.

 

Figure 16: Adding Paste From menu item.

 

Figure 16: Adding Paste From menu item.

 

Figure 17: Adding Clear All menu item.

 

Figure 17: Adding Clear All menu item.

 

Our completed menu items look something like the following.

 

Figure 18: A completed menu items.

 

Figure 18: A completed menu items.

 

Add WM_PALETTECHANGED and WM_QUERYNEWPALETTE windows messages to the CMainFrame class.

 

Figure 19: Adding Windows message handlers to CMainFrame class.

 

Figure 19: Adding Windows message handlers to CMainFrame class.

 

Add the following #define directive in MainFrm.h.

 

#define WM_VIEWPALETTECHANGED WM_USER + 5

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 1.

 

In MainFrm.cpp, modify and/or add the following codes.

 

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

      // TODO: Modify the Window class or styles here by modifying

      //  the CREATESTRUCT cs

      return CMDIFrameWnd::PreCreateWindow(cs);

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 2.

 

BOOL CMainFrame::OnQueryNewPalette()

{

      TRACE("CMainFrame::OnQueryNewPalette\n");

      CClientDC dc(this);

      // don't bother if we're not using a palette

      if((dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE) == 0) return TRUE;

      // determine the active view

      HWND hActiveView = NULL;

      CFrameWnd* pActiveFrm = GetActiveFrame();

      if(pActiveFrm != NULL) {

            CView* pActiveView = pActiveFrm->GetActiveView();

            if(pActiveView != NULL) {

                  hActiveView = pActiveView->GetSafeHwnd();

            }

      }

      // iterate through all views

      BOOL bBackground;

      CView* pView;

      CDocument* pDoc;

      CDocTemplate* pTemplate;

      POSITION posView;

      POSITION posDoc;

      POSITION posTemplate = AfxGetApp()->GetFirstDocTemplatePosition();

      while(posTemplate != NULL) {

            pTemplate = AfxGetApp()->GetNextDocTemplate(posTemplate);

            posDoc = pTemplate->GetFirstDocPosition();

            while(posDoc != NULL) {

                  pDoc = pTemplate->GetNextDoc(posDoc);

                  posView = pDoc->GetFirstViewPosition();

                  while(posView != NULL) {

                        pView = pDoc->GetNextView(posView);

                        bBackground = !(hActiveView == pView->GetSafeHwnd());

                        // background mode if view is not the active view

                        pView->SendMessage(WM_VIEWPALETTECHANGED, bBackground);

                  }

            }

      }

return TRUE;

}

 

void CMainFrame::OnPaletteChanged(CWnd* pFocusWnd)

{

      TRACE("CMainFrame::OnPaletteChanged\n");

      if(GetSafeHwnd() != pFocusWnd->GetSafeHwnd())

      {

            OnQueryNewPalette();

      }

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

Listing 3.

 

Add in the following #define directive in mymfc30aView.h file.

 

#define WM_VIEWPALETTECHANGED WM_USER + 5

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 4.

 

Then, manually or using ClassView, add member variables as shown below. These variables are private by default.

 

    // for tracking

    CRectTracker m_tracker;

    CRect m_rectTracker; // logical coordinates

    CSize m_sizeTotal;   // document size

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 5.

 

Use ClassView to add private member functions as shown here to CMymfc30aView class.

 

private:

    BOOL DoPasteDib(COleDataObject* pDataObject);

    COleDataSource* SaveDib();

 

 

Listing 6.

 

Figure 1: Adding member function, DoPasteDib() to CMymfc30aView class.

 

Figure 1: Adding member function, DoPasteDib() to CMymfc30aView class.

 

 

Figure 20: Adding member function, SaveDib() to CMymfc30aView class.

 

Figure 20: Adding member function, SaveDib() to CMymfc30aView class.

 

Then, add the following codes (mymfc30aView.cpp).

 

//////////////////////////////////////////////////////////////

// helper functions used for clipboard and drag-drop

 

BOOL CMymfc30aView::DoPasteDib(COleDataObject* pDataObject)

{

    // update command user interface should keep us out of here if not CF_DIB

    if (!pDataObject->IsDataAvailable(CF_DIB)) {

        TRACE("CF_DIB format is unavailable\n");

        return FALSE;

    }

    CMymfc30aDoc* pDoc = GetDocument();

    // Seems to be MOVEABLE memory, so we must use GlobalLock!

    //  (hDib != lpDib) GetGlobalData copies the memory, so we can

    //  hang onto it until we delete the CDib.

    HGLOBAL hDib = pDataObject->GetGlobalData(CF_DIB);

    ASSERT(hDib != NULL);

    LPVOID lpDib = ::GlobalLock(hDib);

    ASSERT(lpDib != NULL);

    pDoc->m_dib.AttachMemory(lpDib, TRUE, hDib);

    pDoc->SetModifiedFlag();

    pDoc->UpdateAllViews(NULL);

    return TRUE;

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 7.

 

COleDataSource* CMymfc30aView::SaveDib()

{

    CDib& dib = GetDocument()->m_dib;

    if (dib.GetSizeImage() > 0) {

        COleDataSource* pSource = new COleDataSource();

        int nHeaderSize = dib.GetSizeHeader();

        int nImageSize = dib.GetSizeImage();

        HGLOBAL hHeader = ::GlobalAlloc(GMEM_SHARE, nHeaderSize + nImageSize);

        LPVOID pHeader = ::GlobalLock(hHeader);

        ASSERT(pHeader != NULL);

        LPVOID pImage = (LPBYTE) pHeader + nHeaderSize;

        memcpy(pHeader, dib.m_lpBMIH, nHeaderSize);

        memcpy(pImage, dib.m_lpImage, nImageSize);

        // Receiver is supposed to free the global memory

        ::GlobalUnlock(hHeader);

        pSource->CacheGlobalData(CF_DIB, hHeader);

        return pSource;

    }

    return NULL;

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 8.

 

Using ClassWizard, add OnPrepareDC(), a virtual function for CMymfc30aView class.

 

Figure 21: Adding/overriding OnPrepareDC() virtual function.

 

Figure 21: Adding/overriding OnPrepareDC() virtual function.

 

Add window messages to the CMymfc30aView class as shown below.

 

 

Figure 22: Adding Window messages to CMymfc30aView class.

 

Figure 22: Adding Window messages to CMymfc30aView class.

 

Add command and update command handlers. Take note that the update command handler for ID_EDIT_COPY, ID_EDIT_COPYTO and ID_EDIT_CUT is same.

 

ID

Handler

 

ID_EDIT_COPY

Command.

OnEditCopy()

ID_EDIT_COPY

Update command

OnUpdateEditCopy()

ID_EDIT_COPYTO

Command.

OnEditCopyto()

ID_EDIT_COPYTO

Update command

OnUpdateEditCopy()

ID_EDIT_CUT

Command.

OnEditCut()

ID_EDIT_CUT

Update command

OnUpdateEditCopy()

ID_EDIT_PASTE

Command

OnEditPaste()

ID_EDIT_PASTE

Update command.

OnUpdateEditPaste()

ID_EDIT_PASTEFROM

Command.

OnEditPastefrom()

 

Table 5.

 

Figure 23: Adding Command and Update Commands to CMymfc30aView class.

 

Figure 23: Adding Command and Update Commands to CMymfc30aView class.

 

Figure 24: Adding Command and Update Commands to CMymfc30aView class.

 

Figure 24: Adding Command and Update Commands to CMymfc30aView class.

 

Figure 25: A completed commands and command updates addition.

 

Figure 25: A completed commands and command updates addition.

 

Add codes to mymfc30aView.cpp.

 

CMymfc30aView::CMymfc30aView() : m_sizeTotal(800, 1050), // 8 by 10.5 inches

                                                   //  when printed

    m_rectTracker(50, 50, 250, 250)

{    }

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 9.

 

void CMymfc30aView::OnDraw(CDC* pDC)

{

   CDib& dib = GetDocument()->m_dib;

    m_tracker.m_rect = m_rectTracker;

    pDC->LPtoDP(m_tracker.m_rect); // tracker wants device coordinates

    m_tracker.Draw(pDC);

    dib.Draw(pDC, m_rectTracker.TopLeft(), m_rectTracker.Size());

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 10.

 

void CMymfc30aView::OnInitialUpdate()

{

    SetScrollSizes(MM_TEXT, m_sizeTotal);

    m_tracker.m_nStyle = CRectTracker::solidLine | CRectTracker::resizeOutside;

    CScrollView::OnInitialUpdate();

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 11.

 

BOOL CMymfc30aView::OnPreparePrinting(CPrintInfo* pInfo)

{

    pInfo->SetMaxPage(1);

    return DoPreparePrinting(pInfo);

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 12.

 

void CMymfc30aView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)

{

    // custom MM_LOENGLISH; positive y is down

    if (pDC->IsPrinting())

    {

        int nHsize = pDC->GetDeviceCaps(HORZSIZE) * 1000 / 254;

        int nVsize = pDC->GetDeviceCaps(VERTSIZE) * 1000 / 254;

        pDC->SetMapMode(MM_ANISOTROPIC);

        pDC->SetWindowExt(nHsize, nVsize);

        pDC->SetViewportExt(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));

    }

    else {

        CScrollView::OnPrepareDC(pDC, pInfo);

    }

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 13.

 

void CMymfc30aView::OnEditCopy()

{

    COleDataSource* pSource = SaveDib();

    if (pSource)

    {

        pSource->SetClipboard(); // OLE deletes data source

    }

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 14.

 

void CMymfc30aView::OnUpdateEditCopy(CCmdUI* pCmdUI)

{

    // serves Copy, Cut, and Copy To

    CDib& dib = GetDocument()->m_dib;

    pCmdUI->Enable(dib.GetSizeImage() > 0L);

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 15.

 

void CMymfc30aView::OnEditCopyto()

{

    CDib& dib = GetDocument()->m_dib;

    CFileDialog dlg(FALSE, "bmp", "*.bmp");

    if (dlg.DoModal() != IDOK) return;

 

    BeginWaitCursor();

    dib.CopyToMapFile(dlg.GetPathName());

    EndWaitCursor();

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 16.

 

void CMymfc30aView::OnEditCut()

{

    OnEditCopy();

    GetDocument()->OnEditClearAll();

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 17.

 

void CMymfc30aView::OnEditPaste()

{

    CMymfc30aDoc* pDoc = GetDocument();

    COleDataObject dataObject;

    VERIFY(dataObject.AttachClipboard());

    DoPasteDib(&dataObject);

    CClientDC dc(this);

    pDoc->m_dib.UsePalette(&dc);

    pDoc->SetModifiedFlag();

    pDoc->UpdateAllViews(NULL);

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 18.

 

void CMymfc30aView::OnUpdateEditPaste(CCmdUI* pCmdUI)

{

    COleDataObject dataObject;

    BOOL bAvail = dataObject.AttachClipboard() && dataObject.IsDataAvailable(CF_DIB);

    pCmdUI->Enable(bAvail);

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 19.

 

void CMymfc30aView::OnEditPastefrom()

{

    CMymfc30aDoc* pDoc = GetDocument();

    CFileDialog dlg(TRUE, "bmp", "*.bmp");

    if (dlg.DoModal() != IDOK) return;

    if (pDoc->m_dib.AttachMapFile(dlg.GetPathName(), TRUE))

    { // share

        CClientDC dc(this);

        pDoc->m_dib.SetSystemPalette(&dc);

        pDoc->m_dib.UsePalette(&dc);

        pDoc->SetModifiedFlag();

        pDoc->UpdateAllViews(NULL);

    }

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 20.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

void CMymfc30aView::OnLButtonDown(UINT nFlags, CPoint point)

{

    if (m_tracker.Track(this, point, FALSE, NULL)) {

        CClientDC dc(this);

        OnPrepareDC(&dc);

        m_rectTracker = m_tracker.m_rect;

        dc.DPtoLP(m_rectTracker); // Update logical coordinates

        Invalidate();

    }

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 21.

 

BOOL CMymfc30aView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)

{

    if (m_tracker.SetCursor(pWnd, nHitTest))

    { return TRUE; }

    else

    { return CScrollView::OnSetCursor(pWnd, nHitTest, message); }

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 22.

 

void CMymfc30aView::OnSetFocus(CWnd* pOldWnd)

{

      CScrollView::OnSetFocus(pOldWnd);

      AfxGetApp()->m_pMainWnd->SendMessage(WM_PALETTECHANGED, (UINT) GetSafeHwnd());

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 23.

 

Manually add the following message map function in mymfc30aView.h

 

afx_msg LONG OnViewPaletteChanged(UINT wParam, LONG lParam);

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 24.

 

And in mymfc30aView.cpp, add the following code.

 

ON_MESSAGE(WM_VIEWPALETTECHANGED, OnViewPaletteChanged)

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 25.

 

Finally add the code in mymfc30aView.cpp

 

LONG CMymfc30aView::OnViewPaletteChanged(UINT wParam, LONG lParam)

{

      TRACE("CMymfc30aView::OnViewPaletteChanged, HWND = %x, code = %d\n", GetSafeHwnd(), wParam);

      CClientDC dc(this);

      GetDocument()->m_dib.UsePalette(&dc, wParam);

      Invalidate();

      return 0;

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 26.

 

Add the #include statement in mymfc30aView.cpp and mymfc30aDoc.cpp.

 

#include "cdib.h"

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 27.

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 28.

 

Using ClassWizard add the DeleteContents() virtual function to CMymfc30aDoc class.

 

Figure 26: Adding DeleteContents() to CMymfc30aDoc class.

 

Figure 26: Adding DeleteContents() to CMymfc30aDoc class.

 

Then add command and update command for ID_EDIT_CLEAR_ALL f the CMymfc30aDoc class.

 

Figure 27: Adding command and update command for ID_EDIT_CLEAR_ALL.

 

Figure 27: Adding command and update command for ID_EDIT_CLEAR_ALL.

 

Change the protected to public for the generated message map functions in mymfc30aDoc.h (or you can use friend keyword).

 

// Generated message map functions

public:

      //{{AFX_MSG(CMymfc30aDoc)

      afx_msg void OnEditClearAll();

      afx_msg void OnUpdateEditClearAll(CCmdUI* pCmdUI);

      //}}AFX_MSG

      DECLARE_MESSAGE_MAP()

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 29.

 

Add member variable to CMymfc30aDoc class.

 

public:

    CDib m_dib;

 

Figure 28: Adding member variable, m_dib to CMymfc30aDoc class.

 

Figure 28: Adding member variable, m_dib to CMymfc30aDoc class.

 

Finally add the codes.

 

void CMymfc30aDoc::Serialize(CArchive& ar)

{

   m_dib.Serialize(ar);

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 30.

 

void CMymfc30aDoc::OnEditClearAll()

{

    DeleteContents();

    UpdateAllViews(NULL);

    SetModifiedFlag();

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 31.

 

void CMymfc30aDoc::OnUpdateEditClearAll(CCmdUI* pCmdUI)

{

    pCmdUI->Enable(m_dib.GetSizeImage() > 0);

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 32.

 

void CMymfc30aDoc::DeleteContents()

{

   m_dib.Empty();

}

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 33.

 

Finally add the following line in your StdAfx.h file for automation support.

 

#include <afxole.h>

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 34.

 

Then, add the following call at the start of the application's InitInstance() function.

 

AfxOleInit();

 

Uniform Data Transfer: OLE and Clipboard - MFC C++ code snippet

 

Listing 35.

 

 

 

 

 

 

 

 

 

 

 

 

Further reading and digging:

  1. DCOM at MSDN.

  2. COM+ at MSDN.

  3. COM at MSDN.

  4. Win32 process, thread and synchronization story can be found starting from Module R.

  5. MSDN MFC 7.0 class library online documentation.

  6. MSDN MFC 9.0 class library online documentation - latest version.

  7. MSDN Library

  8. Windows data type.

  9. Win32 programming Tutorial.

  10. The best of C/C++, MFC, Windows and other related books.

  11. Unicode and Multibyte character set: Story and program examples.

 

 


 

| Tenouk C & C++ | MFC Home | Uniform Data Transfer & OLE 1 | Uniform Data Transfer & OLE 3 | Download | Site Index |