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.

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