Finestre delle proprietà e pagine delle proprietà

Le proprietà di un oggetto vengono esposte ai client allo stesso modo dei metodi tramite interfacce COM o l'implementazione IDispatch dell'oggetto, consentendo la modifica delle proprietà tramite programmi che chiamano questi metodi. La tecnologia OLE delle pagine delle proprietà consente di creare un'interfaccia utente per le proprietà di un oggetto in base agli standard dell'interfaccia utente di Windows. Di conseguenza, le proprietà vengono esposte agli utenti finali. La finestra delle proprietà di un oggetto è una finestra di dialogo a schede in cui ogni scheda corrisponde a una pagina delle proprietà specifica. Il modello OLE per l'utilizzo delle pagine delle proprietà è costituito da queste funzionalità:

  • Ogni pagina delle proprietà viene gestita da un oggetto in-process che implementa IPropertyPage o IPropertyPage2. Ogni pagina viene identificata con un CLSID univoco.
  • Un oggetto specifica il supporto per le pagine delle proprietà implementando ISpecifyPropertyPages. Tramite questa interfaccia il chiamante può ottenere un elenco di CLSID che identificano le pagine delle proprietà specifiche supportate dall'oggetto. Se l'oggetto specifica un CLSID della pagina delle proprietà, l'oggetto deve essere in grado di ricevere modifiche alle proprietà dalla pagina delle proprietà.
  • Qualsiasi parte di codice (client o oggetto) che desidera visualizzare la finestra delle proprietà di un oggetto passa il puntatore IUnknown dell'oggetto (o una matrice se devono essere interessati più oggetti) insieme a una matrice di CLSID di pagina a OleCreatePropertyFrame o OleCreatePropertyFrameIndirect, che crea la finestra di dialogo a schede.
  • La finestra di dialogo della cornice delle proprietà crea un'istanza singola di ogni pagina delle proprietà, usando CoCreateInstance in ogni CLSID. Il frame della proprietà ottiene almeno un puntatore IPropertyPage per ogni pagina. Inoltre, il frame crea un oggetto sito della pagina delle proprietà in se stesso per ogni pagina. Ogni sito implementa IPropertyPageSite e questo puntatore viene passato a ogni pagina. La pagina comunica quindi con il sito tramite questo puntatore all'interfaccia.
  • Ogni pagina viene inoltre resa consapevole dell'oggetto o degli oggetti per cui è stato richiamato; ovvero, la cornice delle proprietà passa i puntatori IUnknowndegli oggetti a ogni pagina. Quando viene richiesto di applicare modifiche agli oggetti, ogni pagina esegue una query per il puntatore di interfaccia appropriato e passa nuovi valori di proprietà agli oggetti in qualsiasi modo. Non vi sono accordi su come tale comunicazione debba avvenire.
  • Un oggetto può anche supportare l'esplorazione per proprietà tramite l'interfaccia IPerPropertyBrowsing che consente all'oggetto di specificare quale proprietà deve ricevere lo stato attivo iniziale quando viene visualizzata la pagina delle proprietà e specificare stringhe e valori che possono essere visualizzati dal client nella propria interfaccia utente.

Queste funzionalità sono illustrate nel diagramma seguente:

Diagram that shows the property sheets and property pages features.

Queste interfacce sono definite come segue:

interface ISpecifyPropertyPages : IUnknown 
  { 
    HRESULT GetPages([out] CAUUID *pPages); 
  }; 
 
 
interface IPropertyPage : IUnknown 
  { 
    HRESULT SetPageSite([in] IPropertyPageSite *pPageSite); 
    HRESULT Activate([in] HWND hWndParent, [in] LPCRECT prc 
        , [in] BOOL bModal); 
    HRESULT Deactivate(void); 
    HRESULT GetPageInfo([out] PROPPAGEINFO *pPageInfo); 
    HRESULT SetObjects([in] ULONG cObjects 
        , [in, max_is(cObjects)] IUnknown **ppunk); 
    HRESULT Show([in] UINT nCmdShow); 
    HRESULT Move([in] LPCRECT prc); 
    HRESULT IsPageDirty(void); 
    HRESULT Apply(void); 
    HRESULT Help([in] LPCOLESTR pszHelpDir); 
    HRESULT TranslateAccelerator([in] LPMSG pMsg); 
  } 
 
interface IPropertyPageSite : IUnknown 
  { 
    HRESULT OnStatusChange([in] DWORD dwFlags); 
    HRESULT GetLocaleID([out] LCID *pLocaleID); 
    HRESULT GetPageContainer([out] IUnknown **ppUnk); 
    HRESULT TranslateAccelerator([in] LPMSG pMsg); 
  } 
 

Il metodo ISpecifyPropertyPages::GetPages restituisce una matrice conteggiata di valori UUID (GUID) ognuno dei quali descrive il CLSID di una pagina delle proprietà che l'oggetto desidera visualizzare. Chiunque richiami la finestra delle proprietà con OleCreatePropertyFrame o OleCreatePropertyFrameIndirect passa questa matrice alla funzione. Si noti che se il chiamante desidera visualizzare le pagine delle proprietà per più oggetti, deve passare solo l'intersezione degli elenchi CLSID di tutti gli oggetti a queste funzioni. In altre parole, il chiamante deve richiamare solo le pagine delle proprietà comuni a tutti gli oggetti.

Inoltre, il chiamante passa anche i puntatori IUnknown agli oggetti interessati alle funzioni API. Entrambe le funzioni API creano una finestra di dialogo con frame di proprietà e creano un'istanza di un sito di pagina con IPropertyPageSite per ogni pagina che verrà caricata. Tramite questa interfaccia una pagina delle proprietà può:

  • Recuperare la lingua corrente utilizzata nella finestra delle proprietà tramite GetLocaleID.
  • Chiedere al fotogramma di elaborare le sequenze di tasti tramite TranslateAccelerator.
  • Notificare al frame le modifiche nella pagina tramite OnStatusChange.
  • Ottenere un puntatore di interfaccia per il frame stesso tramite GetPageContainer, anche se al momento non sono definite interfacce per il frame per questa funzione restituisce sempre E_NOTIMPL.

La cornice delle proprietà crea un'istanza di ogni oggetto pagina delle proprietà e ottiene l'interfaccia IPropertyPage di ogni pagina. Tramite questa interfaccia il frame informa la pagina del relativo sito di pagina (SetPageSite), recupera le dimensioni e le stringhe della pagina (GetPageInfo), passa i puntatori di interfaccia agli oggetti interessati (SetObjects), indica alla pagina quando creare ed eliminare i relativi controlli (Attiva e Disattiva), indica alla pagina di mostrare o riposizionare se stesso (Mostra e sposta)), indica alla pagina di applicare i valori correnti agli oggetti interessati (Applica), i controlli sullo stato dirty della pagina (IsPageDirty), richiama la Guida (Guida) e passa le sequenze di tasti alla pagina (TranslateAccelerator).

Un oggetto può anche supportare l'esplorazione per proprietà, che fornisce:

  1. Un modo (tramite IPerPropertyBrowsing e IPropertyPage2) per specificare quale proprietà nella pagina delle proprietà deve essere data lo stato attivo iniziale quando viene visualizzata per la prima volta una finestra delle proprietà
  2. Un modo (tramite IPerPropertyBrowsing) per l'oggetto di specificare valori predefiniti e stringhe descrittive corrispondenti che possono essere visualizzate nella propria interfaccia utente di un client per le proprietà.

Un oggetto può scegliere di supportare (2) senza supportare (1), ad esempio quando l'oggetto non dispone di una finestra delle proprietà.

Le interfacce IPropertyPage2 e IPerPropertyBrowsing sono definite come segue:

interface IPerPropertyBrowsing : IUnknown 
  { 
    HRESULT GetDisplayString([in] DISPID dispID, [out] BSTR *pbstr); 
    HRESULT MapPropertyToPage([in] DISPID dispID, [out] CLSID *pclsid); 
    HRESULT GetPredefinedStrings([in] DISPID dispID, [out] CALPOLESTR *pcaStringsOut, [out] CADWORD *pcaCookiesOut); 
    HRESULT GetPredefinedValue([in] DISPID dispID, [in] DWORD dwCookie, [out] VARIANT *pvarOut); 
  } 
 
interface IPropertyPage2 : IPropertyPage 
  { 
    HRESULT EditProperty([in] DISPID dispID); 
  } 
 

Per specificare il supporto per tali funzionalità, l'oggetto implementa IPerPropertyBrowsing. Tramite questa interfaccia, il chiamante può richiedere le informazioni necessarie per ottenere l'esplorazione, ad esempio stringhe predefinite (GetPredefinedStrings) e valori (GetPredefinedValue), nonché una stringa di visualizzazione per una determinata proprietà (GetDisplayString).

Inoltre, il client può ottenere il CLSID della pagina delle proprietà che consente all'utente di modificare una determinata proprietà identificata con un DISPID (MapPropertyToPage). Il client indica quindi al frame delle proprietà di attivare inizialmente la pagina passando CLSID e DISPID a OleCreatePropertyFrameIndirect. Il frame attiva prima la pagina e passa il DISPID alla pagina tramite IPropertyPage2::EditProperty. La pagina imposta quindi lo stato attivo sul campo di modifica della proprietà. In questo modo, un client può passare da un nome di proprietà nella propria interfaccia utente alla pagina delle proprietà che può modificare tale proprietà.

Pagine delle proprietà e finestre delle proprietà