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.

840 lines
26 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows/NT **/
  3. /** Copyright(c) Microsoft Corp., 1991 **/
  4. /**********************************************************************/
  5. /*
  6. WNETENUM.CXX
  7. This file contains the implementation of
  8. NPOpenEnum - open a resource enumeration handle
  9. NPEnumResource - walk through all the resource
  10. NPCloseEnum - end of walk through
  11. FILE HISTORY:
  12. terryk 27-Sep-91 Created
  13. terryk 01-Nov-91 WIN32 conversion
  14. terryk 08-Nov-91 Code review changes
  15. terryk 18-Nov-91 Split to 2 files - wnetenum.cxx and
  16. enumnode.cxx
  17. terryk 10-Dec-91 check parameters in WNetOpenEnum
  18. terryk 28-Dec-91 changed DWORD to UINT
  19. Yi-HsinS31-Dec-91 Unicode work
  20. terryk 03-Jan-92 Capitalize the Resource_XXX manifest
  21. terryk 10-Jan-92 Returned WN_SUCCESS if the buffer is too
  22. small for 1 entry.
  23. */
  24. #define INCL_WINDOWS
  25. #define INCL_DOSERRORS
  26. #define INCL_NETERRORS
  27. #define INCL_NETCONS
  28. #define INCL_NETUSE
  29. #define INCL_NETWKSTA
  30. #define INCL_NETACCESS // NetPasswordSet declaration
  31. #define INCL_NETCONFIG
  32. #define INCL_NETREMUTIL
  33. #define INCL_NETSHARE
  34. #define INCL_NETSERVER
  35. #define INCL_NETSERVICE
  36. #define INCL_NETLIB
  37. #define INCL_ICANON
  38. #define _WINNETWK_
  39. #include <lmui.hxx>
  40. #undef _WINNETWK_
  41. #define INCL_BLT_WINDOW
  42. #include <blt.hxx>
  43. #include <dbgstr.hxx>
  44. #include <winnetwk.h>
  45. #include <winnetp.h>
  46. #include <npapi.h>
  47. #include <wnetenum.h>
  48. #include <winlocal.h>
  49. #include <mnet.h>
  50. #include <lmobj.hxx>
  51. #include <lmoshare.hxx>
  52. #include <lmoesh.hxx>
  53. #include <lmoeuse.hxx>
  54. #include <lmodev.hxx>
  55. #include <lmosrv.hxx>
  56. #include <lmowks.hxx>
  57. #include <lmoesrv.hxx>
  58. #include <lmsvc.hxx>
  59. #include <uibuffer.hxx>
  60. #include <uitrace.hxx>
  61. #include <uiassert.hxx>
  62. #include <uatom.hxx>
  63. #include <regkey.hxx>
  64. #include <array.hxx>
  65. #include <string.hxx>
  66. #include <strchlit.hxx> // for SERVER_INIT_STRING
  67. #include <miscapis.hxx>
  68. #include <wnetenum.hxx>
  69. //
  70. // Macros for rounding a value up/down to a TCHAR boundary.
  71. // Note: These macros assume that sizeof(TCHAR) is a power of 2.
  72. //
  73. #define ROUND_DOWN(x) ((x) & ~(sizeof(TCHAR) - 1))
  74. #define ROUND_UP(x) (((x) + sizeof(TCHAR) - 1) & ~(sizeof(TCHAR) - 1))
  75. /*******************************************************************
  76. Global variables
  77. ********************************************************************/
  78. #define ARRAY_SIZE 64
  79. extern NET_ENUM_HANDLE_TABLE *vpNetEnumArray;
  80. /* Winnet locking handle
  81. */
  82. HANDLE vhSemaphore ;
  83. /* Name of the provider
  84. */
  85. const TCHAR * pszNTLanMan = NULL ;
  86. #define LM_WKSTA_NODE SZ("System\\CurrentControlSet\\Services\\LanmanWorkstation\\NetworkProvider")
  87. #define LM_PROVIDER_VALUE_NAME SZ("Name")
  88. /*******************************************************************
  89. NAME: InitWNetEnum
  90. SYNOPSIS: Initialize the Enum handle array
  91. RETURN: APIERR - it will return ERROR_OUT_OF_MEMORY if it does
  92. not have enough space
  93. HISTORY:
  94. terryk 24-Oct-91 Created
  95. davidhov 20-Oct-92 updated REG_KEY usage
  96. ********************************************************************/
  97. APIERR InitWNetEnum()
  98. {
  99. TRACEEOL( "NTLANMAN.DLL: InitWNetEnum()" );
  100. vpNetEnumArray = new NET_ENUM_HANDLE_TABLE( ARRAY_SIZE );
  101. if ( vpNetEnumArray == NULL )
  102. {
  103. DBGEOL( "NTLANMAN.DLL: InitWNetEnum() ERROR_NOT_ENOUGH_MEMORY" );
  104. return ERROR_NOT_ENOUGH_MEMORY;
  105. }
  106. APIERR err = vpNetEnumArray->QueryError();
  107. if ( !err )
  108. {
  109. if ( (vhSemaphore = ::CreateSemaphore( NULL, 1, 1, NULL )) == NULL)
  110. {
  111. err = ::GetLastError() ;
  112. DBGEOL( "NTLANMAN.DLL: InitWNetEnum() semaphore error " << err );
  113. }
  114. }
  115. return err ;
  116. }
  117. /********************************************************************
  118. NAME: GetLMProviderName
  119. SYNOPSIS: Get Provider Name into the global variable pszNTLanMan
  120. RETURN: APIERR - it will return ERROR_OUT_OF_MEMORY if it does
  121. not have enough space
  122. HISTORY:
  123. congpay 14-Dec-92 Created
  124. ********************************************************************/
  125. APIERR GetLMProviderName()
  126. {
  127. if (pszNTLanMan)
  128. {
  129. return NERR_Success;
  130. }
  131. APIERR err = NERR_Success;
  132. REG_KEY *pRegKeyFocusServer = NULL;
  133. do { // error breakout
  134. /* Traverse the registry and get the list of computer alert
  135. * names.
  136. */
  137. pRegKeyFocusServer = REG_KEY::QueryLocalMachine();
  138. if ( ( pRegKeyFocusServer == NULL ) ||
  139. ((err = pRegKeyFocusServer->QueryError())) )
  140. {
  141. err = err? err : ERROR_NOT_ENOUGH_MEMORY ;
  142. break ;
  143. }
  144. ALIAS_STR nlsRegKeyName( LM_WKSTA_NODE ) ;
  145. REG_KEY regkeyLMProviderNode( *pRegKeyFocusServer, nlsRegKeyName );
  146. REG_KEY_INFO_STRUCT regKeyInfo;
  147. REG_VALUE_INFO_STRUCT regValueInfo ;
  148. if ( (err = regkeyLMProviderNode.QueryError()) ||
  149. (err = regkeyLMProviderNode.QueryInfo( &regKeyInfo )) )
  150. {
  151. break ;
  152. }
  153. BUFFER buf( (UINT) regKeyInfo.ulMaxValueLen ) ;
  154. regValueInfo.nlsValueName = LM_PROVIDER_VALUE_NAME ;
  155. if ( (err = buf.QueryError() ) ||
  156. (err = regValueInfo.nlsValueName.QueryError()) )
  157. {
  158. break;
  159. }
  160. regValueInfo.pwcData = buf.QueryPtr();
  161. regValueInfo.ulDataLength = buf.QuerySize() ;
  162. if ( (err = regkeyLMProviderNode.QueryValue( &regValueInfo )))
  163. {
  164. break;
  165. }
  166. /* Null terminate the computer list string we just retrieved from
  167. * the registry.
  168. */
  169. TCHAR * pszProviderName = (TCHAR *)( buf.QueryPtr() +
  170. regValueInfo.ulDataLengthOut -
  171. sizeof(TCHAR) );
  172. *pszProviderName = TCH('\0') ;
  173. ALIAS_STR nlsComputerList( (TCHAR *) buf.QueryPtr()) ;
  174. pszNTLanMan = new TCHAR[ nlsComputerList.QueryTextSize() ] ;
  175. if ( pszNTLanMan == NULL )
  176. {
  177. err = ERROR_NOT_ENOUGH_MEMORY ;
  178. break ;
  179. }
  180. nlsComputerList.CopyTo( (TCHAR *) pszNTLanMan,
  181. nlsComputerList.QueryTextSize()) ;
  182. } while (FALSE) ;
  183. delete pRegKeyFocusServer ;
  184. return err;
  185. }
  186. /*******************************************************************
  187. NAME: TermWNetEnum
  188. SYNOPSIS: clear up the Enum handle array
  189. HISTORY:
  190. terryk 24-Oct-91 Created
  191. ********************************************************************/
  192. VOID TermWNetEnum()
  193. {
  194. TRACEEOL( "NTLANMAN.DLL: TermWNetEnum()" );
  195. delete vpNetEnumArray;
  196. vpNetEnumArray = NULL;
  197. REQUIRE( ::CloseHandle( vhSemaphore ) ) ;
  198. vhSemaphore = NULL ;
  199. delete (void *) pszNTLanMan ;
  200. pszNTLanMan = NULL ;
  201. }
  202. /*******************************************************************
  203. NAME: NPOpenEnum
  204. SYNOPSIS: Create a new Enum handle
  205. ENTRY: UINT dwScope - determine the scope of the enumeration.
  206. This can be one of:
  207. RESOURCE_CONNECTED - all currently connected resource
  208. RESOURCE_GLOBALNET - all resources on the network
  209. RESOURCE_CONTEXT - resources in the user's current
  210. and default network context
  211. UINT dwType - used to specify the type of resources of
  212. interest. This is a bitmask which may be any
  213. combination of:
  214. RESOURCETYPE_DISK - all disk resources
  215. RESOURCETYPE_PRINT - all print resources
  216. If this is 0, all types of resources are returned.
  217. If a provider does not have the capability to
  218. distinguish between print and disk resources at a
  219. level, it may return all resources.
  220. UINT dwUsage - Used to specify the usage of resources
  221. of interested. This is a bitmask which may be any
  222. combination of:
  223. RESOURCEUSAGE_CONNECTABLE - all connectable
  224. resources
  225. RESOURCEUSAGE_CONTAINER - all container resources
  226. The bitmask may be 0 to match all.
  227. RESOURCEUSAGE_ATTACHED - signifies that the function
  228. should fail if the caller is not authenticated (even
  229. if the network allows enumeration without authenti-
  230. cation).
  231. This parameter is ignored if dwScope is not
  232. RESOURCE_GLOBALNET.
  233. NETRESOURCE * lpNetResource - This specifies the
  234. container to perform the enumeration. The
  235. NETRESOURCE must have been obtained via
  236. NPEnumResource( and must have the
  237. RESOURCEUSAGE_Connectable bit set ), or NULL. If it
  238. is NULL,the logical root of the network is assumed.
  239. An application would normally start off by calling
  240. NPOpenEnum with this parameter set to NULL, and
  241. then use the returned results for further
  242. enumeration. If dwScope is RESOURCE_CONNECTED, this
  243. must be NULL.
  244. If dwScope is RESOURCE_CONTEXT, this is ignored.
  245. HANDLE * lphEnum - If function call is successful, this
  246. will contain a handle that can then be used for
  247. NPEnumResource.
  248. EXIT: HANDLE * lphEnum - will contain the handle number
  249. RETURNS: WN_SUCCESS if the call is successful. Otherwise,
  250. GetLastError should be called for extended error
  251. information. Extened error codes include:
  252. WN_NOT_CONTAINER - lpNetResource does not point to a
  253. container
  254. WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType,
  255. or bad combination of parameters is specified
  256. WN_NOT_NETWORK - network is not present
  257. WN_NET_ERROR - a network specific error occured.
  258. WNetGetLastError should be called to obtain further
  259. information.
  260. HISTORY:
  261. terryk 24-Oct-91 Created
  262. Johnl 06-Mar-1992 Added Computer validation check
  263. on container enumeration
  264. JohnL 03-Apr-1992 Fixed dwUsage == CONNECTED|CONTAINER
  265. bug (would return WN_BAD_VALUE)
  266. ChuckC 01-Aug-1992 Simplified, corrected and commented
  267. the messy cases wrt to dwUsage.
  268. AnirudhS 03-Mar-1995 Added support for RESOURCE_CONTEXT
  269. AnirudhS 26-Apr-1996 Simplified, corrected and commented
  270. the messy cases wrt dwScope.
  271. ********************************************************************/
  272. DWORD APIENTRY
  273. NPOpenEnum(
  274. UINT dwScope,
  275. UINT dwType,
  276. UINT dwUsage,
  277. LPNETRESOURCE lpNetResource,
  278. HANDLE * lphEnum )
  279. {
  280. UIASSERT( lphEnum != NULL );
  281. APIERR err ;
  282. if ( err = CheckLMService() )
  283. return err ;
  284. if ( dwType & ~( RESOURCETYPE_DISK | RESOURCETYPE_PRINT ) )
  285. {
  286. return WN_BAD_VALUE;
  287. }
  288. NET_ENUMNODE *pNetEnum;
  289. if ( dwScope == RESOURCE_CONNECTED )
  290. {
  291. /*
  292. * we are looking for current uses
  293. */
  294. if ( lpNetResource != NULL )
  295. {
  296. return WN_BAD_VALUE;
  297. }
  298. err = GetLMProviderName();
  299. if (err)
  300. return(err);
  301. pNetEnum = new USE_ENUMNODE( dwScope, dwType, dwUsage, lpNetResource );
  302. }
  303. else if ( dwScope == RESOURCE_CONTEXT )
  304. {
  305. /*
  306. * we are looking for servers in the domain
  307. * Note that lpNetResource is ignored
  308. * dwType is decoded in the CONTEXT_ENUMNODE constructor
  309. */
  310. pNetEnum = new CONTEXT_ENUMNODE( dwScope, dwType, dwUsage, NULL );
  311. }
  312. else if ( dwScope == RESOURCE_SHAREABLE )
  313. {
  314. /*
  315. * We are looking for shareable resources
  316. * Use SHARE_ENUMNODE, which decodes dwScope when it enumerates
  317. * If we're not given a server, return an EMPTY_ENUMNODE
  318. */
  319. if (lpNetResource != NULL
  320. &&
  321. lpNetResource->lpRemoteName != NULL
  322. &&
  323. lpNetResource->lpRemoteName[0] == TCH('\\')
  324. &&
  325. lpNetResource->lpRemoteName[1] == TCH('\\'))
  326. {
  327. pNetEnum = new SHARE_ENUMNODE( dwScope, dwType, dwUsage, lpNetResource );
  328. }
  329. else
  330. {
  331. pNetEnum = new EMPTY_ENUMNODE( dwScope, dwType, dwUsage, lpNetResource );
  332. }
  333. }
  334. else if ( dwScope == RESOURCE_GLOBALNET )
  335. {
  336. /* Look for the combination of all bits and substitute "All" for
  337. * them. Ignore bits we don't know about.
  338. * Note: RESOURCEUSAGE_ATTACHED is a no-op for us, since LanMan
  339. * always tries to authenticate when doing an enumeration.
  340. */
  341. dwUsage &= (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER);
  342. if ( dwUsage == (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER) )
  343. {
  344. dwUsage = 0 ;
  345. }
  346. /*
  347. * we are looking for global resources out on the net
  348. */
  349. if ( lpNetResource == NULL || lpNetResource->lpRemoteName == NULL)
  350. {
  351. /*
  352. * at top level, therefore enumerating domains. if user
  353. * asked for connectable, well, there aint none.
  354. */
  355. if ( dwUsage == RESOURCEUSAGE_CONNECTABLE )
  356. {
  357. pNetEnum = new EMPTY_ENUMNODE( dwScope,
  358. dwType,
  359. dwUsage,
  360. lpNetResource );
  361. }
  362. else
  363. {
  364. pNetEnum = new DOMAIN_ENUMNODE( dwScope,
  365. dwType,
  366. dwUsage,
  367. lpNetResource );
  368. }
  369. }
  370. else
  371. {
  372. /*
  373. * we are assured of lpRemoteName != NULL.
  374. * things get interesting here. the cases are as follows:
  375. *
  376. * if (dwUsage == 0)
  377. * if have \\ in front
  378. * return shares
  379. * else
  380. * return servers
  381. * else if (dwUsage == CONNECTABLE)
  382. * if have \\ in front
  383. * return shares
  384. * else
  385. * empty enum
  386. * else if (dwUsage == CONTAINER)
  387. * if have \\ in front
  388. * empty enum
  389. * else
  390. * return server
  391. *
  392. * In interest of code size, i've reorganized the above
  393. * cases to minimized the bodies of the ifs.
  394. *
  395. * chuckc.
  396. */
  397. if ( ((dwUsage == RESOURCEUSAGE_CONNECTABLE) ||
  398. (dwUsage == 0)
  399. )
  400. &&
  401. ((lpNetResource->lpRemoteName[0] == TCH('\\')) &&
  402. (lpNetResource->lpRemoteName[1] == TCH('\\'))
  403. )
  404. )
  405. {
  406. /* Confirm that this really is a computer name (i.e., a
  407. * container we can enumerate).
  408. */
  409. if ( ::I_MNetNameValidate( NULL,
  410. &(lpNetResource->lpRemoteName[2]),
  411. NAMETYPE_COMPUTER,
  412. 0L))
  413. {
  414. return WN_BAD_VALUE ;
  415. }
  416. pNetEnum = new SHARE_ENUMNODE( dwScope, dwType, dwUsage,
  417. lpNetResource );
  418. }
  419. else if ( ((dwUsage == RESOURCEUSAGE_CONTAINER) ||
  420. (dwUsage == 0)
  421. )
  422. &&
  423. (lpNetResource->lpRemoteName[0] != TCH('\\'))
  424. )
  425. {
  426. pNetEnum = new SERVER_ENUMNODE( dwScope, dwType, dwUsage,
  427. lpNetResource );
  428. }
  429. else if (
  430. // ask for share but aint starting from server
  431. (
  432. (dwUsage == RESOURCEUSAGE_CONNECTABLE)
  433. &&
  434. (lpNetResource->lpRemoteName[0] != TCH('\\'))
  435. )
  436. ||
  437. // ask for server but is starting from server
  438. (
  439. (dwUsage == RESOURCEUSAGE_CONTAINER)
  440. &&
  441. ((lpNetResource->lpRemoteName[0] == TCH('\\')) &&
  442. (lpNetResource->lpRemoteName[1] == TCH('\\'))
  443. )
  444. )
  445. )
  446. {
  447. pNetEnum = new EMPTY_ENUMNODE( dwScope,
  448. dwType,
  449. dwUsage,
  450. lpNetResource );
  451. }
  452. else
  453. {
  454. // incorrect dwUsage
  455. return WN_BAD_VALUE;
  456. }
  457. }
  458. }
  459. else
  460. {
  461. // invalid dwScope
  462. return WN_BAD_VALUE;
  463. }
  464. if ( pNetEnum == NULL )
  465. {
  466. return WN_OUT_OF_MEMORY;
  467. }
  468. else if ( err = pNetEnum->QueryError() )
  469. {
  470. delete pNetEnum;
  471. return MapError(err);
  472. }
  473. if ( pNetEnum->IsFirstGetInfo() )
  474. {
  475. if (( err = pNetEnum->GetInfo()) != WN_SUCCESS )
  476. {
  477. delete pNetEnum;
  478. return MapError(err);
  479. }
  480. }
  481. ////////////////////////////////////////// Enter critical section
  482. if ( err = WNetEnterCriticalSection() )
  483. {
  484. delete pNetEnum;
  485. return err ;
  486. }
  487. ASSERT( vpNetEnumArray != NULL );
  488. INT iPos = vpNetEnumArray->QueryNextAvail();
  489. if ( iPos < 0 )
  490. {
  491. WNetLeaveCriticalSection() ;
  492. delete pNetEnum;
  493. return WN_OUT_OF_MEMORY;
  494. }
  495. vpNetEnumArray->SetNode( (UINT)iPos, pNetEnum );
  496. *lphEnum = UintToPtr((UINT)iPos);
  497. WNetLeaveCriticalSection() ;
  498. ////////////////////////////////////////// Leave critical section
  499. return err ;
  500. }
  501. /*******************************************************************
  502. NAME: NPEnumResource
  503. SYNOPSIS: Perform an enumeration based on handle returned by
  504. NPOpenEnum.
  505. ENTRY: HANDLE hEnum - This must be a handle obtained from
  506. NPOpenEnum call
  507. UINT *lpcRequested - Specifies the number of entries
  508. requested. It may be 0xFFFFFFFF to request as many as
  509. possible. On successful call, this location will receive
  510. the number of entries actually read.
  511. VOID *lpBuffer - A pointer to the buffer to receive the
  512. enumeration result, which are returned as an array
  513. of NETRESOURCE entries. The buffer is valid until
  514. the next call using hEnum.
  515. UINT * lpBufferSize - This specifies the size of the
  516. buffer passed to the function call. If WN_MORE_DATA
  517. is returned and no entries were enumerated, then this
  518. will be set to the minimum buffer size required.
  519. EXIT: UINT *lpcRequested - will receive the number of entries
  520. actually read.
  521. RETURNS: WN_SUCCESS if the call is successful, the caller should
  522. continue to call NPEnumResource to continue the
  523. enumeration.
  524. WN_NO_MORE_ENTRIES - no more entries found, the
  525. enumeration completed successfully ( the contents of the
  526. return buffer is undefined). Otherwise, GetLastError
  527. should be called for extended error information.
  528. Extended error codes include:
  529. WN_MORE_DATA - the buffer is too small even for one
  530. entry
  531. WN_BAD_HANDLE - hEnum is not a valid handle
  532. WN_NOT_NETWORK - network is not present. This
  533. condition is checked for before hEnum is tested for
  534. validity.
  535. WN_NET_ERROR - a network specific error occured.
  536. WNetGetLastError should be called to obtain further
  537. information.
  538. HISTORY:
  539. terryk 24-Oct-91 Created
  540. KeithMo 15-Sep-92 Align *lpcBufferSize as needed.
  541. ********************************************************************/
  542. DWORD APIENTRY
  543. NPEnumResource(
  544. HANDLE hEnum,
  545. UINT * lpcRequested,
  546. LPVOID lpBuffer,
  547. UINT * lpcBufferSize )
  548. {
  549. APIERR err ;
  550. if (( lpBuffer == NULL ) ||
  551. ( lpcRequested == NULL ) ||
  552. ( lpcBufferSize == NULL ))
  553. {
  554. return WN_BAD_VALUE;
  555. }
  556. if ( err = WNetEnterCriticalSection() )
  557. {
  558. return err ;
  559. }
  560. ASSERT( vpNetEnumArray != NULL );
  561. NET_ENUMNODE *pNode = vpNetEnumArray->QueryNode(PtrToUint(hEnum));
  562. WNetLeaveCriticalSection() ;
  563. if ( pNode == NULL )
  564. {
  565. return WN_BAD_HANDLE;
  566. }
  567. else if ( pNode->IsFirstGetInfo() )
  568. {
  569. if ( err = CheckLMService() )
  570. {
  571. return err ;
  572. }
  573. if (( err = pNode->GetInfo()) != WN_SUCCESS )
  574. {
  575. return ( MapError(err) );
  576. }
  577. }
  578. LPNETRESOURCE pNetResource = ( LPNETRESOURCE ) lpBuffer;
  579. UINT cbRemainSize = ROUND_DOWN(*lpcBufferSize);
  580. UINT cRequested = (*lpcRequested);
  581. *lpcRequested = 0;
  582. while ( *lpcRequested < cRequested )
  583. {
  584. err = pNode->GetNetResource((BYTE *)pNetResource, &cbRemainSize );
  585. if ( err == WN_MORE_DATA )
  586. {
  587. /* If we can't even fit one into the buffer, then set the required
  588. * buffer size and return WN_MORE_DATA.
  589. */
  590. if ( *lpcRequested == 0 )
  591. {
  592. *lpcBufferSize = ROUND_UP(cbRemainSize);
  593. }
  594. else
  595. {
  596. err = NERR_Success ;
  597. }
  598. break;
  599. }
  600. if ( err == WN_NO_MORE_ENTRIES )
  601. {
  602. if ( *lpcRequested != 0 )
  603. {
  604. err = NERR_Success ;
  605. }
  606. break;
  607. }
  608. if ( err != WN_SUCCESS )
  609. {
  610. break ;
  611. }
  612. /* err == WN_SUCCESS
  613. */
  614. (*lpcRequested) ++;
  615. if ( sizeof( NETRESOURCE ) > cbRemainSize )
  616. {
  617. break ;
  618. }
  619. pNetResource ++;
  620. cbRemainSize -= (UINT)sizeof( NETRESOURCE );
  621. }
  622. return err ;
  623. }
  624. /*******************************************************************
  625. NAME: NPCloseEnum
  626. SYNOPSIS: Closes an enumeration.
  627. ENTRY: HANDLE hEnum - this must be a handle obtained from
  628. NPOpenEnum call.
  629. RETURNS: WN_SUCCESS if the call is successful. Otherwise,
  630. GetLastError should be called for extended error information.
  631. Extended error codes include:
  632. WN_NO_NETWORK - network is not present. this condition is
  633. checked for before hEnum is tested for validity.
  634. WN_BAD_HANDLE - hEnum is not a valid handle.
  635. WN_NET_ERROR - a network specific error occured.
  636. WNetGetLastError should be called to obtain further
  637. information.
  638. HISTORY:
  639. terryk 24-Oct-91 Created
  640. ********************************************************************/
  641. DWORD APIENTRY
  642. NPCloseEnum(
  643. HANDLE hEnum )
  644. {
  645. APIERR err ;
  646. if ( err = WNetEnterCriticalSection() )
  647. {
  648. return err ;
  649. }
  650. ASSERT( vpNetEnumArray != NULL );
  651. NET_ENUMNODE *pNode = vpNetEnumArray->QueryNode(PtrToUint(hEnum));
  652. if ( pNode == NULL )
  653. {
  654. // cannot find the node
  655. err = WN_BAD_HANDLE;
  656. }
  657. else
  658. {
  659. vpNetEnumArray->ClearNode(PtrToUint(hEnum));
  660. }
  661. WNetLeaveCriticalSection() ;
  662. return err ;
  663. }
  664. /*******************************************************************
  665. NAME: WNetEnterCriticalSection
  666. SYNOPSIS: Locks the LM network provider enumeration code
  667. EXIT: vhSemaphore will be locked
  668. RETURNS: NERR_Success if successful, error code otherwise
  669. NOTES: We wait for 7 seconds for the semaphonre to be freed
  670. HISTORY:
  671. Johnl 27-Apr-1992 Created
  672. ********************************************************************/
  673. APIERR WNetEnterCriticalSection( void )
  674. {
  675. APIERR err = NERR_Success ;
  676. switch( WaitForSingleObject( vhSemaphore, 7000L ))
  677. {
  678. case 0:
  679. break ;
  680. case WAIT_TIMEOUT:
  681. err = WN_FUNCTION_BUSY ;
  682. break ;
  683. case 0xFFFFFFFF:
  684. err = ::GetLastError() ;
  685. break ;
  686. default:
  687. UIASSERT(FALSE) ;
  688. err = WN_WINDOWS_ERROR ;
  689. break ;
  690. }
  691. return err ;
  692. }
  693. /*******************************************************************
  694. NAME: WNetLeaveCriticalSection
  695. SYNOPSIS: Unlocks the enumeration methods
  696. RETURNS:
  697. NOTES:
  698. HISTORY:
  699. Johnl 27-Apr-1992 Created
  700. ********************************************************************/
  701. void WNetLeaveCriticalSection( void )
  702. {
  703. REQUIRE( ReleaseSemaphore( vhSemaphore, 1, NULL ) ) ;
  704. }