How can I enable dragging cells with right mouse button and display a popup-menu when the user release the mouse button? In the popup-menu I would like the user to give the option to copy or move the cells.

Here is the steps how to implement this behavior:

a) Add the following menu resource to your resource file:

IDR_MENU_DNDACTION MENU DISCARDABLE 
BEGIN
    POPUP "Drop Action"
    BEGIN
        MENUITEM "&Copy",                       ID_DND_COPY
        MENUITEM "&Move",                       ID_DND_MOVE
    END
END

b) Next, add the following handlers to the message map of your grid view

   ON_WM_RBUTTONDOWN()
   ON_COMMAND(ID_DND_MOVE, OnDndMove)
   ON_COMMAND(ID_DND_COPY, OnDndCopy)

c) In your header file, add the following attributes and overrides:

// Attributes
   BOOL m_bRButton;
   UINT m_nDndAction;
// Operations
   virtual BOOL OnGridDrop(CGXNoOleDataObjectProxy* pDataObject,
      DROPEFFECT dropEffect, CPoint point);
   virtual BOOL DndDropActionMenu(CGXNoOleDataObjectProxy* pDataObject,
      DROPEFFECT dropEffect, CPoint point);
// Generated message map functions
   afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
   afx_msg void OnDndMove();
   afx_msg void OnDndCopy();

d) Here are the implementation of this functions:

void C1stGridView::OnRButtonDown(UINT nFlags, CPoint point) 
{
   if (GetCapture() == NULL)
   {
      CRect   rectHit;
      ROWCOL  nRow, nCol;
      int     ht = HitTest(point, &nRow, &nCol);
      if (ht == GX_SELEDGEHIT)
      {
         if (m_nDndFlags)
         {
            ROWCOL ncRow = nRow;
            ROWCOL ncCol = nCol;
            CGXRange rgCovered(nRow, nCol);
            if (GetCoveredCellsRowCol(nRow, nCol, rgCovered))
            {
               ncRow = rgCovered.top;
               ncCol = rgCovered.left;
            }
            m_bRButton = TRUE;
            BOOL b = DndStartDragDrop(ncRow, ncCol);
            m_bRButton = FALSE;
            if (b)
               return;
         }
      }
   }
   // check, if user clicked on a header or cell in the grid
   
   CGXGridView::OnRButtonDown(nFlags, point);
}
BOOL C1stGridView::OnGridDrop(CGXNoOleDataObjectProxy* pDataObject,
   DROPEFFECT dropEffect, CPoint point)
{
   // Kill the timer started in OnGridDragEnter.
   if (!m_bDndGlobalTimer && m_dwDndDropTargetFlags & GX_DNDEGDESCROLL)
      m_pGridWnd->KillTimer(GX_TIMER_DNDSCROLLOTHER);
   // kill timer for this window
   if (m_bDndGlobalTimer)
   {
      m_pGridWnd->KillTimer(GX_TIMER_DNDSCROLLSELF);
      m_bDndGlobalTimer = FALSE;
   }
   if (m_bRButton)
      dropEffect = DndDropActionMenu(pDataObject, dropEffect, point);
   return CGXGridCore::OnGridDrop(pDataObject,   dropEffect, point);
}
BOOL C1stGridView::DndDropActionMenu(CGXNoOleDataObjectProxy* pDataObject,
   DROPEFFECT dropEffect, CPoint pt)
{
   if (dropEffect == DROPEFFECT_MOVE)
   {
      CMenu CopyMoveMenu;
      m_nDndAction = 0;
      CopyMoveMenu.LoadMenu(IDR_MENU_DNDACTION);
      CMenu* pPopup = CopyMoveMenu.GetSubMenu(0);
  
      ClientToScreen(&pt);
      
      pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, 
pt.x,  pt.y, this, NULL);
      MSG msg;
      while (::PeekMessage(&msg, m_hWnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
      {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
      }
      
      switch (m_nDndAction)
      {
      case ID_DND_COPY:   dropEffect = DROPEFFECT_COPY; break;
      case ID_DND_MOVE:   dropEffect = DROPEFFECT_MOVE; break;
      default:         dropEffect = DROPEFFECT_NONE; break;
      }
   }
   return dropEffect;
}
void C1stGridView::OnDndMove() 
{
   m_nDndAction = ID_DND_MOVE;
}
void C1stGridView::OnDndCopy() 
{
   m_nDndAction = ID_DND_COPY;
}