Solved

CListCtrl and Drag and Drop

Posted on 1998-06-10
26
1,087 Views
Last Modified: 2008-02-01
I've got a list view in which I've got a list of files.  I'd like to have the use select some files and then drag then out to another folder where it copies those files.  Explorer does this very thing everyday so I know it's possible.
This will become worth more points once I have them available.
0
Comment
Question by:ElmerFud
  • 14
  • 12
26 Comments
 
LVL 10

Accepted Solution

by:
RONSLOW earned 30 total points
ID: 1165589
Construct a COleDataSource object when you get a begin drag message in you list view, initialize it with the filename of the corresponging item (in CF_FILENAME format), and call the data source object's DoDragDrop member function.
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1165590
something like this ...

CString name = ... file name of selected item
int buflen = name.GetLength() + 1;
HANDLE hData =
::GlobalAlloc (GMEM_MOVEABLE | GMEM_SHARE, buflen);
LPTSTR* pString = (LPTSTR)::GlobalLock (hData);
strcpy(pString,string);
::GlobalUnlock (hData);
COleDataSource ods;
ods.CacheGlobalData (CF_FILENAME, hData);
ods.DoDragDrop (DROPEFFECT_COPY);


0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1165591
Better is to use CF_HDROP instead of CF_FILENAME

Set up a DROPFILES object .. this supports a list of file name (double null terminated)

Lookup DROPFILE or CF_HDROP in the on-line help for further info

0
Optimizing Cloud Backup for Low Bandwidth

With cloud storage prices going down a growing number of SMBs start to use it for backup storage. Unfortunately, business data volume rarely fits the average Internet speed. This article provides an overview of main Internet speed challenges and reveals backup best practices.

 
LVL 1

Author Comment

by:ElmerFud
ID: 1165592
ok, I'm gonna try it.  I'm kind of confused as to where I should put this code, is there some event that is related to the user trying to drag an item from the ListView?  I'm gonna play around with it this morning and see what I come up with.  I've got 5 more points today.  This is worth 50 easy, I just didn't hav ethe points yesterday.
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1165593
I'd try a handler for LVN_BEGINDRAG.

0
 
LVL 1

Author Comment

by:ElmerFud
ID: 1165594
Ahhh!  That makes since.  :)  Gonna try it right now.  Be back ASAP.
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1165595
Good luck .. I haven't tried it myself yet (got my own problems at the moment) .. but you should have the concept at least.  I'll give it a go myself ASAP .. when the panic subsides

0
 
LVL 1

Author Comment

by:ElmerFud
ID: 1165596
Ahhh!  That makes since.  :)  Gonna try it right now.  Be back ASAP.
0
 
LVL 1

Author Comment

by:ElmerFud
ID: 1165597
I'm most certainly doing this wrong.  I'm very confused.  :) Here's my function.  I don't think I'm doing the multiple files thingy right. There is very little documentation on the clipboard formats which are built into Visual C++.

void CNoteDlg::OnBegindragFileList(NMHDR* pNMHDR, LRESULT* pResult)
{
  NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

  CString Files = "";
  int i = m_FileList.GetNextItem( -1, LVNI_ALL | LVNI_SELECTED);
  while( i != -1 )
  {
    Files += CurDir + "Recieved Files\\" + m_FileList.GetItemText(i, 0) + "\0\0";
    i = m_FileList.GetNextItem(i, LVNI_ALL | LVNI_SELECTED);
  }

  HANDLE hData = ::GlobalAlloc (GMEM_MOVEABLE | GMEM_SHARE, Files.GetLength() + 1);
  LPTSTR pString = (LPTSTR)::GlobalLock (hData);
  strcpy(pString, Files);
  ::GlobalUnlock (hData);
  COleDataSource ods;
  ods.CacheGlobalData(CF_HDROP, hData);
  ods.DoDragDrop (DROPEFFECT_COPY);
  GlobalFree(hData);
      
  *pResult = 0;
}

i'm pretty sure this line is wrong:
  ods.CacheGlobalData(CF_HDROP, hData);
I need to turn it into the right data structure.  I'm gonna fiddle with it some more.  Anyway Good luck with your troubles there.  Answer when ever you can.  I frequently find myself putting out the flames.  :)
-ElmerFud

0
 
LVL 1

Author Comment

by:ElmerFud
ID: 1165598
I'm most certainly doing this wrong.  I'm very confused.  :) Here's my function.  I don't think I'm doing the multiple files thingy right. There is very little documentation on the clipboard formats which are built into Visual C++.

void CNoteDlg::OnBegindragFileList(NMHDR* pNMHDR, LRESULT* pResult)
{
  NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

  CString Files = "";
  int i = m_FileList.GetNextItem( -1, LVNI_ALL | LVNI_SELECTED);
  while( i != -1 )
  {
    Files += CurDir + "Recieved Files\\" + m_FileList.GetItemText(i, 0) + "\0\0";
    i = m_FileList.GetNextItem(i, LVNI_ALL | LVNI_SELECTED);
  }

  HANDLE hData = ::GlobalAlloc (GMEM_MOVEABLE | GMEM_SHARE, Files.GetLength() + 1);
  LPTSTR pString = (LPTSTR)::GlobalLock (hData);
  strcpy(pString, Files);
  ::GlobalUnlock (hData);
  COleDataSource ods;
  ods.CacheGlobalData(CF_HDROP, hData);
  ods.DoDragDrop (DROPEFFECT_COPY);
  GlobalFree(hData);
      
  *pResult = 0;
}

i'm pretty sure this line is wrong:
  ods.CacheGlobalData(CF_HDROP, hData);
I need to turn it into the right data structure.  I'm gonna fiddle with it some more.  Anyway Good luck with your troubles there.  Answer when ever you can.  I frequently find myself putting out the flames.  :)
-ElmerFud

0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1165599
You cannot build up strings with embedded '\0' in them using CString .. as it takes the nul char as meaning the end of string.

I suggest building the CString with, say, ';' separators, then doing a strdup on it and changing all the ';' into '\0'.  Or just build it up in a char[] buffer yourself.

Then try again.

PS: You probably graded too early on this one .. if you cannot get it to work then other experts cannot come in here to help you further (if I am unable to do so).

But thanks anyway for the points and appreciation.

0
 
LVL 1

Author Comment

by:ElmerFud
ID: 1165600
I'm most certainly doing this wrong.  I'm very confused.  :) Here's my function.  I don't think I'm doing the multiple files thingy right. There is very little documentation on the clipboard formats which are built into Visual C++.

void CNoteDlg::OnBegindragFileList(NMHDR* pNMHDR, LRESULT* pResult)
{
  NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

  CString Files = "";
  int i = m_FileList.GetNextItem( -1, LVNI_ALL | LVNI_SELECTED);
  while( i != -1 )
  {
    Files += CurDir + "Recieved Files\\" + m_FileList.GetItemText(i, 0) + "\0\0";
    i = m_FileList.GetNextItem(i, LVNI_ALL | LVNI_SELECTED);
  }

  HANDLE hData = ::GlobalAlloc (GMEM_MOVEABLE | GMEM_SHARE, Files.GetLength() + 1);
  LPTSTR pString = (LPTSTR)::GlobalLock (hData);
  strcpy(pString, Files);
  ::GlobalUnlock (hData);
  COleDataSource ods;
  ods.CacheGlobalData(CF_HDROP, hData);
  ods.DoDragDrop (DROPEFFECT_COPY);
  GlobalFree(hData);
      
  *pResult = 0;
}

i'm pretty sure this line is wrong:
  ods.CacheGlobalData(CF_HDROP, hData);
I need to turn it into the right data structure.  I'm gonna fiddle with it some more.  Anyway Good luck with your troubles there.  Answer when ever you can.  I frequently find myself putting out the flames.  :)
-ElmerFud

0
 
LVL 1

Author Comment

by:ElmerFud
ID: 1165601
I just learned a good lesson.  don't use the reload button in Expert's Exchange  :)  I'll try that.
0
 
LVL 1

Author Comment

by:ElmerFud
ID: 1165602
Why am I getting this error?

E:\Projects\cpp\vtifs\NoteDlg.cpp(420) : error C2065: 'CF_FILENAME' : undeclared identifier

I searched for it and I got:

Searching for 'CF_FILENAME'...
C:\Program Files\devstudio\VC\include\SHLOBJ.H(2235):#define CFSTR_FILENAMEA         TEXT("FileName")                // CF_FILENAMEA
C:\Program Files\devstudio\VC\include\SHLOBJ.H(2236):#define CFSTR_FILENAMEW         TEXT("FileNameW")               // CF_FILENAMEW
C:\Program Files\devstudio\VC\include\SHLOBJ.H(2238):#define CFSTR_FILENAMEMAPA      TEXT("FileNameMap")             // CF_FILENAMEMAPA
C:\Program Files\devstudio\VC\include\SHLOBJ.H(2239):#define CFSTR_FILENAMEMAPW      TEXT("FileNameMapW")            // CF_FILENAMEMAPW
4 occurrence(s) have been found.

so I did:
#include <SHLOBJ.H>

I thought maybe I could get it to do one file.
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1165603
Use CF_HDROP instead - it allows multiple files [if you can build the string :-)]

If you want the CF_FILENAME format .. use CF_FILENAMEA (unless you are using UNICODE)

0
 
LVL 1

Author Comment

by:ElmerFud
ID: 1165604
I see.  I was using CF_DROP, but I couldn't get that to work so I went for the one fie drag.  There is no on-line help for CF_HDROP.  It is refered to in several places, but never defined.  I'll keep trying.  There is a definition for DROPFILE, but that doesn't do me any good.
0
 
LVL 1

Author Comment

by:ElmerFud
ID: 1165605
CF_FILENAMEA is also undeclared
0
 
LVL 1

Author Comment

by:ElmerFud
ID: 1165606
typedef struct _DROPFILES {
    DWORD pFiles; // offset of file list
    POINT pt;     // drop point (coordinates depend on fNC)
    BOOL fNC;     // see below
    BOOL fWide;   // TRUE if file contains wide characters,
                  // FALSE otherwise
} DROPFILES, FAR * LPDROPFILES

what is the "offset of file list"?  I've been passing in a pointer to the filelist.
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1165607
oops meant CFSTR_FILENAMEA

anyway .. docs say ...
===
CF_HDROP format

The global memory object contains a DROPFILES structure. If the object was copied to the clipboard as part of a drag-and-drop operation, the pt member of DROPFILES includes the coordinates of the point where the drop occurred. The pFiles member is the offset to a double null-terminated list of file names. An application can retrieve information from the data object by passing the object's handle to the DragQueryFile and DragQueryPoint functions.
===

so .. if you place the list of names directly after the DROPFILES struct then pFiles would be 'sizeof(DROPFILES)' (I guess).

0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1165608
I got this from online help on CF_HDROP (I've got MSDN though .. but should be in platform SDK help?)

There isn't a lot though.
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1165609
There is a MS sample callsed FILEDRAG.EXE that you can donwload from MS FTP site .. it might help

0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1165610
It has a routine...

HGLOBAL CreateHDrop()
{
  HGLOBAL hGlobal;
  // for my sample I am assuming number of files as 2
  int cnt = 2;
  // allocate space for DROPFILE structure plus the number of
  // file and one extra byte for final NULL terminator
  hGlobal = GlobalAlloc(GHND|GMEM_SHARE,(DWORD) (sizeof(DROPFILES)+(_MAX_PATH)*cnt+1));
  if(hGlobal == NULL) return hGlobal;
  LPDROPFILES pDropFiles;
  pDropFiles = (LPDROPFILES)GlobalLock(hGlobal);
  // set the offset where the starting point of the file start
  pDropFiles->pFiles = sizeof(DROPFILES);
  // file does not contain wide characters
  pDropFiles->fWide=FALSE;
  int CurPosition = sizeof(DROPFILES);
  for (int i = 0;i < cnt;i++) {
    TCHAR pszTempPath[MAX_PATH];
    TCHAR szFileName[_MAX_PATH];
    //Get File Name
    wsprintf(szFileName, "myfile%d.txt",i);
    // Create the Temp FileName, Also Note, I don't delete it.
    // since the file has exist on the hard drive. for an
    //application to open it.
    // if I delete it this will not work.
    CreateMyTempFile(szFileName, pszTempPath);
    // copy the file into global memory
    lstrcpy((LPSTR)((LPSTR)(pDropFiles)+CurPosition),TEXT(pszTempPath));
    // move the current position beyond the file name copied
    // don't forget the Null terminator (+1)
    CurPosition +=strlen(pszTempPath)+1;
  }
  // final null terminator as per CF_HDROP Format specs.
  ((LPSTR)pDropFiles)[CurPosition]=0;
  GlobalUnlock(hGlobal);
  return hGlobal;
}

This might be of some help

0
 
LVL 1

Author Comment

by:ElmerFud
ID: 1165611
I'll give that a shot.  Thanks.
0
 
LVL 1

Author Comment

by:ElmerFud
ID: 1165612
Didn't work.  I'm begining to wonder if there's isn't something wrong with how I set up my project.  Does it have to be an "ole server" to work?  Is there any check box or anything that I'm missing?  Could you e-mail me the source for that whole project rhamilto@geocites.com?
0
 
LVL 1

Author Comment

by:ElmerFud
ID: 1165613
I though yuo'd be glad to know that I got it to work.  :)  You need to make this call beforee doig any OLE stuff:

      OleInitialize(NULL);

and this call when you're done:

      OleUninitialize();

Silly me.  Anyway, thank you for your time.
-Elmer
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1165614
Aha .. forgot about that .. sorry I've been asleep.  I live in Australia .. so I sleep while you work [actually, sometimes I sleep while _I_ work :-)].

Glad you've got it going.

I'd be very interested to see the code you ended up with, if you wouldn't mind emailing me at roger.onslow@compsys.com.au

Thanks

0

Featured Post

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
why "." vs "->" 23 120
Retrieve PID of MicrosoftEdge.exe with GetForegroundWindow() 6 152
Getting IP address 8 79
Should CArray be used for a list of pointers in C++? 19 102
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question