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.

557 lines
15 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1998
  6. //
  7. // File: dcbufmgr.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "stdafx.h"
  11. #include "dscmn.h" // Smart_DsHandle
  12. #include "dcbufmgr.h"
  13. #include "process.h"
  14. #ifdef _DEBUG
  15. #define new DEBUG_NEW
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19. #define DSGETDCINFO_LEVEL_1 1
  20. unsigned __stdcall GetDCThreadFunc( void* lParam );
  21. //+---------------------------------------------------------------------------
  22. //
  23. // Function: CDCBufferManager::CDCBufferManager
  24. //
  25. // Synopsis: constructor
  26. //
  27. //----------------------------------------------------------------------------
  28. CDCBufferManager::CDCBufferManager(HWND hDlg) :
  29. m_cRef(0), m_hDlg(hDlg)
  30. {
  31. TRACE(_T("CDCBufferManager::CDCBufferManager, this=%x\n"), this);
  32. m_lContinue = 1;
  33. }
  34. //+---------------------------------------------------------------------------
  35. //
  36. // Function: CDCBufferManager::~CDCBufferManager
  37. //
  38. // Synopsis: destructor
  39. //
  40. //----------------------------------------------------------------------------
  41. CDCBufferManager::~CDCBufferManager()
  42. {
  43. TRACE(_T("CDCBufferManager::~CDCBufferManager, this=%x\n"), this);
  44. ASSERT(0 >= m_cRef);
  45. FreeBuffer();
  46. }
  47. //+---------------------------------------------------------------------------
  48. //
  49. // Function: CDCBufferManager::CreateInstance
  50. //
  51. // Synopsis: Create an instance of CDCBufferManager.
  52. //
  53. //----------------------------------------------------------------------------
  54. HRESULT
  55. CDCBufferManager::CreateInstance(
  56. IN HWND hDlg,
  57. OUT CDCBufferManager **ppDCBufferManager
  58. )
  59. {
  60. TRACE(_T("CDCBufferManager::CreateInstance, hDlg=%x\n"), hDlg);
  61. ASSERT(ppDCBufferManager);
  62. *ppDCBufferManager = new CDCBufferManager(hDlg);
  63. if ( !(*ppDCBufferManager) )
  64. return E_OUTOFMEMORY;
  65. (*ppDCBufferManager)->AddRef();
  66. return S_OK;
  67. }
  68. //+---------------------------------------------------------------------------
  69. //
  70. // Function: CDCBufferManager::AddRef
  71. //
  72. // Synopsis: Increment reference count of this instance
  73. //
  74. //----------------------------------------------------------------------------
  75. LONG
  76. CDCBufferManager::AddRef()
  77. {
  78. TRACE(_T("CDCBufferManager::AddRef, this=%x, preValue=%d\n"), this, m_cRef);
  79. return InterlockedIncrement(&m_cRef);
  80. }
  81. //+---------------------------------------------------------------------------
  82. //
  83. // Function: CDCBufferManager::Release
  84. //
  85. // Synopsis: Decrement reference count of this instance.
  86. // When the reference count reaches 0, delete this instance.
  87. //
  88. //----------------------------------------------------------------------------
  89. LONG
  90. CDCBufferManager::Release()
  91. {
  92. TRACE(_T("CDCBufferManager::Release, this=%x, preValue=%d\n"), this, m_cRef);
  93. if (InterlockedDecrement(&m_cRef) <= 0)
  94. {
  95. delete this;
  96. return 0;
  97. }
  98. return m_cRef;
  99. }
  100. //+---------------------------------------------------------------------------
  101. //
  102. // Function: CDCBufferManager::SignalExit
  103. //
  104. // Synopsis: Called by the owner dialog to signal the related threads to exit.
  105. //
  106. //----------------------------------------------------------------------------
  107. void
  108. CDCBufferManager::SignalExit()
  109. {
  110. TRACE(_T("CDCBufferManager::SignalExit\n"));
  111. InterlockedExchange(&m_lContinue, FALSE);
  112. }
  113. //+---------------------------------------------------------------------------
  114. //
  115. // Function: CDCBufferManager::ShouldExit
  116. //
  117. // Synopsis: Threads are calling this function periodically to see
  118. // if the owner dialog signals them to exit.
  119. //
  120. //----------------------------------------------------------------------------
  121. BOOL
  122. CDCBufferManager::ShouldExit()
  123. {
  124. TRACE(_T("CDCBufferManager::ShouldExit %d\n"), !m_lContinue);
  125. return (!m_lContinue);
  126. }
  127. //+---------------------------------------------------------------------------
  128. //
  129. // Function: CDCBufferManager::LoadInfo
  130. //
  131. // Synopsis: The Owner dialog call it to get a pointer to the info of the specified domain.
  132. // The buffer consists of entries.
  133. // Each entry is in the form of (LPTSTR szDomainName, CDCSITEINFO* pEntry).
  134. //
  135. // LoadInfo() will first look up in the buffer.
  136. // If a valid entry is found, pass back pEntry to caller.
  137. // If an error entry is found, reset it (clear the error) and retry.
  138. // If an inprogress entry is found, do nothing. The caller will handle a THREAD_DONE later.
  139. // If no entry in the buffer, create a new entry, kick off a thread.
  140. //
  141. // When the owner dialog get THREAD_DONE message, the related entry
  142. // in the buffer should either be a valid entry or an error entry.
  143. //
  144. //----------------------------------------------------------------------------
  145. HRESULT
  146. CDCBufferManager::LoadInfo(
  147. IN PCTSTR pszDomainDnsName,
  148. OUT CDCSITEINFO **ppInfo
  149. )
  150. {
  151. ASSERT(pszDomainDnsName);
  152. ASSERT(*pszDomainDnsName);
  153. ASSERT(ppInfo);
  154. ASSERT(*ppInfo == NULL); // prevent memory leak
  155. TRACE(_T("CDCBufferManager::LoadInfo for %s\n"), pszDomainDnsName);
  156. BOOL bStartNewThread = FALSE;
  157. HRESULT hr = S_OK;
  158. PVOID ptr = NULL;
  159. CDCSITEINFO* pEntry = NULL;
  160. m_CriticalSection.Lock(); // Lock buffer
  161. if (m_map.Lookup(pszDomainDnsName, ptr))
  162. {
  163. //
  164. // Found an entry in the buffer.
  165. //
  166. if (ptr)
  167. {
  168. pEntry = (CDCSITEINFO*)ptr;
  169. switch (pEntry->GetEntryType())
  170. {
  171. case BUFFER_ENTRY_TYPE_VALID:
  172. // return the valid entry pointer
  173. *ppInfo = pEntry;
  174. break;
  175. case BUFFER_ENTRY_TYPE_ERROR:
  176. // kick off a thread to retry
  177. pEntry->ReSet();
  178. bStartNewThread = TRUE;
  179. break;
  180. case BUFFER_ENTRY_TYPE_INPROGRESS:
  181. // do nothing
  182. break;
  183. }
  184. }
  185. } else
  186. {
  187. //
  188. // not found in the buffer, need to start a new thread
  189. //
  190. bStartNewThread = TRUE;
  191. pEntry = new CDCSITEINFO();
  192. if (pEntry)
  193. m_map.SetAt(pszDomainDnsName, pEntry);
  194. else
  195. hr = E_OUTOFMEMORY;
  196. }
  197. if (SUCCEEDED(hr) && bStartNewThread)
  198. {
  199. hr = StartThread(pszDomainDnsName);
  200. if (FAILED(hr))
  201. {
  202. delete pEntry;
  203. m_map.RemoveKey(pszDomainDnsName);
  204. }
  205. }
  206. m_CriticalSection.Unlock(); // Unlock buffer
  207. return hr;
  208. }
  209. //+---------------------------------------------------------------------------
  210. //
  211. // Function: CDCBufferManager::AddInfo
  212. //
  213. // Synopsis: Called by the thread function to add one result to the buffer.
  214. // It will pass back the pointer to the entry in the 5th parameters.
  215. //
  216. //----------------------------------------------------------------------------
  217. HRESULT
  218. CDCBufferManager::AddInfo(
  219. IN PCTSTR pszDomainDnsName,
  220. IN DWORD cInfo,
  221. IN PVOID pDCInfo,
  222. IN HRESULT hr,
  223. OUT PVOID* ppv
  224. )
  225. {
  226. ASSERT(pszDomainDnsName);
  227. ASSERT(*pszDomainDnsName);
  228. ASSERT(ppv);
  229. ASSERT(*ppv == NULL); // prevent memory leak
  230. TRACE(_T("CDCBufferManager::AddInfo for %s, cInfo=%d, hr=%x\n"),
  231. pszDomainDnsName, cInfo, hr);
  232. PVOID p = NULL;
  233. m_CriticalSection.Lock(); // Lock buffer
  234. //
  235. // the entry must have been existed with a non-NULL pointer
  236. //
  237. m_map.Lookup(pszDomainDnsName, p);
  238. ASSERT(p);
  239. ((CDCSITEINFO*)p)->SetEntry(pszDomainDnsName, cInfo, pDCInfo, hr);
  240. m_CriticalSection.Unlock(); // Unlock buffer
  241. *ppv = p;
  242. return hr;
  243. }
  244. //+---------------------------------------------------------------------------
  245. //
  246. // Function: CDCBufferManager::FreeBuffer
  247. //
  248. // Synopsis: Clear m_map.
  249. // This member holds all the results returned by various threads
  250. // since the initialization of the owner dialog. Each one is
  251. // in the form of (DomainName ==> CDCSITEINFO*)
  252. //
  253. //----------------------------------------------------------------------------
  254. void
  255. CDCBufferManager::FreeBuffer()
  256. {
  257. CString csDomainDnsName;
  258. PVOID ptr = NULL;
  259. m_CriticalSection.Lock(); // Lock buffer
  260. for (POSITION pos = m_map.GetStartPosition(); pos; )
  261. {
  262. m_map.GetNextAssoc(pos, csDomainDnsName, ptr);
  263. if (ptr)
  264. delete ((CDCSITEINFO*)ptr);
  265. }
  266. m_map.RemoveAll();
  267. m_CriticalSection.Unlock(); // Unlock buffer
  268. }
  269. //+---------------------------------------------------------------------------
  270. //
  271. // Function: CDCBufferManager::ThreadReport
  272. //
  273. // Synopsis: Report THREAD_DONE to the owner dialog.
  274. //
  275. //----------------------------------------------------------------------------
  276. void
  277. CDCBufferManager::ThreadReport(
  278. IN PVOID ptr,
  279. IN HRESULT hr
  280. )
  281. {
  282. ASSERT(ptr);
  283. TRACE(_T("CDCBufferManager::ThreadReport ptr=%x, hr=%x\n"), ptr, hr);
  284. PostMessage(m_hDlg, WM_USER_GETDC_THREAD_DONE,
  285. reinterpret_cast<WPARAM>(ptr), hr);
  286. }
  287. /////////////////////////////////////////////////////////
  288. //
  289. // thread info structure
  290. typedef struct _GetDCThreadInfo
  291. {
  292. PTSTR pszDomainDnsName;
  293. CDCBufferManager *pDCBufferManager;
  294. } GETDCTHREADINFO;
  295. //+---------------------------------------------------------------------------
  296. //
  297. // Function: CDCBufferManager::StartThread
  298. //
  299. // Synopsis: Start a thread.
  300. //
  301. // Pass the following info to the thread function:
  302. //
  303. // pszDomainDnsName:
  304. // domain we need to get a list of DCs for.
  305. // pDCBufferManager:
  306. // the CDCBufferManager instance for the ThreadFunc to
  307. // add result to the buffer
  308. //
  309. //----------------------------------------------------------------------------
  310. HRESULT
  311. CDCBufferManager::StartThread(
  312. IN PCTSTR pszDomainDnsName
  313. )
  314. {
  315. ASSERT(pszDomainDnsName);
  316. ASSERT(*pszDomainDnsName);
  317. TRACE(_T("CDCBufferManager::StartThread for %s\n"), pszDomainDnsName);
  318. GETDCTHREADINFO *pThreadInfo = new GETDCTHREADINFO;
  319. if (!pThreadInfo)
  320. return E_OUTOFMEMORY;
  321. pThreadInfo->pszDomainDnsName = _tcsdup(pszDomainDnsName);
  322. if ( !(pThreadInfo->pszDomainDnsName) )
  323. {
  324. delete pThreadInfo;
  325. return E_OUTOFMEMORY;
  326. }
  327. pThreadInfo->pDCBufferManager = this;
  328. AddRef();
  329. unsigned threadID;
  330. HANDLE pThread = (HANDLE)_beginthreadex(
  331. NULL, //void *security,
  332. 0, //unsigned stack_size,
  333. &GetDCThreadFunc, //unsigned ( __stdcall *start_address )( void * ),
  334. (void *)pThreadInfo, //void *arglist,
  335. 0, //unsigned initflag,
  336. &threadID //unsigned *thrdaddr
  337. );
  338. if (!pThread)
  339. {
  340. free(pThreadInfo->pszDomainDnsName);
  341. delete pThreadInfo;
  342. Release();
  343. return E_FAIL;
  344. }
  345. return S_OK;
  346. }
  347. //+---------------------------------------------------------------------------
  348. //
  349. // Function: GetDCThreadFunc
  350. //
  351. // Synopsis: The GetDC Thread Function.
  352. // This function invokes DsGetDomainControllerInfo() to get a list
  353. // of DCs in the specified domain, and add them to the buffer of
  354. // CDCBufferManager instance.
  355. // This function regularly checks to see if the owner dialog signals
  356. // it to exit, if not, it will finish its normal operation and
  357. // post a THREAD_DONE message to the owner dialog.
  358. //
  359. //----------------------------------------------------------------------------
  360. unsigned __stdcall GetDCThreadFunc( void* lParam )
  361. {
  362. GETDCTHREADINFO *pThreadInfo = reinterpret_cast<GETDCTHREADINFO *>(lParam);
  363. ASSERT(pThreadInfo);
  364. ASSERT(pThreadInfo->pszDomainDnsName);
  365. ASSERT(*(pThreadInfo->pszDomainDnsName));
  366. ASSERT(pThreadInfo->pDCBufferManager);
  367. TRACE(_T("GetDCThreadFunc pszDomainDnsName=%s, pDCBufferManager=%x\n"),
  368. pThreadInfo->pszDomainDnsName, pThreadInfo->pDCBufferManager);
  369. //
  370. // retrieve information passed into this function
  371. //
  372. CString csDomain = pThreadInfo->pszDomainDnsName;
  373. CDCBufferManager *pDCBufferManager = pThreadInfo->pDCBufferManager;
  374. free(pThreadInfo->pszDomainDnsName);
  375. delete pThreadInfo;
  376. PVOID pEntry = NULL;
  377. DWORD cInfo = 0;
  378. PDS_DOMAIN_CONTROLLER_INFO_1 pInfo = NULL;
  379. DWORD dwErr = 0;
  380. HRESULT hr = S_OK;
  381. Smart_DsHandle shDs; // smart pointer, will Unbind automatically
  382. if (pDCBufferManager->ShouldExit())
  383. goto Thread_Exit;
  384. dwErr = DsBind(NULL, const_cast<LPTSTR>(static_cast<LPCTSTR>(csDomain)), &shDs);
  385. if (pDCBufferManager->ShouldExit())
  386. goto Thread_Exit;
  387. if (ERROR_SUCCESS != dwErr) {
  388. // DsBind() failed.
  389. // Add an error entry in the buffer.
  390. hr = HRESULT_FROM_WIN32(dwErr);
  391. pDCBufferManager->AddInfo(csDomain, 0, NULL, hr, &pEntry);
  392. goto Thread_Exit;
  393. }
  394. dwErr = DsGetDomainControllerInfo(
  395. shDs, // HANDLE hDs
  396. const_cast<LPTSTR>(static_cast<LPCTSTR>(csDomain)), // LPTSTR DomainName
  397. DSGETDCINFO_LEVEL_1, // DWORD InfoLevel
  398. &cInfo, // DWORD *pcOut
  399. reinterpret_cast<VOID **>(&pInfo) // VOID **ppInfo
  400. );
  401. if (pDCBufferManager->ShouldExit())
  402. {
  403. if ((ERROR_SUCCESS == dwErr) && pInfo)
  404. DsFreeDomainControllerInfo(DSGETDCINFO_LEVEL_1, cInfo, pInfo);
  405. goto Thread_Exit;
  406. }
  407. if (ERROR_SUCCESS != dwErr) {
  408. // DsGetDomainControllerInfo() failed.
  409. // Add an error entry in the buffer
  410. hr = HRESULT_FROM_WIN32(dwErr);
  411. pDCBufferManager->AddInfo(csDomain, 0, NULL, hr, &pEntry);
  412. goto Thread_Exit;
  413. }
  414. //
  415. // Add result to the buffer in CDCBufferManager
  416. //
  417. hr = pDCBufferManager->AddInfo(csDomain, cInfo, pInfo, S_OK, &pEntry);
  418. if (FAILED(hr))
  419. DsFreeDomainControllerInfo(DSGETDCINFO_LEVEL_1, cInfo, pInfo);
  420. Thread_Exit:
  421. if (FALSE == pDCBufferManager->ShouldExit())
  422. {
  423. //
  424. // report THREAD_DONE with the pointer to the entry
  425. //
  426. if (pEntry)
  427. pDCBufferManager->ThreadReport(pEntry, hr);
  428. }
  429. //
  430. // Decrement the reference count on the CDCBufferManager instance
  431. //
  432. pDCBufferManager->Release();
  433. return 0;
  434. }
  435. ///////////////////////////////////////////////
  436. // class CDCSITEINFO
  437. CDCSITEINFO::CDCSITEINFO()
  438. {
  439. m_csDomainName.Empty();
  440. m_cInfo = 0;
  441. m_pDCInfo = NULL;
  442. m_hr = S_OK;
  443. }
  444. CDCSITEINFO::~CDCSITEINFO()
  445. {
  446. if (m_pDCInfo)
  447. DsFreeDomainControllerInfo(DSGETDCINFO_LEVEL_1, m_cInfo, m_pDCInfo);
  448. }
  449. void
  450. CDCSITEINFO::SetEntry(LPCTSTR pszDomainName, DWORD cInfo, PVOID pDCInfo, HRESULT hr)
  451. {
  452. m_csDomainName = pszDomainName;
  453. m_cInfo = cInfo;
  454. m_pDCInfo = (PDS_DOMAIN_CONTROLLER_INFO_1)pDCInfo;
  455. m_hr = hr;
  456. }
  457. enum BUFFER_ENTRY_TYPE
  458. CDCSITEINFO::GetEntryType()
  459. {
  460. if (FAILED(m_hr))
  461. return BUFFER_ENTRY_TYPE_ERROR;
  462. if (m_cInfo == 0 || m_pDCInfo == NULL)
  463. return BUFFER_ENTRY_TYPE_INPROGRESS;
  464. return BUFFER_ENTRY_TYPE_VALID;
  465. }
  466. void
  467. CDCSITEINFO::ReSet()
  468. {
  469. ASSERT(GetEntryType() == BUFFER_ENTRY_TYPE_ERROR);
  470. m_hr = S_OK;
  471. ASSERT(GetEntryType() == BUFFER_ENTRY_TYPE_INPROGRESS);
  472. }