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.

556 lines
14 KiB

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