Date: | December 7, 2004 / year-entry #411 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20041207-00/?p=37123 |
Comments: | 24 |
Summary: | Let's say that we did want to support Move in our drag/drop program, for whatever reason. Let's do it with some scratch file instead of clock.avi, though. Create a file somewhere that you don't mind losing; let's say it's C:\throwaway.txt. Change the function OnLButtonDown as follows: void OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y,... |
Let's say that we did want to support Move in our
drag/drop program, for whatever reason.
Let's do it with some scratch file instead
of void OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) { IDataObject *pdto; if (SUCCEEDED(GetUIObjectOfFile(hwnd, L"C:\\throwaway.txt", IID_IDataObject, (void**)&pdto))) { IDropSource *pds = new CDropSource(); if (pds) { DWORD dwEffect; if (DoDragDrop(pdto, pds, DROPEFFECT_COPY | DROPEFFECT_LINK | DROPEFFECT_MOVE, &dwEffect) == DRAGDROP_S_DROP) { if (dwEffect & DROPEFFECT_MOVE) { DeleteFile(TEXT("C:\\throwaway.txt")); } } pds->Release(); } pdto->Release(); } } Oh wait, there are people out there who think I'm advocating hard-coded paths, so let me change the program to operate on a path passed on the command line. This is code that is purely a distraction from the point of this article, which is why I avoided it originally. Personally I dislike it when somebody hands me a sample program that is 90% unrelated to the technology the program is trying to demonstrate. I have to go digging through the code hunting for the 10% of stuff that matters. #include <shellapi.h> LPWSTR *g_argv; LPCWSTR g_pszTarget; void OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) { IDataObject *pdto; if (SUCCEEDED(GetUIObjectOfFile(hwnd, g_pszTarget, IID_IDataObject, (void**)&pdto))) { ... DeleteFileW(g_pszTarget); ... } BOOL InitApp(void) { int argc; g_argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (!g_argv || argc != 2) return FALSE; g_pszTarget = g_argv[1]; if (PathIsRelative(g_pszTarget)) return FALSE; ... } Woo-hoo, eight distracting lines of code that have nothing to do with the subject of dragging shell objects around. I hope you're happy. Where was I? Oh right, explaining the first batch of blue code that by now has scrolled off your screen thanks to the intervening meaningless drivel.
Now that we allow move, we need to check whether the resulting effect
was
Notice that
(One case where
If the data object represents a file, then the shell is pretty
good at figuring out how to move the file to the destination
instead of copying it and asking you to delete the original.
You will typically get But what if you want to know whether the operation was a move, regardless of whether the operation was optimized by the drop target? We'll look at that next time. (By the way, if you execute a Move of the throwaway file, don't forget to move it back so you can run the scratch program again!) |
Comments (24)
Comments are closed. |
Oh well, sorry for the bad formatting… I don’t know how to make this appear correctly..
Regards,
Anonymous,
Then you wouldn’t be able to compile the example and run it – the point of the series is that you can try these examples yourself because they’re full examples.
"Voila, everybody wins !! "
Raymond is doing the community a service with his posts (which are done on his own time, IIRC). Rather than looking for a solution in which "everybody wins", maybe we should just be thankful that Raymond bothers with this at all.
He didn’t have to do it in such a condescending way just to prove a point, IMHO. He preferred to stick the command line work inline, defer explanations of the actual point of interest until he did it, and then complained how irrelevant part obscurs the relevant – when he could have moved the comand line-related code into a function and called it in place of the hard-coded path instead, just to prove a meaningless point.
Well, the code doesn’t obscur anything in this case – the programmer does.
Moving the command line code into a function and calling it when I needed the path would have created a potential security hole. Though not the case for command lines, a general function would permit the opportunity for the function to return a different path each time, resulting in the wrong file being deleted. It also would have opened the issue of "who frees the memory" which I also wanted to avoid.
Don’t worry kids, mommy has your bottle.
In the meantime, I’m glad I’m finally getting a simple primer on dragging shell objects.
"I’m glad I’m finally getting a simple primer on dragging shell objects. "
Likewise.
Raymond: I’m sorry to say that you sound rather childish when bitching about having to write proper code. I’m rather disappointed in you.
Next time, just call a non-existent pretend method GetFilenameOrWhatever() {…} and leave its implementation up to the audience. I know, they won’t be able to copy-paste-run the example. Big deal.
Copy/paste/run is important because I often will talk about behavior you encounter while running the program, and if we’re not all running the same program, the discussion will be harder to follow.
I agree w/ac & mschaef:
Raymond is doing us ALL a favour and personally I am smart enought to understand that C:WindowsClock.avi is and example for "Any darn file you want".
I would rather Raymond use that example to create a running example than include a whole bunch of meaningless GUI code (like ac said) that might or migth not compile because of some weird library the orignal programmer is using.
Thank you Raymond for your great articles. I have more respect for Windows and MS developers after reading your articles and I really appreciate your efforts.
Anybody claiming that GetFilenameOrWhatever (with implementation left to the user) is actually better than hardcoded path is out of frikkin mind. Time to deflate your egos.
Rayomond, you’re a lot of fun!
OT: Might want to drop a note to the SDK team that the documentation for CommandLineToArgvW is incorrect. It claims GlobalFree should be used to free the returned pointer, when actually LocalFree should be used, as the function allocates the memory with LocalAlloc.
The point of an example is to demonstrate and illustrate an idea. What you do with an example is examine it until you <em>understand</em> it.
Bearing this in mind it is clear that the original post with clock.avi and no clutter is the best way to illustrate the idea.
I think it’s time the whole sorry saga was forgotten and for the people who complain to leave quietly.
For the last time, I WASN’T COMPLAINING! Jeez, some people are waaaaay too sensitive, or have a humour deficiency… I just thought it was a quick comedy dig that Raymond is always telling us about the developers who have caused Windows to be filled with bizarre workarounds because they’d made assumptions and lo and behold there was just such an assumption.
I think I’ll just go away until everyone has calmed down…
Mat, I think it’s reasonably obvious you were tongue in cheek with your posts the other day, but it sparked off some others who seemed to think it was a serious issue that people might take Raymond’s code and plug it straight into their own apps. I think anyone who does something like that deserves what they get – you use examples for learning, not for solving your problem without bothering to learn. I don’t think Raymond needed to sound quite so pissy about it, but it’s his journal, and I think I would be a bit ticked off with people like that as well ;)
I start all programs with hard coded paths. Hard coded everything. As the program starts to work I go back and change hard coded things. I know how to find paths et al (and will probably cut and paste previous written code in to do it) but for the part that does work I wnat to make that work first and without other factors needing to be fixed.
If I’m my own customer then I’ll leave hard coded paths in and edit the source for each execution of the program.
I don’t think you need to be so pedantic to be correct. Use a variable name instead of a hard-coded path, and a small comment to explain why you use it. For example:
<pre>
// ‘the_file_path’ points to a wide string holding the path to your file.
// don’t forget to build it appropriately. hard-coded paths are pure evil !!
if (SUCCEEDED(GetUIObjectOfFile(hwnd,
the_file_path,
IID_IDataObject, (void**)&pdto))) {
</pre>
Voila, everybody wins !!
Great article, but what if I want to
move c:windowsclock.avi?
This code is top-notch and very informative, as always. The insights and demonstrations given here will always not only be worth a read, but even improve the lives of the developers reading it.
However, lately your tone has been condescending and verging on elitist, which is a huge shame.
Guys, stop looking the gift horse in the mouth, or it might just wander off.
Seriously, if I was getting this much grief for something I did for free I would start to consider whether it is something still worth doing.
The only thing I have to say about hard coded paths and example files etc is that when I write proof of concept apps to operate on COM controls I always end up using the polygon ATL example control. It’s my clock.avi :)
Will other parts of this series be looking at implementing IDropTarget and IDataObject, because implementing IDataObject for some custom COM object has always seemed quite intimidating to me.
Some of you guys are pretty silly bitching about Raymond’s hardcoded paths. If you can’t see past hardcoded paths in *sample code* demonstrating anything but *file handling*, then perhaps you should get another job. Maybe "Grumpy old [wo]man" pays well. :P
Hi Raymond
I understand your point about avoiding clutter in a demonstration program. However I have some sympathy for the person who complained about the hard-coded path. The fact is that so many programmers make that mistake and ship broken software. Some programming concetps are too ugly and dangerous to live: for example you wouldn’t publish an example with "goto" spagetti in it. I agree that the command-line stuff is overkill, but a quick call to GetWindowsDirectory() might be appropriate.