Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

CListCtrl and Drag and Drop

Posted on 1998-06-10
26
Medium Priority
?
1,160 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 120 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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
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

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

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

This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.
Suggested Courses

916 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