Drag n'Drop on desktop
Noel DANJOU -- NoelD@msn.com Sunday, February 16, 1997 Hello, Environment : VC++ 4.2-flat, Win 95 In one application I would like to be able to drag one or more items from a CListView to one or more text files on the desktop. I found out that I need to register the CFSTR_FILECONTENTS & CFSTR_FILEGROUPDESCRIPTOR clipboard formats and use COleDataSource but that does not work with the code I wrote and I can't figure out where I am wrong. Please could you help me debug my code I attached it below : Thanks for your time, Noel -- S O U R C E C O D E -- in View : // refdbView.cpp : implementation of the CRefdbView class // #include "stdafx.h" #include "afxole.h" #include "refdb.h" #include "DataSrc.h" // OLE Drag n'Drop source #include "shlobj.h" // CFSTR_* definitions #include "reflectr.h" #include "refdbDoc.h" #include "refdbVw.h" #include "tools.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif [...] UINT gcfFileContents = 0; UINT gcfFileGroupDescriptor = 0; [...] ///////////////////////////////////////////////////////////////////////////// // CRefdbView message handlers int CRefdbView::OnCreate(LPCREATESTRUCT lpCreateStruct) { lpCreateStruct->style |= LVS_REPORT | LVS_OWNERDRAWFIXED; if (CListView::OnCreate(lpCreateStruct) == -1) return -1; // Give the document a pointer to this view GetDocument()->m_pListView = this; CreateColumns(); gcfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS); gcfFileGroupDescriptor = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR); return 0; } [...] ///////////////////////////////////////////////////////////////////////////// // Drag n'Drop [...] void CRefdbView::OnLButtonDown(UINT nFlags, CPoint point) { CListView::OnLButtonDown(nFlags, point); CListCtrlEx& ctlList = (CListCtrlEx&)GetListCtrl(); // Create an OLE data source on the heap CReflectorDataSource* pDataSource = NULL; pDataSource = new CReflectorDataSource; pDataSource->SetListCtrl(&ctlList); // default FORMATETC is NULL -> tymed = TYMED_HGLOBAL pDataSource->DelayRenderData(CF_TEXT); // e.g. target is WordPad pDataSource->DelayRenderData(gcfFileContents); // e.g. target is Desktop pDataSource->DelayRenderData(gcfFileGroupDescriptor); // required by FileContents // Uses default COleDropSource implementation. if (DROPEFFECT_MOVE == pDataSource->DoDragDrop(DROPEFFECT_COPY | DROPEFFECT_MOVE)) { // TODO: remove items } delete pDataSource; } void CRefdbView::OnEditCopy() { CReflectorDataSource* pDataSource = NULL; CListCtrlEx& ctlList = (CListCtrlEx&)GetListCtrl(); pDataSource = new CReflectorDataSource; pDataSource->SetListCtrl(&ctlList); // default FORMATETC is NULL -> tymed = TYMED_HGLOBAL pDataSource->DelayRenderData(CF_TEXT); // e.g. target is WordPad // The Clipboard now owns the allocated memory and will delete this // data object when new data is put on the Clipboard pDataSource->SetClipboard(); delete pDataSource; } void CRefdbView::OnUpdateEditCopy(CCmdUI* pCmdUI) { CListCtrl& ctlList = (CListCtrl&)GetListCtrl(); pCmdUI->Enable(ctlList.GetSelectedCount() > 0); } [...] in DataSrc.cpp : --------------------- // DataSrc.cpp : implementation file // #include "stdafx.h" #include "refdb.h" #include "reflectr.h" #include "DataSrc.h" #include "shlobj.h" // FILEGROUPDESCRIPTOR structure definition #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define CU_FILE_SIZE 215 #define CU_DATA_SIZE 1024 extern UINT gcfFileContents; extern UINT gcfFileGroupDescriptor; ///////////////////////////////////////////////////////////////////////////// // CReflectorDataSource CReflectorDataSource::CReflectorDataSource() { m_pCtlList = NULL; } CReflectorDataSource::~CReflectorDataSource() { } BEGIN_MESSAGE_MAP(CReflectorDataSource, COleDataSource) //{{AFX_MSG_MAP(CReflectorDataSource) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CReflectorDataSource message handlers BOOL CReflectorDataSource::OnRenderGlobalData(LPFORMATETC lpFormatEtc, HGLOBAL* phGlobal) { ASSERT(gcfFileContents); ASSERT(gcfFileGroupDescriptor); if (lpFormatEtc->cfFormat == CF_TEXT) { CreateText(phGlobal); } else if (lpFormatEtc->cfFormat == gcfFileContents) { CreateFileContents(phGlobal); } else if (lpFormatEtc->cfFormat == gcfFileGroupDescriptor) { CreateFileDescriptor(phGlobal); } else { TRACE("OnRenderGlobalData() : Format not supported !\n"); return FALSE; } if (*phGlobal == NULL) return FALSE; return TRUE; } void CReflectorDataSource::CreateText(HGLOBAL* phData) { TRACE("CreateText()\n"); HGLOBAL hData = *phData; ASSERT(m_pCtlList != NULL); int count = m_pCtlList->GetSelectedCount(); // allocate space for the number of reflector items if (hData == NULL) hData = GlobalAlloc(GHND | GMEM_SHARE, (DWORD)(sizeof(TCHAR) * CU_DATA_SIZE * count)); // Failure ? if (hData == NULL) return; CString strYes; CString strNo; CString strCountry; CString strLetters; CString strFullName; CString strShortName; CString strIPAddress; CString strContactName; CString strContactEmail; CString strConferenceID; CString strAddToMenu; CString strSendVideo; CString strReceiveVideo; CString strIsRunning; strYes.LoadString(IDS_YES); strNo.LoadString(IDS_NO); strCountry.LoadString(IDS_COUNTRY); strLetters.LoadString(IDS_LETTERS); strFullName.LoadString(IDS_FULLNAME); strShortName.LoadString(IDS_SHORTNAME); strIPAddress.LoadString(IDS_IPADDRESS); strContactName.LoadString(IDS_CONTACT_NAME); strContactEmail.LoadString(IDS_CONTACT_EMAIL); strConferenceID.LoadString(IDS_CONFERENCE_ID); strAddToMenu.LoadString(IDS_ADD_TO_MENU); strSendVideo.LoadString(IDS_SEND_VIDEO); strReceiveVideo.LoadString(IDS_RECEIVE_VIDEO); strIsRunning.LoadString(IDS_IS_RUNNING); CReflector* pReflector; LPSTR lpData = (LPSTR)GlobalLock(hData); *lpData = 0; int iItem = m_pCtlList->GetNextItem(-1, LVNI_SELECTED); while (iItem != -1) { if ((pReflector = m_pCtlList->GetReflector(iItem)) == NULL) break; strcat(lpData, strCountry); strcat(lpData, pReflector->m_strCountry); strcat(lpData, strLetters); strcat(lpData, pReflector->m_strLetters); strcat(lpData, strFullName); strcat(lpData, pReflector->m_strFullName); strcat(lpData, strShortName); strcat(lpData, pReflector->m_strShortName); strcat(lpData, strIPAddress); strcat(lpData, pReflector->m_strIPAddress); strcat(lpData, strContactName); strcat(lpData, pReflector->m_strContactName); strcat(lpData, strContactEmail); strcat(lpData, pReflector->m_strContactEmail); strcat(lpData, strConferenceID); strcat(lpData, pReflector->m_strConferenceID); strcat(lpData, strAddToMenu); strcat(lpData, pReflector->m_bAddToMenu ? strYes : strNo); strcat(lpData, strSendVideo); strcat(lpData, pReflector->m_bSendVideo ? strYes : strNo); strcat(lpData, strReceiveVideo); strcat(lpData, pReflector->m_bReceiveVideo ? strYes : strNo); strcat(lpData, strIsRunning); strcat(lpData, pReflector->m_bIsRunning ? strYes : strNo); strcat(lpData, _T("\n\n")); // Move to next item iItem = m_pCtlList->GetNextItem(iItem, LVNI_SELECTED); } GlobalUnlock(hData); *phData = hData; } void CReflectorDataSource::CreateFileContents(HGLOBAL* phData) { TRACE("CreateFileContents()\n"); HGLOBAL hData = *phData; ASSERT(m_pCtlList != NULL); int count = m_pCtlList->GetSelectedCount(); // allocate space for the number of files if (hData == NULL) hData = GlobalAlloc(GHND | GMEM_SHARE, (DWORD)(CU_FILE_SIZE * count)); // Failure ? if (hData == NULL) return; LPTSTR lpData = (LPTSTR)GlobalLock(hData); CReflector* pReflector; CString strOptions; strOptions.LoadString(IDS_OPTIONS_TEXT); int iItem = m_pCtlList->GetNextItem(-1, LVNI_SELECTED); while (iItem != -1) { if ((pReflector = m_pCtlList->GetReflector(iItem)) == NULL) break; strcpy(lpData, pReflector->m_strIPAddress); strcat(lpData, _T("\r\n")); strcat(lpData, pReflector->m_strConferenceID); strcat(lpData, strOptions); TRACE1("content : %s\n", lpData); lpData += CU_FILE_SIZE; // Move to next item iItem = m_pCtlList->GetNextItem(iItem, LVNI_SELECTED); } GlobalUnlock(hData); *phData = hData; } static TCHAR BASED_CODE szExt[] = _T(".cu"); void CReflectorDataSource::CreateFileDescriptor(HGLOBAL* phData) { TRACE("CreateFileDescriptor()\n"); HGLOBAL hData = *phData; ASSERT(m_pCtlList != NULL); int count = m_pCtlList->GetSelectedCount(); ASSERT(count); // allocate space for FILEGROUPDESCRIPTOR structure plus the number of file // Note: FILEGROUPDESCRIPTOR holds one FILEDESCRIPTOR that's why "count-1" if (hData == NULL) hData = GlobalAlloc(GHND | GMEM_SHARE, (DWORD)(sizeof(FILEGROUPDESCRIPTOR) + (sizeof(FILEDESCRIPTOR) * (count-1)))); // Failure ? if (hData == NULL) return; LPFILEGROUPDESCRIPTOR pfgd = (LPFILEGROUPDESCRIPTOR)GlobalLock(hData); pfgd->cItems = count; CReflector* pReflector; LPFILEDESCRIPTOR pfd = &pfgd->fgd[0]; CString strFileName; int iItem = m_pCtlList->GetNextItem(-1, LVNI_SELECTED); while (iItem != -1) { if ((pReflector = m_pCtlList->GetReflector(iItem)) == NULL) break; strFileName = pReflector->m_strFullName + szExt; pfd->dwFlags = FD_FILESIZE; // Only the file name and size fields are valid pfd->nFileSizeLow = CU_FILE_SIZE; lstrcpy(pfd->cFileName, strFileName); TRACE1("filename : %s\n", pfd->cFileName); pfd++; // point to next FILEDESCRIPTOR structure // Move to next item iItem = m_pCtlList->GetNextItem(iItem, LVNI_SELECTED); } GlobalUnlock(hData); *phData = hData; } ===================================================== Noel DANJOU 12/21/1968 Village Paillette Software Engineer @ PalmCom 50320 Saint Jean des Champs Email: noeld@msn.com France UIN : 187712 NetMeeting 2.0 B2: callto:uls.microsoft.com/noeld@msn.com Home Pages: http://ourworld.compuserve.com/homepages/noeld/ (personal) http://ourworld.compuserve.com/homepages/gil_mic/ (company) =====================================================
Noel DANJOU -- NoelD@msn.com Wednesday, February 19, 1997 Hello, Environment : VC++ 4.2-flat, Win 95 In one application I would like to be able to drag one or more items from a CListView to one or more text files on the desktop. I found out that I need to register the CFSTR_FILECONTENTS & CFSTR_FILEGROUPDESCRIPTOR clipboard formats and use COleDataSource but that does not work with the code I wrote and I can't figure out where I am wrong. Please could you help me debug my code I attached it below : Thanks for your time, Noel -- S O U R C E C O D E -- in View : // refdbView.cpp : implementation of the CRefdbView class // #include "stdafx.h" #include "afxole.h" #include "refdb.h" #include "DataSrc.h" // OLE Drag n'Drop source #include "shlobj.h" // CFSTR_* definitions #include "reflectr.h" #include "refdbDoc.h" #include "refdbVw.h" #include "tools.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif [...] UINT gcfFileContents = 0; UINT gcfFileGroupDescriptor = 0; [...] ///////////////////////////////////////////////////////////////////////////// // CRefdbView message handlers int CRefdbView::OnCreate(LPCREATESTRUCT lpCreateStruct) { lpCreateStruct->style |= LVS_REPORT | LVS_OWNERDRAWFIXED; if (CListView::OnCreate(lpCreateStruct) == -1) return -1; // Give the document a pointer to this view GetDocument()->m_pListView = this; CreateColumns(); gcfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS); gcfFileGroupDescriptor = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR); return 0; } [...] ///////////////////////////////////////////////////////////////////////////// // Drag n'Drop [...] void CRefdbView::OnLButtonDown(UINT nFlags, CPoint point) { CListView::OnLButtonDown(nFlags, point); CListCtrlEx& ctlList = (CListCtrlEx&)GetListCtrl(); // Create an OLE data source on the heap CReflectorDataSource* pDataSource = NULL; pDataSource = new CReflectorDataSource; pDataSource->SetListCtrl(&ctlList); // default FORMATETC is NULL -> tymed = TYMED_HGLOBAL pDataSource->DelayRenderData(CF_TEXT); // e.g. target is WordPad pDataSource->DelayRenderData(gcfFileContents); // e.g. target is Desktop pDataSource->DelayRenderData(gcfFileGroupDescriptor); // required by FileContents // Uses default COleDropSource implementation. if (DROPEFFECT_MOVE == pDataSource->DoDragDrop(DROPEFFECT_COPY | DROPEFFECT_MOVE)) { // TODO: remove items } delete pDataSource; } void CRefdbView::OnEditCopy() { CReflectorDataSource* pDataSource = NULL; CListCtrlEx& ctlList = (CListCtrlEx&)GetListCtrl(); pDataSource = new CReflectorDataSource; pDataSource->SetListCtrl(&ctlList); // default FORMATETC is NULL -> tymed = TYMED_HGLOBAL pDataSource->DelayRenderData(CF_TEXT); // e.g. target is WordPad // The Clipboard now owns the allocated memory and will delete this // data object when new data is put on the Clipboard pDataSource->SetClipboard(); delete pDataSource; } void CRefdbView::OnUpdateEditCopy(CCmdUI* pCmdUI) { CListCtrl& ctlList = (CListCtrl&)GetListCtrl(); pCmdUI->Enable(ctlList.GetSelectedCount() > 0); } [...] in DataSrc.cpp : --------------------- // DataSrc.cpp : implementation file // #include "stdafx.h" #include "refdb.h" #include "reflectr.h" #include "DataSrc.h" #include "shlobj.h" // FILEGROUPDESCRIPTOR structure definition #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define CU_FILE_SIZE 215 #define CU_DATA_SIZE 1024 extern UINT gcfFileContents; extern UINT gcfFileGroupDescriptor; ///////////////////////////////////////////////////////////////////////////// // CReflectorDataSource CReflectorDataSource::CReflectorDataSource() { m_pCtlList = NULL; } CReflectorDataSource::~CReflectorDataSource() { } BEGIN_MESSAGE_MAP(CReflectorDataSource, COleDataSource) //{{AFX_MSG_MAP(CReflectorDataSource) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CReflectorDataSource message handlers BOOL CReflectorDataSource::OnRenderGlobalData(LPFORMATETC lpFormatEtc, HGLOBAL* phGlobal) { ASSERT(gcfFileContents); ASSERT(gcfFileGroupDescriptor); if (lpFormatEtc->cfFormat == CF_TEXT) { CreateText(phGlobal); } else if (lpFormatEtc->cfFormat == gcfFileContents) { CreateFileContents(phGlobal); } else if (lpFormatEtc->cfFormat == gcfFileGroupDescriptor) { CreateFileDescriptor(phGlobal); } else { TRACE("OnRenderGlobalData() : Format not supported !\n"); return FALSE; } if (*phGlobal == NULL) return FALSE; return TRUE; } void CReflectorDataSource::CreateText(HGLOBAL* phData) { TRACE("CreateText()\n"); HGLOBAL hData = *phData; ASSERT(m_pCtlList != NULL); int count = m_pCtlList->GetSelectedCount(); // allocate space for the number of reflector items if (hData == NULL) hData = GlobalAlloc(GHND | GMEM_SHARE, (DWORD)(sizeof(TCHAR) * CU_DATA_SIZE * count)); // Failure ? if (hData == NULL) return; CString strYes; CString strNo; CString strCountry; CString strLetters; CString strFullName; CString strShortName; CString strIPAddress; CString strContactName; CString strContactEmail; CString strConferenceID; CString strAddToMenu; CString strSendVideo; CString strReceiveVideo; CString strIsRunning; strYes.LoadString(IDS_YES); strNo.LoadString(IDS_NO); strCountry.LoadString(IDS_COUNTRY); strLetters.LoadString(IDS_LETTERS); strFullName.LoadString(IDS_FULLNAME); strShortName.LoadString(IDS_SHORTNAME); strIPAddress.LoadString(IDS_IPADDRESS); strContactName.LoadString(IDS_CONTACT_NAME); strContactEmail.LoadString(IDS_CONTACT_EMAIL); strConferenceID.LoadString(IDS_CONFERENCE_ID); strAddToMenu.LoadString(IDS_ADD_TO_MENU); strSendVideo.LoadString(IDS_SEND_VIDEO); strReceiveVideo.LoadString(IDS_RECEIVE_VIDEO); strIsRunning.LoadString(IDS_IS_RUNNING); CReflector* pReflector; LPSTR lpData = (LPSTR)GlobalLock(hData); *lpData = 0; int iItem = m_pCtlList->GetNextItem(-1, LVNI_SELECTED); while (iItem != -1) { if ((pReflector = m_pCtlList->GetReflector(iItem)) == NULL) break; strcat(lpData, strCountry); strcat(lpData, pReflector->m_strCountry); strcat(lpData, strLetters); strcat(lpData, pReflector->m_strLetters); strcat(lpData, strFullName); strcat(lpData, pReflector->m_strFullName); strcat(lpData, strShortName); strcat(lpData, pReflector->m_strShortName); strcat(lpData, strIPAddress); strcat(lpData, pReflector->m_strIPAddress); strcat(lpData, strContactName); strcat(lpData, pReflector->m_strContactName); strcat(lpData, strContactEmail); strcat(lpData, pReflector->m_strContactEmail); strcat(lpData, strConferenceID); strcat(lpData, pReflector->m_strConferenceID); strcat(lpData, strAddToMenu); strcat(lpData, pReflector->m_bAddToMenu ? strYes : strNo); strcat(lpData, strSendVideo); strcat(lpData, pReflector->m_bSendVideo ? strYes : strNo); strcat(lpData, strReceiveVideo); strcat(lpData, pReflector->m_bReceiveVideo ? strYes : strNo); strcat(lpData, strIsRunning); strcat(lpData, pReflector->m_bIsRunning ? strYes : strNo); strcat(lpData, _T("\n\n")); // Move to next item iItem = m_pCtlList->GetNextItem(iItem, LVNI_SELECTED); } GlobalUnlock(hData); *phData = hData; } void CReflectorDataSource::CreateFileContents(HGLOBAL* phData) { TRACE("CreateFileContents()\n"); HGLOBAL hData = *phData; ASSERT(m_pCtlList != NULL); int count = m_pCtlList->GetSelectedCount(); // allocate space for the number of files if (hData == NULL) hData = GlobalAlloc(GHND | GMEM_SHARE, (DWORD)(CU_FILE_SIZE * count)); // Failure ? if (hData == NULL) return; LPTSTR lpData = (LPTSTR)GlobalLock(hData); CReflector* pReflector; CString strOptions; strOptions.LoadString(IDS_OPTIONS_TEXT); int iItem = m_pCtlList->GetNextItem(-1, LVNI_SELECTED); while (iItem != -1) { if ((pReflector = m_pCtlList->GetReflector(iItem)) == NULL) break; strcpy(lpData, pReflector->m_strIPAddress); strcat(lpData, _T("\r\n")); strcat(lpData, pReflector->m_strConferenceID); strcat(lpData, strOptions); TRACE1("content : %s\n", lpData); lpData += CU_FILE_SIZE; // Move to next item iItem = m_pCtlList->GetNextItem(iItem, LVNI_SELECTED); } GlobalUnlock(hData); *phData = hData; } static TCHAR BASED_CODE szExt[] = _T(".cu"); void CReflectorDataSource::CreateFileDescriptor(HGLOBAL* phData) { TRACE("CreateFileDescriptor()\n"); HGLOBAL hData = *phData; ASSERT(m_pCtlList != NULL); int count = m_pCtlList->GetSelectedCount(); ASSERT(count); // allocate space for FILEGROUPDESCRIPTOR structure plus the number of file // Note: FILEGROUPDESCRIPTOR holds one FILEDESCRIPTOR that's why "count-1" if (hData == NULL) hData = GlobalAlloc(GHND | GMEM_SHARE, (DWORD)(sizeof(FILEGROUPDESCRIPTOR) + (sizeof(FILEDESCRIPTOR) * (count-1)))); // Failure ? if (hData == NULL) return; LPFILEGROUPDESCRIPTOR pfgd = (LPFILEGROUPDESCRIPTOR)GlobalLock(hData); pfgd->cItems = count; CReflector* pReflector; LPFILEDESCRIPTOR pfd = &pfgd->fgd[0]; CString strFileName; int iItem = m_pCtlList->GetNextItem(-1, LVNI_SELECTED); while (iItem != -1) { if ((pReflector = m_pCtlList->GetReflector(iItem)) == NULL) break; strFileName = pReflector->m_strFullName + szExt; pfd->dwFlags = FD_FILESIZE; // Only the file name and size fields are valid pfd->nFileSizeLow = CU_FILE_SIZE; lstrcpy(pfd->cFileName, strFileName); TRACE1("filename : %s\n", pfd->cFileName); pfd++; // point to next FILEDESCRIPTOR structure // Move to next item iItem = m_pCtlList->GetNextItem(iItem, LVNI_SELECTED); } GlobalUnlock(hData); *phData = hData; } ===================================================== Noel DANJOU 12/21/1968 Village Paillette Software Engineer @ PalmCom 50320 Saint Jean des Champs Email: noeld@msn.com France UIN : 187712 NetMeeting 2.0 B2: callto:uls.microsoft.com/noeld@msn.com Home Pages: http://ourworld.compuserve.com/homepages/noeld/ (personal) http://ourworld.compuserve.com/homepages/gil_mic/ (company) =====================================================
Become an MFC-L member | Вернуться в корень Архива |