Bug 106082; Adds code to select item in Explorer window for Reveal(); r=sgehani, sr=hyatt

This commit is contained in:
law%netscape.com 2002-02-20 05:41:34 +00:00
Родитель 982f319308
Коммит 66bd14ab37
1 изменённых файлов: 151 добавлений и 4 удалений

Просмотреть файл

@ -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;
} }