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.

848 lines
27 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. extern
  273. BOOLEAN IsThisADfsDomain(
  274. IN LPCWSTR pwszDomainName);
  275. DWORD APIENTRY
  276. NPOpenEnum(
  277. UINT dwScope,
  278. UINT dwType,
  279. UINT dwUsage,
  280. LPNETRESOURCE lpNetResource,
  281. HANDLE * lphEnum )
  282. {
  283. UIASSERT( lphEnum != NULL );
  284. APIERR err ;
  285. if ( err = CheckLMService() )
  286. return err ;
  287. if ( dwType & ~( RESOURCETYPE_DISK | RESOURCETYPE_PRINT ) )
  288. {
  289. return WN_BAD_VALUE;
  290. }
  291. NET_ENUMNODE *pNetEnum;
  292. if ( dwScope == RESOURCE_CONNECTED )
  293. {
  294. /*
  295. * we are looking for current uses
  296. */
  297. if ( lpNetResource != NULL )
  298. {
  299. return WN_BAD_VALUE;
  300. }
  301. err = GetLMProviderName();
  302. if (err)
  303. return(err);
  304. pNetEnum = new USE_ENUMNODE( dwScope, dwType, dwUsage, lpNetResource );
  305. }
  306. else if ( dwScope == RESOURCE_CONTEXT )
  307. {
  308. /*
  309. * we are looking for servers in the domain
  310. * Note that lpNetResource is ignored
  311. * dwType is decoded in the CONTEXT_ENUMNODE constructor
  312. */
  313. pNetEnum = new CONTEXT_ENUMNODE( dwScope, dwType, dwUsage, NULL );
  314. }
  315. else if ( dwScope == RESOURCE_SHAREABLE )
  316. {
  317. /*
  318. * We are looking for shareable resources
  319. * Use SHARE_ENUMNODE, which decodes dwScope when it enumerates
  320. * If we're not given a server, return an EMPTY_ENUMNODE
  321. */
  322. if (lpNetResource != NULL
  323. &&
  324. lpNetResource->lpRemoteName != NULL
  325. &&
  326. lpNetResource->lpRemoteName[0] == TCH('\\')
  327. &&
  328. lpNetResource->lpRemoteName[1] == TCH('\\')
  329. )
  330. {
  331. if (!IsThisADfsDomain(lpNetResource->lpRemoteName))
  332. {
  333. pNetEnum = new SHARE_ENUMNODE( dwScope, dwType, dwUsage, lpNetResource );
  334. }
  335. else
  336. {
  337. pNetEnum = new EMPTY_ENUMNODE( dwScope, dwType, dwUsage, lpNetResource );
  338. }
  339. }
  340. }
  341. else if ( dwScope == RESOURCE_GLOBALNET )
  342. {
  343. /* Look for the combination of all bits and substitute "All" for
  344. * them. Ignore bits we don't know about.
  345. * Note: RESOURCEUSAGE_ATTACHED is a no-op for us, since LanMan
  346. * always tries to authenticate when doing an enumeration.
  347. */
  348. dwUsage &= (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER);
  349. if ( dwUsage == (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER) )
  350. {
  351. dwUsage = 0 ;
  352. }
  353. /*
  354. * we are looking for global resources out on the net
  355. */
  356. if (lpNetResource == NULL || lpNetResource->lpRemoteName == NULL)
  357. {
  358. /*
  359. * at top level, therefore enumerating domains. if user
  360. * asked for connectable, well, there aint none.
  361. */
  362. if ( dwUsage == RESOURCEUSAGE_CONNECTABLE )
  363. {
  364. pNetEnum = new EMPTY_ENUMNODE( dwScope,
  365. dwType,
  366. dwUsage,
  367. lpNetResource );
  368. }
  369. else
  370. {
  371. pNetEnum = new DOMAIN_ENUMNODE( dwScope,
  372. dwType,
  373. dwUsage,
  374. lpNetResource );
  375. }
  376. }
  377. else
  378. {
  379. /*
  380. * we are assured of lpRemoteName != NULL.
  381. * things get interesting here. the cases are as follows:
  382. *
  383. * if (dwUsage == 0)
  384. * if have \\ in front
  385. * return shares
  386. * else
  387. * return servers
  388. * else if (dwUsage == CONNECTABLE)
  389. * if have \\ in front
  390. * return shares
  391. * else
  392. * empty enum
  393. * else if (dwUsage == CONTAINER)
  394. * if have \\ in front
  395. * empty enum
  396. * else
  397. * return server
  398. *
  399. * In interest of code size, i've reorganized the above
  400. * cases to minimized the bodies of the ifs.
  401. *
  402. * chuckc.
  403. */
  404. if ( ((dwUsage == RESOURCEUSAGE_CONNECTABLE) ||
  405. (dwUsage == 0)
  406. )
  407. &&
  408. ((lpNetResource->lpRemoteName[0] == TCH('\\')) &&
  409. (lpNetResource->lpRemoteName[1] == TCH('\\'))
  410. )
  411. )
  412. {
  413. /* Confirm that this really is a computer name (i.e., a
  414. * container we can enumerate).
  415. */
  416. if ( ::I_MNetNameValidate( NULL,
  417. &(lpNetResource->lpRemoteName[2]),
  418. NAMETYPE_COMPUTER,
  419. 0L))
  420. {
  421. return WN_BAD_VALUE ;
  422. }
  423. pNetEnum = new SHARE_ENUMNODE( dwScope, dwType, dwUsage,
  424. lpNetResource );
  425. }
  426. else if ( ((dwUsage == RESOURCEUSAGE_CONTAINER) ||
  427. (dwUsage == 0)
  428. )
  429. &&
  430. (lpNetResource->lpRemoteName[0] != TCH('\\'))
  431. )
  432. {
  433. pNetEnum = new SERVER_ENUMNODE( dwScope, dwType, dwUsage,
  434. lpNetResource );
  435. }
  436. else if (
  437. // ask for share but aint starting from server
  438. (
  439. (dwUsage == RESOURCEUSAGE_CONNECTABLE)
  440. &&
  441. (lpNetResource->lpRemoteName[0] != TCH('\\'))
  442. )
  443. ||
  444. // ask for server but is starting from server
  445. (
  446. (dwUsage == RESOURCEUSAGE_CONTAINER)
  447. &&
  448. ((lpNetResource->lpRemoteName[0] == TCH('\\')) &&
  449. (lpNetResource->lpRemoteName[1] == TCH('\\'))
  450. )
  451. )
  452. )
  453. {
  454. pNetEnum = new EMPTY_ENUMNODE( dwScope,
  455. dwType,
  456. dwUsage,
  457. lpNetResource );
  458. }
  459. else
  460. {
  461. // incorrect dwUsage
  462. return WN_BAD_VALUE;
  463. }
  464. }
  465. }
  466. else
  467. {
  468. // invalid dwScope
  469. return WN_BAD_VALUE;
  470. }
  471. if ( pNetEnum == NULL )
  472. {
  473. return WN_OUT_OF_MEMORY;
  474. }
  475. else if ( err = pNetEnum->QueryError() )
  476. {
  477. delete pNetEnum;
  478. return MapError(err);
  479. }
  480. if ( pNetEnum->IsFirstGetInfo() )
  481. {
  482. if (( err = pNetEnum->GetInfo()) != WN_SUCCESS )
  483. {
  484. delete pNetEnum;
  485. return MapError(err);
  486. }
  487. }
  488. ////////////////////////////////////////// Enter critical section
  489. if ( err = WNetEnterCriticalSection() )
  490. {
  491. delete pNetEnum;
  492. return err ;
  493. }
  494. ASSERT( vpNetEnumArray != NULL );
  495. INT iPos = vpNetEnumArray->QueryNextAvail();
  496. if ( iPos < 0 )
  497. {
  498. WNetLeaveCriticalSection() ;
  499. delete pNetEnum;
  500. return WN_OUT_OF_MEMORY;
  501. }
  502. vpNetEnumArray->SetNode( (UINT)iPos, pNetEnum );
  503. *lphEnum = UintToPtr((UINT)iPos);
  504. WNetLeaveCriticalSection() ;
  505. ////////////////////////////////////////// Leave critical section
  506. return err ;
  507. }
  508. /*******************************************************************
  509. NAME: NPEnumResource
  510. SYNOPSIS: Perform an enumeration based on handle returned by
  511. NPOpenEnum.
  512. ENTRY: HANDLE hEnum - This must be a handle obtained from
  513. NPOpenEnum call
  514. UINT *lpcRequested - Specifies the number of entries
  515. requested. It may be 0xFFFFFFFF to request as many as
  516. possible. On successful call, this location will receive
  517. the number of entries actually read.
  518. VOID *lpBuffer - A pointer to the buffer to receive the
  519. enumeration result, which are returned as an array
  520. of NETRESOURCE entries. The buffer is valid until
  521. the next call using hEnum.
  522. UINT * lpBufferSize - This specifies the size of the
  523. buffer passed to the function call. If WN_MORE_DATA
  524. is returned and no entries were enumerated, then this
  525. will be set to the minimum buffer size required.
  526. EXIT: UINT *lpcRequested - will receive the number of entries
  527. actually read.
  528. RETURNS: WN_SUCCESS if the call is successful, the caller should
  529. continue to call NPEnumResource to continue the
  530. enumeration.
  531. WN_NO_MORE_ENTRIES - no more entries found, the
  532. enumeration completed successfully ( the contents of the
  533. return buffer is undefined). Otherwise, GetLastError
  534. should be called for extended error information.
  535. Extended error codes include:
  536. WN_MORE_DATA - the buffer is too small even for one
  537. entry
  538. WN_BAD_HANDLE - hEnum is not a valid handle
  539. WN_NOT_NETWORK - network is not present. This
  540. condition is checked for before hEnum is tested for
  541. validity.
  542. WN_NET_ERROR - a network specific error occured.
  543. WNetGetLastError should be called to obtain further
  544. information.
  545. HISTORY:
  546. terryk 24-Oct-91 Created
  547. KeithMo 15-Sep-92 Align *lpcBufferSize as needed.
  548. ********************************************************************/
  549. DWORD APIENTRY
  550. NPEnumResource(
  551. HANDLE hEnum,
  552. UINT * lpcRequested,
  553. LPVOID lpBuffer,
  554. UINT * lpcBufferSize )
  555. {
  556. APIERR err ;
  557. if (( lpBuffer == NULL ) ||
  558. ( lpcRequested == NULL ) ||
  559. ( lpcBufferSize == NULL ))
  560. {
  561. return WN_BAD_VALUE;
  562. }
  563. if ( err = WNetEnterCriticalSection() )
  564. {
  565. return err ;
  566. }
  567. ASSERT( vpNetEnumArray != NULL );
  568. NET_ENUMNODE *pNode = vpNetEnumArray->QueryNode(PtrToUint(hEnum));
  569. WNetLeaveCriticalSection() ;
  570. if ( pNode == NULL )
  571. {
  572. return WN_BAD_HANDLE;
  573. }
  574. else if ( pNode->IsFirstGetInfo() )
  575. {
  576. if ( err = CheckLMService() )
  577. {
  578. return err ;
  579. }
  580. if (( err = pNode->GetInfo()) != WN_SUCCESS )
  581. {
  582. return ( MapError(err) );
  583. }
  584. }
  585. LPNETRESOURCE pNetResource = ( LPNETRESOURCE ) lpBuffer;
  586. UINT cbRemainSize = ROUND_DOWN(*lpcBufferSize);
  587. UINT cRequested = (*lpcRequested);
  588. *lpcRequested = 0;
  589. while ( *lpcRequested < cRequested )
  590. {
  591. err = pNode->GetNetResource((BYTE *)pNetResource, &cbRemainSize );
  592. if ( err == WN_MORE_DATA )
  593. {
  594. /* If we can't even fit one into the buffer, then set the required
  595. * buffer size and return WN_MORE_DATA.
  596. */
  597. if ( *lpcRequested == 0 )
  598. {
  599. *lpcBufferSize = ROUND_UP(cbRemainSize);
  600. }
  601. else
  602. {
  603. err = NERR_Success ;
  604. }
  605. break;
  606. }
  607. if ( err == WN_NO_MORE_ENTRIES )
  608. {
  609. if ( *lpcRequested != 0 )
  610. {
  611. err = NERR_Success ;
  612. }
  613. break;
  614. }
  615. if ( err != WN_SUCCESS )
  616. {
  617. break ;
  618. }
  619. /* err == WN_SUCCESS
  620. */
  621. (*lpcRequested) ++;
  622. if ( sizeof( NETRESOURCE ) > cbRemainSize )
  623. {
  624. break ;
  625. }
  626. pNetResource ++;
  627. cbRemainSize -= (UINT)sizeof( NETRESOURCE );
  628. }
  629. return err ;
  630. }
  631. /*******************************************************************
  632. NAME: NPCloseEnum
  633. SYNOPSIS: Closes an enumeration.
  634. ENTRY: HANDLE hEnum - this must be a handle obtained from
  635. NPOpenEnum call.
  636. RETURNS: WN_SUCCESS if the call is successful. Otherwise,
  637. GetLastError should be called for extended error information.
  638. Extended error codes include:
  639. WN_NO_NETWORK - network is not present. this condition is
  640. checked for before hEnum is tested for validity.
  641. WN_BAD_HANDLE - hEnum is not a valid handle.
  642. WN_NET_ERROR - a network specific error occured.
  643. WNetGetLastError should be called to obtain further
  644. information.
  645. HISTORY:
  646. terryk 24-Oct-91 Created
  647. ********************************************************************/
  648. DWORD APIENTRY
  649. NPCloseEnum(
  650. HANDLE hEnum )
  651. {
  652. APIERR err ;
  653. if ( err = WNetEnterCriticalSection() )
  654. {
  655. return err ;
  656. }
  657. ASSERT( vpNetEnumArray != NULL );
  658. NET_ENUMNODE *pNode = vpNetEnumArray->QueryNode(PtrToUint(hEnum));
  659. if ( pNode == NULL )
  660. {
  661. // cannot find the node
  662. err = WN_BAD_HANDLE;
  663. }
  664. else
  665. {
  666. vpNetEnumArray->ClearNode(PtrToUint(hEnum));
  667. }
  668. WNetLeaveCriticalSection() ;
  669. return err ;
  670. }
  671. /*******************************************************************
  672. NAME: WNetEnterCriticalSection
  673. SYNOPSIS: Locks the LM network provider enumeration code
  674. EXIT: vhSemaphore will be locked
  675. RETURNS: NERR_Success if successful, error code otherwise
  676. NOTES: We wait for 7 seconds for the semaphonre to be freed
  677. HISTORY:
  678. Johnl 27-Apr-1992 Created
  679. ********************************************************************/
  680. APIERR WNetEnterCriticalSection( void )
  681. {
  682. APIERR err = NERR_Success ;
  683. switch( WaitForSingleObject( vhSemaphore, 7000L ))
  684. {
  685. case 0:
  686. break ;
  687. case WAIT_TIMEOUT:
  688. err = WN_FUNCTION_BUSY ;
  689. break ;
  690. case 0xFFFFFFFF:
  691. err = ::GetLastError() ;
  692. break ;
  693. default:
  694. UIASSERT(FALSE) ;
  695. err = WN_WINDOWS_ERROR ;
  696. break ;
  697. }
  698. return err ;
  699. }
  700. /*******************************************************************
  701. NAME: WNetLeaveCriticalSection
  702. SYNOPSIS: Unlocks the enumeration methods
  703. RETURNS:
  704. NOTES:
  705. HISTORY:
  706. Johnl 27-Apr-1992 Created
  707. ********************************************************************/
  708. void WNetLeaveCriticalSection( void )
  709. {
  710. REQUIRE( ReleaseSemaphore( vhSemaphore, 1, NULL ) ) ;
  711. }