зеркало из https://github.com/mozilla/gecko-dev.git
Bug 156422 Win32's nsILocalFile.reveal() doesn't select file p=dean_tessman r=law (tweaked by brofield@jellycan.com r=me) sr=alecf
This commit is contained in:
Родитель
f7bc60ff82
Коммит
f3b448e4ef
|
@ -22,6 +22,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Doug Turner <dougt@netscape.com>
|
||||
* Dean Tessman <dean_tessman@hotmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
|
@ -68,6 +69,7 @@
|
|||
#include "nsITimelineService.h"
|
||||
|
||||
#include "nsAutoLock.h"
|
||||
#include "SpecialSystemDirectory.h"
|
||||
|
||||
// _mbsstr isn't declared in w32api headers but it's there in the libs
|
||||
#ifdef __MINGW32__
|
||||
|
@ -2167,178 +2169,36 @@ nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor)
|
|||
NS_IMETHODIMP
|
||||
nsLocalFile::Reveal()
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
PRBool isDirectory = PR_FALSE;
|
||||
nsCAutoString path;
|
||||
nsAutoString unicodePath;
|
||||
// make sure mResolvedPath is set
|
||||
nsresult rv = ResolveAndStat(PR_TRUE);
|
||||
if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND)
|
||||
return rv;
|
||||
|
||||
IsDirectory(&isDirectory);
|
||||
if (isDirectory)
|
||||
{
|
||||
GetNativePath(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIFile> parent;
|
||||
GetParent(getter_AddRefs(parent));
|
||||
if (parent)
|
||||
{
|
||||
parent->GetNativePath(path);
|
||||
parent->GetPath(unicodePath);
|
||||
}
|
||||
}
|
||||
// use the full path to explorer for security
|
||||
nsCOMPtr<nsILocalFile> winDir;
|
||||
rv = GetSpecialSystemDirectory(Win_WindowsDirectory, getter_AddRefs(winDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCAutoString explorerPath;
|
||||
rv = winDir->GetNativePath(explorerPath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
explorerPath.Append("\\explorer.exe");
|
||||
|
||||
// Remember the current fg window.
|
||||
HWND origWin, fgWin;
|
||||
origWin = fgWin = ::GetForegroundWindow();
|
||||
// Always open a new window for files because Win2K doesn't appear to select
|
||||
// the file if a window showing that folder was already open. If the resolved
|
||||
// path is a directory then instead of opening the parent and selecting it,
|
||||
// we open the directory itself.
|
||||
nsCAutoString explorerParams;
|
||||
if (mFileInfo64.type != PR_FILE_DIRECTORY) // valid because we ResolveAndStat above
|
||||
explorerParams.Append("/n,/select,");
|
||||
explorerParams.Append('\"');
|
||||
explorerParams.Append(mResolvedPath);
|
||||
explorerParams.Append('\"');
|
||||
|
||||
// use the app registry name to launch a shell execute....
|
||||
LONG r = (LONG) ::ShellExecute( NULL, "open", path.get(), NULL, NULL, SW_SHOWNORMAL);
|
||||
if (r < 32)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// If this is a directory, then we don't need to select a file.
|
||||
if (isDirectory)
|
||||
if (::ShellExecute(NULL, "open", explorerPath.get(), explorerParams.get(),
|
||||
NULL, SW_SHOWNORMAL) <= (HINSTANCE) 32)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
// Resources we may need to free when done.
|
||||
IShellFolder *desktopFolder = 0;
|
||||
IMalloc *shellMalloc = 0;
|
||||
IShellFolder *folder = 0;
|
||||
LPITEMIDLIST folder_pidl = 0;
|
||||
LPITEMIDLIST file_pidl = 0;
|
||||
LPITEMIDLIST win95_file_pidl = 0;
|
||||
HMODULE shell32 = 0;
|
||||
|
||||
// We break out of this do/while non-loop at any point where we have to give up.
|
||||
do {
|
||||
// Wait for the window to open. We wait a maximum of 2 seconds.
|
||||
// If we get the wrong window, that will be dealt with below.
|
||||
for (int iter = 10; iter; iter--)
|
||||
{
|
||||
fgWin = ::GetForegroundWindow();
|
||||
if (fgWin != origWin)
|
||||
break; // for loopo
|
||||
::Sleep(200);
|
||||
}
|
||||
// If we failed to locate the new window, give up.
|
||||
if (origWin == fgWin)
|
||||
break; // do/while
|
||||
|
||||
// Now we have the explorer window. We need to send it the "select item"
|
||||
// message (which isn't trivial, so buckly your seat belt)...
|
||||
|
||||
// We need the explorer's process id.
|
||||
DWORD pid = 0;
|
||||
::GetWindowThreadProcessId(fgWin, &pid);
|
||||
|
||||
// Get desktop folder.
|
||||
HRESULT rc = ::SHGetDesktopFolder(&desktopFolder);
|
||||
if (!desktopFolder)
|
||||
break;
|
||||
|
||||
// Get IMalloc interface to use for shell pidls.
|
||||
rc = ::SHGetMalloc(&shellMalloc);
|
||||
if (!shellMalloc)
|
||||
break;
|
||||
|
||||
// Convert folder path to pidl. This requires the Unicode path name.
|
||||
// It returns a pidl that must be freed via shellMalloc->Free.
|
||||
ULONG eaten = 0;
|
||||
rc = desktopFolder->ParseDisplayName( 0,
|
||||
0,
|
||||
(LPOLESTR)unicodePath.get(),
|
||||
&eaten,
|
||||
&folder_pidl,
|
||||
0 );
|
||||
if (!folder_pidl)
|
||||
break;
|
||||
|
||||
// Now get IShellFolder interface for the folder we opened.
|
||||
rc = desktopFolder->BindToObject( folder_pidl,
|
||||
0,
|
||||
IID_IShellFolder,
|
||||
(void**)&folder );
|
||||
if (!folder)
|
||||
break;
|
||||
|
||||
// Now get file name pidl from that folder.
|
||||
nsAutoString unicodeLeaf;
|
||||
if (NS_FAILED(GetLeafName(unicodeLeaf)))
|
||||
break;
|
||||
rc = folder->ParseDisplayName( 0,
|
||||
0,
|
||||
(LPOLESTR)unicodeLeaf.get(),
|
||||
&eaten,
|
||||
&file_pidl,
|
||||
0 );
|
||||
if (!file_pidl)
|
||||
break;
|
||||
|
||||
// We need the module handle for shell32.dll.
|
||||
shell32 = ::GetModuleHandle("shell32.dll");
|
||||
if (!shell32)
|
||||
break;
|
||||
|
||||
// Allocate shared memory copy of pidl. This uses the undocumented "SHAllocShared"
|
||||
// function. Note that it is freed automatically after the ::SendMessage so we
|
||||
// don't have to free it.
|
||||
static HANDLE(WINAPI*SHAllocShared)(LPVOID,ULONG,DWORD) = (HANDLE(WINAPI*)(LPVOID,ULONG,DWORD))::GetProcAddress(shell32, (LPCTSTR)520);
|
||||
HANDLE pidlHandle = 0;
|
||||
if (SHAllocShared)
|
||||
{
|
||||
// We need the size of the pidl, which we get via another undocumented
|
||||
// API: "ILGetSize".
|
||||
UINT (WINAPI*ILGetSize)(LPCITEMIDLIST) = (UINT(WINAPI*)(LPCITEMIDLIST))::GetProcAddress(shell32, (LPCTSTR)152);
|
||||
if (!ILGetSize)
|
||||
break;
|
||||
pidlHandle = SHAllocShared((void*)(ITEMIDLIST*)file_pidl,
|
||||
ILGetSize(file_pidl),
|
||||
pid);
|
||||
if (!pidlHandle)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// On Win95, there is no SHAllocShared. Instead, we clone the file's pidl in
|
||||
// the shell's global heap (via ILGlobalClone) and pass that.
|
||||
LPITEMIDLIST(WINAPI*ILGlobalClone)(LPCITEMIDLIST) = (LPITEMIDLIST(WINAPI*)(LPCITEMIDLIST))::GetProcAddress(shell32, (LPCTSTR)20);
|
||||
if (!ILGlobalClone)
|
||||
break;
|
||||
win95_file_pidl = ILGlobalClone(file_pidl);
|
||||
if (!win95_file_pidl)
|
||||
break;
|
||||
// Arrange so that this pidl is passed on the ::SendMessage.
|
||||
pidlHandle = win95_file_pidl;
|
||||
}
|
||||
|
||||
// Send message to select this file.
|
||||
::SendMessage(fgWin,
|
||||
WM_USER+5,
|
||||
SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE,
|
||||
(LPARAM)pidlHandle );
|
||||
} while ( PR_FALSE );
|
||||
|
||||
// Clean up (freeing stuff as needed, in reverse order).
|
||||
if (win95_file_pidl)
|
||||
{
|
||||
// We need to free this using ILGlobalFree, another undocumented API.
|
||||
static void (WINAPI*ILGlobalFree)(LPCITEMIDLIST) = (void(WINAPI*)(LPCITEMIDLIST))::GetProcAddress(shell32,(LPCTSTR)156);
|
||||
if (ILGlobalFree)
|
||||
ILGlobalFree(win95_file_pidl);
|
||||
}
|
||||
if (file_pidl)
|
||||
shellMalloc->Free(file_pidl);
|
||||
if (folder_pidl)
|
||||
shellMalloc->Free(folder_pidl);
|
||||
if (folder)
|
||||
folder->Release();
|
||||
if (shellMalloc)
|
||||
shellMalloc->Release();
|
||||
if (desktopFolder)
|
||||
desktopFolder->Release();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче