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.

896 lines
23 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name :
  4. rpcutil.c
  5. Abstract:
  6. This module defines functions that may help to replace the rpc util
  7. functions from rpcutil.lib
  8. Author:
  9. Murali R. Krishnan ( MuraliK ) 15-Sept-1995
  10. Environment:
  11. Win32 User Mode
  12. Project:
  13. Common Code for Internet Services
  14. Functions Exported:
  15. MIDL_user_allocate()
  16. MIDL_user_free()
  17. RpcBindHandleForServer()
  18. RpcBindHandleFree()
  19. Revision History:
  20. Murali R. Krishnan (MuraliK) 21-Dec-1995 Support TcpIp binding & free.
  21. Murali R. Krishnan (MuraliK) 20-Feb-1996 Support Lpc binding & free.
  22. --*/
  23. /************************************************************
  24. * Include Headers
  25. ************************************************************/
  26. # include <windows.h>
  27. # include <rpc.h>
  28. # include "apiutil.h"
  29. # if DBG
  30. # include <stdio.h>
  31. # include <stdlib.h>
  32. # define DBGPRINTF(s) { CHAR rgchBuff[1024]; \
  33. sprintf s ; \
  34. OutputDebugStringA( rgchBuff); \
  35. }
  36. # define DBG_CONTEXT ( rgchBuff)
  37. # else // DBG
  38. # define DBGPRINTF(s) /* nothing */
  39. # define DBG_CONTEXT /* nothing */
  40. # endif // DBG
  41. #define ISRPC_CLIENT_OVER_TCPIP 0x00000001
  42. #define ISRPC_CLIENT_OVER_NP 0x00000002
  43. #define ISRPC_CLIENT_OVER_SPX 0x00000004
  44. #define ISRPC_CLIENT_OVER_LPC 0x00000008
  45. // # define MAX_COMPUTERNAME_LENGTH (255)
  46. /************************************************************
  47. * Functions
  48. ************************************************************/
  49. PVOID
  50. MIDL_user_allocate(IN size_t size)
  51. /*++
  52. Routine Description:
  53. MIDL memory allocation.
  54. Arguments:
  55. size : Memory size requested.
  56. Return Value:
  57. Pointer to the allocated memory block.
  58. --*/
  59. {
  60. PVOID pvBlob;
  61. pvBlob = LocalAlloc( LPTR, size);
  62. return( pvBlob );
  63. } // MIDL_user_allocate()
  64. VOID
  65. MIDL_user_free(IN PVOID pvBlob)
  66. /*++
  67. Routine Description:
  68. MIDL memory free .
  69. Arguments:
  70. pvBlob : Pointer to a memory block that is freed.
  71. Return Value:
  72. None.
  73. --*/
  74. {
  75. LocalFree( pvBlob);
  76. return;
  77. } // MIDL_user_free()
  78. RPC_STATUS
  79. RpcBindHandleOverNamedPipe( OUT handle_t * pBindingHandle,
  80. IN LPWSTR pwszServerName,
  81. IN LPWSTR pwszEndpoint,
  82. IN LPWSTR pwszOptions
  83. )
  84. /*++
  85. This function uses the parameters supplied and generates a named pipe
  86. binding handle for RPC.
  87. Arguments:
  88. pBindingHandle pointer to location which will contain binding handle
  89. on successful return
  90. pwszServerName pointer to string containing the name of the server
  91. to which, this function will obtain a binding.
  92. pwszEndpoint pointer to string containing the Named Pipe Endpoint
  93. pwszOptions pointer to string containing any additional options for
  94. binding.
  95. Returns:
  96. RPC_STATUS - RPC_S_OK on success
  97. Also on success, the binding handle is stored in pBindingHandle.
  98. It should freed after usage, using the RpcBindingFree() function.
  99. --*/
  100. {
  101. RPC_STATUS rpcStatus;
  102. LPWSTR pwszBinding = NULL;
  103. if ( pBindingHandle != NULL) {
  104. *pBindingHandle = NULL; // init the value
  105. }
  106. //
  107. // Compose the binding string for named pipe binding
  108. //
  109. rpcStatus = RpcStringBindingComposeW(0, // ObjUuid
  110. L"ncacn_np", // prot seq: named pipe
  111. pwszServerName, // NetworkAddr
  112. pwszEndpoint, // Endpoint
  113. pwszOptions, // Options
  114. &pwszBinding); // StringBinding
  115. if ( rpcStatus == RPC_S_OK ) {
  116. //
  117. // establish the binding handle using string binding.
  118. //
  119. rpcStatus = RpcBindingFromStringBindingW(pwszBinding,
  120. pBindingHandle );
  121. }
  122. //
  123. // Cleanup and return back.
  124. //
  125. if ( pwszBinding != NULL) {
  126. RpcStringFreeW(&pwszBinding);
  127. }
  128. if ( rpcStatus != RPC_S_OK) {
  129. if ( pBindingHandle != NULL && *pBindingHandle != NULL) {
  130. // RPC should have freed the binding handle.
  131. // We will free it now.
  132. RpcBindingFree(*pBindingHandle);
  133. *pBindingHandle = NULL;
  134. }
  135. }
  136. return (rpcStatus);
  137. } // RpcBindHandleOverNamedPipe()
  138. RPC_STATUS
  139. RpcBindHandleOverLpc( OUT handle_t * pBindingHandle,
  140. IN LPWSTR pwszEndpoint,
  141. IN LPWSTR pwszOptions
  142. )
  143. /*++
  144. This function uses the parameters supplied and generates a lpc
  145. binding handle for RPC.
  146. Arguments:
  147. pBindingHandle pointer to location which will contain binding handle
  148. on successful return
  149. pwszEndpoint pointer to string containing the lpc Endpoint
  150. pwszOptions pointer to string containing any additional options for
  151. binding.
  152. Returns:
  153. RPC_STATUS - RPC_S_OK on success
  154. Also on success, the binding handle is stored in pBindingHandle.
  155. It should freed after usage, using the RpcBindingFree() function.
  156. --*/
  157. {
  158. RPC_STATUS rpcStatus;
  159. LPWSTR pwszBinding = NULL;
  160. if ( pBindingHandle != NULL) {
  161. *pBindingHandle = NULL; // init the value
  162. }
  163. //
  164. // Compose the binding string for named pipe binding
  165. //
  166. rpcStatus = RpcStringBindingComposeW(0, // ObjUuid
  167. L"ncalrpc", // prot seq: lpc
  168. NULL, // NetworkAddr
  169. pwszEndpoint, // Endpoint
  170. pwszOptions, // Options
  171. &pwszBinding); // StringBinding
  172. if ( rpcStatus == RPC_S_OK ) {
  173. //
  174. // establish the binding handle using string binding.
  175. //
  176. rpcStatus = RpcBindingFromStringBindingW(pwszBinding,
  177. pBindingHandle );
  178. }
  179. //
  180. // Cleanup and return back.
  181. //
  182. if ( pwszBinding != NULL) {
  183. RpcStringFreeW(&pwszBinding);
  184. }
  185. if ( rpcStatus != RPC_S_OK) {
  186. if ( pBindingHandle != NULL && *pBindingHandle != NULL) {
  187. // RPC should have freed the binding handle.
  188. // We will free it now.
  189. RpcBindingFree(*pBindingHandle);
  190. *pBindingHandle = NULL;
  191. }
  192. }
  193. return (rpcStatus);
  194. } // RpcBindHandleOverLpc()
  195. #ifndef CHICAGO
  196. //
  197. // If changes are made to the NT version, check out the windows 95
  198. // version located right after this routine and see if the change
  199. // needs to be propagated there too.
  200. //
  201. RPC_STATUS
  202. RpcBindHandleOverTcpIp( OUT handle_t * pBindingHandle,
  203. IN LPWSTR pwszServerName,
  204. IN LPWSTR pwszInterfaceName
  205. )
  206. /*++
  207. NT Version
  208. This function uses the parameters supplied and generates a dynamic end point
  209. binding handle for RPC over TCP/IP.
  210. Arguments:
  211. pBindingHandle pointer to location which will contain binding handle
  212. on successful return
  213. pwszServerName pointer to string containing the name of the server
  214. to which, this function will obtain a binding.
  215. pwszInterfaceName pointer to string containing the interface name
  216. Returns:
  217. RPC_STATUS - RPC_S_OK on success
  218. Also on success, the binding handle is stored in pBindingHandle.
  219. It should freed after usage, using the RpcBindingFree() function.
  220. --*/
  221. {
  222. RPC_STATUS rpcStatus;
  223. LPWSTR pwszBinding = NULL;
  224. if ( pBindingHandle != NULL) {
  225. *pBindingHandle = NULL; // init the value
  226. }
  227. //
  228. // Compose the binding string for named pipe binding
  229. //
  230. rpcStatus = RpcStringBindingComposeW(0, // ObjUuid
  231. L"ncacn_ip_tcp", // tcpip seq
  232. pwszServerName, // NetworkAddr
  233. NULL, // Endpoint
  234. L"", // Options
  235. &pwszBinding); // StringBinding
  236. DBGPRINTF( (DBG_CONTEXT, "\nRpcStringBindingComposeW(%S, %S) return %S."
  237. " Error = %ld\n",
  238. L"ncacn_ip_tcp",
  239. pwszServerName,
  240. pwszBinding,
  241. rpcStatus)
  242. );
  243. if ( rpcStatus == RPC_S_OK ) {
  244. //
  245. // establish the binding handle using string binding.
  246. //
  247. rpcStatus = RpcBindingFromStringBindingW(pwszBinding,
  248. pBindingHandle );
  249. DBGPRINTF( (DBG_CONTEXT,
  250. "RpcBindingFromStringBindingW(%S) return %d."
  251. "Binding=%p\n",
  252. pwszBinding,
  253. rpcStatus,
  254. *pBindingHandle)
  255. );
  256. }
  257. if ( rpcStatus == RPC_S_OK) {
  258. //
  259. // set up the security information
  260. //
  261. rpcStatus =
  262. RpcBindingSetAuthInfoW(*pBindingHandle,
  263. pwszInterfaceName, // pszPrincipalName
  264. RPC_C_AUTHN_LEVEL_CONNECT,
  265. RPC_C_AUTHN_WINNT,
  266. NULL, // AuthnIdentity
  267. 0 // AuthzSvc
  268. );
  269. DBGPRINTF( (DBG_CONTEXT,
  270. "RpcBindingSetAuthInfo(%S(Interface=%S), %p)"
  271. " return %d.\n",
  272. pwszBinding,
  273. pwszInterfaceName,
  274. *pBindingHandle,
  275. rpcStatus
  276. )
  277. );
  278. }
  279. //
  280. // Cleanup and return back.
  281. //
  282. if ( pwszBinding != NULL) {
  283. DWORD rpcStatus1 = RpcStringFreeW(&pwszBinding);
  284. DBGPRINTF( (DBG_CONTEXT, "RpcStringFreeW() returns %d.",
  285. rpcStatus1)
  286. );
  287. }
  288. if ( rpcStatus != RPC_S_OK) {
  289. if ( pBindingHandle != NULL && *pBindingHandle != NULL) {
  290. // RPC should have freed the binding handle.
  291. // We will free it now.
  292. DWORD rpcStatus1 = RpcBindingFree(*pBindingHandle);
  293. DBGPRINTF( (DBG_CONTEXT, "RpcBindingFree() returns %d.\n",
  294. rpcStatus1)
  295. );
  296. *pBindingHandle = NULL;
  297. }
  298. }
  299. return (rpcStatus);
  300. } // RpcBindHandleOverTcpIp()
  301. #else // CHICAGO
  302. RPC_STATUS
  303. RpcBindHandleOverTcpIp( OUT handle_t * pBindingHandle,
  304. IN LPWSTR pwszServerName,
  305. IN LPWSTR pwszInterfaceName
  306. )
  307. /*++
  308. Windows 95 version
  309. This function uses the parameters supplied and generates a dynamic end point
  310. binding handle for RPC over TCP/IP.
  311. Arguments:
  312. pBindingHandle pointer to location which will contain binding handle
  313. on successful return
  314. pwszServerName pointer to string containing the name of the server
  315. to which, this function will obtain a binding.
  316. pwszInterfaceName pointer to string containing the interface name
  317. Returns:
  318. RPC_STATUS - RPC_S_OK on success
  319. Also on success, the binding handle is stored in pBindingHandle.
  320. It should freed after usage, using the RpcBindingFree() function.
  321. --*/
  322. {
  323. RPC_STATUS rpcStatus;
  324. LPSTR pszBindingA = NULL;
  325. CHAR szServerA[MAX_PATH];
  326. CHAR szInterfaceA[MAX_PATH];
  327. int cch;
  328. if ( pBindingHandle != NULL) {
  329. *pBindingHandle = NULL; // init the value
  330. }
  331. *szServerA = '0';
  332. if (pwszServerName)
  333. cch = WideCharToMultiByte(CP_ACP,
  334. 0,
  335. pwszServerName,
  336. -1,
  337. szServerA,
  338. sizeof(szServerA)/sizeof(CHAR),
  339. NULL,NULL
  340. );
  341. *szInterfaceA = '0';
  342. if(pwszInterfaceName)
  343. cch = WideCharToMultiByte(CP_ACP,
  344. 0,
  345. pwszInterfaceName,
  346. -1,
  347. szInterfaceA,
  348. sizeof(szInterfaceA)/sizeof(CHAR),
  349. NULL,NULL
  350. );
  351. //
  352. // Compose the binding string for named pipe binding
  353. //
  354. rpcStatus = RpcStringBindingCompose(0, // ObjUuid
  355. "ncacn_ip_tcp", // tcpip seq
  356. szServerA, // NetworkAddr
  357. NULL, // Endpoint
  358. NULL, //L"", // Options
  359. &pszBindingA); // StringBinding
  360. DBGPRINTF( (DBG_CONTEXT, "\nRpcStringBindingCompose(%s, %s) return %s."
  361. " Error = %ld\n",
  362. "ncacn_ip_tcp",
  363. szServerA,
  364. pszBindingA,
  365. rpcStatus)
  366. );
  367. if ( rpcStatus == RPC_S_OK ) {
  368. //
  369. // establish the binding handle using string binding.
  370. //
  371. rpcStatus = RpcBindingFromStringBinding(pszBindingA,
  372. pBindingHandle );
  373. DBGPRINTF( (DBG_CONTEXT,
  374. "RpcBindingFromStringBinding(%s) return %d."
  375. "Binding=%08x\n",
  376. pszBindingA,
  377. rpcStatus,
  378. *pBindingHandle)
  379. );
  380. }
  381. if ( rpcStatus == RPC_S_OK) {
  382. //
  383. // set up the security information
  384. //
  385. rpcStatus =
  386. RpcBindingSetAuthInfo(*pBindingHandle,
  387. szInterfaceA, // pszPrincipalName
  388. RPC_C_AUTHN_LEVEL_CONNECT,
  389. RPC_C_AUTHN_WINNT,
  390. NULL, // AuthnIdentity
  391. 0 // AuthzSvc
  392. );
  393. DBGPRINTF( (DBG_CONTEXT,
  394. "RpcBindingSetAuthInfo(%s(Interface=%s), %08x)"
  395. " return %d.\n",
  396. pszBindingA,
  397. szInterfaceA,
  398. *pBindingHandle,
  399. rpcStatus
  400. )
  401. );
  402. }
  403. //
  404. // Cleanup and return back.
  405. //
  406. if ( pszBindingA != NULL) {
  407. DWORD rpcStatus1 = RpcStringFree(&pszBindingA);
  408. DBGPRINTF( (DBG_CONTEXT, "RpcStringFreeW() returns %d.",
  409. rpcStatus1)
  410. );
  411. }
  412. if ( rpcStatus != RPC_S_OK) {
  413. if ( pBindingHandle != NULL && *pBindingHandle != NULL) {
  414. // RPC should have freed the binding handle.
  415. // We will free it now.
  416. DWORD rpcStatus1 = RpcBindingFree(*pBindingHandle);
  417. DBGPRINTF( (DBG_CONTEXT, "RpcBindingFree() returns %d.\n",
  418. rpcStatus1)
  419. );
  420. *pBindingHandle = NULL;
  421. }
  422. }
  423. return (rpcStatus);
  424. } // RpcBindHandleOverTcpIp()
  425. #endif
  426. #ifndef CHICAGO
  427. DWORD
  428. RpcuFindProtocolToUse( IN LPCWSTR pwszServerName)
  429. /*++
  430. Given the server name this funciton determines the protocol
  431. to use for RPC binding.
  432. The transport used is determined dynamically based on following rules.
  433. If server name is NULL or 127.0.0.1 or same as local computer name
  434. then use the LPC.
  435. If server name starts with a leading "\\" (double slash),
  436. then attempt RPC binding over NamedPipe.
  437. If server name does not start with leading "\\",
  438. then attempt RPC binding over TCPIP.
  439. If TCPIP binding fails, then this function tries binding over NamedPipe.
  440. Argument:
  441. pwszServerName - pointer to string containing the name of the server
  442. Returns:
  443. DWORD containing the type of protocol to use.
  444. --*/
  445. {
  446. static WCHAR g_wchLocalMachineName[ MAX_COMPUTERNAME_LENGTH + 1];
  447. BOOL fLeadingSlashes;
  448. DWORD dwBindProtocol = ISRPC_CLIENT_OVER_NP;
  449. BOOL fLocalMachine;
  450. if ( pwszServerName == NULL ||
  451. _wcsicmp( L"127.0.0.1", pwszServerName) == 0) {
  452. return (ISRPC_CLIENT_OVER_LPC);
  453. }
  454. if ( g_wchLocalMachineName[0] == L'\0') {
  455. DWORD cchComputerNameLen = MAX_COMPUTERNAME_LENGTH;
  456. //
  457. // Obtain the local computer name
  458. //
  459. if (!GetComputerNameW( g_wchLocalMachineName,
  460. &cchComputerNameLen)
  461. ) {
  462. *g_wchLocalMachineName = L'\0';
  463. }
  464. }
  465. fLeadingSlashes = ((*pwszServerName == L'\\') &&
  466. (*(pwszServerName+1) == L'\\')
  467. );
  468. //
  469. // Check to see if machine name matches local computer name
  470. // if so, use LPC
  471. //
  472. fLocalMachine = !_wcsicmp( g_wchLocalMachineName,
  473. ((fLeadingSlashes) ?
  474. (pwszServerName + 2) : pwszServerName)
  475. );
  476. if ( fLocalMachine) {
  477. return (ISRPC_CLIENT_OVER_LPC);
  478. }
  479. if ( !fLeadingSlashes) {
  480. DWORD nDots;
  481. LPCWSTR pszName;
  482. //
  483. // Check if the name has dotted decimal name.
  484. // If so then suggest TCP binding.
  485. //
  486. for( nDots = 0, pszName = pwszServerName;
  487. ((pszName = wcschr( pszName, L'.' )) != NULL);
  488. nDots++, pszName++)
  489. ;
  490. if ( nDots == 3) {
  491. //
  492. // if the string has 3 DOTs exactly then this string must represent
  493. // an IpAddress.
  494. //
  495. return(ISRPC_CLIENT_OVER_TCPIP);
  496. }
  497. }
  498. return ( ISRPC_CLIENT_OVER_NP);
  499. } // RpcuFindProtocolToUse()
  500. #endif
  501. RPC_STATUS
  502. RpcBindHandleForServer( OUT handle_t * pBindingHandle,
  503. IN LPWSTR pwszServerName,
  504. IN LPWSTR pwszInterfaceName,
  505. IN LPWSTR pwszOptions
  506. )
  507. /*++
  508. This function uses the parameters supplied and generates a binding
  509. handle for RPC.
  510. It is assumed that binding over named pipe uses static end point
  511. with the interface name and options as provided.
  512. Arguments:
  513. pBindingHandle pointer to location which will contain binding handle
  514. on successful return
  515. pwszServerName pointer to string containing the name of the server
  516. to which, this function will obtain a binding.
  517. pwszInterfaceName pointer to string containing the interface name
  518. pwszOptions pointer to string containing any additional options for
  519. binding.
  520. Returns:
  521. RPC_STATUS - RPC_S_OK on success
  522. Also on success, the binding handle is stored in pBindingHandle.
  523. It should freed after usage, using the RpcBindingFree() function.
  524. --*/
  525. {
  526. RPC_STATUS rpcStatus = RPC_S_SERVER_UNAVAILABLE;
  527. LPWSTR pwszBinding = NULL;
  528. DWORD dwBindProtocol = 0;
  529. if ( pBindingHandle != NULL) {
  530. *pBindingHandle = NULL; // init the value
  531. }
  532. #ifndef CHICAGO
  533. dwBindProtocol = RpcuFindProtocolToUse( pwszServerName);
  534. #else
  535. dwBindProtocol = ISRPC_CLIENT_OVER_TCPIP;
  536. #endif
  537. switch ( dwBindProtocol) {
  538. case ISRPC_CLIENT_OVER_LPC:
  539. {
  540. WCHAR rgchLpc[1024];
  541. //
  542. // generate a LPC end point name from the interface name.
  543. // the End point = <InterfaceName>_LPC
  544. //
  545. if ( lstrlenW( pwszInterfaceName) >=
  546. ( sizeof(rgchLpc)/sizeof(WCHAR) - 6)) {
  547. SetLastError( ERROR_INVALID_PARAMETER);
  548. return ( ERROR_INVALID_PARAMETER);
  549. }
  550. lstrcpyW( rgchLpc, pwszInterfaceName);
  551. lstrcatW( rgchLpc, L"_LPC");
  552. //
  553. // Attempt binding over static LPC.
  554. //
  555. rpcStatus = RpcBindHandleOverLpc( pBindingHandle,
  556. rgchLpc,
  557. pwszOptions
  558. );
  559. DBGPRINTF(( DBG_CONTEXT,
  560. " RpcBindingOverLpc(%S) returns %d."
  561. " Handle = %p\n",
  562. pwszServerName, rpcStatus, *pBindingHandle));
  563. break;
  564. }
  565. case ISRPC_CLIENT_OVER_TCPIP:
  566. // # ifdef RPC_BIND_OVER_TCP
  567. //
  568. // Attempt binding over TCPIP using Dynamic Endpoint.
  569. //
  570. rpcStatus = RpcBindHandleOverTcpIp( pBindingHandle,
  571. pwszServerName,
  572. pwszInterfaceName);
  573. DBGPRINTF(( DBG_CONTEXT,
  574. " RpcBindingOverTcpIp(%S) returns %d. Handle = %p\n",
  575. pwszServerName, rpcStatus, *pBindingHandle));
  576. if ( rpcStatus == RPC_S_OK) {
  577. break; // done with RPC binding over TCP
  578. }
  579. // Fall Through
  580. // # endif // RPC_BIND_OVER_TCP
  581. case ISRPC_CLIENT_OVER_NP:
  582. {
  583. WCHAR rgchNp[1024];
  584. //
  585. // generate a NamedPipe end point name from the interface name.
  586. // the End point = \PIPE\<InterfaceName>
  587. //
  588. lstrcpyW( rgchNp, L"\\PIPE\\");
  589. if ( lstrlenW( pwszInterfaceName) >=
  590. ( sizeof(rgchNp)/sizeof(WCHAR) - 10)) {
  591. SetLastError( ERROR_INVALID_PARAMETER);
  592. return ( ERROR_INVALID_PARAMETER);
  593. }
  594. lstrcatW( rgchNp, pwszInterfaceName);
  595. //
  596. // Attempt binding over static NamedPipe.
  597. //
  598. rpcStatus = RpcBindHandleOverNamedPipe( pBindingHandle,
  599. pwszServerName,
  600. rgchNp,
  601. pwszOptions
  602. );
  603. DBGPRINTF(( DBG_CONTEXT,
  604. " RpcBindingOverNamedPipe(%S) returns %d."
  605. " Handle = %p\n",
  606. pwszServerName, rpcStatus, *pBindingHandle));
  607. break;
  608. }
  609. default:
  610. break;
  611. } // switch()
  612. return ( rpcStatus);
  613. } // RpcBindHandleForServer()
  614. RPC_STATUS
  615. RpcBindHandleFree(IN OUT handle_t * pBindingHandle)
  616. /*++
  617. Description:
  618. This function frees up the binding handle allocated using
  619. RpcBindHandleForServer(). It uses RPC Binding Free routing to do this.
  620. This function acts just as a thunk so that the alloc/free of RPC contexts
  621. are consolidated within this module.
  622. Arguments:
  623. pBindingHandle pointer to RPC binding handle that needs to be freed.
  624. Returns:
  625. RPC_STATUS - containig the RPC status. RPC_S_OK for success.
  626. --*/
  627. {
  628. return ( RpcBindingFree( pBindingHandle));
  629. } // RpcBindHandleFree()
  630. /************************ End of File ***********************/