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


 

 

 

 

 

Uniform Data Transfer:

-Clipboard Transfer and OLE Drag and Drop 4-

 

 

 

 

 

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. MFC Drag and Drop

  2. The Source Side of the Transfer

  3. The Destination Side of the Transfer

  4. The Drag-and-Drop Sequence

  5. The MYMFC30B Example: OLE Drag and Drop

  6. The MYMFC30B Steps From Scratch

 

MFC Drag and Drop

 

Drag and drop was the ultimate justification for the data object code you've been looking at. OLE supports this feature with its IDropSource and IDropTarget interfaces plus some library code that manages the drag-and-drop process. The MFC library offers good drag-and-drop support at the view level, so we'll use it. Be aware that drag-and-drop transfers are immediate and independent of the clipboard. If the user cancels the operation, there's no "memory" of the object being dragged.

Drag-and-drop transfers should work consistently between applications, between windows of the same application, and within a window. When the user starts the operation, the cursor should change to an arrow-rectangle combination. If the user holds down the Ctrl key, the cursor turns into a plus sign (+), which indicates that the object is being copied rather than moved. MFC also supports drag-and-drop operations for items in compound documents. This is the next level up in MFC OLE support, and it's not covered in this Module. Look up the MSDN’s OCLIENT example in the online documentation under Visual C++ Samples.

 

The Source Side of the Transfer

 

When your source program starts a drag-and-drop operation for a data object, it calls COleDataSource::DoDragDrop. This function internally creates an object of MFC class COleDropSource, which implements the IOleDropSource interface. DoDragDrop() is one of those functions that don't return for a while. It returns when the user drops the object or cancels the operation or when a specified number of milliseconds have elapsed. If you're programming drag-and-drop operations to work with a CRectTracker object, you should call DoDragDrop() only when the user clicks inside the tracking rectangle, not on its border. CRectTracker::HitTest gives you that information. When you call DoDragDrop(), you need to set a flag that tells you whether the user is dropping the object into the same view (or document) that it was dragged from.

 

The Destination Side of the Transfer

 

If you want to use the MFC library's view class drag-and-drop support, you must add a data member of class COleDropTarget to your derived view class. This class implements the IDropTarget interface, and it holds an IDropSource pointer that links back to the COleDropSource object. In your view's OnInitialUpdate() function, you call the Register() member function for the embedded COleDropTarget object. After you have made your view a drop target, you must override four CView virtual functions, which the framework calls during the drag-and-drop operation. Here's a summary of what they should do, assuming that you're using a tracker.

 

 

 

Virtual function

Description

OnDragEnter()

Adjusts the focus rectangle and then calls OnDragOver().

OnDragOver()

Moves the dotted focus rectangle and sets the drop effect (determines cursor shape).

OnDragLeave()

Cancels the transfer operation; returns the rectangle to its original position and size.

OnDrop()

Adjusts the focus rectangle and then calls the DoPaste() helper function to get formats from the data object.

 

Table 1.

 

The Drag-and-Drop Sequence

 

Figure 1 illustrates the MFC drag-and-drop process.

 

Figure 1:  MFC OLE drag-and-drop processing.

 

Figure 1:  MFC OLE drag-and-drop processing.

 

Here's a summary of what's going on:

 

  1. User presses the left mouse button in the source view window.

  2. Mouse button handler calls CRectTracker::HitTest and finds out that the cursor was inside the tracker rectangle.

  3. Handler stores formats in a COleDataSource object.

  4. Handler calls COleDataSource::DoDragDrop for the data source.

  5. User moves the cursor to the view window of the target application.

  6. OLE calls IDropTarget::OnDragEnter and OnDragOver() for the COleDropTarget object, which calls the corresponding virtual functions in the target's view. The OnDragOver() function is passed a COleDataObject pointer for the source object, which the target tests for a format it can understand.

  7. OnDragOver() returns a drop effect code, which OLE uses to set the cursor.

  8. OLE calls IDataSource::QueryContinueDrag on the source side to find out whether the drag operation is still in progress. The MFC COleDataSource class responds appropriately.

  9. User releases the mouse button to drop the object in the target view window.

  10. OLE calls IDropTarget::OnDrop, which calls OnDrop() for the target's view. Because OnDrop() is passed a COleDataObject pointer, it can retrieve the desired format from that object.

  11. When OnDrop() returns in the target program, DoDragDrop() can return in the source program.

 

The MYMFC30B Example: OLE Drag and Drop

 

This example picks up where the MYMFC30A example leaves off. It adds drag-and-drop support, using the existing SaveDib() and DoPasteDib() helper functions. All of the clipboard code is the same. You should be able to adapt MYMFC30B to other applications that require drag and drop for data objects.

To prepare MYMFC30B, open the mfcproject\Mymfc30b.dsw workspace and build the project. Run the application, and test drag and drop between child windows and between instances of the program.

 

The MYMFC30B Steps From Scratch

 

This is MDI application without ActiveX Controls and Automation support. The view base class is CScrollView.

 

Figure 2: MYMFC30B – Visual C++ new project dialog.

 

Figure 2: MYMFC30B – Visual C++ new project dialog.

 

Figure 3: MYMFC30B – AppWizard step 1 of 6, select MDI application.

 

Figure 3: MYMFC30B – AppWizard step 1 of 6, select MDI application.

 

Figure 4: MYMFC30B – AppWizard step 2 of 6.

 

Figure 4: MYMFC30B – AppWizard step 2 of 6.

 

Figure 5: MYMFC30B – AppWizard step 3 of 6, deselect the Automation and ActiveX Controls options.

 

Figure 5: MYMFC30B – AppWizard step 3 of 6, deselect the Automation and ActiveX Controls options.

 

Figure 6: MYMFC30B – AppWizard step 4 of 6.

 

Figure 6: MYMFC30B – AppWizard step 4 of 6.

 

Figure 7: MYMFC30B – AppWizard step 5 of 6.

 

Figure 7: MYMFC30B – AppWizard step 5 of 6.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

Figure 8: MYMFC30B – AppWizard step 4 of 6, change the view base class to CScrollView.

 

Figure 8: MYMFC30B – AppWizard step 4 of 6, change the view base class to CScrollView.

 

Figure 9: MYMFC30B project summary.

 

Figure 9: MYMFC30B project summary.

 

Add the CDib class. Copy the cdib.h and cdib.cpp from previous project and paste them to this project. Add those files by using the Add to Project menu as shown below.

 

Figure 10:  Adding files for Cdib class.

 

Figure 10:  Adding files for Cdib class.

 

Figure 11: Selecting cdib.cpp and cdib.h files for Cdib class.

 

Figure 11: Selecting cdib.cpp and cdib.h files for Cdib class.

 

Add menu items under the Edit menu of the IDR_MYMFC3TYPE. Use the information in the following Table. Replace the Undo menu with the Clear All.

 

ID

Menu caption

Prompt

Separator

-

-

ID_EDIT_CLEAR_ALL

Clear A&ll

-

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

 

Table 2.

 

Figure 12: Replacing Undo with Clear All menu item.

 

Figure 12: Replacing Undo with Clear All menu item.

 

Figure 13: Adding Copy To menu item.

 

Figure 13: Adding Copy To menu item.

 

 

Figure 14: Adding Paste From menu item.

 

Figure 14: Adding Paste From menu item.

 

Figure 15: A completed menu items for MYMFC30B.

 

Figure 15: A completed menu items for MYMFC30B.

 

Add WM_PALETTECHANGED and WM_QUERYNEWPALETTE windows messages to the CMainFrame class.

 

Figure 16: Adding Windows message handler to the CMainFrame class.

 

Figure 16: Adding Windows message handler to the CMainFrame class.

 

Add the following #define directive in MainFrm.h.

 

#define WM_VIEWPALETTECHANGED WM_USER + 5

 

C++ code snippet - Uniform data transfer: OLE drag/drop and clipboard transfer

 

Listing 1.

 

In MainFrm.cpp, add the following codes.

 

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

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

C++ code snippet - Uniform data transfer: OLE drag/drop and clipboard transfer

 

Listing 2.

 

Using ClassWizard, add the following virtual function to CMymfc30bView class.

 

Figure 17: Adding virtual functions virtual function to CMymfc30bView class.

 

Figure 17: Adding virtual functions virtual function to CMymfc30bView class.

 

Add window messages to the CMymfc30bView class as shown below.

 

 

Figure 18: Adding window messages to the CMymfc30bView class.

 

Figure 18: Adding window messages to the CMymfc30bView 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 3.

 

 

Figure 19: Adding update command handlers for ID_EDIT_CUT.

 

Figure 19: Adding update command handlers for ID_EDIT_CUT.

 

Figure 20: Adding update command handlers for ID_EDIT_COPYTO.

 

Figure 20: Adding update command handlers for ID_EDIT_COPYTO.

 

Figure 21: Adding command handlers for ID_EDIT_PASTEFROM.

 

Figure 21: Adding command handlers for ID_EDIT_PASTEFROM.

 

Manually or using ClassView, add member variables as shown below in mymfc30bView.h. These variables are private by default.

 

    // for tracking

    CRectTracker m_tracker;

    CRect m_rectTracker;

    // for drag-and-drop

    CRect m_rectTrackerEnter; // original logical coords

    COleDropTarget m_dropTarget;

    CSize m_dragOffset; // device coords

    CSize m_sizeTotal;  // document size

 

C++ code snippet - Uniform data transfer: OLE drag/drop and clipboard transfer

 

Listing 3.

 

Then, using ClassView or manually add the following member functions.

 

private:

    BOOL DoPasteDib(COleDataObject* pDataObject);

    COleDataSource* SaveDib();

    void MoveTrackRect(CPoint point);

 

Figure 22: Adding a member function.

 

Figure 22: Adding a member function.

 

 

C++ code snippet - Uniform data transfer: OLE drag/drop and clipboard transfer

 

Listing 4.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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