root/trunk/RDragDropFiles.cpp

Revision 5, 8.0 kB (checked in by qbert, 6 years ago)

Initial ( and last :( ) commit

Line 
1 // RDragDropFiles.cpp: implementation of the RDragDropFiles class.
2 //
3 /*
4     Author:         Richard Chambers, rickcham@mindspring.com
5
6     Copyright:      Richard Chambers, 2002
7
8     Version:        1.0
9
10     Rights of Use:  This source code may be used by anyone for any reason
11                     so long as the copyright information is maintained.
12
13                     There is no warranty, express or implied, as to fitness
14                     of purpose nor is there any other warranty, expressed
15                     or implied, as to correct functioning.
16
17                     This software depends on the existance of two functions
18                     in the Windows API as well as the correct function of
19                     those functions.  See the Requires section below.
20
21     Requires:       RDragDropFiles.h containing the class declaration.
22                     DragQueryFile function from the Windows API.
23                     Client must provide a correct HDROP handle to the constructor.
24                     Client must initialize file drop using DragAcceptFiles.
25
26     Assumptions:    If debug is turned on, the macro _DEBUG is defined and ASSERT
27                     is enabled.  If debug is turned off, the macro _DEBUG is
28                     undefined and ASSERT is disabled.
29
30                     The DragQueryFile Window s API function remains unchanged
31                     across Windows versions (Windows 95/98/ME/NT/2000).
32
33     Edit History:
34
35  */
36
37 /*
38     Description:
39
40     This file implements the file drag and drop functionality
41     by encapsulating the DragQueryFile function call for the
42     Windows file drag and drop.
43
44     This is not the same as the Windows OLE drag and drop.
45
46     In order to activate a window as a drop target, you must
47     insert a call to DragAcceptFiles into your OnCreate
48     handler of your window.
49
50     Then catch the WM_DROPFILES message (OnDropFiles method of
51     a CView class using Visual C++ Class Wizard) and use this
52     class in the method.
53
54     void CScreen01View::OnDropFiles(HDROP hDropInfo)
55     {
56         rjc::RDragDropFiles myFiles (hDropInfo);
57         CString buf;
58
59         while (myFiles ()) {
60             myFiles.sNextFile (buf);
61             ...  do something with buf .....
62         }
63     }
64
65  */
66
67 #include "stdafx.h"
68 //#include "screen01.h"
69 #include "RDragDropFiles.h"
70
71 #ifdef _DEBUG
72 #undef THIS_FILE
73 static char THIS_FILE[]=__FILE__;
74 #define new DEBUG_NEW
75 #endif
76
77 using namespace rjc;
78
79 //////////////////////////////////////////////////////////////////////
80 // Construction/Destruction
81 //////////////////////////////////////////////////////////////////////
82
83 RDragDropFiles::RDragDropFiles(HDROP hDrop)
84     :hDropInfo (hDrop), nFiles (0), iPosition (0)
85 {
86     ASSERT (hDropInfo);
87
88     if (hDropInfo) {
89         nFiles = DragQueryFile (hDropInfo, 0xFFFFFFFF, NULL, 0);
90     }
91
92     ASSERT (nFiles > 0);
93 }
94
95 RDragDropFiles::~RDragDropFiles()
96 {
97     //  Release the drag and drop resources
98     //  We check that hDropInfo is valid before
99     //  doing the DragFinish in case the client has
100     //  called the Clear method in order to prevent
101     //  the use of DragFinish when the object goes out
102     //  of scope.
103     //  Reference counting is left as an exercise.
104     if (hDropInfo) {
105         DragFinish(hDropInfo);
106     }
107 }
108
109 /*
110     In the following three methods for iterating over the list
111     of files, we require the client to provide us a CString
112     for the buffer.  We require the client's CString so that
113     we don't have to do funky pointers and stuff.  The client
114     can provide us an auto object on the stack which will be
115     cleaned up when it goes out of scope.
116
117     We will also set the CString to Empty if there is not a file
118     name to put into it.  That way the client can depend on the
119     value of the CString to be logically correct.
120
121     The client can either call the constructor and then start
122     iterating using sNextFile or the client can use sFirstFile
123     or Reset to start at the beginning of the list after iterating
124     some of it then continue with sNextFile.
125
126     iPosition, which is the file position in the list of files,
127     is a 1 index rather an a 0 index.  However, DragQueryFile
128     uses a 0 index so we subtract 1 from iPosition.  We are
129     using 1 index in our class as it simplifies the code when
130     mixing sFirstFile, sNextFile, and Reset.
131
132     sFirstFile forces iPosition to 1 for the first file in
133     the list.  sCurrFile forces iPosition to 1 if it is 0 so
134     as to ensure the correct functioning of sNextFile if it is
135     used after a sCurrFile.
136
137     We use DragQueryFile to find the length of the pathname
138     we want to get, set our CString length accordingly, and
139     then copy the pathname of the file into our CString.  The
140     pathname is a standard C string with an end of string
141     terminator at the end for which we also have to account.
142
143     When we do the CString.ReleaseBuffer, CString will recalc
144     the length information based on the end of string terminator.
145  */
146
147
148 CString & RDragDropFiles::sFirstFile (CString & sBuff)
149 {
150     ASSERT (hDropInfo);
151
152     iPosition = 1;
153     if (iPosition <= nFiles) {
154         UINT nLen = DragQueryFile (hDropInfo, iPosition - 1, NULL, 0);
155         char *pzsFN = sBuff.GetBufferSetLength (nLen+2);
156         DragQueryFile (hDropInfo, iPosition - 1, pzsFN, nLen+2);
157         sBuff.ReleaseBuffer ();
158     }
159     else {
160         sBuff.Empty ();
161     }
162     return sBuff;
163 }
164
165 CString & RDragDropFiles::sNextFile (CString & sBuff)
166 {
167     ASSERT (hDropInfo);
168     ASSERT (iPosition < nFiles);
169     ASSERT (iPosition >= 0);
170
171     if (iPosition < nFiles) {
172         iPosition++;
173         UINT nLen = DragQueryFile (hDropInfo, iPosition - 1, NULL, 0);
174         char *pzsFN = sBuff.GetBufferSetLength (nLen+2);
175         DragQueryFile (hDropInfo, iPosition - 1, pzsFN, nLen+2);
176         sBuff.ReleaseBuffer ();
177     }
178     else {
179         sBuff.Empty ();
180     }
181     return sBuff;
182 }
183
184
185 CString & RDragDropFiles::sCurrFile (CString & sBuff)
186 {
187     ASSERT (hDropInfo);
188     ASSERT (iPosition <= nFiles);
189
190     if (iPosition < 1)
191         iPosition = 1;
192
193     if (iPosition <= nFiles) {
194         UINT nLen = DragQueryFile (hDropInfo, iPosition - 1, NULL, 0);
195         char *pzsFN = sBuff.GetBufferSetLength (nLen+2);
196         DragQueryFile (hDropInfo, iPosition - 1, pzsFN, nLen+2);
197         sBuff.ReleaseBuffer ();
198     }
199     else {
200         sBuff.Empty ();
201     }
202     return sBuff;
203 }
204
205 #ifdef _DEBUG
206 // non-debug versions of these are inline in RDragDropFiles.h
207
208 // Any changes made to functionality should be reflected in the
209 // in-line versions as well.
210
211 // Need to do retesting in both debug and non-debug configurations.
212
213 /*
214     uCount - provide a count of the files in the drop list.
215  */
216 UINT RDragDropFiles::uCount ()
217 {
218     ASSERT (hDropInfo);
219
220     if (hDropInfo) {
221         return nFiles;
222     }
223     else {
224         return 0;
225     }
226 }
227
228 /*
229     function operator - returns whether there are any more
230     files to obtain from the list of dropped files.
231
232     iPosition == 0 if after Reset or newly constructed.
233     iPosition == 1 if after sFirstFile or sCurrFile or first sNextFile (iPosition was 0)
234
235     We are using increment before fetch in sNextFile so iPosition == nFiles on
236     exit from last legal sNextFile.  iPostion should be less than nFiles if
237     the next call to sNextFile will return an item from the file list.
238  */
239 boolean RDragDropFiles::operator () ()
240 {
241     ASSERT (hDropInfo);
242
243     return (hDropInfo && (iPosition < nFiles));
244 }
245
246 /*
247     IsEmpty - return whether the list of files is empty.
248         An empty list is either hDropInfo is not a good
249         item or the number of files being dropped is less
250         than 1 (in other words zero).
251
252     IsEmpty tells us if there are any files in the list and not
253     whether iPosition points to a legal list entry.
254  */
255 boolean RDragDropFiles::IsEmpty ()
256 {
257     return (!hDropInfo || (nFiles < 1));
258 }
259
260 /*
261     Reset - reset the position so that we can iterate over
262         the list from the beginning.  Set iPosition to 0
263         allowing sNextFile to work correctly if called
264         after doing a Reset.
265  */
266 void    RDragDropFiles::Reset ()
267 {
268     ASSERT (hDropInfo);
269
270     iPosition = 0;
271
272     ASSERT (iPosition < nFiles);
273 }
274
275 /*
276     Clear - clear the object's stored data.
277         The purpose of clear is to object's data before
278         its destructor is called in those cases where
279         the client wants to use the hDropIno for something
280         else.
281
282         The main reason to use this method is to prevent
283         the call to DragFinish(hDropInfo); when the object's
284         destructor is called as it goes out of scope.
285  */
286 void RDragDropFiles::Clear ()
287 {
288     ASSERT (hDropInfo);
289
290     hDropInfo = 0;
291     nFiles = 0;
292 }
293
294 #endif
Note: See TracBrowser for help on using the browser.