зеркало из https://github.com/mozilla/pjs.git
Bug 106082; Adds code to select item in Explorer window for Reveal(); r=sgehani, sr=hyatt
This commit is contained in:
Родитель
982f319308
Коммит
66bd14ab37
|
@ -1932,6 +1932,7 @@ nsLocalFile::Reveal()
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
PRBool isDirectory = PR_FALSE;
|
PRBool isDirectory = PR_FALSE;
|
||||||
nsXPIDLCString path;
|
nsXPIDLCString path;
|
||||||
|
nsXPIDLString unicodePath;
|
||||||
|
|
||||||
IsDirectory(&isDirectory);
|
IsDirectory(&isDirectory);
|
||||||
if (isDirectory)
|
if (isDirectory)
|
||||||
|
@ -1943,15 +1944,161 @@ nsLocalFile::Reveal()
|
||||||
nsCOMPtr<nsIFile> parent;
|
nsCOMPtr<nsIFile> parent;
|
||||||
GetParent(getter_AddRefs(parent));
|
GetParent(getter_AddRefs(parent));
|
||||||
if (parent)
|
if (parent)
|
||||||
|
{
|
||||||
parent->GetPath(getter_Copies(path));
|
parent->GetPath(getter_Copies(path));
|
||||||
|
parent->GetUnicodePath(getter_Copies(unicodePath));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remember the current fg window.
|
||||||
|
HWND origWin, fgWin;
|
||||||
|
origWin = fgWin = ::GetForegroundWindow();
|
||||||
|
|
||||||
// use the app registry name to launch a shell execute....
|
// use the app registry name to launch a shell execute....
|
||||||
LONG r = (LONG) ::ShellExecute( NULL, "explore", (const char *) path, NULL, NULL, SW_SHOWNORMAL);
|
LONG r = (LONG) ::ShellExecute( NULL, "open", (const char *) path, NULL, NULL, SW_SHOWNORMAL);
|
||||||
if (r < 32)
|
if (r < 32)
|
||||||
rv = NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
else
|
|
||||||
rv = NS_OK;
|
// If this is a directory, then we don't need to select a file.
|
||||||
|
if (isDirectory)
|
||||||
|
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.
|
||||||
|
nsXPIDLString unicodeLeaf;
|
||||||
|
if (NS_FAILED(GetUnicodeLeafName(getter_Copies(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;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче