HOWTO: Web Browser Navigation Using a PIDLID: Q167834
|
This article illustrates programmatic navigation via a pointer to an item identifier list (PIDL) by providing an example of navigating to the Favorites Folder (CSIDL_FAVORITES).
The Web Browser object model implemented in Shdocvw.dll exposes two
component classes that provide browsing services: WebBrowser and
InternetExplorer. While the former represents the WebBrowser ActiveX
Control, the latter represents the stand-alone browser.
In Internet Explorer (IE) 3.x, both classes implemented the IWebBrowser
interface. Using the Navigate method of this interface, clients could
easily navigate to a specified URL (for example, http://www.microsoft.com).
Version 4.0 extends these classes to implement the IWebBrowser2 interface, which
introduces the Navigate2 method. Navigate2 provides the same capabilities
as Navigate, but it also can be used to navigate to a folder by specifying
a pointer to an item identifier list (PIDL). PIDLs were introduced with
Windows 95 and provide a way to uniquely identify an item within the
shell's namespace. PIDLs are also supported on NT 4.0. For more information
on PIDLs and the shell namespace, see the reference to the Internet Client
SDK below.
The following code demonstrates how to obtain a PIDL from the shell, how to
create an instance of the browser and obtain the IWebBrowser2 interface,
and how to call the Navigate2 method. Observe that the Web browser expects
the first parameter in the call to Navigate2 to be a SAFEARRAY of bytes.
The following code provides a generic routine, InitVARIANTFromPidl, that
packs a PIDL into a VARIANT, which holds such an array.
Note that because it is not currently possible to represent a PIDL in
Visual Basic it is not possible to call the Navigate2 method from a Visual
Basic application:
#include <windows.h>
#define INITGUID
#include <initguid.h>
#include <exdisp.h>
#include <shlguid.h>
#include <memory.h>
#include <shlobj.h>
// macros for walking PIDLs
#define _ILSkip(pidl, cb) ((LPITEMIDLIST)(((BYTE*)(pidl))+cb))
#define _ILNext(pidl) _ILSkip(pidl, (pidl)->mkid.cb)
HRESULT FreeResources(LPVOID pData);
HRESULT TestPidl(LPITEMIDLIST pidl);
LPITEMIDLIST PidlFromVARIANT(VARIANT* pvarLoc);
LPSAFEARRAY MakeSafeArrayFromData(LPBYTE pData,DWORD cbData);
HRESULT InitVARIANTFromPidl(LPVARIANT pVar, LPITEMIDLIST pidl);
UINT ILGetSize(LPITEMIDLIST pidl);
void main()
{
HRESULT hr;
LPMALLOC pMalloc = NULL;
LPITEMIDLIST pidl, pidl2 = NULL;
IWebBrowser2* pWebBrowser = NULL;
VARIANT vPIDL = {0}, vDummy = {0};
if (FAILED(CoInitialize(NULL)))
{
return;
}
// Get the pidl for your favorite special folder,
// in this case literally, the Favorites folder
if (FAILED(hr = SHGetSpecialFolderLocation(NULL,
CSIDL_FAVORITES, &pidl)))
{
goto Error;
}
// Pack the pidl into a VARIANT
if (FAILED(hr = InitVARIANTFromPidl(&vPIDL, pidl)))
{
goto Error;
}
// Verify for testing purposes only that the pidl was packed
// properly. Don't clean up pidl2 because it's a copy of the
// pointer, not a clone of the id list itself
pidl2 = PidlFromVARIANT(&vPIDL);
if (FAILED(hr = TestPidl(pidl2)))
{
OutputDebugString("PIDL test failed");
goto Error;
}
// Instantiate a browser
if (FAILED(hr = CoCreateInstance(CLSID_InternetExplorer,
NULL, CLSCTX_SERVER, IID_IWebBrowser2,
(LPVOID*)&pWebBrowser)))
{
goto Error;
}
// Show the browser, and navigate to the special location
// represented by the pidl
hr = pWebBrowser->put_Visible(VARIANT_TRUE);
hr = pWebBrowser->Navigate2(&vPIDL, &vDummy, &vDummy,
&vDummy, &vDummy);
Error:
// Clean up
VariantClear(&vPIDL);
if (pWebBrowser)
{
pWebBrowser->Release();
}
if (pidl)
{
FreeResources((LPVOID)pidl);
}
CoUninitialize();
}
// Exercise the PIDL by performing common operations upon it.
//
HRESULT TestPidl(LPITEMIDLIST pidl)
{
HRESULT hr;
LPSHELLFOLDER pshfDesktop = NULL, pshf = NULL;
DWORD uFlags = SHGDN_NORMAL;
STRRET strret;
if (!pidl)
{
return E_INVALIDARG;
}
hr = SHGetDesktopFolder(&pshfDesktop);
if (!pshfDesktop)
{
return hr;
}
hr = pshfDesktop->BindToObject(pidl,
NULL,
IID_IShellFolder,
(LPVOID*)&pshf);
if (!pshf)
{
goto Error;
}
hr = pshfDesktop->GetDisplayNameOf(pidl, uFlags, &strret);
if (STRRET_WSTR == strret.uType)
{
FreeResources((LPVOID)strret.pOleStr);
}
Error:
if (pshf) pshf->Release();
if (pshf) pshfDesktop->Release();
return hr;
}
// Use the shell's IMalloc implementation to free resources
HRESULT FreeResources(LPVOID pData)
{
HRESULT hr;
LPMALLOC pMalloc = NULL;
if (SUCCEEDED(hr = SHGetMalloc(&pMalloc)))
{
pMalloc->Free((LPVOID)pData);
pMalloc->Release();
}
return hr;
}
// Given a VARIANT, pull out the PIDL using brute force
LPITEMIDLIST PidlFromVARIANT(LPVARIANT pvarLoc)
{
if (pvarLoc)
{
if (V_VT(pvarLoc) == (VT_ARRAY|VT_UI1))
{
LPITEMIDLIST pidl = (LPITEMIDLIST)pvarLoc->parray->pvData;
return pidl;
}
}
return NULL;
}
// Pack a PIDL into a VARIANT
HRESULT InitVARIANTFromPidl(LPVARIANT pvar, LPITEMIDLIST pidl)
{
if (!pidl || !pvar)
{
return E_POINTER;
}
// Get the size of the pidl and allocate a SAFEARRAY of
// equivalent size
UINT cb = ILGetSize(pidl);
LPSAFEARRAY psa = MakeSafeArrayFromData((LPBYTE)pidl, cb);
if (!psa)
{
VariantInit(pvar);
return E_OUTOFMEMORY;
}
V_VT(pvar) = VT_ARRAY|VT_UI1;
V_ARRAY(pvar) = psa;
return NOERROR;
}
// Allocate a SAFEARRAY of cbData size and pack pData into it
LPSAFEARRAY MakeSafeArrayFromData(LPBYTE pData, DWORD cbData)
{
LPSAFEARRAY psa;
if (!pData || 0 == cbData)
{
return NULL; // nothing to do
}
// create a one-dimensional safe array of BYTEs
psa = SafeArrayCreateVector(VT_UI1, 0, cbData);
if (psa)
{
// copy data into the area in safe array reserved for data
// Note we party directly on the pointer instead of using locking/
// unlocking functions. Since we just created this and no one
// else could possibly know about it or be using it, this is okay.
memcpy(psa->pvData,pData,cbData);
}
return psa;
}
// Get the size of the PIDL by walking the item id list
UINT ILGetSize(LPITEMIDLIST pidl)
{
UINT cbTotal = 0;
if (pidl)
{
cbTotal += sizeof(pidl->mkid.cb); // Null terminator
while (pidl->mkid.cb)
{
cbTotal += pidl->mkid.cb;
pidl = _ILNext(pidl);
}
}
return cbTotal;
}
Internet Client SDK Documentation: Application and Internet Services, Windows Shell API, Shell's Namespace.
Additional query words:
Keywords : kbcode kbIE400 kbIE401 kbIE500
Version : 4.0
Platform : WINDOWS
Issue type : kbhowto
Last Reviewed: April 29, 1999