Closed
Bug 156422
Opened 22 years ago
Closed 20 years ago
Win32's nsILocalFile.reveal() (used by Reveal Location) doesn't select file
Categories
(Core Graveyard :: File Handling, defect)
Tracking
(Not tracked)
RESOLVED
FIXED
People
(Reporter: neil, Assigned: deanis74)
References
()
Details
(Keywords: fixed-aviary1.0.1, fixed1.7.6)
Attachments
(2 files, 4 obsolete files)
7.43 KB,
patch
|
law
:
review+
alecf
:
superreview-
|
Details | Diff | Splinter Review |
9.20 KB,
patch
|
neil
:
review+
alecf
:
superreview+
caillon
:
approval-aviary1.0.1+
caillon
:
approval1.7.6+
|
Details | Diff | Splinter Review |
Possibly a Windows 95 thing because I noticed that the code looked very complicated especially in comparison with the Perl that I use: sub reveal { system "$ENV{'windir'}\\explorer.exe /n,/select,$_[0]" }
Ummm... wow, that's some complicated code! What Neil suggests works great for me on Win2K, and is a lot faster than what we currently do, because of the up to 2 second wait. Running explorer directly with "/select" works for folders as well. Both of these work fine for me: explorer /n,/select,c:\winnt\explorer.exe explorer /n,/select,c:\winnt
This isn't just Win95, it's not working for me on Win2K either. What I meant in my last comment is that Neil's suggestion works fine for me on Win2K. I think we should simplify the code a lot and go with that. Oh wait, but what if the user has a custom shell installed? Does our current code even work with that?
Reporter | ||
Comment 3•22 years ago
|
||
Dean, in the case of a custom shell, then running explorer will (if memory serves me correctly) still open an explorer window with the file selected, which is probably what we want anyway. Are you in a position to write a patch for this?
Patch incorporating Neil's suggestion. If the file is not found, an error is raised that "The path '<path and filename>' does not exist or is not a directory." If you ask me, this code is much simpler and less prone to errors. Oh, and I think it works.
Reporter | ||
Comment 7•22 years ago
|
||
Comment on attachment 92317 [details] [diff] [review] cvs diff -u xpcom/io >- LONG r = (LONG) ::ShellExecute( NULL, "open", path.get(), NULL, NULL, SW_SHOWNORMAL); >- if (r < 32) >+ LONG r; >+ r = (LONG) ::ShellExecute(NULL, "open", explorerPath.get(), explorerParams.get(), >+ NULL, SW_SHOWNORMAL); >+ if (r < 32) >+ rv = NS_ERROR_FAILURE; Dean, you may have copied bad code, but my docs say that ShellExecute returns <= 32 on error. Also, why didn't you inline the LONG r? I noticed that you seem to use 4-space indentation; is that consistent with the rest of the file? The old code appeared to use 2-space indentation.
1. Yes, you're right. I copied the existing code but it should check for <= 32. 2. You mean 'if ::ShellExecute() <= 32 return NS_ERROR_FAILURE'? Good question. Again, I copied from the existing code. 3. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ Most of the file follows the tab width of 4, but Reveal and Launch don't.
Reporter | ||
Comment 9•22 years ago
|
||
Dean, that's fine by me.
Assignee | ||
Comment 10•22 years ago
|
||
1. No longer use a variable to handle the return value from ::ShellExecute(). 2. No longer use the rv variable, as there are only three return points, and one already uses the variable ret. 3. Changed < 32 to <= 32. 4. Pass ::GetForegroundWindow() to ::ShellExecute which, according to how I read the docs, should make the foreground window the owner of any messageboxes (eg. file not found). In practice, this doesn't make a lick of difference on Win2K. The messagebox still comes up without a parent.
Attachment #92317 -
Attachment is obsolete: true
Reporter | ||
Comment 11•22 years ago
|
||
> 4. Pass ::GetForegroundWindow() to ::ShellExecute which, according to how I
> read the docs, should make the foreground window the owner of any messageboxes
> (eg. file not found). In practice, this doesn't make a lick of difference on
> Win2K. The messagebox still comes up without a parent.
Other uses of ShellExecute in Mozilla all appear to pass NULL so which is
better, consistency or correctness? :-)
Assignee | ||
Comment 12•22 years ago
|
||
Makes no difference to me.
Assignee | ||
Comment 13•22 years ago
|
||
Aw man, I could've sworn I cc:ed Bill when I took this bug from him. Bill, there's a working, simple patch for this. Any thoughts?
Assignee | ||
Comment 14•22 years ago
|
||
Comment on attachment 92530 [details] [diff] [review] take 2 Need to double-quote the filename, to account for filenames with spaces, commas, etc.
Attachment #92530 -
Flags: needs-work+
Assignee | ||
Comment 15•22 years ago
|
||
1. Always wrap the filename in double quotes, to handle long filenames. 2. Remove the const declarations. These are used only once, no need for the extra code. 3. Remove passing ::GetForegroundWindow() as hWnd to ::ShellExecute(), to keep in line with other uses of ::ShellExecute() in the app. Ready for r=/sr=.
Attachment #92530 -
Attachment is obsolete: true
Reporter | ||
Comment 16•22 years ago
|
||
> Need to double-quote the filename, to account for filenames with spaces,
> commas, etc.
FYI it appears to work with or without quotes on Windows 95, e.g.
C:\WINDOWS\explorer.exe /n,/select,C:\Program Files\Paint Shop Pro\psp.exe
Assignee | ||
Comment 17•22 years ago
|
||
Yes, it works for names with spaces but doesn't work for names with commas in them. c:\winnt\explorer.exe /n,/select,c:\temp\test,1.txt fails, while c:\winnt\explorer.exe /n,/select,"c:\temp\test,1.txt" works. So there are at least some filenames that need to be quoted, so I just quote them all.
Reporter | ||
Comment 18•22 years ago
|
||
Silly me for not reading all of the text that I quoted. /Slaps wrist/
Comment 19•22 years ago
|
||
Comment on attachment 94582 [details] [diff] [review] double-quote the filename I think the lines: + explorerParams.Append(""""); are wrong. That translates to two empty strings concatenated, I believe. I think they should be: + explorerParams.Append("\""); With that fixed, r=law.
Attachment #94582 -
Flags: review+
Assignee | ||
Comment 20•22 years ago
|
||
Wow, that's just dumb of me! Yes, I'll definitely change that for the final patch. Who can sr= this?
Comment 21•22 years ago
|
||
Comment on attachment 94582 [details] [diff] [review] double-quote the filename well, I guess this is ok but I'm not a huge fan of executing explorer directly. There must be a way to do this in-process, no? I guess I'm concerned about some sort of security exploit involving executing explorer directly. Maybe we should get mitch in on this. also, the """" looks odd to me. Are you sure you didn't mean "\"\""? because to me, """" looks like two empty strings concatenated together, similar to "a""b"
Comment 22•22 years ago
|
||
cc'ing mstoltz for security stuff (mitch - see my previous comment) - do we have a "secure" way of executing external processes - i.e. filtering valid filenames, etc?
Assignee | ||
Comment 23•22 years ago
|
||
> also, the """" looks odd to me. Are you sure you didn't mean "\"\""? because to > me, """" looks like two empty strings concatenated together, similar to "a""b" Alec, yes. See comment 19 and 20. It should be "\"". I've spent too much time in other languages lately, and I forgot the C way of doing it.
Assignee | ||
Comment 24•22 years ago
|
||
Incidentally, though, """" adds a double quote for me, not a blank string. It has the same effect as "\"".
Comment 25•22 years ago
|
||
I am concerned about the security of this change. Let's hold off on checking this in until we make sure it can't be used for anything sneaky.
Assignee | ||
Comment 26•22 years ago
|
||
I don't know how it can do anything "sneaky", since it uses "/select". The existing code does a ShellExecute(), and if you ask me the things it does are a lot more risky than what this code proposes.
Assignee | ||
Comment 27•22 years ago
|
||
Mitchell, Alec, and Bill, have you thought about the security implications of this? I maintain that it's a safe way of doing things, and I believe that Windows probably does this internally.
Reporter | ||
Comment 28•22 years ago
|
||
Actually Windows doesn't even bother to verify the path to explorer.exe :-)
Updated•22 years ago
|
QA Contact: sairuh → petersen
Assignee | ||
Comment 29•21 years ago
|
||
Can we decide if this is a security concern or not? I'm fine with the new code, and it sounds like Neil too.
Comment 30•21 years ago
|
||
I'm not sure if calling Explorer is a security risk or not. We probably need to make sure we filter the parameters we pass, to make sure they can't do anything nasty, but we don't have a standardized way of doing that. CCing Darin; he may know more about calling Explorer.
Assignee | ||
Comment 31•21 years ago
|
||
Looking at the registry, the "Explore" context menu for folders uses this command: explorer /e,/root,{f39a0dc0-9cc8-11d0-a599-00c04fd64433},%L
Reporter | ||
Comment 32•21 years ago
|
||
Strange, I have (both 95 and 2000) C:\WINDOWS\Explorer.exe /e,/idlist,%I,%L
Assignee | ||
Comment 33•21 years ago
|
||
I've got the same thing I mentioned on my work and home machines, both running Windows 2000. That wasn't my point, though. I was hoping to address the question of whether it's OK to do this, and I haven't heard any security problems from using the Explore command, so I don't think what we're doing is anything out of the ordinary.
Comment 34•21 years ago
|
||
I've been asked to comment. Not that I have any uncommon knowledge about this. But it seems to me you just want to be extra careful to use the full path to Explorer.exe and to the target file, and to not send any surprising parameters to Explorer. And none of that buffer overflow stuff. The patch looks fine to me. If it makes anyone feel any better, there's a page on MSDN about "security issues of calling ShellExecute." It says what I just said. Or maybe it's the other way around. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/sec_shell.asp
Reporter | ||
Comment 35•21 years ago
|
||
Comment on attachment 94582 [details] [diff] [review] double-quote the filename We need this to fix bug 211894.
Attachment #94582 -
Flags: superreview?(alecf)
Comment 36•20 years ago
|
||
Comment on attachment 94582 [details] [diff] [review] double-quote the filename woah woah. I was going to say that I'm considering this.. but then I saw + explorerParams.Append(""""); This is the same as + explorerParams.Append("" ""); which is the same as + explorerParams.Append(""); which appends nothing. I think what you meant was + explorerParams.Append("\""); but even better might be + explorerParams.Append('\"'); I still want to know if there is a safer way of calling explorer, and I'm trying to figure out why the old way wasn't good. I realize it was complex, but it relied on system APIs rather than passing specific (undocumented?) parameters to explorer.
Attachment #94582 -
Flags: superreview?(alecf) → superreview-
Assignee | ||
Comment 37•20 years ago
|
||
> woah woah. I was going to say that I'm considering this.. but then I saw > + explorerParams.Append(""""); > > This is the same as > + explorerParams.Append("" ""); > > which is the same as > + explorerParams.Append(""); > >which appends nothing. Really? In my testing it appended a double quote (") (see comment 24). Regardless, I'm fine changing that to use whatever syntax, that's minor. One of the reasons the old method isn't good is because it waits a maximum of only two seconds for the Explorer window to open before selecting the file. We could pump that up to 10 seconds, even 100 seconds, but because it's on a set timer there's always the chance that Explorer will take longer to open than we're waiting.
Status: NEW → ASSIGNED
Comment 38•20 years ago
|
||
Since Dean seems to be busy, I've taken his patch as the base and updated it. The parameter /n is now not passed to explorer. This way explorer will reuse any existing window which is already showing that folder. If there is no existing window or existing windows are showing other folders, it will create a new one. This is more user friendly behaviour I think. One question, should Reveal() always show the parent folder of an item, including the case of a directory? i.e. should Reveal() on C:\windows, (a) open an explorer window showing the contents of c:\windows, or (b) open an explorer window showing c:\ with windows selected. This patch does (a) which seems to be more natural. I've verified that this patch also fixes bug 211894.
Comment 39•20 years ago
|
||
Attachment #149388 -
Attachment is obsolete: true
Attachment #149389 -
Flags: superreview?(alecf)
Attachment #149389 -
Flags: review?(neil.parkwaycc.co.uk)
Reporter | ||
Comment 40•20 years ago
|
||
Comment on attachment 149389 [details] [diff] [review] patch 5 >+ nsresult rv; >+ >+ rv = ResolveAndStat(PR_TRUE); Any reason why you separated out the declaration and removed the comment? >+ if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) >+ return rv; >+ // If there is no existing explorer window *showing that folder* then this will >+ // open a new window, otherwise it will reuse the existing window. >+ // If the resolved path is a directory then we want to open it rather than >+ // opening the parent and selecting it, so we don't append the /select option. >+ nsCAutoString explorerParams; >+ if (mFileInfo64.type != PR_FILE_DIRECTORY) // valid because we ResolveAndStat above >+ explorerParams.Append("/select,"); Sigh... this works fine in Windows 95 but on my W2K server it doesn't select the file if the folder is already open :-( >+ if (::ShellExecute(::GetForegroundWindow(), "open", explorerPath.get(), I'm still not keen on GetForegroundWindow() because it may not be ours. >+ explorerParams.get(), NULL, SW_SHOWNORMAL) <= (HINSTANCE) 32) This indentation is confusing... an extra 4 spaces perhaps? >+ return NS_ERROR_FAILURE;
Comment 41•20 years ago
|
||
>+ nsresult rv; >+ >+ rv = ResolveAndStat(PR_TRUE); >Any reason why you separated out the declaration and removed the >comment? Just personal style. I tend to separate variable declarations like nsresult when I use the declared variable many times through the body of the function. I find it makes it easier to see the declaration rather than having it buried, and if the code gets moved around I don't get compile errors because I'm now using the variable before it's declared. Since it's a simple stack variable it's no more efficient one way or the other. The comment I just removed because it matches the style of all other ResolveAndStat calls. Easily replaced if you'd prefer. >+ // opening the parent and selecting it, so we don't append the /select option. >+ nsCAutoString explorerParams; >+ if (mFileInfo64.type != PR_FILE_DIRECTORY) // valid because we ResolveAndStat above >+ explorerParams.Append("/select,"); > Sigh... this works fine in Windows 95 but on my W2K server it > doesn't select the file if the folder is already open :-( I find the existing code doesn't always work either. We could always change it so that we use the "/n" option. If we are opening a new window then it should always select the file. >+ if (::ShellExecute(::GetForegroundWindow(), "open", explorerPath.get(), I'm still not keen on GetForegroundWindow() because it may not be ours. >+ explorerParams.get(), NULL, SW_SHOWNORMAL) <= (HINSTANCE) 32) > This indentation is confusing... an extra 4 spaces perhaps? Will do.
Reporter | ||
Comment 42•20 years ago
|
||
(In reply to comment #41) > The comment I just removed because it matches the style of all other > ResolveAndStat calls. Easily replaced if you'd prefer. Fine, although strangely they all seem to say nsresult rv = ResolveAndStat(PR_TRUE); ;-) > We could always change it so that we use the "/n" option. > If we are opening a new window then it should always select the file. OK, but just to clarify, this is just in the /select case. >> I'm still not keen on GetForegroundWindow() because it may not be ours. No comment on this one?
Comment 43•20 years ago
|
||
> nsresult rv = ResolveAndStat(PR_TRUE); Ok. I'll join the lusting throng and do it that way too. >> I'm still not keen on GetForegroundWindow() because it may not be ours. > No comment on this one? Sorry, I missed that one. I just copied the existing code, but I also didn't like that code when I saw it. What about if we just parent any dialog to the desktop window instead? GetDesktopWindow()
Assignee | ||
Comment 44•20 years ago
|
||
> >> I'm still not keen on GetForegroundWindow() because it may not be ours. > > No comment on this one? > > Sorry, I missed that one. I just copied the existing code, but I also didn't > like that code when I saw it. What about if we just parent any dialog to the > desktop window instead? GetDesktopWindow() Based on comment 10 and comment 11, I say pass NULL. I'm also fine with using /n all the time. That would give us predictable behavior.
Comment 45•20 years ago
|
||
The way I've found the win32 API is that NULL for a hwnd is the same as GetDesktopWindow() when it needs a parent anyhow, so passing NULL for the parent is no different to passing the desktop window anyhow. I have no problem with that change. As for always using "/n", I think that if we should only use it when we are specifying the "/select" parameter, since it seems that 2K doesn't select an object when it doesn't open the window. I guess this would be consistent with the Microsoft aim to prevent non-active windows from modifying the current users actions. i.e. if Mozilla isn't active at the time that it tries to open the window, then it shouldn't try to modify the currently selected object in explorer. This behaviour changed in 2K. I have no problemm with specifying /n when we also specify /select. However, when we are opening a folder (is what I have specified is the correct behaviour?) then we should not specify /n. Is this agreeable?
Assignee | ||
Comment 46•20 years ago
|
||
I can live with that.
Comment 47•20 years ago
|
||
Patch with requested changes.
Attachment #149389 -
Attachment is obsolete: true
Attachment #149464 -
Flags: superreview?(alecf)
Attachment #149464 -
Flags: review?(neil.parkwaycc.co.uk)
Attachment #149389 -
Flags: superreview?(alecf)
Attachment #149389 -
Flags: review?(neil.parkwaycc.co.uk)
Reporter | ||
Updated•20 years ago
|
Attachment #149464 -
Flags: review?(neil.parkwaycc.co.uk) → review+
Comment 48•20 years ago
|
||
To address alecf's concerns in comment 36: > I still want to know if there is a safer way of calling explorer Using the full path to explorer.exe in the system directory is as safe as we can get. All of Microsoft's own code either does this or just calls "explorer.exe" without a path. Additionally the "explorer.exe" file is protected by Windows File Protection on Win2K+, so there shouldn't be much chance of trojans on those platforms. > I'm trying to figure out why the old way wasn't good. I realize > it was complex, but it relied on system APIs rather than > passing specific (undocumented?) parameters to explorer. It is complex, it uses undocumented API and it doesn't always work. This way is simple, it uses documented parameters to explorer <http://support.microsoft.com/support/kb/articles/Q130/5/10.asp> and it works. I've searched for an in-process method of doing this but I can't find a way for *all* windows versions. Microsoft must have seen that this functionality was missing and has added the SHOpenFolderAndSelectItems() function, but available only in XP.
Comment 49•20 years ago
|
||
Comment on attachment 149464 [details] [diff] [review] patch 6 sorry for the delay, I was out of town. thanks for doing the research on this one... sr=alecf
Attachment #149464 -
Flags: superreview?(alecf) → superreview+
Comment 50•20 years ago
|
||
As I lack CVS write access, I would greatly appreciate if someone would check this in for me. Regards, Brodie. Note that this fixes this bug as well as bug 211894.
Reporter | ||
Comment 51•20 years ago
|
||
Fix checked in.
Status: ASSIGNED → RESOLVED
Closed: 20 years ago
Resolution: --- → FIXED
Comment 52•19 years ago
|
||
Comment on attachment 149464 [details] [diff] [review] patch 6 since this fixes bug 211894, this would be good to have on the 1.7 branch
Attachment #149464 -
Flags: approval1.7.6?
Comment 54•19 years ago
|
||
Thanks for bringing this to our attention, blocking 1.7.6/aviary1.0.1 per drivers.
Flags: blocking1.7.6?
Flags: blocking1.7.6+
Flags: blocking-aviary1.0.1+
Comment 56•19 years ago
|
||
Comment on attachment 149464 [details] [diff] [review] patch 6 retroactive a=caillon for 1.0.1. We will also need this for 1.7.6 so a=caillon for that as well.
Attachment #149464 -
Flags: approval1.7.6?
Attachment #149464 -
Flags: approval1.7.6+
Attachment #149464 -
Flags: approval-aviary1.0.1+
Comment 57•19 years ago
|
||
retroactively marked, perhaps, but drivers consensus was reached prior to checkin. Now checked in to 1.7 branch as well.
Keywords: fixed1.7.6
Updated•8 years ago
|
Product: Core → Core Graveyard
You need to log in
before you can comment on or make changes to this bug.
Description
•