| Tenouk C & C++ | MFC Home | Uniform Data Transfer & OLE 2 | Uniform Data Transfer & OLE 4 | Download | Site Index |


 

 

 

 

 

 

Uniform Data Transfer:

Clipboard Transfer and OLE Drag and Drop 3

 

 

 

 

 

 

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 Story

  2. The CMainFrame Class

  3. The CMymfc30aDoc Class

  4. The CMymfc30aView Class

 

 

Build and run MYMFC30A program. Use the Paste From menu to paste a BMP file.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Figure 29: MYMFC30A in action. Select the Paste From menu.

 

Figure 29: MYMFC30A in action. Select the Paste From menu.

 

 

Figure 30: Browsing BMP file under Windows directory.

 

Figure 30: Browsing BMP file under Windows directory.

 

Figure 31: The pasted BMP file in MYMFC30A.

 

Figure 31: The pasted BMP file in MYMFC30A.

 

Next, select the Copy To menu.

 

Figure 32: Testing the Copy To menu.

 

Figure 32: Testing the Copy To menu.

 

Find appropriate directory and put the BMP new filename. Click the Save button.

 

Figure 33: Copying the BMP file to a new file (save as).

 

Figure 33: Copying the BMP file to a new file (save as).

 

Test the Clear All menu. This will clear the current BMP.

 

Figure 34: Testing the Clear All menu.

 

Figure 34: Testing the Clear All menu.

 

The Story

 

The CMainFrame Class

 

This class contains the handlers OnQueryNewPalette() and OnPaletteChanged() for the WM_QUERYNEWPALETTE and WM_PALETTECHANGED messages, respectively. These handlers send a user-defined WM_VIEWPALETTECHANGED message to all the views, and then the handler calls CDib::UsePalette to realize the palette. The value of wParam tells the view whether it should realize the palette in background or foreground mode.

 

The CMymfc30aDoc Class

 

This class is pretty straightforward. It contains an embedded CDib object, m_dib, plus a Clear All command handler. The overridden DeleteContents() member function calls the CDib::Empty function.

 

The CMymfc30aView Class

 

This class contains the clipboard function command handlers, the tracking code, the DIB drawing code, and the palette message handler. Listing 36 shows the header and implementation files with manually entered code in orange.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

MYMFC30AVIEW.H

 

// mymfc30aView.h : interface of the CMymfc30aView class

//

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

 

#if !defined(AFX_MYMFC30AVIEW_H__856698BD_A201_40D4_8CD7_4A9F20DA6994__INCLUDED_)

#define AFX_MYMFC30AVIEW_H__856698BD_A201_40D4_8CD7_4A9F20DA6994__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

#define WM_VIEWPALETTECHANGED     WM_USER + 5

 

class CMymfc30aView : public CScrollView

{

    // for tracking

    CRectTracker m_tracker;

    CRect m_rectTracker; // logical coordinates

    CSize m_sizeTotal;   // document size

 

protected: // create from serialization only

       CMymfc30aView();

       DECLARE_DYNCREATE(CMymfc30aView)

 

// Attributes

public:

       CMymfc30aDoc* GetDocument();

 

// Operations

public:

 

// Overrides

       // ClassWizard generated virtual function overrides

       //{{AFX_VIRTUAL(CMymfc30aView)

       public:

       virtual void OnDraw(CDC* pDC);  // overridden to draw this view

       virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

       virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL);

       protected:

       virtual void OnInitialUpdate(); // called first time after construct

       virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);

       virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);

       virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

       //}}AFX_VIRTUAL

 

// Implementation

public:

       virtual ~CMymfc30aView();

#ifdef _DEBUG

       virtual void AssertValid() const;

       virtual void Dump(CDumpContext& dc) const;

#endif

 

protected:

 

// Generated message map functions

protected:

       //{{AFX_MSG(CMymfc30aView)

       afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

       afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);

       afx_msg void OnSetFocus(CWnd* pOldWnd);

       afx_msg void OnEditCopy();

       afx_msg void OnUpdateEditCopy(CCmdUI* pCmdUI);

       afx_msg void OnEditCopyto();

       afx_msg void OnEditCut();

       afx_msg void OnEditPaste();

       afx_msg void OnUpdateEditPaste(CCmdUI* pCmdUI);

       afx_msg void OnEditPastefrom();

       //}}AFX_MSG

       afx_msg LONG OnViewPaletteChanged(UINT wParam, LONG lParam);

       DECLARE_MESSAGE_MAP()

private:

       COleDataSource* SaveDib();

       BOOL DoPasteDib(COleDataObject* pDataObject);

};

 

#ifndef _DEBUG  // debug version in mymfc30aView.cpp

inline CMymfc30aDoc* CMymfc30aView::GetDocument()

   { return (CMymfc30aDoc*)m_pDocument; }

#endif

 

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

 

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

 

#endif // !defined(AFX_MYMFC30AVIEW_H__856698BD_A201_40D4_8CD7_4A9F20DA6994__INCLUDED_)

 

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

MYMFC30AVIEW.CPP

 

// mymfc30aView.cpp : implementation of the CMymfc30aView class

//

 

#include "stdafx.h"

#include "mymfc30a.h"

 

#include "cdib.h"

 

#include "mymfc30aDoc.h"

#include "mymfc30aView.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[ ] = __FILE__;

#endif

 

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

// CMymfc30aView

 

IMPLEMENT_DYNCREATE(CMymfc30aView, CScrollView)

 

BEGIN_MESSAGE_MAP(CMymfc30aView, CScrollView)

       //{{AFX_MSG_MAP(CMymfc30aView)

       ON_WM_LBUTTONDOWN()

       ON_WM_SETCURSOR()

       ON_WM_SETFOCUS()

       ON_COMMAND(ID_EDIT_COPY, OnEditCopy)

       ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)

       ON_COMMAND(ID_EDIT_COPYTO, OnEditCopyto)

       ON_COMMAND(ID_EDIT_CUT, OnEditCut)

       ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)

       ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)

       ON_COMMAND(ID_EDIT_PASTEFROM, OnEditPastefrom)

       //}}AFX_MSG_MAP

       ON_MESSAGE(WM_VIEWPALETTECHANGED, OnViewPaletteChanged)

       // Standard printing commands

       ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)

       ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint)

       ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)

END_MESSAGE_MAP()

 

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

// CMymfc30aView construction/destruction

 

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

    m_rectTracker(50, 50, 250, 250)

 

{

       // TODO: add construction code here

}

 

CMymfc30aView::~CMymfc30aView()

{             }

 

BOOL CMymfc30aView::PreCreateWindow(CREATESTRUCT& cs)

{

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

       //  the CREATESTRUCT cs

       return CScrollView::PreCreateWindow(cs);

}

 

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

// CMymfc30aView drawing

 

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());

}

 

void CMymfc30aView::OnInitialUpdate()

{

    SetScrollSizes(MM_TEXT, m_sizeTotal);

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

    CScrollView::OnInitialUpdate();

}

 

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

// CMymfc30aView printing

 

BOOL CMymfc30aView::OnPreparePrinting(CPrintInfo* pInfo)

{

    pInfo->SetMaxPage(1);

    return DoPreparePrinting(pInfo);

}

 

void CMymfc30aView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

       // TODO: add extra initialization before printing

}

 

void CMymfc30aView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

       // TODO: add cleanup after printing

}

 

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

// CMymfc30aView diagnostics

 

#ifdef _DEBUG

void CMymfc30aView::AssertValid() const

{

       CScrollView::AssertValid();

}

 

void CMymfc30aView::Dump(CDumpContext& dc) const

{

       CScrollView::Dump(dc);

}

 

CMymfc30aDoc* CMymfc30aView::GetDocument() // non-debug version is inline

{

       ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMymfc30aDoc)));

       return (CMymfc30aDoc*)m_pDocument;

}

#endif //_DEBUG

 

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

// CMymfc30aView message handlers

 

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;

}

 

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;

}

 

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

{

    // TODO: Add your specialized code here and/or call the base class

    // 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);

    }

}

 

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

{

       // TODO: Add your message handler code here and/or call default

       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();

    }

}

 

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

{

       // TODO: Add your message handler code here and/or call default

       if (m_tracker.SetCursor(pWnd, nHitTest)) {

        return TRUE;

    }

    else {

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

    }

}

 

void CMymfc30aView::OnSetFocus(CWnd* pOldWnd)

{

       CScrollView::OnSetFocus(pOldWnd);

       CScrollView::OnSetFocus(pOldWnd);

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

}

 

void CMymfc30aView::OnEditCopy()

{

       // TODO: Add your command handler code here

       COleDataSource* pSource = SaveDib();

       if (pSource) {

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

    }

}

 

void CMymfc30aView::OnUpdateEditCopy(CCmdUI* pCmdUI)

{

    // TODO: Add your command update UI handler code here

    // serves Copy, Cut, and Copy To

    CDib& dib = GetDocument()->m_dib;

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

}

 

void CMymfc30aView::OnEditCopyto()

{

    // TODO: Add your command handler code here

    CDib& dib = GetDocument()->m_dib;

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

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

 

    BeginWaitCursor();

    dib.CopyToMapFile(dlg.GetPathName());

    EndWaitCursor();

}

 

void CMymfc30aView::OnEditCut()

{

    // TODO: Add your command handler code here

    OnEditCopy();

    GetDocument()->OnEditClearAll();

}

 

void CMymfc30aView::OnEditPaste()

{

    // TODO: Add your command handler code here

    CMymfc30aDoc* pDoc = GetDocument();

    COleDataObject dataObject;

    VERIFY(dataObject.AttachClipboard());

    DoPasteDib(&dataObject);

    CClientDC dc(this);

    pDoc->m_dib.UsePalette(&dc);

    pDoc->SetModifiedFlag();

    pDoc->UpdateAllViews(NULL);

}

 

void CMymfc30aView::OnUpdateEditPaste(CCmdUI* pCmdUI)

{

    // TODO: Add your command update UI handler code here

    COleDataObject dataObject;

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

    pCmdUI->Enable(bAvail);

}

 

void CMymfc30aView::OnEditPastefrom()

{

    // TODO: Add your command handler code here

    // You can try changing to other extensions...

    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);

    }

}

 

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;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Listing 36: The CMymfc30aView class listing.

 

Several interesting things happen in the view class. In the DoPasteDib() helper, we can call GetGlobalData() because we can attach the returned HGLOBAL variable to the document’s Cdib object. If we called GetData(), we would have to copy the memory block ourselves. The Paste From and Copy To command handlers rely on the memory-mapped file support in the Cdib class. The OnPrepareDC() function creates a special printer-mapping mode that is just like MM_LOENGLISH except that positive y is down. One pixel on the display corresponds to 0.01 inch on the printer.

 

 

Continue on next module...

 

-------------------End part I-----------------

 

 

 

 

 

 

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 2 | Uniform Data Transfer & OLE 4 | Download | Site Index |