Compartir a través de


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

Conceptual

Desarrollo de controladores de protocolo

Descripción de los controladores de protocolo

Notificación del índice de cambios

Adición de iconos y menús contextuales

Instalación y registro de los controladores de protocolo

Creación de un conector de Search para un controlador de protocolo

Depuración de controladores de protocolo