windows-nt/Source/XPSP1/NT/admin/admt/wizards/ouselect.cpp
2020-09-26 16:20:57 +08:00

477 lines
14 KiB
C++

// ContainerSelectionDlg.cpp : implementation file
//
#include "stdafx.h"
#include "OuSelect.h"
#include "iads.h"
#include <DSCLIENT.H>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CContainerSelectionDlg dialog
typedef int (CALLBACK * DSBROWSEFORCONTAINER)(PDSBROWSEINFOW dsInfo);
DSBROWSEFORCONTAINER DsBrowseForContainerX;
const BSTR sQuery = L"(|(objectClass=organizationalUnit) (objectClass=container))";
HTREEITEM root;
CContainerSelectionDlg::CContainerSelectionDlg(CWnd* pParent /*=NULL*/)
: CDialog(CContainerSelectionDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CContainerSelectionDlg)
m_strCont = _T("");
//}}AFX_DATA_INIT
}
void CContainerSelectionDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CContainerSelectionDlg)
DDX_Control(pDX, IDOK, m_btnOK);
DDX_Control(pDX, IDC_TREE1, m_trOUTree);
DDX_Text(pDX, IDC_EDIT1, m_strCont);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CContainerSelectionDlg, CDialog)
//{{AFX_MSG_MAP(CContainerSelectionDlg)
ON_BN_CLICKED(IDOK, OnOk)
ON_NOTIFY(TVN_SELCHANGED, IDC_TREE1, OnSelchangedTree1)
ON_NOTIFY(NM_DBLCLK, IDC_TREE1, OnDblclkTree1)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CContainerSelectionDlg message handlers
void PadOUName(WCHAR * sPath)
{
WCHAR sTemp[255];
int off = 0;
WCHAR sSpecial[] = L"#+\"<>=\\;,/";
// Find the first = sign
wcscpy(sTemp, sPath);
for ( DWORD i = 0; i < wcslen(sTemp); i++ )
{
if ( wcschr(sSpecial, sTemp[i]) )
{
sPath[i + off] = L'\\';
off++;
}
sPath[i + off] = sTemp[i];
}
sPath[i+off] = L'\0';
}
void UnPadOUName(WCHAR * sPath)
{
WCHAR sTemp[255];
int off = 0;
DWORD i = 0;
// Copy everything after the first = sign (if one exists)
WCHAR * pTemp = wcschr(sPath, L'=');
if ( pTemp )
{
wcscpy(sTemp, ++pTemp);
off = wcslen(pTemp) - wcslen(sPath);
}
else
wcscpy(sTemp, sPath);
for ( ; i < wcslen(sTemp); i++ )
{
if ( sTemp[i] == L'\\' )
{
i++;
off++;
}
sPath[i - off] = sTemp[i];
}
sPath[i-off] = L'\0';
}
void CContainerSelectionDlg::OnOk()
{
CDialog::OnOK();
}
BOOL CContainerSelectionDlg::OnInitDialog()
{
// CWaitCursor wait;
CDialog::OnInitDialog();
/* if ( m_strDomain.IsEmpty() )
return TRUE;
LoadImageList();
root = m_trOUTree.InsertItem(m_strDomain, 0, 1);
domain = _bstr_t(m_strDomain);
ExpandCompletely(root, L"");
::SysFreeString(domain);
FindContainer();
*/
HMODULE hMod = NULL;
hMod = LoadLibrary(L"dsuiext.dll");
if ( hMod )
{
WCHAR sDomPath[255];
wsprintf(sDomPath, L"LDAP://%s", (WCHAR*) m_strDomain);
DsBrowseForContainerX = (DSBROWSEFORCONTAINER)GetProcAddress(hMod, "DsBrowseForContainerW");
WCHAR * sContPath, * sContName;
BrowseForContainer(m_hWnd, sDomPath, &sContPath, &sContName);
m_strCont = sContPath;
CoTaskMemFree(sContPath);
CoTaskMemFree(sContName);
UpdateData(FALSE);
}
OnOK();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
HRESULT CContainerSelectionDlg::PopulateContainer(
HTREEITEM tvItemParent, //in- Item to expand
_bstr_t sContName, //in- Name of the container.
INetObjEnumeratorPtr pQuery //in- Query Object
)
{
HRESULT hr = E_FAIL;
IEnumVARIANT * pEnum = NULL;
SAFEARRAY * psaCols = NULL;
SAFEARRAYBOUND bd = { 2, 0 };
LPWSTR pCols[] = { L"name", L"objectClass" };
BSTR HUGEP * pData;
_variant_t var;
DWORD dwFetch = 0;
SAFEARRAY * psaVals;
_bstr_t sValName;
_bstr_t sType;
_variant_t * pDataVar;
_variant_t varVal;
WCHAR sTempName[255];
WCHAR sPath[255];
int img = 0;
psaCols = SafeArrayCreate(VT_BSTR, 1, &bd);
if ( psaCols )
{
hr = SafeArrayAccessData(psaCols, (void HUGEP **)&pData);
if ( SUCCEEDED(hr) )
{
pData[0] = SysAllocString(pCols[0]);
pData[1] = SysAllocString(pCols[1]);
}
SafeArrayUnaccessData(psaCols);
}
if ( SUCCEEDED(hr))
hr = pQuery->raw_SetQuery(sContName, domain, sQuery, ADS_SCOPE_ONELEVEL, FALSE);
if ( SUCCEEDED(hr) )
hr = pQuery->raw_SetColumns(psaCols);
if ( SUCCEEDED(hr))
hr = pQuery->raw_Execute(&pEnum);
if ( pEnum )
{
while ( pEnum->Next(1, &var, &dwFetch) == S_OK )
{
psaVals = V_ARRAY(&var);
hr = SafeArrayAccessData(psaVals, (void**)&pDataVar);
if ( SUCCEEDED(hr) )
{
varVal = pDataVar[0];
if ( varVal.vt == VT_BSTR ) sValName = V_BSTR(&varVal);
varVal = pDataVar[1];
if ( varVal.vt == VT_BSTR ) sType = V_BSTR(&varVal);
SafeArrayUnaccessData(psaVals);
}
if ( SUCCEEDED(hr) )
{
//
wcscpy(sPath, (WCHAR*) sValName);
PadOUName(sPath);
if ( wcsicmp(sType, L"organizationalUnit") == 0 )
{
wsprintf(sTempName, L"OU=%s", sPath);
img = 4;
}
else
{
wsprintf(sTempName, L"CN=%s", sPath);
img = 2;
}
if ( wcsicmp(sTempName, L"CN=System") != 0 )
m_trOUTree.InsertItem(sTempName, img, img+1, tvItemParent);
}
}
}
// Clean up
if ( pEnum ) pEnum->Release();
VariantInit(&var);
return hr;
}
HRESULT CContainerSelectionDlg::ExpandCompletely(HTREEITEM tvItem, _bstr_t parentCont)
{
HTREEITEM tvChild;
WCHAR currCont[255];
CString sContName;
HRESULT hr = S_OK;
INetObjEnumeratorPtr pQuery(__uuidof(NetObjEnumerator));
// First populate this container
hr = PopulateContainer( tvItem, parentCont, pQuery);
// Check if it has children. If it does then for each child call this function recursively
if ( m_trOUTree.ItemHasChildren(tvItem) )
{
tvChild = m_trOUTree.GetChildItem(tvItem);
while ( tvChild )
{
// Get the name of the
sContName = m_trOUTree.GetItemText(tvChild);
if ( wcslen(parentCont) > 0 )
wsprintf(currCont, L"%s,%s", sContName, (WCHAR*)parentCont);
else
wcscpy(currCont, sContName);
ExpandCompletely(tvChild, currCont);
tvChild = m_trOUTree.GetNextSiblingItem(tvChild);
}
}
return hr;
}
BOOL CContainerSelectionDlg::LoadImageList()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
// set up icon list for list box
// use bitmaps
CBitmap cont;
CBitmap ou;
CBitmap openCont;
CBitmap openOU;
CBitmap dir;
CBitmap dirOpen;
COLORREF cr = 0x000000;
if (
dir.LoadBitmap(IDB_DIR)
&& dirOpen.LoadBitmap(IDB_OPEN_DIR)
&& cont.LoadBitmap(IDB_CONT)
&& ou.LoadBitmap(IDB_OU)
&& openCont.LoadBitmap(IDB_OPEN_CONT)
&& openOU.LoadBitmap(IDB_OPEN_OU)
)
{
cr = GetFirstBitmapPixel(this,IDB_CONT);
ilist.Create(IDB_DIR, 16, 16, cr);
ilist.Add(&dirOpen, cr);
ilist.Add(&cont,cr);
ilist.Add(&openCont,cr);
ilist.Add(&ou,cr);
ilist.Add(&openOU,cr);
m_trOUTree.SetImageList(&ilist,TVSIL_NORMAL);
}
return TRUE;
}
COLORREF CContainerSelectionDlg::GetFirstBitmapPixel(CWnd * window,UINT idbBitmap)
{
CBitmap bmp;
COLORREF color = 0x00ffffff;
if ( bmp.LoadBitmap(idbBitmap) )
{
// Get Device context
CDC * windowDC = window->GetDC();
HDC hdcImage = ::CreateCompatibleDC(windowDC->m_hDC);
CBitmap * tempBmp = (CBitmap *)::SelectObject(hdcImage,(HBITMAP)bmp);
// now get the pixel
if ( windowDC && hdcImage && tempBmp )
{
color = GetPixel(hdcImage,0, 0);
}
if ( tempBmp )
::SelectObject(hdcImage,tempBmp);
if ( hdcImage )
::DeleteObject(hdcImage);
}
return color;
}
void CContainerSelectionDlg::OnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
m_strCont = L"";
HTREEITEM tvSelected, tvParent;
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
tvSelected = m_trOUTree.GetSelectedItem();
if ( tvSelected )
{
// We dont want to process the domain name in the Container name so go upto
// the point where we have a parent. i.e. Child of the domain node.
while( tvParent = m_trOUTree.GetParentItem(tvSelected) )
{
// Build the container list by walking up the tree.
if ( m_strCont.IsEmpty() )
m_strCont = m_trOUTree.GetItemText(tvSelected);
else
m_strCont = m_strCont + CString(L",") + m_trOUTree.GetItemText(tvSelected);
tvSelected = tvParent;
}
}
m_btnOK.EnableWindow(!m_strCont.IsEmpty());
UpdateData(FALSE);
*pResult = 0;
}
void CContainerSelectionDlg::OnDblclkTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
UpdateData();
if ( !m_strCont.IsEmpty() )
OnOk();
*pResult = 0;
}
HRESULT CContainerSelectionDlg::FindContainer()
{
CString strName;
int ndx = 0, oldNdx = -1;
// We can find the container iff there is one specified.
if (!m_strCont.IsEmpty())
{
OpenContainer(m_strCont, root);
}
return S_OK;
}
HTREEITEM CContainerSelectionDlg::OpenContainer(CString strCont, HTREEITEM rootSub)
{
int ndx = -1;
CString strLeft, strRight;
HTREEITEM tvItem = NULL;
WCHAR sTemp[255];
if ( !strCont.IsEmpty() && rootSub )
{
ndx = strCont.Find(L",", 0);
if ( ndx > -1 )
{
// Get the right side of the comma string and Call this again to open the parent container.
strLeft = strCont.Left(ndx);
strRight = strCont.Mid(ndx + 1);
tvItem = OpenContainer(strRight, rootSub);
tvItem = OpenContainer(strLeft, tvItem);
}
else
{
// We have a container name so lets find it below rootSub node.
wcscpy(sTemp,strCont);
UnPadOUName(sTemp);
strCont = CString(sTemp);
tvItem = m_trOUTree.GetChildItem(rootSub);
while (tvItem)
{
if ( m_trOUTree.GetItemText(tvItem) == strCont )
{
m_trOUTree.Expand(tvItem, 0);
m_trOUTree.Select(tvItem, TVGN_CARET);
break;
}
tvItem = m_trOUTree.GetNextSiblingItem(tvItem);
}
}
}
return tvItem;
}
HRESULT CContainerSelectionDlg::BrowseForContainer(HWND hWnd,//Handle to window that should own the browse dialog.
LPOLESTR szRootPath, //Root of the browse tree. NULL for entire forest.
LPOLESTR *ppContainerADsPath, //Return the ADsPath of the selected container.
LPOLESTR *ppContainerClass //Return the ldapDisplayName of the container's class.
)
{
HRESULT hr = E_FAIL;
DSBROWSEINFO dsbi;
OLECHAR szPath[1000];
OLECHAR szClass[MAX_PATH];
DWORD result;
if (!ppContainerADsPath)
return E_POINTER;
::ZeroMemory( &dsbi, sizeof(dsbi) );
dsbi.hwndOwner = hWnd;
dsbi.cbStruct = sizeof (DSBROWSEINFO);
dsbi.pszCaption = L"Browse for Container"; // The caption (titlebar text)
dsbi.pszTitle = L"Select a target container."; //Text for the dialog.
dsbi.pszRoot = szRootPath; //ADsPath for the root of the tree to display in the browser.
//Specify NULL with DSBI_ENTIREDIRECTORY flag for entire forest.
//NULL without DSBI_ENTIREDIRECTORY flag displays current domain rooted at LDAP.
dsbi.pszPath = szPath; //Pointer to a unicode string buffer.
dsbi.cchPath = sizeof(szPath)/sizeof(OLECHAR);//count of characters for buffer.
dsbi.dwFlags = DSBI_RETURN_FORMAT | //Return the path to object in format specified in dwReturnFormat
DSBI_RETURNOBJECTCLASS; //Return the object class
dsbi.pfnCallback = NULL;
dsbi.lParam = 0;
dsbi.dwReturnFormat = ADS_FORMAT_X500; //Specify the format.
//This one returns an ADsPath. See ADS_FORMAT enum in IADS.H
dsbi.pszObjectClass = szClass; //Pointer to a unicode string buffer.
dsbi.cchObjectClass = sizeof(szClass)/sizeof(OLECHAR);//count of characters for buffer.
//if root path is NULL, make the forest the root.
if (!szRootPath)
dsbi.dwFlags |= DSBI_ENTIREDIRECTORY;
//Display browse dialog box.
result = DsBrowseForContainerX( &dsbi ); // returns -1, 0, IDOK or IDCANCEL
if (result == IDOK)
{
//Allocate memory for string
*ppContainerADsPath = (OLECHAR *)CoTaskMemAlloc (sizeof(OLECHAR)*(wcslen(szPath)+1));
if (*ppContainerADsPath)
{
wcscpy(*ppContainerADsPath, szPath);
//Caller must free using CoTaskMemFree
hr = S_OK;
}
else
hr=E_FAIL;
if (ppContainerClass)
{
//Allocate memory for string
*ppContainerClass = (OLECHAR *)CoTaskMemAlloc (sizeof(OLECHAR)*(wcslen(szClass)+1));
if (*ppContainerClass)
{
wcscpy(*ppContainerClass, szClass);
//Call must free using CoTaskMemFree
hr = S_OK;
}
else
hr=E_FAIL;
}
}
else
hr = E_FAIL;
return hr;
}