Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

476 lines
14 KiB

  1. // ContainerSelectionDlg.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "OuSelect.h"
  5. #include "iads.h"
  6. #include <DSCLIENT.H>
  7. #ifdef _DEBUG
  8. #define new DEBUG_NEW
  9. #undef THIS_FILE
  10. static char THIS_FILE[] = __FILE__;
  11. #endif
  12. /////////////////////////////////////////////////////////////////////////////
  13. // CContainerSelectionDlg dialog
  14. typedef int (CALLBACK * DSBROWSEFORCONTAINER)(PDSBROWSEINFOW dsInfo);
  15. DSBROWSEFORCONTAINER DsBrowseForContainerX;
  16. const BSTR sQuery = L"(|(objectClass=organizationalUnit) (objectClass=container))";
  17. HTREEITEM root;
  18. CContainerSelectionDlg::CContainerSelectionDlg(CWnd* pParent /*=NULL*/)
  19. : CDialog(CContainerSelectionDlg::IDD, pParent)
  20. {
  21. //{{AFX_DATA_INIT(CContainerSelectionDlg)
  22. m_strCont = _T("");
  23. //}}AFX_DATA_INIT
  24. }
  25. void CContainerSelectionDlg::DoDataExchange(CDataExchange* pDX)
  26. {
  27. CDialog::DoDataExchange(pDX);
  28. //{{AFX_DATA_MAP(CContainerSelectionDlg)
  29. DDX_Control(pDX, IDOK, m_btnOK);
  30. DDX_Control(pDX, IDC_TREE1, m_trOUTree);
  31. DDX_Text(pDX, IDC_EDIT1, m_strCont);
  32. //}}AFX_DATA_MAP
  33. }
  34. BEGIN_MESSAGE_MAP(CContainerSelectionDlg, CDialog)
  35. //{{AFX_MSG_MAP(CContainerSelectionDlg)
  36. ON_BN_CLICKED(IDOK, OnOk)
  37. ON_NOTIFY(TVN_SELCHANGED, IDC_TREE1, OnSelchangedTree1)
  38. ON_NOTIFY(NM_DBLCLK, IDC_TREE1, OnDblclkTree1)
  39. //}}AFX_MSG_MAP
  40. END_MESSAGE_MAP()
  41. /////////////////////////////////////////////////////////////////////////////
  42. // CContainerSelectionDlg message handlers
  43. void PadOUName(WCHAR * sPath)
  44. {
  45. WCHAR sTemp[255];
  46. int off = 0;
  47. WCHAR sSpecial[] = L"#+\"<>=\\;,/";
  48. // Find the first = sign
  49. wcscpy(sTemp, sPath);
  50. for ( DWORD i = 0; i < wcslen(sTemp); i++ )
  51. {
  52. if ( wcschr(sSpecial, sTemp[i]) )
  53. {
  54. sPath[i + off] = L'\\';
  55. off++;
  56. }
  57. sPath[i + off] = sTemp[i];
  58. }
  59. sPath[i+off] = L'\0';
  60. }
  61. void UnPadOUName(WCHAR * sPath)
  62. {
  63. WCHAR sTemp[255];
  64. int off = 0;
  65. DWORD i = 0;
  66. // Copy everything after the first = sign (if one exists)
  67. WCHAR * pTemp = wcschr(sPath, L'=');
  68. if ( pTemp )
  69. {
  70. wcscpy(sTemp, ++pTemp);
  71. off = wcslen(pTemp) - wcslen(sPath);
  72. }
  73. else
  74. wcscpy(sTemp, sPath);
  75. for ( ; i < wcslen(sTemp); i++ )
  76. {
  77. if ( sTemp[i] == L'\\' )
  78. {
  79. i++;
  80. off++;
  81. }
  82. sPath[i - off] = sTemp[i];
  83. }
  84. sPath[i-off] = L'\0';
  85. }
  86. void CContainerSelectionDlg::OnOk()
  87. {
  88. CDialog::OnOK();
  89. }
  90. BOOL CContainerSelectionDlg::OnInitDialog()
  91. {
  92. // CWaitCursor wait;
  93. CDialog::OnInitDialog();
  94. /* if ( m_strDomain.IsEmpty() )
  95. return TRUE;
  96. LoadImageList();
  97. root = m_trOUTree.InsertItem(m_strDomain, 0, 1);
  98. domain = _bstr_t(m_strDomain);
  99. ExpandCompletely(root, L"");
  100. ::SysFreeString(domain);
  101. FindContainer();
  102. */
  103. HMODULE hMod = NULL;
  104. hMod = LoadLibrary(L"dsuiext.dll");
  105. if ( hMod )
  106. {
  107. WCHAR sDomPath[255];
  108. wsprintf(sDomPath, L"LDAP://%s", (WCHAR*) m_strDomain);
  109. DsBrowseForContainerX = (DSBROWSEFORCONTAINER)GetProcAddress(hMod, "DsBrowseForContainerW");
  110. WCHAR * sContPath, * sContName;
  111. BrowseForContainer(m_hWnd, sDomPath, &sContPath, &sContName);
  112. m_strCont = sContPath;
  113. CoTaskMemFree(sContPath);
  114. CoTaskMemFree(sContName);
  115. UpdateData(FALSE);
  116. }
  117. OnOK();
  118. return TRUE; // return TRUE unless you set the focus to a control
  119. // EXCEPTION: OCX Property Pages should return FALSE
  120. }
  121. HRESULT CContainerSelectionDlg::PopulateContainer(
  122. HTREEITEM tvItemParent, //in- Item to expand
  123. _bstr_t sContName, //in- Name of the container.
  124. INetObjEnumeratorPtr pQuery //in- Query Object
  125. )
  126. {
  127. HRESULT hr = E_FAIL;
  128. IEnumVARIANT * pEnum = NULL;
  129. SAFEARRAY * psaCols = NULL;
  130. SAFEARRAYBOUND bd = { 2, 0 };
  131. LPWSTR pCols[] = { L"name", L"objectClass" };
  132. BSTR HUGEP * pData;
  133. _variant_t var;
  134. DWORD dwFetch = 0;
  135. SAFEARRAY * psaVals;
  136. _bstr_t sValName;
  137. _bstr_t sType;
  138. _variant_t * pDataVar;
  139. _variant_t varVal;
  140. WCHAR sTempName[255];
  141. WCHAR sPath[255];
  142. int img = 0;
  143. psaCols = SafeArrayCreate(VT_BSTR, 1, &bd);
  144. if ( psaCols )
  145. {
  146. hr = SafeArrayAccessData(psaCols, (void HUGEP **)&pData);
  147. if ( SUCCEEDED(hr) )
  148. {
  149. pData[0] = SysAllocString(pCols[0]);
  150. pData[1] = SysAllocString(pCols[1]);
  151. }
  152. SafeArrayUnaccessData(psaCols);
  153. }
  154. if ( SUCCEEDED(hr))
  155. hr = pQuery->raw_SetQuery(sContName, domain, sQuery, ADS_SCOPE_ONELEVEL, FALSE);
  156. if ( SUCCEEDED(hr) )
  157. hr = pQuery->raw_SetColumns(psaCols);
  158. if ( SUCCEEDED(hr))
  159. hr = pQuery->raw_Execute(&pEnum);
  160. if ( pEnum )
  161. {
  162. while ( pEnum->Next(1, &var, &dwFetch) == S_OK )
  163. {
  164. psaVals = V_ARRAY(&var);
  165. hr = SafeArrayAccessData(psaVals, (void**)&pDataVar);
  166. if ( SUCCEEDED(hr) )
  167. {
  168. varVal = pDataVar[0];
  169. if ( varVal.vt == VT_BSTR ) sValName = V_BSTR(&varVal);
  170. varVal = pDataVar[1];
  171. if ( varVal.vt == VT_BSTR ) sType = V_BSTR(&varVal);
  172. SafeArrayUnaccessData(psaVals);
  173. }
  174. if ( SUCCEEDED(hr) )
  175. {
  176. //
  177. wcscpy(sPath, (WCHAR*) sValName);
  178. PadOUName(sPath);
  179. if ( wcsicmp(sType, L"organizationalUnit") == 0 )
  180. {
  181. wsprintf(sTempName, L"OU=%s", sPath);
  182. img = 4;
  183. }
  184. else
  185. {
  186. wsprintf(sTempName, L"CN=%s", sPath);
  187. img = 2;
  188. }
  189. if ( wcsicmp(sTempName, L"CN=System") != 0 )
  190. m_trOUTree.InsertItem(sTempName, img, img+1, tvItemParent);
  191. }
  192. }
  193. }
  194. // Clean up
  195. if ( pEnum ) pEnum->Release();
  196. VariantInit(&var);
  197. return hr;
  198. }
  199. HRESULT CContainerSelectionDlg::ExpandCompletely(HTREEITEM tvItem, _bstr_t parentCont)
  200. {
  201. HTREEITEM tvChild;
  202. WCHAR currCont[255];
  203. CString sContName;
  204. HRESULT hr = S_OK;
  205. INetObjEnumeratorPtr pQuery(__uuidof(NetObjEnumerator));
  206. // First populate this container
  207. hr = PopulateContainer( tvItem, parentCont, pQuery);
  208. // Check if it has children. If it does then for each child call this function recursively
  209. if ( m_trOUTree.ItemHasChildren(tvItem) )
  210. {
  211. tvChild = m_trOUTree.GetChildItem(tvItem);
  212. while ( tvChild )
  213. {
  214. // Get the name of the
  215. sContName = m_trOUTree.GetItemText(tvChild);
  216. if ( wcslen(parentCont) > 0 )
  217. wsprintf(currCont, L"%s,%s", sContName, (WCHAR*)parentCont);
  218. else
  219. wcscpy(currCont, sContName);
  220. ExpandCompletely(tvChild, currCont);
  221. tvChild = m_trOUTree.GetNextSiblingItem(tvChild);
  222. }
  223. }
  224. return hr;
  225. }
  226. BOOL CContainerSelectionDlg::LoadImageList()
  227. {
  228. AFX_MANAGE_STATE(AfxGetStaticModuleState())
  229. // set up icon list for list box
  230. // use bitmaps
  231. CBitmap cont;
  232. CBitmap ou;
  233. CBitmap openCont;
  234. CBitmap openOU;
  235. CBitmap dir;
  236. CBitmap dirOpen;
  237. COLORREF cr = 0x000000;
  238. if (
  239. dir.LoadBitmap(IDB_DIR)
  240. && dirOpen.LoadBitmap(IDB_OPEN_DIR)
  241. && cont.LoadBitmap(IDB_CONT)
  242. && ou.LoadBitmap(IDB_OU)
  243. && openCont.LoadBitmap(IDB_OPEN_CONT)
  244. && openOU.LoadBitmap(IDB_OPEN_OU)
  245. )
  246. {
  247. cr = GetFirstBitmapPixel(this,IDB_CONT);
  248. ilist.Create(IDB_DIR, 16, 16, cr);
  249. ilist.Add(&dirOpen, cr);
  250. ilist.Add(&cont,cr);
  251. ilist.Add(&openCont,cr);
  252. ilist.Add(&ou,cr);
  253. ilist.Add(&openOU,cr);
  254. m_trOUTree.SetImageList(&ilist,TVSIL_NORMAL);
  255. }
  256. return TRUE;
  257. }
  258. COLORREF CContainerSelectionDlg::GetFirstBitmapPixel(CWnd * window,UINT idbBitmap)
  259. {
  260. CBitmap bmp;
  261. COLORREF color = 0x00ffffff;
  262. if ( bmp.LoadBitmap(idbBitmap) )
  263. {
  264. // Get Device context
  265. CDC * windowDC = window->GetDC();
  266. HDC hdcImage = ::CreateCompatibleDC(windowDC->m_hDC);
  267. CBitmap * tempBmp = (CBitmap *)::SelectObject(hdcImage,(HBITMAP)bmp);
  268. // now get the pixel
  269. if ( windowDC && hdcImage && tempBmp )
  270. {
  271. color = GetPixel(hdcImage,0, 0);
  272. }
  273. if ( tempBmp )
  274. ::SelectObject(hdcImage,tempBmp);
  275. if ( hdcImage )
  276. ::DeleteObject(hdcImage);
  277. }
  278. return color;
  279. }
  280. void CContainerSelectionDlg::OnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult)
  281. {
  282. m_strCont = L"";
  283. HTREEITEM tvSelected, tvParent;
  284. NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  285. tvSelected = m_trOUTree.GetSelectedItem();
  286. if ( tvSelected )
  287. {
  288. // We dont want to process the domain name in the Container name so go upto
  289. // the point where we have a parent. i.e. Child of the domain node.
  290. while( tvParent = m_trOUTree.GetParentItem(tvSelected) )
  291. {
  292. // Build the container list by walking up the tree.
  293. if ( m_strCont.IsEmpty() )
  294. m_strCont = m_trOUTree.GetItemText(tvSelected);
  295. else
  296. m_strCont = m_strCont + CString(L",") + m_trOUTree.GetItemText(tvSelected);
  297. tvSelected = tvParent;
  298. }
  299. }
  300. m_btnOK.EnableWindow(!m_strCont.IsEmpty());
  301. UpdateData(FALSE);
  302. *pResult = 0;
  303. }
  304. void CContainerSelectionDlg::OnDblclkTree1(NMHDR* pNMHDR, LRESULT* pResult)
  305. {
  306. UpdateData();
  307. if ( !m_strCont.IsEmpty() )
  308. OnOk();
  309. *pResult = 0;
  310. }
  311. HRESULT CContainerSelectionDlg::FindContainer()
  312. {
  313. CString strName;
  314. int ndx = 0, oldNdx = -1;
  315. // We can find the container iff there is one specified.
  316. if (!m_strCont.IsEmpty())
  317. {
  318. OpenContainer(m_strCont, root);
  319. }
  320. return S_OK;
  321. }
  322. HTREEITEM CContainerSelectionDlg::OpenContainer(CString strCont, HTREEITEM rootSub)
  323. {
  324. int ndx = -1;
  325. CString strLeft, strRight;
  326. HTREEITEM tvItem = NULL;
  327. WCHAR sTemp[255];
  328. if ( !strCont.IsEmpty() && rootSub )
  329. {
  330. ndx = strCont.Find(L",", 0);
  331. if ( ndx > -1 )
  332. {
  333. // Get the right side of the comma string and Call this again to open the parent container.
  334. strLeft = strCont.Left(ndx);
  335. strRight = strCont.Mid(ndx + 1);
  336. tvItem = OpenContainer(strRight, rootSub);
  337. tvItem = OpenContainer(strLeft, tvItem);
  338. }
  339. else
  340. {
  341. // We have a container name so lets find it below rootSub node.
  342. wcscpy(sTemp,strCont);
  343. UnPadOUName(sTemp);
  344. strCont = CString(sTemp);
  345. tvItem = m_trOUTree.GetChildItem(rootSub);
  346. while (tvItem)
  347. {
  348. if ( m_trOUTree.GetItemText(tvItem) == strCont )
  349. {
  350. m_trOUTree.Expand(tvItem, 0);
  351. m_trOUTree.Select(tvItem, TVGN_CARET);
  352. break;
  353. }
  354. tvItem = m_trOUTree.GetNextSiblingItem(tvItem);
  355. }
  356. }
  357. }
  358. return tvItem;
  359. }
  360. HRESULT CContainerSelectionDlg::BrowseForContainer(HWND hWnd,//Handle to window that should own the browse dialog.
  361. LPOLESTR szRootPath, //Root of the browse tree. NULL for entire forest.
  362. LPOLESTR *ppContainerADsPath, //Return the ADsPath of the selected container.
  363. LPOLESTR *ppContainerClass //Return the ldapDisplayName of the container's class.
  364. )
  365. {
  366. HRESULT hr = E_FAIL;
  367. DSBROWSEINFO dsbi;
  368. OLECHAR szPath[1000];
  369. OLECHAR szClass[MAX_PATH];
  370. DWORD result;
  371. if (!ppContainerADsPath)
  372. return E_POINTER;
  373. ::ZeroMemory( &dsbi, sizeof(dsbi) );
  374. dsbi.hwndOwner = hWnd;
  375. dsbi.cbStruct = sizeof (DSBROWSEINFO);
  376. dsbi.pszCaption = L"Browse for Container"; // The caption (titlebar text)
  377. dsbi.pszTitle = L"Select a target container."; //Text for the dialog.
  378. dsbi.pszRoot = szRootPath; //ADsPath for the root of the tree to display in the browser.
  379. //Specify NULL with DSBI_ENTIREDIRECTORY flag for entire forest.
  380. //NULL without DSBI_ENTIREDIRECTORY flag displays current domain rooted at LDAP.
  381. dsbi.pszPath = szPath; //Pointer to a unicode string buffer.
  382. dsbi.cchPath = sizeof(szPath)/sizeof(OLECHAR);//count of characters for buffer.
  383. dsbi.dwFlags = DSBI_RETURN_FORMAT | //Return the path to object in format specified in dwReturnFormat
  384. DSBI_RETURNOBJECTCLASS; //Return the object class
  385. dsbi.pfnCallback = NULL;
  386. dsbi.lParam = 0;
  387. dsbi.dwReturnFormat = ADS_FORMAT_X500; //Specify the format.
  388. //This one returns an ADsPath. See ADS_FORMAT enum in IADS.H
  389. dsbi.pszObjectClass = szClass; //Pointer to a unicode string buffer.
  390. dsbi.cchObjectClass = sizeof(szClass)/sizeof(OLECHAR);//count of characters for buffer.
  391. //if root path is NULL, make the forest the root.
  392. if (!szRootPath)
  393. dsbi.dwFlags |= DSBI_ENTIREDIRECTORY;
  394. //Display browse dialog box.
  395. result = DsBrowseForContainerX( &dsbi ); // returns -1, 0, IDOK or IDCANCEL
  396. if (result == IDOK)
  397. {
  398. //Allocate memory for string
  399. *ppContainerADsPath = (OLECHAR *)CoTaskMemAlloc (sizeof(OLECHAR)*(wcslen(szPath)+1));
  400. if (*ppContainerADsPath)
  401. {
  402. wcscpy(*ppContainerADsPath, szPath);
  403. //Caller must free using CoTaskMemFree
  404. hr = S_OK;
  405. }
  406. else
  407. hr=E_FAIL;
  408. if (ppContainerClass)
  409. {
  410. //Allocate memory for string
  411. *ppContainerClass = (OLECHAR *)CoTaskMemAlloc (sizeof(OLECHAR)*(wcslen(szClass)+1));
  412. if (*ppContainerClass)
  413. {
  414. wcscpy(*ppContainerClass, szClass);
  415. //Call must free using CoTaskMemFree
  416. hr = S_OK;
  417. }
  418. else
  419. hr=E_FAIL;
  420. }
  421. }
  422. else
  423. hr = E_FAIL;
  424. return hr;
  425. }