Directory Services

Example Code for Implementation of the Property Sheet COM Object

The following code example shows how to implement an Active Directory® property sheet extension.

IShellExtInit Implementation

The following code example demonstrates how to implement the IShellExtInit methods.

[C++]
/**************************************************************************

	CPropSheetExt::Initialize()

**************************************************************************/

STDMETHODIMP CPropSheetExt::Initialize( LPCITEMIDLIST pidlFolder,
										IDataObject *pDataObj,
										HKEY hKeyProgId)
{
	STGMEDIUM   stm;
	FORMATETC   fe;
	HRESULT	 hr = S_OK;

	if(NULL == pDataObj)
	{
		return E_INVALIDARG;
}

	hr = pDataObj->QueryInterface(IID_IDataObject, (LPVOID*)&m_pdo);
	if(FAILED(hr))
	{
		return hr;
}

	fe.cfFormat = RegisterClipboardFormat(CFSTR_DSOBJECTNAMES);
	fe.ptd = NULL;
	fe.dwAspect = DVASPECT_CONTENT;
	fe.lindex = -1;
	fe.tymed = TYMED_HGLOBAL;
	hr = m_pdo->GetData(&fe, &stm);
	if(SUCCEEDED(hr))
	{
		LPDSOBJECTNAMES pdson = (LPDSOBJECTNAMES)GlobalLock(stm.hGlobal);

		if(pdson)
		{
			LPWSTR  pwszName = (LPWSTR)((LPBYTE)pdson + pdson->aObjects[0].offsetName);
		
			m_pwszADsPath = (LPWSTR)GlobalAlloc(GPTR, (lstrlenW(pwszName) + 1) * sizeof(WCHAR));
			if(m_pwszADsPath)
			{
				lstrcpyW(m_pwszADsPath, pwszName);
		}
		
			LPWSTR  pwszClass = (LPWSTR)((LPBYTE)pdson + pdson->aObjects[0].offsetClass);
			pwszClass = NULL;

			GlobalUnlock(stm.hGlobal);
	}
	
		ReleaseStgMedium(&stm);
}

	m_hwndNotifyObj = CreateADsNotificationObject(pDataObj);

	if(m_hwndNotifyObj)
	{
		ADSPROPINITPARAMS   InitParams;
	
		hr = GetADsPageInfo(m_hwndNotifyObj, &InitParams);
		if(SUCCEEDED(hr))
		{
			if(InitParams.pDsObj)
			{
				hr = InitParams.pDsObj->QueryInterface( IID_IDirectoryObject, 
														(LPVOID*) & m_pDirObj);
		}
	}
}

	fe.cfFormat = RegisterClipboardFormat(CFSTR_DS_DISPLAY_SPEC_OPTIONS);
	fe.ptd = NULL;
	fe.dwAspect = DVASPECT_CONTENT;
	fe.lindex = -1;
	fe.tymed = TYMED_HGLOBAL;
	hr = pDataObj->GetData(&fe, &stm);
	if(SUCCEEDED(hr))
	{
		PDSDISPLAYSPECOPTIONS   pdso;
	
		pdso = (PDSDISPLAYSPECOPTIONS)GlobalLock(stm.hGlobal);
		if(pdso)
		{
			DWORD   dwBytes = GlobalSize(stm.hGlobal);

			m_pDispSpecOpts = (PDSDISPLAYSPECOPTIONS)GlobalAlloc(GPTR, dwBytes);
			if(m_pDispSpecOpts)
			{
				CopyMemory(m_pDispSpecOpts, pdso, dwBytes);
		}
		
			GlobalUnlock(stm.hGlobal);
	}

		ReleaseStgMedium(&stm);
}

	return hr;
}

IShellPropSheetExt Implementation

The following code example demonstrates how to implement the IShellPropSheetExt methods.

[C++]
/**************************************************************************

	CPropSheetExt::AddPages()

**************************************************************************/

STDMETHODIMP CPropSheetExt::AddPages(   LPFNADDPROPSHEETPAGE pfnAddPage, 
										LPARAM lParam)
{
	PROPSHEETPAGE  psp;
	HPROPSHEETPAGE hPage;

	psp.dwSize		= sizeof(psp);
	psp.dwFlags	 = PSP_USETITLE | PSP_USECALLBACK;
	psp.hInstance	 = g_hInst;
	psp.pszTemplate   = MAKEINTRESOURCE(IDD_PAGEDLG);
	psp.hIcon		 = 0;
	psp.pszTitle	= g_szPageTitle;
	psp.pfnDlgProc	= (DLGPROC)PageDlgProc;
	psp.pcRefParent   = NULL;
	psp.pfnCallback   = PageCallbackProc;
	//pass the object pointer to the dialog box
	psp.lParam		= (LPARAM)this;

	hPage = CreatePropertySheetPage(&psp);
			
	if(hPage) 
	{
		if(pfnAddPage(hPage, lParam))
		{
			/*
			Maintain this object until the page is released in 
			PageCallbackProc.
			*/
			this->AddRef();
			return S_OK;
	}
		else
		{
			DestroyPropertySheetPage(hPage);
	}
}
	else
	{
		return E_OUTOFMEMORY;
}

	return E_FAIL;
}

/**************************************************************************

	CPropSheetExt::ReplacePage()

**************************************************************************/

STDMETHODIMP CPropSheetExt::ReplacePage(	UINT uPageID, 
											LPFNADDPROPSHEETPAGE lpfnAddPage, 
											LPARAM lParam)
{
	return E_NOTIMPL;
}

Miscellaneous Implementation

The following code example shows how to implement the utility methods and functions used in the code example above.

[C++]
/**************************************************************************

	CreateADsNotificationObject()
   
**************************************************************************/

HWND CreateADsNotificationObject(IDataObject *pDataObject)
{
	STGMEDIUM   stm;
	FORMATETC   fe;
	HRESULT	 hr;
	HWND		hwndNotifyObject = NULL;

	fe.cfFormat = RegisterClipboardFormat(CFSTR_DSOBJECTNAMES);
	fe.ptd = NULL;
	fe.dwAspect = DVASPECT_CONTENT;
	fe.lindex = -1;
	fe.tymed = TYMED_HGLOBAL;
	hr = pDataObject->GetData(&fe, &stm);
	if(SUCCEEDED(hr))
	{
		LPDSOBJECTNAMES pdson = (LPDSOBJECTNAMES)GlobalLock(stm.hGlobal);

		if(pdson)
		{
			LPWSTR  pwszName = (LPWSTR)((LPBYTE)pdson + pdson->aObjects[0].offsetName);
		
			hr = ADsPropCreateNotifyObj(pDataObject, pwszName, &hwndNotifyObject);

			GlobalUnlock(stm.hGlobal);
	}
	
		ReleaseStgMedium(&stm);
}

	return hwndNotifyObject;
}

/**************************************************************************

	GetADsPageInfo()
   
**************************************************************************/

HRESULT GetADsPageInfo(HWND hwndNotifyObject, ADSPROPINITPARAMS *pip)
{
	if(!IsWindow(hwndNotifyObject))
	{
		return E_INVALIDARG;
}

	if(IsBadWritePtr(pip, sizeof(ADSPROPINITPARAMS)))
	{
		return E_INVALIDARG;
}

	ADSPROPINITPARAMS   InitParams;

	InitParams.dwSize = sizeof(ADSPROPINITPARAMS);
	if(ADsPropGetInitInfo(hwndNotifyObject, &InitParams))
	{
		*pip = InitParams;

		return InitParams.hr;
}

	return E_FAIL;
}

/**************************************************************************

	CPropSheetExt::PageDlgProc

**************************************************************************/

#define THIS_POINTER_PROP  TEXT("ThisPointerProperty")

BOOL CALLBACK CPropSheetExt::PageDlgProc(   HWND hWnd, 
											UINT uMsg, 
											WPARAM wParam, 
											LPARAM lParam)
{
	//get the object pointer
	CPropSheetExt *pExt = (CPropSheetExt*)GetProp(hWnd, THIS_POINTER_PROP);

	switch(uMsg)
	{
	case WM_INITDIALOG:
		{
			/*
			Get the pointer to the object. This is contained in the LPARAM of 
			the PROPSHEETPAGE structure.
			*/
			LPPROPSHEETPAGE pPage = (LPPROPSHEETPAGE)lParam;

			if(pPage)
			{
				pExt = (CPropSheetExt*)pPage->lParam;

				if(pExt)
				{
					//set the page window handle in the object
					pExt->m_hwndPage = hWnd;
				
					//store the object pointer with this particular page dialog
					SetProp(hWnd, THIS_POINTER_PROP, (HANDLE)pExt);

					ADsPropSetHwnd(pExt->m_hwndNotifyObj, hWnd, g_szPageTitle);

					//forward the message to the message handler
					return pExt->OnInitDialog(wParam, lParam);
			}
		}
	}
		break;

	case WM_NOTIFY:
		if(pExt)
		{
			//forward the message to the message handler
			return pExt->OnNotify(wParam, lParam);
	}
		break;

	case WM_COMMAND:
		if(pExt)
		{
			//forward the message to the message handler
			return pExt->OnCommand(wParam, lParam);
	}
		return FALSE;

	case WM_DESTROY:
		if(pExt)
		{
			//forward the message to the message handler
			pExt->OnDestroy();
	}
	
		//remove the property from the page
		RemoveProp(hWnd, THIS_POINTER_PROP);
		break; 
}

	return FALSE;
}


/**************************************************************************

	CPropSheetExt::PageCallbackProc()

	This function is called when the page is created and released. This is 
	even called if the page is never actually displayed. 

**************************************************************************/

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

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

			if(pPropSheetExt)
			{
				if(IsWindow(pPropSheetExt->m_hwndNotifyObj))
				{
					SendMessage(pPropSheetExt->m_hwndNotifyObj, 
						WM_ADSPROP_NOTIFY_EXIT, 
						0, 
						0);

					pPropSheetExt->m_hwndNotifyObj = NULL;
			}
				pPropSheetExt->Release();
		}
	}
		break;
}

	return FALSE;
}