//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1999 // // File: DSDirect.cpp // // Contents: ADSI wrapper object implementation // // History: 02-feb-97 jimharr Created // // //-------------------------------------------------------------------------- #include "stdafx.h" #include "resource.h" #include "dsutil.h" #include "dsdirect.h" #include "cmnquery.h" #include "dsquery.h" #include "dscache.h" #include "dssnap.h" #include "dsthread.h" #include "newobj.h" #include "querysup.h" #include #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define BAIL_IF_ERROR(hr) \ if (FAILED(hr)) { \ goto cleanup; \ }\ #define BAIL_ON_FAILURE(hr) \ if (FAILED(hr)) { \ goto error; \ }\ extern inline BOOL CleanName (LPWSTR pszObjectName) { WCHAR * ptr = NULL; ptr = wcschr (pszObjectName, L'=') + 1; //NTRAID#NTBUG9-571994-2002/03/10-jmessec 1) ptr is never null, since it is incremented in statement above. //NTRAID#NTBUG9-571994-2002/03/10-jmessec 2) wcscpy is undefined if source and dest buffers overlap //NTRAID#NTBUG9-571994-2002/03/10-jmessec 3) WTF? CleanName() changes string truncates everything to the left of, and including, //an equal sign? Poor naming convention //NTRAID#NTBUG9-571994-2002/03/10-jmessec 4) Possible localization issue? //NTRAID#NTBUG9-571994-2002/03/10-jmessec 5) Only cleans before the first instance of "="; is this intended behavior? //NTRAID#NTBUG9-571994-2002/03/10-jmessec 6) Appears to be dead code? //NTRAID#NTBUG9-571994-2002/03/10-jmessec 7) Possible NULL pointer dereference (pszObjectName) //NTRAID#NTBUG9-571994-2002/03/10-jmessec 8) dereferences ptr value = 1 if there is no "=" in the string if (ptr) { wcscpy (pszObjectName, ptr); return TRUE; } else return FALSE; } CDSDirect::CDSDirect() { ASSERT (FALSE); m_pCD = NULL; } // WARNING: pCD may still be in its constructor and may not be fully constructed yet CDSDirect::CDSDirect(CDSComponentData * pCD) { m_pCD = pCD; } CDSDirect::~CDSDirect() { } HRESULT CDSDirect::DeleteObject(CDSCookie* pCookie, BOOL raiseUI) { CComBSTR strParent; CComBSTR strThisRDN; CComPtr spDSContainer; CComPtr spDSObject; // bind to the ADSI object CString strPath; m_pCD->GetBasePathsInfo()->ComposeADsIPath(strPath, pCookie->GetPath()); HRESULT hr = DSAdminOpenObject(strPath, IID_IADs, (void **) &spDSObject, TRUE /*bServer*/); if (FAILED(hr)) { goto error; } // retrieve the parent's path hr = spDSObject->get_Parent(&strParent); if (FAILED(hr)) { goto error; } // get the RDN of this object hr = spDSObject->get_Name (&strThisRDN); if (FAILED(hr)) { goto error; } // bind to the parent ADSI object hr = DSAdminOpenObject(strParent, IID_IADsContainer, (void **) &spDSContainer, TRUE /*bServer*/); if (FAILED(hr)) { goto error; } hr = spDSContainer->Delete(CComBSTR(pCookie->GetClass()), CComBSTR(strThisRDN)); error: if ((!SUCCEEDED(hr)) & raiseUI) { HWND hwnd; m_pCD->m_pFrame->GetMainWindow(&hwnd); PVOID apv[1] = {(LPWSTR)pCookie->GetName()}; ReportErrorEx( m_pCD->m_hwnd, IDS_12_DELETE_FAILED, hr, MB_OK | MB_ICONERROR, apv, 1); } return hr; } HRESULT CDSDirect::GetParentDN(CDSCookie* pCookie, CString& szParentDN) { HRESULT hr = S_OK; CString szObjPath; CComPtr spDSObj; m_pCD->GetBasePathsInfo()->ComposeADsIPath(szObjPath, pCookie->GetPath()); hr = DSAdminOpenObject(szObjPath, IID_IADs, (void **)&spDSObj, TRUE /*bServer*/); if (SUCCEEDED(hr)) { CComBSTR ParentPath; hr = spDSObj->get_Parent(&ParentPath); StripADsIPath(ParentPath, szParentDN); } return hr; } /////////////////////////////////////////////////////////////////////////// // CSnapinMoveHandler class CSnapinMoveHandler : public CMoveHandlerBase { public: CSnapinMoveHandler(CDSComponentData* pComponentData, HWND hwnd, LPCWSTR lpszBrowseRootPath, CDSCookie* pCookie) : CMoveHandlerBase(pComponentData, hwnd, lpszBrowseRootPath) { m_pCookie = pCookie; } protected: virtual UINT GetItemCount() { return (UINT)1;} virtual HRESULT BeginTransaction() { return GetTransaction()->Begin(m_pCookie, GetDestPath(), GetDestClass(), IsDestContainer()); } virtual void GetNewPath(UINT, CString& szNewPath) { GetComponentData()->GetBasePathsInfo()->ComposeADsIPath(szNewPath, m_pCookie->GetPath()); } virtual void GetName(UINT, CString& strref) { strref = m_pCookie->GetName(); return; } virtual void GetItemPath(UINT, CString& szPath) { szPath = m_pCookie->GetPath(); } virtual PCWSTR GetItemClass(UINT) { return m_pCookie->GetClass(); } virtual HRESULT OnItemMoved(UINT, IADs* pIADs) { CComBSTR bsPath; HRESULT hr = pIADs->get_ADsPath(&bsPath); if (SUCCEEDED(hr)) { CString szPath; StripADsIPath(bsPath, szPath); m_pCookie->SetPath(szPath); } return hr; } virtual void GetClassOfMovedItem(CString& szClass) { szClass.Empty(); if (NULL != m_pCookie) szClass = m_pCookie->GetClass(); } private: CDSCookie* m_pCookie; }; HRESULT CDSDirect::MoveObject(CDSCookie *pCookie) { HWND hwnd; m_pCD->m_pFrame->GetMainWindow(&hwnd); HRESULT hr = S_OK; CString strPartialRootPath = m_pCD->GetRootPath(); if (SNAPINTYPE_SITE == m_pCD->QuerySnapinType()) { // This is where we correct the root path CPathCracker pathCracker; hr = pathCracker.Set(const_cast((LPCTSTR)strPartialRootPath), ADS_SETTYPE_DN); ASSERT( SUCCEEDED(hr) ); long cRootPathElements = 0; hr = pathCracker.GetNumElements( &cRootPathElements ); ASSERT( SUCCEEDED(hr) ); CComBSTR bstr = pCookie->GetPath(); hr = pathCracker.Set(bstr, ADS_SETTYPE_DN); ASSERT( SUCCEEDED(hr) ); long cCookiePathElements = 0; hr = pathCracker.GetNumElements( &cCookiePathElements ); ASSERT( SUCCEEDED(hr) ); // // Strip off all but one path element past the base config path // for (INT i = cCookiePathElements - cRootPathElements; i > 1; i--) { hr = pathCracker.RemoveLeafElement(); ASSERT( SUCCEEDED(hr) ); } hr = pathCracker.SetDisplayType(ADS_DISPLAY_FULL); ASSERT( SUCCEEDED(hr) ); hr = pathCracker.Retrieve( ADS_FORMAT_X500_DN, &bstr ); ASSERT( SUCCEEDED(hr) && bstr != NULL ); strPartialRootPath = bstr; } CString strRootPath = m_pCD->GetBasePathsInfo()->GetProviderAndServerName(); strRootPath += strPartialRootPath; CSnapinMoveHandler moveHandler(m_pCD, hwnd, strRootPath, pCookie); return moveHandler.Move(); } HRESULT CDSDirect::RenameObject(CDSCookie* pCookie, LPCWSTR NewName) { HRESULT hr = S_OK; IADs * pDSObject = NULL; IDispatch * pDispObj = NULL; IADsContainer * pContainer = NULL; CComBSTR bsParentPath; CString szNewAttrName; CString szNewNamingContext; CString szClass; CString szObjectPath, szNewPath; CString csNewName; CString szPath; CDSClassCacheItemBase* pItem = NULL; CComBSTR bsEscapedName; CPathCracker pathCracker; HWND hwnd; m_pCD->m_pFrame->GetMainWindow(&hwnd); // // create a transaction object, the destructor will call End() on it // CDSNotifyHandlerTransaction transaction(m_pCD); transaction.SetEventType(DSA_NOTIFY_REN); if (pCookie == NULL) { return E_INVALIDARG; } // // Retrieve class info from cache // szClass = pCookie->GetClass(); BOOL found = m_pCD->m_pClassCache->Lookup ((LPCWSTR)szClass, pItem); ASSERT (found == TRUE); csNewName = NewName; csNewName.TrimLeft(); csNewName.TrimRight(); // // get the new name in the form "cn=foo" or "ou=foo" // szNewAttrName = pItem->GetNamingAttribute(); szNewAttrName += L"="; szNewAttrName += csNewName; TRACE(_T("_RenameObject: Attributed name is %s.\n"), szNewAttrName); // // bind to object // m_pCD->GetBasePathsInfo()->ComposeADsIPath(szObjectPath, pCookie->GetPath()); hr = DSAdminOpenObject(szObjectPath, IID_IADs, (void **)&pDSObject, TRUE /*bServer*/); if (!SUCCEEDED(hr)) { goto error; } // // get the path of the object container // hr = pDSObject->get_Parent (&bsParentPath); if (!SUCCEEDED(hr)) { goto error; } pDSObject->Release(); pDSObject = NULL; // // bind to the object container // hr = DSAdminOpenObject(bsParentPath, IID_IADsContainer, (void **)&pContainer, TRUE /*bServer*/); if (!SUCCEEDED(hr)) { goto error; } // // build the new LDAP path // szNewNamingContext = szNewAttrName; szNewNamingContext += L","; StripADsIPath(bsParentPath, szPath); szNewNamingContext += szPath; m_pCD->GetBasePathsInfo()->ComposeADsIPath(szNewPath, szNewNamingContext); // // start the transaction // // It's ok for containerness to be determined from the cookie since we are concerned // whether the DS object is a container not whether it is a container in the UI // hr = transaction.Begin(pCookie, szNewPath, szClass, pCookie->IsContainerClass()); // // ask for confirmation // if (transaction.NeedNotifyCount() > 0) { CString szMessage, szAssocData; szMessage.LoadString(IDS_CONFIRM_RENAME); szAssocData.LoadString(IDS_EXTENS_RENAME); CThemeContextActivator activator; CConfirmOperationDialog dlg(hwnd, &transaction); dlg.SetStrings(szMessage, szAssocData); if (IDNO == dlg.DoModal()) { transaction.End(); hr = S_OK; goto error; } } hr = pathCracker.GetEscapedElement(0, //reserved (BSTR)(LPCWSTR)szNewAttrName, &bsEscapedName); if (FAILED(hr)) { goto error; } // // do the actual rename // hr = pContainer->MoveHere(CComBSTR(szObjectPath), CComBSTR(bsEscapedName), &pDispObj); if (SUCCEEDED(hr)) { transaction.Notify(0); // let extensions know } else { TRACE(_T("Object Rename Failed with hr: %lx\n"), hr); goto error; } // // rebuild the naming info for the cookie // hr = pDispObj->QueryInterface (IID_IADs, (void **)&pDSObject); if (SUCCEEDED(hr)) { CComBSTR bsPath; hr = pDSObject->get_ADsPath(&bsPath); if (SUCCEEDED(hr)) { StripADsIPath(bsPath, szPath); pCookie->SetPath(szPath); // // remove escaping from name // hr = pathCracker.Set((LPWSTR)bsPath, ADS_SETTYPE_FULL); ASSERT(SUCCEEDED(hr)); hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY); ASSERT(SUCCEEDED(hr)); hr = pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF_EX); ASSERT(SUCCEEDED(hr)); hr = pathCracker.GetElement( 0, &bsPath ); ASSERT(SUCCEEDED(hr)); pCookie->SetName((LPWSTR)bsPath); } } error: // // transaction.End() will be called by the transaction's destructor // // // clear pointers // if (pDispObj) { pDispObj->Release(); } if (pDSObject) { pDSObject->Release(); } return hr; } CDSComponentData* g_pCD = NULL; HRESULT CDSDirect::DSFind(HWND hwnd, LPCWSTR lpszBaseDN) { HRESULT hr; DSQUERYINITPARAMS dqip; OPENQUERYWINDOW oqw; ZeroMemory(&dqip, sizeof(DSQUERYINITPARAMS)); ZeroMemory(&oqw, sizeof(OPENQUERYWINDOW)); ICommonQuery * pCommonQuery = NULL; IDataObject * pDataObject = NULL; hr = CoCreateInstance(CLSID_CommonQuery, NULL, CLSCTX_INPROC_SERVER, IID_ICommonQuery, (PVOID *)&pCommonQuery); if (!SUCCEEDED(hr)) { ReportErrorEx( (m_pCD) ? m_pCD->m_hwnd : NULL, IDS_1_CANT_CREATE_FIND, hr, MB_OK | MB_ICONERROR, NULL, 0, FALSE); return hr; } CString szPath; m_pCD->GetBasePathsInfo()->ComposeADsIPath(szPath, lpszBaseDN); LPWSTR pszDefPath = (LPWSTR)(LPCWSTR)szPath; dqip.cbStruct = sizeof(dqip); dqip.dwFlags = DSQPF_NOSAVE | DSQPF_SHOWHIDDENOBJECTS | DSQPF_ENABLEADMINFEATURES; if (m_pCD->IsAdvancedView()) { dqip.dwFlags |= DSQPF_ENABLEADVANCEDFEATURES; } dqip.pDefaultScope = pszDefPath; dqip.pUserName = NULL; dqip.pPassword = NULL; dqip.pServer = (LPWSTR)(m_pCD->GetBasePathsInfo()->GetServerName()); dqip.dwFlags |= DSQPF_HASCREDENTIALS; oqw.cbStruct = sizeof(oqw); oqw.dwFlags = OQWF_SHOWOPTIONAL; oqw.clsidHandler = CLSID_DsQuery; oqw.pHandlerParameters = &dqip; // oqw.clsidDefaultForm = CLSID_NULL; g_pCD = m_pCD; HWND hwndHidden = m_pCD->GetHiddenWindow(); SetWindowText(hwndHidden,L"DS Find"); hr = pCommonQuery->OpenQueryWindow(hwnd, &oqw, &pDataObject); SetWindowText(hwndHidden, NULL); g_pCD = NULL; if (FAILED(hr)) { ReportErrorEx( m_pCD->m_hwnd, IDS_1_FIND_ERROR, hr, MB_OK | MB_ICONERROR, NULL, 0); } pCommonQuery->Release(); if (pDataObject) { pDataObject->Release(); } return hr; } HRESULT CDSDirect::EnumerateContainer(CDSThreadQueryInfo* pQueryInfo, CWorkerThread* pWorkerThread) { ASSERT(!pQueryInfo->m_bTooMuchData); ASSERT((pQueryInfo->GetType() == dsFolder) || (pQueryInfo->GetType() == queryFolder)); BEGIN_PROFILING_BLOCK("CDSDirect::EnumerateContainer"); HRESULT hr = S_OK; CString ADsPath; UINT nCurrCount = 0; UINT nMaxCount = pQueryInfo->GetMaxItemCount(); BOOL bOverLimit = FALSE; // // This wouldn't normally be the way to use the CPathCracker object // but for performance reasons we are going to create a single instance // for enumerating and pass a reference to the SetCookieFromData so // that we don't do a CoCreateInstance for each cookie // CPathCracker specialPerformancePathCracker; m_pCD->GetBasePathsInfo()->ComposeADsIPath(ADsPath, pQueryInfo->GetPath()); CDSSearch ContainerSrch(m_pCD->m_pClassCache, m_pCD); CDSColumnSet* pColumnSet = NULL; CString szPath; szPath = pQueryInfo->GetPath(); CPathCracker pathCracker; hr = pathCracker.Set(const_cast((LPCTSTR)szPath), ADS_SETTYPE_DN); if (SUCCEEDED(hr)) { CComBSTR bstrLeaf; hr = pathCracker.GetElement(0, &bstrLeaf); if (SUCCEEDED(hr)) { szPath = bstrLeaf; } } if (szPath.Find(_T("ForeignSecurityPrincipals")) != -1) { pColumnSet = m_pCD->FindColumnSet(L"ForeignSecurityPrincipals"); } else { pColumnSet = m_pCD->FindColumnSet(pQueryInfo->GetColumnSetID()); } ASSERT(pColumnSet != NULL); hr = ContainerSrch.Init (ADsPath); if (!SUCCEEDED(hr)) { TRACE(L"!!!search object init failed\n"); ASSERT(FALSE); goto exiting; } // CODEWORK this redoes the GetColumnsForClass calculation ContainerSrch.SetAttributeListForContainerClass (pColumnSet); ContainerSrch.SetFilterString ((LPWSTR)pQueryInfo->GetQueryString()); ContainerSrch.SetSearchScope(pQueryInfo->IsOneLevel() ? ADS_SCOPE_ONELEVEL : ADS_SCOPE_SUBTREE); hr = ContainerSrch.DoQuery(); if (FAILED(hr)) { TRACE(L"!!!search object DoQuery failed\n"); ASSERT(FALSE); goto exiting; } hr = ContainerSrch.GetNextRow (); while ((hr == S_OK) && !bOverLimit ) { CDSCookie* pNewCookie = new CDSCookie(); HRESULT hr2 = ContainerSrch.SetCookieFromData(pNewCookie, specialPerformancePathCracker, pColumnSet); if (SUCCEEDED(hr2)) { CDSUINode* pDSUINode = new CDSUINode(NULL); pDSUINode->SetCookie(pNewCookie); if (pQueryInfo->GetType() == dsFolder) { if (pNewCookie->IsContainerClass()) pDSUINode->MakeContainer(); } pWorkerThread->AddToQueryResult(pDSUINode); if (pWorkerThread->MustQuit()) break; } else { TRACE(L"!!!SetCookieFromData failed\n"); // NTRAID#NTBUG9-546301-2002/03/29-JeffJon-Do not ASSERT // here because SetCookieFromData will return a failure // code if we want to ignore a cookie. This happens when // there are inter-trust accounts or some group types associated // with the security roles //ASSERT(FALSE); delete pNewCookie; } hr = ContainerSrch.GetNextRow(); if (hr == S_OK) { nCurrCount++; if (nCurrCount >= nMaxCount) bOverLimit = TRUE; } } pQueryInfo->m_bTooMuchData = bOverLimit; exiting: END_PROFILING_BLOCK; return hr; } HRESULT CDSDirect::EnumerateRootContainer(CDSThreadQueryInfo* pQueryInfo, CWorkerThread* pWorkerThread) { ASSERT(pQueryInfo->GetType() == rootFolder); HRESULT hr = S_OK; m_pCD->Lock(); // // build the nodes below the root // if (m_pCD->QuerySnapinType() == SNAPINTYPE_SITE) { hr = CreateRootChild(TEXT("CN=Sites,"), pQueryInfo, pWorkerThread); if (!pWorkerThread->MustQuit() && m_pCD->ViewServicesNode()) { hr = CreateRootChild(TEXT("CN=Services,"), pQueryInfo, pWorkerThread); } } else { hr = CreateRootChild(TEXT(""), pQueryInfo, pWorkerThread); } if (m_pCD->m_CreateInfo.IsEmpty()) { InitCreateInfo(); } m_pCD->Unlock(); return hr; } HRESULT CDSDirect::CreateRootChild(LPCTSTR lpcszPrefix, CDSThreadQueryInfo* pQueryInfo, CWorkerThread* pWorkerThread) { TRACE(L"CDSDirect::CreateRootChild(%s)\n", lpcszPrefix); TRACE(L"pQueryInfo->GetPath() = %s\n", pQueryInfo->GetPath()); CString BasePath = lpcszPrefix; BasePath += pQueryInfo->GetPath(); CString ADsPath; m_pCD->GetBasePathsInfo()->ComposeADsIPath(OUT ADsPath, IN BasePath); // create a search object and bind to it CDSSearch Search(m_pCD->m_pClassCache, m_pCD); HRESULT hr = Search.Init(ADsPath); TRACE(L"Search.Init(%s) returned hr = 0x%x\n", (LPCWSTR)ADsPath, hr); if (FAILED(hr)) { return hr; } // // set query parameters // // Search for just this object // Search.SetSearchScope(ADS_SCOPE_BASE); CUIFolderInfo* pFolderInfo = m_pCD->GetRootNode()->GetFolderInfo(); if (pFolderInfo == NULL) { // // This shouldn't happen, but just to be on the safe side... // ASSERT(FALSE); Search.SetAttributeList((LPWSTR *)g_pStandardAttributes, g_nStdCols); } else { CDSColumnSet* pColumnSet = m_pCD->GetRootNode()->GetColumnSet(m_pCD); Search.SetAttributeListForContainerClass(pColumnSet); } Search.SetFilterString (L"(objectClass=*)"); // execute the query hr = Search.DoQuery(); TRACE(L"Search.DoQuery() returned hr = 0x%x\n", hr); if (FAILED(hr)) { return hr; } TRACE(L"Search.GetNextRow() returned hr = 0x%x\n", hr); hr = Search.GetNextRow(); if (FAILED(hr)) { return hr; } // // we got a query result, create a new cookie object // and initialize it from the query result // CDSCookie* pNewCookie = new CDSCookie; Search.SetCookieFromData(pNewCookie,NULL); TRACE(L"Got cookie, pNewCookie->GetName() = %s\n", pNewCookie->GetName()); // // special case if it is a domain DNS object, // we want fo get the canonical name for display // if (wcscmp(pNewCookie->GetClass(), L"domainDNS") == 0) { ADS_SEARCH_COLUMN Column; CString csCanonicalName; int slashLocation; LPWSTR canonicalNameAttrib = L"canonicalName"; Search.SetAttributeList (&canonicalNameAttrib, 1); hr = Search.DoQuery(); if (FAILED(hr)) { return hr; } hr = Search.GetNextRow(); if (FAILED(hr)) { return hr; } hr = Search.GetColumn(canonicalNameAttrib, &Column); if (FAILED(hr)) { return hr; } ColumnExtractString (csCanonicalName, pNewCookie, &Column); slashLocation = csCanonicalName.Find('/'); if (slashLocation != 0) { csCanonicalName = csCanonicalName.Left(slashLocation); } // pNewCookie->SetName(csCanonicalName); TRACE(L"canonical name pNewCookie->GetName() = %s\n", pNewCookie->GetName()); // // Free column data // Search.FreeColumn(&Column); } // // Add the new node to the result list CDSUINode* pDSUINode = new CDSUINode(NULL); pDSUINode->SetCookie(pNewCookie); if (pNewCookie->IsContainerClass()) pDSUINode->MakeContainer(); pWorkerThread->AddToQueryResult(pDSUINode); return S_OK; } //+---------------------------------------------------------------------------- // // Method: CDSDirect::InitCreateInfo // // Synopsis: read schema and finds all object names that for whom // defaultHidingValue is TRUE; // //----------------------------------------------------------------------------- HRESULT CDSDirect::InitCreateInfo(void) { HRESULT hr = S_OK; LPWSTR pAttrs[2] = {L"name", L"lDAPDisplayName"}; CDSSearch Search (m_pCD->GetClassCache(), m_pCD); ADS_SEARCH_COLUMN Column; CString csFilter; CString szSchemaPath; m_pCD->GetBasePathsInfo()->GetSchemaPath(szSchemaPath); Search.Init (szSchemaPath); csFilter = L"(&(objectCategory=CN=Class-Schema,"; csFilter += m_pCD->GetBasePathsInfo()->GetSchemaNamingContext(); csFilter += L")(defaultHidingValue=FALSE))"; Search.SetFilterString((LPWSTR)(LPCWSTR)csFilter); Search.SetAttributeList (pAttrs, 2); Search.SetSearchScope(ADS_SCOPE_ONELEVEL); hr = Search.DoQuery(); if (SUCCEEDED(hr)) { hr = Search.GetNextRow(); if(FAILED(hr)) { TRACE(_T("Search::GetNextRow failed \n")); goto error; } while (hr == S_OK) { hr = Search.GetColumn (pAttrs[1], &Column); if (SUCCEEDED(hr)) { if (!((!wcscmp(Column.pADsValues->CaseIgnoreString, L"builtinDomain")) || (!wcscmp(Column.pADsValues->CaseIgnoreString, L"localGroup")) || (!wcscmp(Column.pADsValues->CaseIgnoreString, L"domainDNS")) || (!wcscmp(Column.pADsValues->CaseIgnoreString, L"domain")) || (!wcscmp(Column.pADsValues->CaseIgnoreString, L"organization")) || (!wcscmp(Column.pADsValues->CaseIgnoreString, L"locality")))) { m_pCD->m_CreateInfo.AddTail (Column.pADsValues->CaseIgnoreString); TRACE(_T("added to createinfo: %s\n"), Column.pADsValues->CaseIgnoreString); } Search.FreeColumn (&Column); } else { goto error; } hr = Search.GetNextRow(); } } error: if (m_pCD->m_CreateInfo.IsEmpty()) { ReportErrorEx (m_pCD->m_hwnd,IDS_1_CANT_GET_SCHEMA_CREATE_INFO,hr, MB_OK | MB_ICONERROR, NULL, 0); } return hr; } HRESULT CDSDirect::ReadDSObjectCookie(IN CDSUINode* pContainerDSUINode, // IN: container where to create object IN LPCWSTR lpszLdapPath, // path of the object OUT CDSCookie** ppNewCookie) // newly created cookie { CComPtr spADs; HRESULT hr = DSAdminOpenObject(lpszLdapPath, IN IID_IADs, OUT (LPVOID *) &spADs, TRUE /*bServer*/); if (FAILED(hr)) { return hr; } return ReadDSObjectCookie(pContainerDSUINode, spADs, ppNewCookie); } HRESULT CDSDirect::ReadDSObjectCookie(IN CDSUINode* pContainerDSUINode, // IN: container where to create object IN IADs* pADs, // pointer to an already bound ADSI object OUT CDSCookie** ppNewCookie) // newly created cookie { ASSERT(pContainerDSUINode != NULL); ASSERT(pContainerDSUINode->IsContainer()); ASSERT(pADs != NULL); ASSERT(ppNewCookie != NULL); // create a new cookie and load data from the DS CDSCookie * pDsCookieNew = new CDSCookie(); CComPtr spDirSearch; CDSColumnSet* pColumnSet = pContainerDSUINode->GetColumnSet(m_pCD); ASSERT(pColumnSet != NULL); HRESULT hr = pADs->QueryInterface (IID_IDirectorySearch, (void **)&spDirSearch); ASSERT (hr == S_OK); CDSSearch Search(m_pCD->GetClassCache(), m_pCD); Search.Init(spDirSearch); Search.SetSearchScope(ADS_SCOPE_BASE); Search.SetAttributeListForContainerClass(pColumnSet); Search.SetFilterString (L"(objectClass=*)"); Search.DoQuery(); hr = Search.GetNextRow(); if (SUCCEEDED(hr) && (hr != S_ADS_NOMORE_ROWS)) { // we got the data, set the cookie Search.SetCookieFromData(pDsCookieNew, pColumnSet); *ppNewCookie = pDsCookieNew; pDsCookieNew = NULL; } if (pDsCookieNew != NULL) { delete pDsCookieNew; } return hr; } ///////////////////////////////////////////////////////////////////// // CDSDirect::CreateDSObject() // // Create a new ADs object. // HRESULT CDSDirect::CreateDSObject(CDSUINode* pContainerDSUINode, // IN: container where to create object LPCWSTR lpszObjectClass, // IN: class of the object to be created IN CDSUINode* pCopyFromDSUINode, // IN: (optional) object to be copied OUT CDSCookie** ppSUINodeNew) // OUT: OPTIONAL: Pointer to new node { CThemeContextActivator activator; ASSERT(pContainerDSUINode != NULL); ASSERT(pContainerDSUINode->IsContainer()); ASSERT(lpszObjectClass != NULL); ASSERT(ppSUINodeNew != NULL); CDSCookie* pContainerDsCookie = pContainerDSUINode->GetCookie(); ASSERT(pContainerDsCookie != NULL); CComPtr spIADsContainer; IADs* pIADs = NULL; CDSClassCacheItemBase* pDsCacheItem = NULL; HRESULT hr; // Data structure to hold temporary attribute information to create object CNewADsObjectCreateInfo createinfo(m_pCD->GetBasePathsInfo(), lpszObjectClass); { CWaitCursor wait; CString strContainerADsIPath; m_pCD->GetBasePathsInfo()->ComposeADsIPath(strContainerADsIPath, pContainerDsCookie->GetPath()); hr = DSAdminOpenObject(strContainerADsIPath, IN IID_IADsContainer, OUT (LPVOID *) &spIADsContainer, TRUE /*bServer*/); if (FAILED(hr)) { PVOID apv[1] = {(LPWSTR)pContainerDsCookie->GetName()}; ReportErrorEx (m_pCD->m_hwnd,IDS_12_CONTAINER_NOT_FOUND,hr, MB_OK | MB_ICONERROR, apv, 1); hr = S_FALSE; // Avoid display another error message to user goto CleanUp; } // Lookup if the object classname is in the cache pDsCacheItem = m_pCD->GetClassCache()->FindClassCacheItem(m_pCD, lpszObjectClass, NULL); ASSERT(pDsCacheItem != NULL); } createinfo.SetContainerInfo(IN spIADsContainer, IN pDsCacheItem, IN m_pCD); if (pCopyFromDSUINode != NULL) { CDSCookie* pCopyFromDsCookie = pCopyFromDSUINode->GetCookie(); CComPtr spIADsCopyFrom; CString szPath; m_pCD->GetBasePathsInfo()->ComposeADsIPath(szPath, pCopyFromDsCookie->GetPath()); hr = createinfo.SetCopyInfo(szPath); if (FAILED(hr)) { PVOID apv[1] = {(LPWSTR)pCopyFromDsCookie->GetName()}; ReportErrorEx (m_pCD->m_hwnd,IDS_12_COPY_READ_FAILED,hr, MB_OK | MB_ICONERROR, apv, 1); hr = S_FALSE; // Avoid display another error message to user goto CleanUp; } } hr = createinfo.HrLoadCreationInfo(); if (FAILED(hr)) { goto CleanUp; } // launch the creation DS object creation wizard hr = createinfo.HrDoModal(m_pCD->m_hwnd); // now examine the results of the call pIADs = createinfo.PGetIADsPtr(); if (hr != S_OK) { // Object was not created because user hit "Cancel" or an error occured. goto CleanUp; } if (pIADs == NULL) { TRACE0("ERROR: Inconsistency between return value from HrDoModal() and IADs pointer.\n"); ReportErrorEx (m_pCD->m_hwnd,IDS_ERR_FATAL,S_OK, MB_OK | MB_ICONERROR, NULL, 0); hr = S_FALSE; // Avoid display another error message to user goto CleanUp; } // successful creation, we need to create a node object for the UI if (pContainerDSUINode->GetFolderInfo()->IsExpanded()) { ReadDSObjectCookie(pContainerDSUINode, pIADs, ppSUINodeNew); } // if expanded CleanUp: if (FAILED(hr)) { CString Name; Name = createinfo.GetName(); PVOID apv[1] = {(LPWSTR)(LPCWSTR)Name}; ReportErrorEx (m_pCD->m_hwnd,IDS_12_GENERIC_CREATION_FAILURE,hr, MB_OK | MB_ICONERROR, apv, 1); } if (pIADs != NULL) pIADs->Release(); return hr; }