Leaked source code of windows server 2003
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.

617 lines
16 KiB

  1. // NetTree.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "NetTree.h"
  5. #include <strsafe.h>
  6. #ifdef _DEBUG
  7. #define new DEBUG_NEW
  8. #undef THIS_FILE
  9. static char THIS_FILE[] = __FILE__;
  10. #endif
  11. /////////////////////////////////////////////////////////////////////////////
  12. // Global variables
  13. extern TCHAR pszTreeEvent[];
  14. /////////////////////////////////////////////////////////////////////////////
  15. // CNetTreeCtrl
  16. CNetTreeCtrl::CNetTreeCtrl()
  17. : m_pThread(NULL), m_bExitThread(FALSE), m_event(TRUE, TRUE, pszTreeEvent)
  18. {
  19. // Get a handle to the process heap
  20. m_hHeap = ::GetProcessHeap();
  21. ASSERT(m_hHeap != NULL);
  22. }
  23. CNetTreeCtrl::~CNetTreeCtrl()
  24. {
  25. // Make sure the thread knows it's time to terminate.
  26. NotifyThread(TRUE);
  27. // Create an event object to match the tree thread event object.
  28. CEvent event(TRUE, TRUE, pszTreeEvent);
  29. // Create a lock object for the event object.
  30. CSingleLock lock(&event);
  31. // Lock the lock object and make the main thread wait for the
  32. // threads to signal their event objects.
  33. lock.Lock();
  34. // Free all of the pointers to LPTSTRs in the list
  35. POSITION pos = m_ptrlistStrings.GetHeadPosition();
  36. while (pos != NULL)
  37. {
  38. // Memory deallocation fails if there's a null char
  39. // at the end of the string.
  40. LPTSTR psz = m_ptrlistStrings.GetNext(pos);
  41. *(::_tcslen(psz) + psz) = (TCHAR)0xFD;
  42. delete[] psz;
  43. }
  44. // Free all of the pointers to NETRESOURCE structs in the list
  45. pos = m_ptrlistContainers.GetHeadPosition();
  46. while (pos != NULL)
  47. {
  48. delete m_ptrlistContainers.GetNext(pos);
  49. }
  50. }
  51. BEGIN_MESSAGE_MAP(CNetTreeCtrl, CTreeCtrl)
  52. //{{AFX_MSG_MAP(CNetTreeCtrl)
  53. ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemExpanding)
  54. ON_WM_SETCURSOR()
  55. ON_WM_DESTROY()
  56. //}}AFX_MSG_MAP
  57. END_MESSAGE_MAP()
  58. /////////////////////////////////////////////////////////////////////////////
  59. // Static member functions
  60. UINT CNetTreeCtrl::FillTree(LPVOID pParam)
  61. {
  62. CEvent event(TRUE, TRUE, pszTreeEvent);
  63. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
  64. PTREEINFO pti = (PTREEINFO)pParam;
  65. CNetTreeCtrl* pTree = (CNetTreeCtrl*)pti->pTree;
  66. BOOL bResult = FALSE;
  67. DWORD dwEntries = 0xFFFFFFFF;
  68. LPVOID lpvBuffer = NULL;
  69. HANDLE hEnum = NULL;
  70. // Because this function may call itself, keep a usage count
  71. // so that pti is freed only when the first instance returns.
  72. static USHORT uUsage = 0;
  73. // Keep a handle to the heap in case the CNetTreeCtrl object
  74. // goes away before the thread ends.
  75. HANDLE hHeap = pTree->m_hHeap;
  76. DWORD dwResult;
  77. LPNETRESOURCE pnrRoot;
  78. HTREEITEM hTreeItem, hTreeExpand;
  79. HRESULT hr;
  80. hTreeItem = hTreeExpand = NULL;
  81. try
  82. {
  83. // Unsignal the event object.
  84. event.ResetEvent();
  85. // Show the wait cursor
  86. pTree->BeginWaitCursor();
  87. // Exit if the handle to the heap is invalid.
  88. if (hHeap == NULL)
  89. goto ExitFunction;
  90. if (pti->hTreeItem == TVI_ROOT)
  91. {
  92. pnrRoot = NULL;
  93. if (pTree->m_imagelist.Create(IDB_NET_TREE, 16, 3, CNetTreeCtrl::IMG_MASK))
  94. {
  95. pTree->SetImageList(&(pTree->m_imagelist), TVSIL_NORMAL);
  96. pTree->m_imagelist.SetBkColor(CLR_NONE);
  97. }
  98. }
  99. else
  100. pnrRoot = (LPNETRESOURCE)pTree->GetItemData(pti->hTreeItem);
  101. // Get an enumeration handle.
  102. if ((dwResult = ::WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY,
  103. RESOURCEUSAGE_CONTAINER, pnrRoot, &hEnum)) != NO_ERROR)
  104. {
  105. // Exit if WNetOpenEnum fails.
  106. dwResult = ::GetLastError();
  107. goto ExitFunction;
  108. }
  109. // Allocate a buffer for enumeration.
  110. if ((lpvBuffer = ::HeapAlloc(hHeap, HEAP_ZERO_MEMORY, pti->dwBufSize)) == NULL)
  111. // Exit if memory allocation failed
  112. goto ExitFunction;
  113. // Retrieve a block of network entries.
  114. while ((dwResult = ::WNetEnumResource(hEnum, &dwEntries, lpvBuffer, &(pti->dwBufSize))) != ERROR_NO_MORE_ITEMS)
  115. {
  116. // See if it's time to exit.
  117. if (pTree->m_bExitThread)
  118. {
  119. pTree->NotifyThread(FALSE);
  120. bResult = TRUE;
  121. goto ExitFunction;
  122. }
  123. // Exit if WNetEnumResource failed.
  124. if (dwResult != NO_ERROR)
  125. {
  126. dwResult = ::GetLastError();
  127. goto ExitFunction;
  128. }
  129. LPNETRESOURCE pnrLeaf = (LPNETRESOURCE)lpvBuffer;
  130. TV_INSERTSTRUCT tviLeaf;
  131. // Fill in the TV_INSERTSTRUCT members.
  132. tviLeaf.hParent = pti->hTreeItem;
  133. tviLeaf.hInsertAfter = TVI_SORT;
  134. tviLeaf.item.hItem = NULL;
  135. tviLeaf.item.state = 0;
  136. tviLeaf.item.stateMask = 0;
  137. tviLeaf.item.cchTextMax = 0;
  138. tviLeaf.item.iSelectedImage = 0;
  139. // Set the correct image for the leaf.
  140. switch (pnrLeaf->dwDisplayType)
  141. {
  142. case RESOURCEDISPLAYTYPE_DOMAIN:
  143. tviLeaf.item.iImage = tviLeaf.item.iSelectedImage = CNetTreeCtrl::IMG_DOMAIN;
  144. break;
  145. case RESOURCEDISPLAYTYPE_SERVER:
  146. tviLeaf.item.iImage = tviLeaf.item.iSelectedImage = CNetTreeCtrl::IMG_SERVER;
  147. break;
  148. default:
  149. tviLeaf.item.iImage = tviLeaf.item.iSelectedImage = CNetTreeCtrl::IMG_ROOT;
  150. }
  151. // Fool the tree into thinking that this leaf has children
  152. // since we don't know initially.
  153. #if 0
  154. if (pnrLeaf->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER)
  155. #else
  156. if (pnrLeaf->dwDisplayType == RESOURCEDISPLAYTYPE_DOMAIN ||
  157. pnrLeaf->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER)
  158. #endif
  159. {
  160. tviLeaf.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  161. tviLeaf.item.cChildren = 0;
  162. }
  163. else
  164. {
  165. tviLeaf.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  166. tviLeaf.item.cChildren = 1;
  167. }
  168. // Add leaves to the branch.
  169. for (DWORD i = 0; i < dwEntries; i++)
  170. {
  171. // See if it's time to exit.
  172. if (pTree->m_bExitThread)
  173. {
  174. pTree->NotifyThread(FALSE);
  175. bResult = TRUE;
  176. goto ExitFunction;
  177. }
  178. // Create a permanent NETRESOURCE struct for later use.
  179. LPNETRESOURCE pnrTemp = new NETRESOURCE;
  180. pTree->m_ptrlistContainers.AddTail(pnrTemp);
  181. ::CopyMemory(pnrTemp, pnrLeaf, sizeof(NETRESOURCE));
  182. // Initialize members.
  183. pnrTemp->lpLocalName = NULL;
  184. pnrTemp->lpRemoteName = NULL;
  185. pnrTemp->lpComment = NULL;
  186. pnrTemp->lpProvider = NULL;
  187. if (pnrLeaf->lpRemoteName != NULL)
  188. {
  189. size_t cch = ::_tcslen(pnrLeaf->lpRemoteName) + 1;
  190. pnrTemp->lpRemoteName = new TCHAR[cch];
  191. if (NULL == pnrTemp->lpRemoteName)
  192. goto ExitFunction;
  193. hr = StringCchCopy(pnrTemp->lpRemoteName, cch, pnrLeaf->lpRemoteName);
  194. if (FAILED(hr))
  195. goto ExitFunction;
  196. pTree->m_ptrlistStrings.AddTail(pnrTemp->lpRemoteName);
  197. }
  198. if (pnrLeaf->lpProvider != NULL)
  199. {
  200. size_t cch = ::_tcslen(pnrLeaf->lpProvider) + 1;
  201. pnrTemp->lpProvider = new TCHAR[cch];
  202. if (NULL == pnrTemp->lpProvider)
  203. goto ExitFunction;
  204. hr = StringCchCopy(pnrTemp->lpProvider, cch, pnrLeaf->lpProvider);
  205. if (FAILED(hr))
  206. goto ExitFunction;
  207. pTree->m_ptrlistStrings.AddTail(pnrTemp->lpProvider);
  208. }
  209. // Increment the buffer pointer.
  210. pnrLeaf++;
  211. // Use "Enterprise" as the item text if this is the root.
  212. if (pti->hTreeItem == TVI_ROOT)
  213. {
  214. CString strRoot;
  215. DWORD cch;
  216. strRoot.LoadString(IDS_TREE_ROOT);
  217. cch = strRoot.GetLength() + 1;
  218. tviLeaf.item.pszText = new TCHAR[cch];
  219. if (NULL == tviLeaf.item.pszText)
  220. goto ExitFunction;
  221. hr = StringCchCopy(tviLeaf.item.pszText, cch, (LPCTSTR)strRoot);
  222. if (FAILED(hr))
  223. goto ExitFunction;
  224. }
  225. else if (pnrTemp->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER)
  226. {
  227. // Skip the initial backslashes before adding the server
  228. // name to the tree.
  229. tviLeaf.item.pszText = pnrTemp->lpRemoteName + 2;
  230. }
  231. else
  232. tviLeaf.item.pszText = pnrTemp->lpRemoteName;
  233. tviLeaf.item.lParam = (LPARAM)(LPVOID)pnrTemp;
  234. // Make sure the pointer to the tree control is still valid.
  235. if (::IsWindow(pTree->m_hWnd))
  236. {
  237. hTreeItem = pTree->InsertItem(&tviLeaf);
  238. }
  239. else // Otherwise, exit the thread.
  240. {
  241. bResult = TRUE;
  242. goto ExitFunction;
  243. }
  244. // Delete the string allocated for the root node text.
  245. if (pti->hTreeItem == TVI_ROOT)
  246. delete tviLeaf.item.pszText;
  247. // See if the lpRemoteName member is equal to the default domain
  248. // name.
  249. #if 0
  250. if (!_tcscmp(pnrTemp->lpRemoteName, pApp->m_strDomain) ||
  251. #else
  252. if (
  253. #endif
  254. pti->hTreeItem == TVI_ROOT)
  255. {
  256. // Store the handle.
  257. hTreeExpand = hTreeItem;
  258. }
  259. // Select the name of the license server in the tree.
  260. #if 0
  261. if (!_tcsicmp(pnrTemp->lpRemoteName, pApp->m_strEnterpriseServer))
  262. #else
  263. if (!_tcsicmp(pnrTemp->lpRemoteName, pApp->m_strDomain))
  264. #endif
  265. {
  266. pTree->SelectItem(hTreeItem);
  267. pTree->EnsureVisible(hTreeItem);
  268. pTree->SetFocus();
  269. }
  270. }
  271. // Everything went all right.
  272. bResult = TRUE;
  273. }
  274. // Expand the branch but only if it isn't the root.
  275. // The root item thinks it has children, but really doesn't the first time through.
  276. if (pti->hTreeItem != TVI_ROOT && pTree->ItemHasChildren(pti->hTreeItem))
  277. {
  278. // Indicate that the branch has been expanded once.
  279. pTree->SetItemState(pti->hTreeItem, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
  280. pTree->Expand(pti->hTreeItem, TVE_EXPAND);
  281. }
  282. // Fill the branch for the current domain if the bExpand member is TRUE.
  283. if (hTreeExpand != NULL && pti->bExpand)
  284. {
  285. TREEINFO ti;
  286. ti.hTreeItem = hTreeExpand;
  287. ti.dwBufSize = pti->dwBufSize;
  288. ti.pTree = pti->pTree;
  289. ti.bExpand = TRUE;
  290. // Increment the usage count.
  291. uUsage++;
  292. FillTree((LPVOID)&ti);
  293. // Decrement the usage count.
  294. uUsage--;
  295. }
  296. ExitFunction:
  297. // Display a message if an error occurred.
  298. if (!bResult)
  299. pTree->ErrorHandler(dwResult);
  300. // Close the enumeration handle.
  301. if (hEnum != NULL)
  302. if (FALSE == (bResult = (::WNetCloseEnum(hEnum) == NO_ERROR)))
  303. dwResult = ::GetLastError();
  304. // Free memory allocated on the heap.
  305. if (lpvBuffer != NULL)
  306. ::HeapFree(hHeap, 0, lpvBuffer);
  307. // Free the TREEINFO pointer only if the usage count is zero.
  308. if (uUsage == 0)
  309. delete pti;
  310. // Reset the thread pointer.
  311. pTree->m_pThread = NULL;
  312. // Turn off the wait cursor
  313. pTree->EndWaitCursor();
  314. // Make sure the tree control still exists before posting a message.
  315. if (::IsWindow(pTree->m_hWnd))
  316. pTree->PostMessage(WM_SETCURSOR);
  317. // Signal the event object.
  318. if (uUsage == 0)
  319. event.SetEvent();
  320. return (UINT)!bResult;
  321. }
  322. catch(...)
  323. {
  324. // Close the enumeration handle.
  325. if (hEnum != NULL)
  326. if (FALSE == (bResult = (::WNetCloseEnum(hEnum) == NO_ERROR)))
  327. dwResult = ::GetLastError();
  328. // Free memory allocated on the heap.
  329. if (lpvBuffer != NULL)
  330. ::HeapFree(hHeap, 0, lpvBuffer);
  331. // Free the TREEINFO pointer
  332. delete pti;
  333. // Reset the thread pointer.
  334. pTree->m_pThread = NULL;
  335. // Turn off the wait cursor
  336. pTree->EndWaitCursor();
  337. // Signal the event object.
  338. event.SetEvent();
  339. return (UINT)2;
  340. }
  341. }
  342. /////////////////////////////////////////////////////////////////////////////
  343. // CNetTreeCtrl member functions
  344. BOOL CNetTreeCtrl::PopulateTree(BOOL bExpand /* = TRUE */, const HTREEITEM hParentBranch /* = TVI_ROOT */,
  345. DWORD dwBufSize /* = BUFFER_SIZE */)
  346. {
  347. PTREEINFO pti = new TREEINFO;
  348. pti->hTreeItem = hParentBranch;
  349. pti->dwBufSize = dwBufSize;
  350. pti->pTree = this;
  351. pti->bExpand = bExpand;
  352. // Don't begin a new thread until the last one has ended.
  353. if (m_pThread != NULL)
  354. {
  355. NotifyThread(TRUE);
  356. CEvent event(TRUE, TRUE, pszTreeEvent);
  357. CSingleLock lock(&event);
  358. // Wait.
  359. lock.Lock();
  360. }
  361. m_pThread = AfxBeginThread((AFX_THREADPROC)FillTree, (LPVOID)pti);
  362. return TRUE;
  363. }
  364. void CNetTreeCtrl::ErrorHandler(const DWORD dwCode)
  365. {
  366. CString strError;
  367. BOOL bNetError = FALSE;
  368. UNREFERENCED_PARAMETER(dwCode);
  369. #ifdef _DEBUG
  370. switch (dwCode)
  371. {
  372. case ERROR_MORE_DATA:
  373. strError = "ERROR_MORE_DATA";
  374. break;
  375. case ERROR_INVALID_HANDLE:
  376. strError = "ERROR_INVALID_HANDLE";
  377. break;
  378. case ERROR_NOT_CONTAINER:
  379. strError = "ERROR_NOT_CONTAINER";
  380. break;
  381. case ERROR_INVALID_PARAMETER:
  382. strError = "ERROR_INVALID_PARAMETER";
  383. break;
  384. case ERROR_NO_NETWORK:
  385. strError = "ERROR_NO_NETWORK";
  386. break;
  387. case ERROR_EXTENDED_ERROR:
  388. strError = "ERROR_EXTENDED_ERROR";
  389. break;
  390. default:
  391. {
  392. #endif // _DEBUG
  393. DWORD dwErrCode;
  394. CString strErrDesc, strProvider;
  395. LPTSTR pszErrDesc = strErrDesc.GetBuffer(MAX_STRING);
  396. LPTSTR pszProvider = strProvider.GetBuffer(MAX_STRING);
  397. if (::WNetGetLastError(&dwErrCode, pszErrDesc, MAX_STRING,
  398. pszProvider, MAX_STRING) == NO_ERROR)
  399. {
  400. strErrDesc.ReleaseBuffer();
  401. strProvider.ReleaseBuffer();
  402. CString strErrMsg;
  403. // Don't display the WNetGetLastError message if dwErrCode == 0.
  404. if (dwErrCode)
  405. {
  406. // Trim of any leading or trailing white space.
  407. strProvider.TrimRight();
  408. strProvider.TrimLeft();
  409. strErrDesc.TrimRight();
  410. strErrDesc.TrimLeft();
  411. strErrMsg.Format(IDS_NET_ERROR, strProvider, strErrDesc);
  412. }
  413. else
  414. strErrMsg.LoadString(IDS_NET_NO_SERVERS);
  415. MessageBox(strErrMsg, AfxGetAppName(), MB_OK | MB_ICONEXCLAMATION);
  416. bNetError = TRUE;
  417. }
  418. else
  419. strError.LoadString(IDS_ERROR);
  420. #ifdef _DEBUG
  421. }
  422. }
  423. #endif // _DEBUG
  424. if (!bNetError)
  425. AfxMessageBox(strError, MB_OK | MB_ICONEXCLAMATION);
  426. }
  427. /////////////////////////////////////////////////////////////////////////////
  428. // CNetTreeCtrl functions
  429. void CNetTreeCtrl::NotifyThread(BOOL bExit)
  430. {
  431. CCriticalSection cs;
  432. if (cs.Lock())
  433. {
  434. m_bExitThread = bExit;
  435. cs.Unlock();
  436. }
  437. }
  438. void CNetTreeCtrl::PumpMessages()
  439. {
  440. // Must call Create() before using the dialog
  441. ASSERT(m_hWnd!=NULL);
  442. MSG msg;
  443. try
  444. {
  445. // Handle dialog messages
  446. while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  447. {
  448. if(!IsDialogMessage(&msg))
  449. {
  450. TranslateMessage(&msg);
  451. DispatchMessage(&msg);
  452. }
  453. }
  454. }
  455. catch(...)
  456. {
  457. TRACE(_T("Exception in CNetTreeCtrl::PumpMessages()\n"));
  458. }
  459. }
  460. /////////////////////////////////////////////////////////////////////////////
  461. // CNetTreeCtrl message handlers
  462. void CNetTreeCtrl::OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult)
  463. {
  464. NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  465. // Exit and stop expansion if the thread is running.
  466. if (m_pThread != NULL)
  467. {
  468. *pResult = TRUE;
  469. return;
  470. }
  471. // Exit if this branch has been expanded once.
  472. if (!(pNMTreeView->itemNew.state & TVIS_EXPANDEDONCE))
  473. {
  474. // Add new leaves to the branch.
  475. if (pNMTreeView->itemNew.mask & TVIF_HANDLE)
  476. {
  477. PopulateTree(FALSE, pNMTreeView->itemNew.hItem);
  478. pNMTreeView->itemNew.mask |= TVIS_EXPANDEDONCE;
  479. }
  480. }
  481. *pResult = FALSE;
  482. }
  483. BOOL CNetTreeCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  484. {
  485. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
  486. if (m_pThread == NULL && pApp->m_pLicenseThread == NULL)
  487. {
  488. return CTreeCtrl::OnSetCursor(pWnd, nHitTest, message);
  489. }
  490. else
  491. {
  492. // Restore the wait cursor if the thread is running.
  493. RestoreWaitCursor();
  494. return TRUE;
  495. }
  496. }
  497. void CNetTreeCtrl::OnDestroy()
  498. {
  499. NotifyThread(TRUE);
  500. PumpMessages();
  501. CTreeCtrl::OnDestroy();
  502. }