345 lines
8.7 KiB
C++
345 lines
8.7 KiB
C++
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
#include "docfind.h"
|
|
#include "dsgetdc.h"
|
|
#include "ntdsapi.h"
|
|
#include "activeds.h"
|
|
#include "iadsp.h"
|
|
#include "lm.h"
|
|
|
|
#ifdef WINNT
|
|
|
|
|
|
// search the DS for computer objects
|
|
|
|
|
|
// BUGBUG: this should be const, but ADSI
|
|
LPTSTR c_aszAttributes[] = { TEXT("DNShostname"), };
|
|
|
|
class CNetFindInDS : public IDFEnum
|
|
{
|
|
private:
|
|
LPTSTR _pszCompName;
|
|
IDocFindFolder *_pdfFolder;
|
|
|
|
LONG _cRef;
|
|
IDirectorySearch* _pds;
|
|
IADsPathname* _padp;
|
|
ADS_SEARCH_HANDLE _hSearch;
|
|
|
|
// helper methods
|
|
HRESULT _StrFromRow(LPTSTR pszProperty, LPTSTR pszBuffer, INT cchBuffer);
|
|
HRESULT _InitSearch(LPCTSTR pszName);
|
|
|
|
public:
|
|
CNetFindInDS(LPCTSTR pszCompName, IShellFolder *psf);
|
|
~CNetFindInDS();
|
|
|
|
// *** IUnknown methods ***
|
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
|
STDMETHODIMP_(ULONG) AddRef();
|
|
STDMETHODIMP_(ULONG) Release();
|
|
|
|
// *** IDFEnum methods ***
|
|
STDMETHODIMP Next(LPITEMIDLIST *ppidl,
|
|
int *pcObjectSearched, int *pcFoldersSearched, BOOL *pfContinue,
|
|
int *pState, HWND hwnd);
|
|
|
|
STDMETHODIMP Skip(int celt)
|
|
{ return E_NOTIMPL; };
|
|
|
|
STDMETHODIMP Reset()
|
|
{ return E_NOTIMPL; };
|
|
|
|
STDMETHODIMP StopSearch()
|
|
{ return E_NOTIMPL; };
|
|
|
|
STDMETHODIMP_(BOOL) FQueryIsAsync()
|
|
{ return FALSE; };
|
|
|
|
STDMETHODIMP GetAsyncCount(DBCOUNTITEM *pdwTotalAsync, int *pnPercentComplete, BOOL *pfQueryDone)
|
|
{ return E_NOTIMPL; };
|
|
|
|
STDMETHODIMP GetItemIDList(UINT iItem, LPITEMIDLIST *ppidl)
|
|
{ return E_NOTIMPL; };
|
|
|
|
STDMETHODIMP GetExtendedDetailsOf(LPCITEMIDLIST pidl, UINT iCol, LPSHELLDETAILS pdi)
|
|
{ return E_NOTIMPL; };
|
|
|
|
STDMETHODIMP GetExtendedDetailsULong(LPCITEMIDLIST pidl, UINT iCol, ULONG *pul)
|
|
{ return E_NOTIMPL; };
|
|
|
|
STDMETHODIMP GetItemID(UINT iItem, DWORD *puWorkID)
|
|
{ return E_NOTIMPL; };
|
|
|
|
STDMETHODIMP SortOnColumn(UINT iCol, BOOL fAscending)
|
|
{ return E_NOTIMPL; };
|
|
};
|
|
|
|
|
|
|
|
// IUnknown
|
|
|
|
|
|
STDMETHODIMP CNetFindInDS::QueryInterface(REFIID riid, void **ppv)
|
|
{
|
|
static const QITAB qit[] =
|
|
{
|
|
{ 0 },
|
|
};
|
|
|
|
return QISearch(this, qit, riid, ppv);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNetFindInDS::AddRef()
|
|
{
|
|
return InterlockedIncrement(&_cRef);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNetFindInDS::Release()
|
|
{
|
|
if (InterlockedDecrement(&_cRef))
|
|
return _cRef;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
// construction / destruction
|
|
|
|
|
|
CNetFindInDS::CNetFindInDS(LPCTSTR pszCompName, IShellFolder* psf) :
|
|
_pszCompName(NULL),
|
|
_pdfFolder(NULL),
|
|
_cRef(1),
|
|
_pds(NULL),
|
|
_hSearch(NULL)
|
|
{
|
|
Str_SetPtr(&_pszCompName, pszCompName);
|
|
psf->QueryInterface(IID_IDocFindFolder, (void **)&_pdfFolder);
|
|
}
|
|
|
|
CNetFindInDS::~CNetFindInDS()
|
|
{
|
|
Str_SetPtr(&_pszCompName, NULL);
|
|
|
|
if ( _hSearch )
|
|
_pds->CloseSearchHandle(_hSearch);
|
|
|
|
if ( _pds )
|
|
_pds->Release();
|
|
if ( _padp )
|
|
_padp->Release();
|
|
|
|
_pdfFolder->Release();
|
|
}
|
|
|
|
|
|
|
|
// given the ADS_SEARCH_COLUMN get a string back from it.
|
|
|
|
|
|
HRESULT CNetFindInDS::_StrFromRow(LPTSTR pszProperty, LPTSTR pszBuffer, INT cchBuffer)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
ADS_SEARCH_COLUMN asc;
|
|
|
|
hres = _pds->GetColumn(_hSearch, pszProperty, &asc);
|
|
if ( SUCCEEDED(hres) )
|
|
{
|
|
switch ( asc.dwADsType )
|
|
{
|
|
case ADSTYPE_DN_STRING:
|
|
case ADSTYPE_CASE_EXACT_STRING:
|
|
case ADSTYPE_CASE_IGNORE_STRING:
|
|
case ADSTYPE_PRINTABLE_STRING:
|
|
case ADSTYPE_NUMERIC_STRING:
|
|
StrCpyN(pszBuffer, asc.pADsValues[0].DNString, cchBuffer);
|
|
break;
|
|
|
|
default:
|
|
hres = E_INVALIDARG; // bad column type
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
|
|
// initialize the search ready with the path the GC:
|
|
|
|
|
|
HRESULT CNetFindInDS::_InitSearch(LPCTSTR pszName)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
PDOMAIN_CONTROLLER_INFO pdci = NULL;
|
|
|
|
|
|
// get the DNS of the domain forest we are part of
|
|
|
|
|
|
DWORD dwres = DsGetDcName(NULL, NULL, NULL, NULL, DS_RETURN_DNS_NAME|DS_DIRECTORY_SERVICE_REQUIRED, &pdci);
|
|
if ( (NO_ERROR == dwres) && pdci->DnsForestName )
|
|
{
|
|
TCHAR szBuffer[MAX_PATH];
|
|
wnsprintf(szBuffer, ARRAYSIZE(szBuffer), TEXT("GC://%s"), pdci->DnsForestName);
|
|
|
|
hres = ADsOpenObject(szBuffer,
|
|
NULL, NULL, ADS_SECURE_AUTHENTICATION,
|
|
IID_IDirectorySearch, (void **)&_pds);
|
|
|
|
if ( SUCCEEDED(hres) )
|
|
{
|
|
ADS_SEARCHPREF_INFO prefInfo[3];
|
|
|
|
|
|
// do a sub tree, async paged search.
|
|
|
|
|
|
prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; // sub-tree search
|
|
prefInfo[0].vValue.dwType = ADSTYPE_INTEGER;
|
|
prefInfo[0].vValue.Integer = ADS_SCOPE_SUBTREE;
|
|
|
|
prefInfo[1].dwSearchPref = ADS_SEARCHPREF_ASYNCHRONOUS; // async
|
|
prefInfo[1].vValue.dwType = ADSTYPE_BOOLEAN;
|
|
prefInfo[1].vValue.Boolean = TRUE;
|
|
|
|
prefInfo[2].dwSearchPref = ADS_SEARCHPREF_PAGESIZE; // paged results
|
|
prefInfo[2].vValue.dwType = ADSTYPE_INTEGER;
|
|
prefInfo[2].vValue.Integer = 32;
|
|
|
|
hres = _pds->SetSearchPreference(prefInfo, ARRAYSIZE(prefInfo));
|
|
if ( SUCCEEDED(hres) )
|
|
{
|
|
|
|
// build a filter that will find all the computer objects whose name starts
|
|
// or ends with the string we have been given, the DS is bad at "contains"
|
|
|
|
|
|
wnsprintf(szBuffer, ARRAYSIZE(szBuffer),
|
|
TEXT("(&(sAMAccountType=805306369)(|(SAMAccountName=%s*)(SAMAccountName=*%s)))"),
|
|
pszName, pszName);
|
|
|
|
hres = _pds->ExecuteSearch(szBuffer, c_aszAttributes, ARRAYSIZE(c_aszAttributes), &_hSearch);
|
|
}
|
|
}
|
|
|
|
NetApiBufferFree(pdci);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
|
|
// itterate over results from a DS search
|
|
|
|
|
|
STDMETHODIMP CNetFindInDS::Next(LPITEMIDLIST *ppidl, int *pcObjectSearched, int *pcFoldersSearched,
|
|
BOOL *pfContinue, int *pState, HWND hwnd)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
WCHAR szName[MAX_PATH], szUNC[MAX_PATH+2];
|
|
|
|
*pState = GNF_DONE;
|
|
*pfContinue = FALSE;
|
|
|
|
|
|
// if _hSearch == NULL then we have not searched yet, therefore initialize the
|
|
// query against the DS.
|
|
|
|
|
|
if ( !_hSearch )
|
|
hres = _InitSearch(_pszCompName);
|
|
|
|
while ( SUCCEEDED(hres) && _hSearch )
|
|
{
|
|
hres = _pds->GetNextRow(_hSearch);
|
|
if ( SUCCEEDED(hres) )
|
|
{
|
|
if ( (hres == S_ADS_NOMORE_ROWS) )
|
|
break;
|
|
|
|
*pcObjectSearched += 1; // we have another object
|
|
|
|
|
|
// get the DNSHostName of the object, this we can then use to construct a
|
|
// UNC name for the object. If this fails then we skip the result (the
|
|
// column may not be defined, or perhaps its not a string, eitherway
|
|
// we should ignore it).
|
|
|
|
|
|
if ( SUCCEEDED(_StrFromRow(TEXT("DNShostName"), szName, ARRAYSIZE(szName))) )
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
INT iFolder;
|
|
|
|
wnsprintf(szUNC, ARRAYSIZE(szUNC), TEXT("\\\\%s"), szName);
|
|
|
|
pidl = ILCreateFromPath(szUNC);
|
|
|
|
if ( !pidl )
|
|
continue;
|
|
|
|
LPITEMIDLIST pidlParent = ILCloneParent(pidl);
|
|
|
|
if (!pidlParent)
|
|
continue;
|
|
|
|
hres = _pdfFolder->AddFolderToFolderList(pidl, FALSE, &iFolder);
|
|
ILFree(pidlParent);
|
|
if ( SUCCEEDED(hres) )
|
|
{
|
|
// append attempts to resize an existing pidl
|
|
// it will return NULL on failure.
|
|
*ppidl = DocFind_AppendIFolder(ILClone(ILFindLastID(pidl)), iFolder);
|
|
|
|
if ( *ppidl )
|
|
{
|
|
ILFree(pidl);
|
|
*pState = GNF_MATCH;
|
|
*pfContinue = TRUE;
|
|
|
|
break; // success we have a result
|
|
}
|
|
}
|
|
|
|
ILFree(pidl);
|
|
ILFree(*ppidl);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// return an enumerator if the user is logged into the DS, if they are
|
|
// not then we return S_FALSE.
|
|
|
|
|
|
STDAPI CNetFindInDS_CreateInstance(LPCTSTR pszCompName, IShellFolder *psf, IDFEnum **ppdfe)
|
|
{
|
|
#ifdef WINNT
|
|
*ppdfe = NULL;
|
|
|
|
if ( !GetEnvironmentVariable(TEXT("USERDNSDOMAIN"), NULL, 0) )
|
|
return S_FALSE;
|
|
|
|
*ppdfe = new CNetFindInDS(pszCompName, psf);
|
|
if ( !*ppdfe )
|
|
return E_OUTOFMEMORY;
|
|
|
|
return S_OK;
|
|
#else
|
|
return S_FALSE; // S_FALSE == use old search
|
|
#endif
|
|
}
|