Ejemplo de código: Extensiones de shell para controladores de protocolo
En el siguiente código de ejemplo se muestra cómo crear extensiones de Shell para un controlador de protocolo personalizado.
Código de ejemplo
Nota:
ESTE CÓDIGO E INFORMACIÓN SE PROPORCIONA "TAL CUAL" SIN GARANTÍA DE NINGÚN TIPO, YA SEA EXPRESADO O IMPLÍCITO, INCLUYENDO, ENTRE OTROS, LAS GARANTÍAS IMPLÍCITAS DE COMERCIABILIDAD O IDONEIDAD PARA UN PROPÓSITO DETERMINADO.
Copyright (c)Microsoft Corporation. Todos los derechos reservados.
// ********************** IDL structure **********************
#include <pshpack1.h>
typedef struct
{
WORD cbSize;
WORD cchUrl; // Store the length of the URL.
WCHAR pwszUrl[1]; // Store the URL.
} URLIDL;
#include <poppack.h>
class ATL_NO_VTABLE CSampleShellFolder :
public CComTearOffObjectBase<CSampleSearchProtocol>,
public IPersistFolder,
public IShellFolder
{
public:
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CSampleShellFolder)
COM_INTERFACE_ENTRY(IPersistFolder)
COM_INTERFACE_ENTRY(IShellFolder)
END_COM_MAP()
CSampleShellFolder();
virtual ~CSampleShellFolder();
HRESULT FinalConstruct() {return S_OK;};
void FinalRelease() {};
// IPersist
STDMETHOD(GetClassID)(CLSID* pCLSID);
// IPersistFolder
STDMETHOD(Initialize)(const ITEMIDLIST* pidl);
// IShellFolder
STDMETHOD(ParseDisplayName)
(HWND hwnd, IBindCtx* pbc, OLECHAR* pszName,
ULONG* pchEaten, ITEMIDLIST** ppidl, ULONG* pdwAttributes);
STDMETHOD(EnumObjects)
(HWND hwnd, DWORD grfFlags, IEnumIDList** ppenmIDList);
STDMETHOD(BindToObject)
(const ITEMIDLIST* pidl, IBindCtx* pbc, REFIID riid, void** ppvObj);
STDMETHOD(BindToStorage)
(const ITEMIDLIST* pidl, IBindCtx* pbc, REFIID riid, void** ppvObj);
STDMETHOD(CompareIDs)
(LPARAM lParam, const ITEMIDLIST* pidl1, const ITEMIDLIST* pidl2);
STDMETHOD(CreateViewObject)
(HWND hwndOwner, REFIID riid, void** ppvObj) ;
STDMETHOD(GetAttributesOf)
(UINT cidl, const ITEMIDLIST** ppidl, SFGAOF* prgfInOut);
STDMETHOD(GetUIObjectOf)
(HWND hwndOwner, UINT cidl, const ITEMIDLIST** ppidl,
REFIID riid, UINT* prgfInOut, void** ppvObj);
STDMETHOD(GetDisplayNameOf)
(const ITEMIDLIST* pidl, DWORD dwFlags, STRRET* pstrName);
STDMETHOD(SetNameOf)
(HWND hwnd, const ITEMIDLIST* pidl, const OLECHAR* pszName,
DWORD dwFlags, ITEMIDLIST** ppidlOut);
// IDL Helper Routines
private:
static HRESULT CreateIDL(CString & strUrl, ITEMIDLIST** ppidl);
static SampleIDL *IsURLIDL(const ITEMIDLIST* pidl);
static HRESULT GetUrlFromIDL (const ITEMIDLIST *pidl, CString & strUrl);
};
// ******************* IDL Helper routines *******************
//------------------------------------------------------------
// GetUrlFromIDL()
//
// Return the URL for the specified PIDL.
//------------------------------------------------------------
HRESULT CSampleShellFolder::GetUrlFromIDL(
const ITEMIDL * pidl,
CString &strUrl)
{
if (IsURLIDL(pidl) == NULL)
return E_FAIL;
URLIDL *pURLIDL=(URLIDL *)pidl;
strUrl.SetString(pURLIDL->pwszUrl,pURLIDL->cchUrl);
return S_OK;
}
//------------------------------------------------------------
// CreateIDL()
//
// Create a PIDL for the specified URL.
//------------------------------------------------------------
HRESULT CSampleShellFolder::CreateIDL(
CString &strUrl,
ITEMIDL** ppidl)
{
HRESULT hr = S_OK;
// Check assertions.
_ASSERTE(ppidl);
// Initialize the return value.
*ppidl = NULL;
// Get the size of the URL
WORD cb;
WORD cbUrl = strUrl.GetLength() * sizeof(WCHAR);
cb = (WORD)sizeof(URLIDL) + cbUrl;
// Allocate an additional WORD, which is the "next"
// PIDL (one of cb==0).
URLIDL* pURLIDL = (URLIDL*)LocalAlloc(LPTR, cb + sizeof(WORD));
hr = (pURLIDL ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
pURLIDL->cbSize = cb;
// Store the number of characters in the URL.
pURLIDL->cchUrl = (WORD)strUrl.GetLength();
// NOTE: CopyChars copies the exact number of characters
// *including* the terminating null character.
CString::CopyChars(
pURLIDL->pwszUrl,
(LPCTSTR)strUrl,
strUrl.GetLength() + 1);
// Terminate the IDL.
ITEMIDL *pidlNext = (ITEMIDL *)
(((LPBYTE)pURLIDL) + pURLIDL->cbSize);
*((WORD *)pidlNext) = 0;
// Return a clone of the IDL.
*ppidl = ILClone((ITEMIDL*)pURLIDL);
hr = (*ppidl ? S_OK : E_OUTOFMEMORY);
// Free the IDL.
LocalFree((HLOCAL)pURLIDL);
}
return hr;
}
//------------------------------------------------------------
// IsURLIDL()
//
// Check the validity of a PIDL, returning a pointer to the
// URLIDL portion of the PIDL.
//------------------------------------------------------------
URLIDL *CSampleShellFolder::IsURLIDL(const ITEMIDL* pidl)
{
URLIDL * pURLIDL = NULL;
CString strSample = L"sample:";
// Check for the presence and length of a PIDL.
// If the PIDL is present and of sufficient length,
// compare it to the start URL.
if (pidl &&
(ILGetSize(pidl) > strSample.GetLength()*sizeof(WCHAR)) )
{
pURLIDL = (URLIDL *)pidl;
CString strUrl;
strUrl.SetString(pURLIDL->pwszUrl, 7);
if (strUrl.CompareNoCase(strSample) == 0)
{
return pURLIDL;
}
}
return NULL;
}
// ************************ IPersist *************************
//------------------------------------------------------------
// IPersist::GetClassID
//
// Retrieve the class identifier (CLSID) of an object. The
// CLSID is a unique value that identifies the code that can
// manipulate the persistent data.
//------------------------------------------------------------
STDMETHODIMP CSampleShellFolder::GetClassID(CLSID* pCLSID)
{
if (pCLSID == NULL)
return E_POINTER;
*pCLSID = CLSID_SampleProtocol;
return S_OK;
}
// ********************* IPersistFolder **********************
//------------------------------------------------------------
// IPersistFolder::Initialize
//
// Instruct a ShellFolder object to initialize itself based
// on the information provided.
//------------------------------------------------------------
STDMETHODIMP CSampleShellFolder::Initialize(const ITEMIDL* pidl)
{
// Since we have only one folder in this sample, there
// is nothing to store.
return S_OK;
}
// ******************** IShellFolder *************************
//------------------------------------------------------------
// IShellFolder::ParseDisplayName
//
// Translate a file object's display name or a folder's
// display name into an item identifier list.
//------------------------------------------------------------
STDMETHODIMP CSampleShellFolder::ParseDisplayName(
HWND hwnd, IBindCtx* pbc,
OLECHAR* pszName,
ULONG* pchEaten,
ITEMIDL** ppidl,
ULONG* pdwAttributes)
{
HRESULT hr = E_FAIL;
if ((pszName == NULL) || (ppidl == NULL))
return E_POINTER;
*ppidl = NULL;
CString strName = L"";
// Get the first seven bytes of the name.
strName.SetString(pszName, 7);
// Determine whether the name starts with "outlook",
// the first seven characters of outlookexpress.
if (strName.CompareNoCase(L"sample:") == 0)
{
// If TRUE, we can assume this is an outlookexpress URL.
CString strUrl = pszName;
// Create the PIDL.
hr = CSampleShellFolder::CreateURLIDL(strUrl, ppidl);
if (SUCCEEDED(hr))
{
if (pchEaten != NULL)
*pchEaten = strUrl.GetLength();
if (pdwAttributes != NULL)
*pdwAttributes = 0;
}
}
return hr;
}
//------------------------------------------------------------
// IShellFolder::EnumObjects
//
// Enable a client to determine the contents of a folder by
// creating an item identifier enumeration object and returning
// its IEnumIDL interface. The methods supported by that
// interface can then be used to enumerate the folder's contents.
//------------------------------------------------------------
STDMETHODIMP CSampleShellFolder::EnumObjects(
HWND hwnd,
DWORD grfFlags,
IEnumIDL** ppenmIDL)
{
return E_NOTIMPL;
}
//------------------------------------------------------------
// IShellFolder::BindToObject
//
// Retrieve an IShellFolder object for a subfolder.
//------------------------------------------------------------
STDMETHODIMP CSampleShellFolder::BindToObject(
const ITEMIDL* pidl,
IBindCtx* pbc,
REFIID riid, void** ppvObj)
{
return E_NOTIMPL;
}
//------------------------------------------------------------
// IShellFolder::BindToStorage
//
// Request a pointer to an object's storage interface.
//------------------------------------------------------------
STDMETHODIMP CSampleShellFolder::BindToStorage(
const ITEMIDL* pidl,
IBindCtx* pbc,
REFIID riid, void** ppvObj)
{
// NOTE: Although this code is not implemented in the sample,
// it is possible to bind to IUrlAccessor->BindToStream()
// to bind to the storage.
return E_NOTIMPL;
}
//------------------------------------------------------------
// IShellFolder::CompareIDs
//
// Determine the relative order of two file objects or folders,
// given their item identifier lists.
//------------------------------------------------------------
STDMETHODIMP CSampleShellFolder::CompareIDs(
LPARAM lParam,
const ITEMIDL* pidl1,
const ITEMIDL* pidl2)
{
if ((pidl1 == NULL) || (pidl2 == NULL))
return E_POINTER;
// Ensure that these are our PIDLs
URLIDL * pURLIDL1 = IsURLIDL(pidl1);
URLIDL * pURLIDL2 = IsURLIDL(pidl2);
if (!pURLIDL1 || !pURLIDL2)
{
return S_FALSE;
}
// Check the query for equality
CString strUrl1;
CString strUrl2;
strUrl1.SetString(pURLIDL1->pwszUrl, pURLIDL1->cchUrl);
strUrl2.SetString(pURLIDL2->pwszUrl, pURLIDL2->cchUrl);
return (strUrl1.CompareNoCase(strUrl2));
}
//------------------------------------------------------------
// IShellFolder::CreateViewObject
//
// Request an object that can be used to obtain information
// from or interact with a folder object.
//------------------------------------------------------------
STDMETHODIMP CSampleShellFolder::CreateViewObject(
HWND hwndOwner,
REFIID riid,
void** ppvObj)
{
return E_NOTIMPL;
}
//------------------------------------------------------------
// IShellFolder::GetAttributesOf
//
// Retrieve the attributes of one or more file objects or
// subfolders.
//------------------------------------------------------------
STDMETHODIMP CSampleShellFolder::GetAttributesOf(
UINT cidl,
const ITEMIDL** ppidl,
SFGAOF* prgfInOut)
{
for ( UINT i = 0; i < cidl; i++)
{
DWORD dwAttrs = 0;
// SFGAO_FOLDER | SFGAO_CANLINK;
dwAttrs |= SFGAO_NONENUMERATED|SFGAO_READONLY;
*prgfInOut &= dwAttrs;
}
return S_OK;
}
//------------------------------------------------------------
// IShellFolder::GetUIObjectOf
//
// Retrieve an OLE interface that can be used to carry out
// actions on the specified file objects or folders.
//------------------------------------------------------------
STDMETHODIMP CSampleShellFolder::GetUIObjectOf(
HWND hwndOwner,
UINT cidl,
const ITEMIDL** ppidl,
REFIID riid,
UINT* prgfInOut,
void** ppvObj)
{
if ((ppidl == NULL) || (ppvObj == NULL))
return E_POINTER;
*ppvObj = NULL;
// Create the appropriate object.
HRESULT hr=S_OK;
// By design, we handle only one object at a time.
if (cidl > 1)
return E_INVALIDARG;
CString strUrl;
hr = GetUrlFromIDL(*ppidl, strUrl);
if (SUCCEEDED(hr))
{
if (riid == __uuidof(IContextMenu))
{
// Return the IContextMenu for this URL
}
else
if (riid == __uuidof(IExtractIcon))
{
// Return the IExtractIcon for this URL
}
else
Hr = E_NOINTERFACE;
}
return hr;
}
//------------------------------------------------------------
// IShellFolder::GetDisplayNameOf
//
// Retrieve the display name for the specified file object
// or subfolder.
//------------------------------------------------------------
STDMETHODIMP CSampleShellFolder::GetDisplayNameOf(
const ITEMIDL* pidl,
DWORD dwFlags,
STRRET* pstrName)
{
HRESULT hr = S_OK;
URLIDL * pURLIDL = IsURLIDL(pidl);
if (pURLIDL)
{
pstrName->uType = STRRET_OFFSET;
pstrName->uOffset = sizeof(WORD) + sizeof(WORD);
}
return hr;
}
//------------------------------------------------------------
// IShellFolder::SetNameOf
//
// Set the display name of a file object or subfolder,
// changing the item identifier in the process.
//------------------------------------------------------------
STDMETHODIMP CSampleShellFolder::SetNameOf(
HWND hwnd,
const ITEMIDL* pidl,
const OLECHAR* pszName,
DWORD dwFlags,
ITEMIDL** ppidlOut)
{
return E_NOTIMPL;
}
Recursos adicionales
- Para obtener ejemplos de código de búsqueda, vea Ejemplos de código de Windows Search.
- Para obtener ejemplos de código de Shell, vea Ejemplos del SDK de Shell.
Temas relacionados