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.
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 30: Browsing BMP file under Windows directory.
Figure 31: The pasted BMP file in MYMFC30A. |
Next, select 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).
Test the Clear All menu. This will clear the current BMP.

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:
Win32 process, thread and synchronization story can be found starting from Module R.
MSDN What's New (MFC Feature Pack) - feature pack.
DCOM at MSDN.
COM+ at MSDN.
COM at MSDN.
Unicode and Multi-byte character set: Story and program examples.