共用方式為


實作屬性頁 COM 物件

屬性表延伸模組是實作為內部伺服器之 COM 物件。 屬性表延伸模組必須實 作 IShellExtInitIShellPropSheetExt 介面。 當使用者為類別的類別對象顯示屬性表時,屬性表延伸模組已在 類別的顯示規範中註冊時,就會具現化屬性表延伸模組。

實作 IShellExtInit

在屬性表擴充 COM 物件具現化之後, 會呼叫 IShellExtInit::Initialize 方法。 IShellExtInit::Initialize 會以 IDataObject 物件提供屬性表延伸模組,其中包含屬性表所套用之目錄對象的相關數據。

IDataObject 包含CFSTR_DSOBJECTNAMES格式的數據 CFSTR_DSOBJECTNAMES資料格式是包含 DSOBJECTNAMES 結構的 HGLOBAL。 DSOBJECTNAMES 結構包含套用屬性表延伸模組的目錄對象資料。

IDataObject 也包含CFSTR_DS_DISPLAY_SPEC_OPTIONS格式的數據。 CFSTR_DS_DISPLAY_SPEC_OPTIONS資料格式是包含 DSDISPLAYSPECOPTIONS 結構的 HGLOBAL DSDISPLAYSPECOPTIONS 包含供延伸模組使用的組態數據。

如果從 IShellExtInit::Initialize回S_OK以外的任何值,則不會顯示屬性表。

不會使用 IShellExtInit::Initialize 方法的 pidlFolderhkeyProgID 參數。

藉由遞增 IDataObject 的參考計數,延伸模組可以儲存 IDataObject 指標。 當不再需要時,必須釋放此介面。

實作 IShellPropSheetExt

在 IShellExtInit::Initialize 傳回之後會呼叫 IShellPropSheetExt::AddPages 方法。 屬性表延伸模組必須在此方法期間新增頁面或頁面。 屬性頁的建立方式是填入 PROPSHEETPAGE 結構,然後將這個結構傳遞至 CreatePropertySheetPage 函式。 然後,在 lpfnAddPage 參數中呼叫傳遞至 IShellPropSheetExt::AddPages回呼函式,以將屬性頁新增至屬性表。

如果從 IShellPropSheetExt::AddPages 傳回S_OK以外的任何值,則不會顯示屬性表。

如果屬性表延伸模組不需要將任何頁面新增至屬性表,則不應該在 lpfnAddPage 參數中呼叫傳遞至 IShellPropSheetExt::AddPages回調函式。

不會使用 IShellPropSheetExt::ReplacePage 方法。

將 Extension 對象傳遞至屬性頁

屬性表擴充對象與屬性頁無關。 在許多情況下,最好能夠從屬性頁使用擴充物件或其他物件。 若要這樣做,請將 PROPSHEETPAGE 結構的 lParam 成員設定為對象指標。 屬性頁接著可以在處理 WM_INITDIALOG訊息時擷取 此值。 對於屬性頁,WM_INITDIALOG訊息的 lParam 參數是 PROPSHEETPAGE 結構的指標。 將WM_INITDIALOG訊息的 lParam 轉換成 PROPSHEETPAGE 指標,然後擷取 PROPSHEETPAGE 結構的 lParam 成員,以擷取物件指標。

下列 C++ 程式代碼範例示範如何將對象傳遞至屬性頁。

case WM_INITDIALOG:
    {
        LPPROPSHEETPAGE pPage = (LPPROPSHEETPAGE)lParam;

        if(NULL != pPage)
        {
            CPropSheetExt *pPropSheetExt;
            pPropSheetExt = (CPropSheetExt*)pPage->lParam;

            if(pPropSheetExt)
            {
                return pPropSheetExt>OnInitDialog(wParam, lParam);
            }
        }
    }
    break;

請注意,呼叫 IShellPropSheetExt::AddPages 之後,屬性表會釋放屬性表延伸物件,而且永遠不會再使用它。 這表示在顯示屬性頁之前,將會刪除延伸模組物件。 當頁面嘗試存取物件指標時,記憶體將會釋出,而且指標無效。 若要修正此問題,請在新增頁面時遞增擴充對象的參考計數,然後在屬性頁對話框終結時釋放物件。 這會建立另一個問題,因為直到第一次顯示頁面之前,才會建立屬性頁對話方塊。 如果用戶從未選取擴充功能頁面,則頁面永遠不會建立並終結。 這會導致擴充對象永遠不會釋放,因此會發生記憶體流失。 若要避免這種情況,請實作屬性頁回呼函式。 若要這樣做,請將PSP_USECALLBACK旗標新增至 PROPSHEETPAGE 結構的 dwFlags 成員,並將 PROPSHEETPAGE 結構的 pfnCallback 成員設定為實作 PropSheetPageProc 函式的位址。 當 PropSheetPageProc 函式收到PSPCB_RELEASE通知時,PropSheetPageProcppsp 參數會包含 PROPSHEETPAGE 結構的指標PROPSHEETPAGE 結構的 lParam 成員包含可用來釋放對象的擴充指標。

下列 C++ 程式代碼範例示範如何釋放延伸模組物件。

UINT CALLBACK CPropSheetExt::PageCallbackProc(  HWND hWnd,
                                                UINT uMsg,
                                                LPPROPSHEETPAGE ppsp)
{
    switch(uMsg)
    {
    case PSPCB_CREATE:
        // Must return TRUE to enable the page to be created.
        return TRUE;

    case PSPCB_RELEASE:
        {
            /*
            Release the object. This is called even if the page dialog box was 
            never actually created.
            */
            CPropSheetExt *pPropSheetExt = (CPropSheetExt*)ppsp->lParam;

            if(pPropSheetExt)
            {
                pPropSheetExt->Release();
            }
        }
        break;
    }

    return FALSE;
}

使用 Notification 物件

由於屬性表延伸模組頁面會顯示在延伸模組未知元件所建立的屬性表內,因此必須使用「管理員」來處理延伸模組頁面與屬性表之間的數據傳輸。 這個「管理員」稱為通知物件。 通知物件會以個別頁面與屬性表之間的仲裁程序運作。

初始化屬性表擴充物件時,延伸模組必須藉由呼叫 ADsPropCreateNotifyObj 來建立通知對象,傳遞IShellExtInit::Initialize 取得的 IDataObject 和目錄物件名稱。 不需要遞增 IDataObject 介面的參考計數,因為 ADsPropCreateNotifyObj 函式所建立的通知物件會執行此動作。 ADsPropCreateNotifyObj 所提供的通知物件句柄應該儲存以供稍後使用。 ADsPropCreateNotifyObj 可以在 IShellExtInit::InitializeIShellPropSheetExt::AddPages 期間呼叫。 當屬性表延伸模組關閉時,它必須將WM_ADSPROP_NOTIFY_EXIT訊息傳送給通知物件。 這會導致通知物件終結本身。 當 PropSheetPageProc 函式收到PSPCB_RELEASE通知時,最好這麼做。

除了CFSTR_DSOBJECTNAMES剪貼簿格式所提供的數據之外,屬性表延伸模組還可以呼叫 ADsPropGetInitInfo 來取得數據。 使用 ADsPropGetInitInfo 的優點之一,就是它提供用來以程式設計方式處理目錄物件的 IDirectoryObject 物件。

注意

與大多數 COM 方法和函式不同,ADsPropGetInitInfo 不會遞增 IDirectoryObject 對象的參考計數 除非先手動遞增參考計數,否則不得釋放 IDirectoryObject

 

第一次建立屬性頁時,延伸模組應該使用頁面的視窗句柄呼叫 ADsPropSetHwnd ,向通知對象註冊頁面。

ADsPropCheckIfWritable 是公用程式函式,屬性表延伸模組可用來判斷是否可以寫入屬性。

其他

屬性頁的句柄會傳遞至頁面對話框程式。 屬性表是屬性頁的直接父代,因此可以使用屬性頁句柄呼叫 GetParent 函式來取得屬性表的句柄。

當延伸模組頁面的內容變更時,延伸模組應該使用 PropSheet_Changed 宏來通知屬性表的變更。 屬性表接著會啟用 [套用] 按鈕。

多重選取屬性表

使用 Windows Server 2003 和更新版本的作業系統,Active Directory 系統管理 MMC 嵌入式管理單元支援多個目錄對象的屬性表延伸模組。 當一次檢視多個項目的屬性時,會顯示這些屬性表。 單一選取屬性表延伸模組和多重選取屬性表延伸模塊之間的主要差異在於 IShellExtInit::Initialize由CFSTR_DSOBJECTNAMES剪貼簿格式提供的 DSOBJECTNAMES 結構將包含多個 DSOBJECT 結構。

建立通知物件時,多重選取屬性表延伸模組必須傳遞由嵌入式管理單元提供的唯一名稱,而不是延伸模組所建立的名稱。 若要取得唯一的名稱,請從 IShellExtInit::Initialize 取得的 IDataObject 要求CFSTR_DS_MULTISELECTPROPPAGE剪貼簿格式。 此數據是 HGLOBAL,其中包含唯一名稱的 Null 終止 Unicode 字串。 接著,這個唯一名稱會傳遞至 ADsPropCreateNotifyObj 函式,以建立通知物件。 屬性表 COM 物件實作範例程序代碼中的 CreateADsNotificationObject 範例函式會示範如何正確執行這項操作,以及與不支援多重選取屬性表的舊版嵌入式管理單元相容。

若為多重選取屬性表,系統只會系結至 DSOBJECT 陣列中的第一個物件。 因此,ADsPropGetInitInfo 只提供陣列中第一個物件的 IDirectoryObject 和可寫入屬性。 陣列中的其他物件不會繫結至 。

多重選取屬性表延伸模組會在 adminMultiselectPropertyPages 屬性下註冊。

Windows Server 2003 的新功能

下列功能是 Windows Server 2003 的新功能。

如果屬性頁發生錯誤,可以使用適當的錯誤數據呼叫 ADsPropSendErrorMessage ADsPropSendErrorMessage 會將所有錯誤訊息儲存在佇列中。 下次呼叫 ADsPropShowErrorDialog,將會顯示這些訊息。 當 ADsPropShowErrorDialog 傳回時,會刪除已排入佇列的訊息。

Windows Server 2003 引進 ADsPropSetHwndWithTitle 函 式。 此函式類似於 ADsPropSetHwnd,但包含頁面標題。 這可讓 ADsPropShowErrorDialog 所顯示的錯誤對話框為使用者提供更有用的數據。 如果屬性表延伸模組使用 ADsPropShowErrorDialog 函式,擴充功能應該使用 ADsPropSetHwndWithTitle,而不是 ADsPropSetHwnd

屬性表 COM 對象的實作範例程序代碼