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.

4646 lines
94 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997 - 2000
  5. //
  6. // File: H N C U T I L . C P P
  7. //
  8. // Contents: Home Networking Configuration Utility Routines
  9. //
  10. // Notes:
  11. //
  12. // Author: jonburs 27 June 2000
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. //
  18. // MPRAPI.DLL import prototypes
  19. //
  20. typedef DWORD
  21. (APIENTRY* PMPRCONFIGBUFFERFREE)(
  22. LPVOID
  23. );
  24. typedef DWORD
  25. (APIENTRY* PMPRCONFIGSERVERCONNECT)(
  26. LPWSTR,
  27. PHANDLE
  28. );
  29. typedef VOID
  30. (APIENTRY* PMPRCONFIGSERVERDISCONNECT)(
  31. HANDLE
  32. );
  33. typedef DWORD
  34. (APIENTRY* PMPRCONFIGTRANSPORTGETHANDLE)(
  35. HANDLE,
  36. DWORD,
  37. PHANDLE
  38. );
  39. typedef DWORD
  40. (APIENTRY* PMPRCONFIGTRANSPORTGETINFO)(
  41. HANDLE,
  42. HANDLE,
  43. LPBYTE*,
  44. LPDWORD,
  45. LPBYTE*,
  46. LPDWORD,
  47. LPWSTR*
  48. );
  49. typedef DWORD
  50. (APIENTRY* PMPRINFOBLOCKFIND)(
  51. LPVOID,
  52. DWORD,
  53. LPDWORD,
  54. LPDWORD,
  55. LPBYTE*
  56. );
  57. //
  58. // The size of the stack buffer to use for building queries. If the
  59. // query exceeeds this length, the working buffer will be allocated from
  60. // the heap
  61. //
  62. const ULONG c_cchQueryBuffer = 256;
  63. HRESULT
  64. HrFromLastWin32Error ()
  65. //+---------------------------------------------------------------------------
  66. //
  67. // Function: HrFromLastWin32Error
  68. //
  69. // Purpose: Converts the GetLastError() Win32 call into a proper HRESULT.
  70. //
  71. // Arguments:
  72. // (none)
  73. //
  74. // Returns: Converted HRESULT value.
  75. //
  76. // Author: danielwe 24 Mar 1997
  77. //
  78. // Notes: This is not inline as it actually generates quite a bit of
  79. // code.
  80. // If GetLastError returns an error that looks like a SetupApi
  81. // error, this function will convert the error to an HRESULT
  82. // with FACILITY_SETUP instead of FACILITY_WIN32
  83. //
  84. {
  85. DWORD dwError = GetLastError();
  86. HRESULT hr;
  87. // This test is testing SetupApi errors only (this is
  88. // temporary because the new HRESULT_FROM_SETUPAPI macro will
  89. // do the entire conversion)
  90. if (dwError & (APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR))
  91. {
  92. hr = HRESULT_FROM_SETUPAPI(dwError);
  93. }
  94. else
  95. {
  96. hr = HRESULT_FROM_WIN32(dwError);
  97. }
  98. return hr;
  99. }
  100. BOOLEAN
  101. ApplicationProtocolExists(
  102. IWbemServices *piwsNamespace,
  103. BSTR bstrWQL,
  104. USHORT usOutgoingPort,
  105. UCHAR ucOutgoingIPProtocol
  106. )
  107. /*++
  108. Routine Description:
  109. Checks if an application protocol already exists that has the
  110. specified outgoing protocol and port.
  111. Arguments:
  112. piwsNamespace - the namespace to use
  113. bstrWQL - a BSTR containing "WQL"
  114. ucOutgoingProtocol - the protocol number to check for
  115. usOutgoingPort - the port to check for
  116. Return Value:
  117. BOOLEAN -- TRUE if the application protocol exists; FALSE otherwise
  118. --*/
  119. {
  120. BSTR bstr;
  121. BOOLEAN fDuplicate = FALSE;
  122. HRESULT hr = S_OK;
  123. int iBytes;
  124. IEnumWbemClassObject *pwcoEnum;
  125. IWbemClassObject *pwcoInstance;
  126. ULONG ulObjs;
  127. OLECHAR wszWhereClause[c_cchQueryBuffer + 1];
  128. _ASSERT(NULL != piwsNamespace);
  129. _ASSERT(NULL != bstrWQL);
  130. _ASSERT(0 == wcscmp(bstrWQL, L"WQL"));
  131. //
  132. // Build the query string
  133. //
  134. iBytes = _snwprintf(
  135. wszWhereClause,
  136. c_cchQueryBuffer,
  137. c_wszApplicationProtocolQueryFormat,
  138. usOutgoingPort,
  139. ucOutgoingIPProtocol
  140. );
  141. if (iBytes >= 0)
  142. {
  143. //
  144. // String fit into buffer; make sure it's null terminated
  145. //
  146. wszWhereClause[c_cchQueryBuffer] = L'\0';
  147. }
  148. else
  149. {
  150. //
  151. // For some reason the string didn't fit into the buffer...
  152. //
  153. hr = E_UNEXPECTED;
  154. _ASSERT(FALSE);
  155. }
  156. if (S_OK == hr)
  157. {
  158. hr = BuildSelectQueryBstr(
  159. &bstr,
  160. c_wszStar,
  161. c_wszHnetApplicationProtocol,
  162. wszWhereClause
  163. );
  164. }
  165. if (S_OK == hr)
  166. {
  167. //
  168. // Execute the query
  169. //
  170. pwcoEnum = NULL;
  171. hr = piwsNamespace->ExecQuery(
  172. bstrWQL,
  173. bstr,
  174. WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
  175. NULL,
  176. &pwcoEnum
  177. );
  178. SysFreeString(bstr);
  179. }
  180. if (S_OK == hr)
  181. {
  182. //
  183. // Attempt to retrieve an item from the enum. If we're successful,
  184. // this is a duplicate protocol.
  185. //
  186. pwcoInstance = NULL;
  187. hr = pwcoEnum->Next(
  188. WBEM_INFINITE,
  189. 1,
  190. &pwcoInstance,
  191. &ulObjs
  192. );
  193. if (SUCCEEDED(hr) && 1 == ulObjs)
  194. {
  195. //
  196. // It's a duplicate
  197. //
  198. fDuplicate = TRUE;
  199. pwcoInstance->Release();
  200. }
  201. pwcoEnum->Release();
  202. }
  203. return fDuplicate;
  204. } // ApplicationProtocolExists
  205. HRESULT
  206. BuildAndString(
  207. LPWSTR *ppwsz,
  208. LPCWSTR pwszLeft,
  209. LPCWSTR pwszRight
  210. )
  211. /*++
  212. Routine Description:
  213. Builds the following string:
  214. pwszLeft AND pwszRight
  215. Arguments:
  216. ppwsz - receives the built string. The caller is responsible for calling
  217. delete[] on this variable. Receives NULL on failure.
  218. pwszLeft - left side of the AND clause
  219. pwszRight - right side of the AND clause
  220. Return Value:
  221. Standard HRESULT
  222. --*/
  223. {
  224. HRESULT hr = S_OK;
  225. ULONG cch;
  226. _ASSERT(NULL != ppwsz);
  227. _ASSERT(NULL != pwszLeft);
  228. _ASSERT(NULL != pwszRight);
  229. //
  230. // length(left) + space + AND + space + length(right) + null
  231. //
  232. cch = wcslen(pwszLeft) + wcslen(pwszRight) + 6;
  233. *ppwsz = new OLECHAR[cch];
  234. if (NULL != *ppwsz)
  235. {
  236. swprintf(
  237. *ppwsz,
  238. L"%s AND %s",
  239. pwszLeft,
  240. pwszRight
  241. );
  242. }
  243. else
  244. {
  245. hr = E_OUTOFMEMORY;
  246. }
  247. return hr;
  248. }
  249. HRESULT
  250. BuildAssociatorsQueryBstr(
  251. BSTR *pBstr,
  252. LPCWSTR pwszObjectPath,
  253. LPCWSTR pwszAssocClass
  254. )
  255. /*++
  256. Routine Description:
  257. Builds a WQL references query and places it into a BSTR. The returned
  258. query is
  259. ASSOCIATORS OF {wszProperties} WHERE AssocClass = pwszAssocClass
  260. Arguments:
  261. pBstr - receives the built query. The caller is responsible for calling
  262. SysFreeString on this variable. Receives NULL on failure.
  263. pwszObjectPath - path of the object to find the references of
  264. pwszAssocClass - the associator class
  265. Return Value:
  266. Standard HRESULT
  267. --*/
  268. {
  269. HRESULT hr = S_OK;
  270. OLECHAR wszBuffer[c_cchQueryBuffer + 1];
  271. OLECHAR *pwszQuery = NULL;
  272. //
  273. // On debug builds, verify that our precomputed string lengths
  274. // match the actual lengths
  275. //
  276. _ASSERT(wcslen(c_wszAssociatorsOf) == c_cchAssociatorsOf);
  277. _ASSERT(wcslen(c_wszWhereAssocClass) == c_cchWhereAssocClass);
  278. //
  279. // All necessary spaces are embedded in the string constants
  280. //
  281. ULONG cchLength = c_cchAssociatorsOf + c_cchWhereAssocClass;
  282. _ASSERT(pwszObjectPath);
  283. _ASSERT(pwszAssocClass);
  284. _ASSERT(pBstr);
  285. *pBstr = NULL;
  286. //
  287. // Determine the length of the query string
  288. //
  289. cchLength += wcslen(pwszObjectPath);
  290. cchLength += wcslen(pwszAssocClass);
  291. //
  292. // If the query string is longer than our stack buffer, we need
  293. // to allocate a buffer off of the heap.
  294. //
  295. if (cchLength <= c_cchQueryBuffer)
  296. {
  297. //
  298. // The buffer is large enough. (Note that since the buffer on the
  299. // stack is one greater than the constant, the terminator is accounted
  300. // for.) Point our working pointer to the stack buffer.
  301. //
  302. pwszQuery = wszBuffer;
  303. }
  304. else
  305. {
  306. //
  307. // Allocate a sufficient buffer from the heap. The +1 is for the
  308. // terminating nul
  309. //
  310. pwszQuery = new OLECHAR[cchLength + 1];
  311. if (NULL == pwszQuery)
  312. {
  313. hr = E_OUTOFMEMORY;
  314. pwszQuery = wszBuffer;
  315. }
  316. }
  317. if (S_OK == hr)
  318. {
  319. //
  320. // Build the actual query string
  321. //
  322. swprintf(
  323. pwszQuery,
  324. L"%s%s%s%s",
  325. c_wszAssociatorsOf,
  326. pwszObjectPath,
  327. c_wszWhereAssocClass,
  328. pwszAssocClass
  329. );
  330. *pBstr = SysAllocString(pwszQuery);
  331. if (NULL == *pBstr)
  332. {
  333. hr = E_OUTOFMEMORY;
  334. }
  335. }
  336. //
  337. // Free the query buffer, if necessary
  338. //
  339. if (wszBuffer != pwszQuery)
  340. {
  341. delete [] pwszQuery;
  342. }
  343. return hr;
  344. }
  345. HRESULT
  346. BuildEqualsString(
  347. LPWSTR *ppwsz,
  348. LPCWSTR pwszLeft,
  349. LPCWSTR pwszRight
  350. )
  351. /*++
  352. Routine Description:
  353. Builds the following string:
  354. pwszLeft = pwszRight
  355. Arguments:
  356. ppwsz - receives the built string. The caller is responsible for calling
  357. delete[] on this variable. Receives NULL on failure.
  358. pwszLeft - left side of the equals clause
  359. pwszRight - right side of the equals clause
  360. Return Value:
  361. Standard HRESULT
  362. --*/
  363. {
  364. HRESULT hr = S_OK;
  365. ULONG cch;
  366. _ASSERT(NULL != ppwsz);
  367. _ASSERT(NULL != pwszLeft);
  368. _ASSERT(NULL != pwszRight);
  369. //
  370. // length(left) + space + = + space + length(right) + null
  371. //
  372. cch = wcslen(pwszLeft) + wcslen(pwszRight) + 4;
  373. *ppwsz = new OLECHAR[cch];
  374. if (NULL != *ppwsz)
  375. {
  376. swprintf(
  377. *ppwsz,
  378. L"%s = %s",
  379. pwszLeft,
  380. pwszRight
  381. );
  382. }
  383. else
  384. {
  385. hr = E_OUTOFMEMORY;
  386. }
  387. return hr;
  388. }
  389. HRESULT
  390. BuildEscapedQuotedEqualsString(
  391. LPWSTR *ppwsz,
  392. LPCWSTR pwszLeft,
  393. LPCWSTR pwszRight
  394. )
  395. /*++
  396. Routine Description:
  397. Builds the following string:
  398. pwszLeft = "pwszRight"
  399. after escaping pwszRight -- replace \ w/ \\ and " with \"
  400. Arguments:
  401. ppwsz - receives the built string. The caller is responsible for calling
  402. delete[] on this variable. Receives NULL on failure.
  403. pwszLeft - left side of the equals clause
  404. pwszRight - right side of the equals clause. This will be escaped, and then
  405. wrapped in quotes
  406. Return Value:
  407. Standard HRESULT
  408. --*/
  409. {
  410. HRESULT hr = S_OK;
  411. ULONG cch;
  412. LPWSTR wszEscaped;
  413. _ASSERT(NULL != ppwsz);
  414. _ASSERT(NULL != pwszLeft);
  415. _ASSERT(NULL != pwszRight);
  416. //
  417. // Escape string
  418. //
  419. wszEscaped = EscapeString(pwszRight);
  420. if (NULL == wszEscaped)
  421. {
  422. return E_OUTOFMEMORY;
  423. }
  424. //
  425. // length(left) + space + = + space + " + length(right) + " + null
  426. //
  427. cch = wcslen(pwszLeft) + wcslen(wszEscaped) + 6;
  428. *ppwsz = new OLECHAR[cch];
  429. if (NULL != *ppwsz)
  430. {
  431. swprintf(
  432. *ppwsz,
  433. L"%s = \"%s\"",
  434. pwszLeft,
  435. wszEscaped
  436. );
  437. delete [] wszEscaped;
  438. }
  439. else
  440. {
  441. hr = E_OUTOFMEMORY;
  442. }
  443. return hr;
  444. }
  445. HRESULT
  446. BuildQuotedEqualsString(
  447. LPWSTR *ppwsz,
  448. LPCWSTR pwszLeft,
  449. LPCWSTR pwszRight
  450. )
  451. /*++
  452. Routine Description:
  453. Builds the following string:
  454. pwszLeft = "pwszRight"
  455. Arguments:
  456. ppwsz - receives the built string. The caller is responsible for calling
  457. delete[] on this variable. Receives NULL on failure.
  458. pwszLeft - left side of the equals clause
  459. pwszRight - right side of the equals clause. This will be wrapped in
  460. quotes
  461. Return Value:
  462. Standard HRESULT
  463. --*/
  464. {
  465. HRESULT hr = S_OK;
  466. ULONG cch;
  467. LPWSTR wsz;
  468. _ASSERT(NULL != ppwsz);
  469. _ASSERT(NULL != pwszLeft);
  470. _ASSERT(NULL != pwszRight);
  471. //
  472. // length(left) + space + = + space + " + length(right) + " + null
  473. //
  474. cch = wcslen(pwszLeft) + wcslen(pwszRight) + 6;
  475. *ppwsz = new OLECHAR[cch];
  476. if (NULL != *ppwsz)
  477. {
  478. swprintf(
  479. *ppwsz,
  480. L"%s = \"%s\"",
  481. pwszLeft,
  482. pwszRight
  483. );
  484. }
  485. else
  486. {
  487. hr = E_OUTOFMEMORY;
  488. }
  489. return hr;
  490. }
  491. HRESULT
  492. BuildReferencesQueryBstr(
  493. BSTR *pBstr,
  494. LPCWSTR pwszObjectPath,
  495. LPCWSTR pwszTargetClass
  496. )
  497. /*++
  498. Routine Description:
  499. Builds a WQL references query and places it into a BSTR. The returned
  500. query is
  501. REFERENCES OF {pwszObjectPath} WHERE ResultClass = pwszTargetClass
  502. if pwszTargetClass is not NULL, and
  503. REFERENCES OF {pwszObjectPath}
  504. otherwise
  505. Arguments:
  506. pBstr - receives the built query. The caller is responsible for calling
  507. SysFreeString on this variable. Receives NULL on failure.
  508. pwszObjectPath - path of the object to find the references of
  509. pwszTargetClass - the class of references desired. May be NULL.
  510. Return Value:
  511. Standard HRESULT
  512. --*/
  513. {
  514. HRESULT hr = S_OK;
  515. OLECHAR wszBuffer[c_cchQueryBuffer + 1];
  516. OLECHAR *pwszQuery = NULL;
  517. //
  518. // On debug builds, verify that our precomputed string lengths
  519. // match the actual lengths
  520. //
  521. _ASSERT(wcslen(c_wszReferencesOf) == c_cchReferencesOf);
  522. _ASSERT(wcslen(c_wszWhereResultClass) == c_cchWhereResultClass);
  523. //
  524. // All necessary spaces are embedded in the string constants
  525. //
  526. ULONG cchLength = c_cchReferencesOf + c_cchWhereResultClass;
  527. _ASSERT(pwszObjectPath);
  528. _ASSERT(pBstr);
  529. *pBstr = NULL;
  530. //
  531. // Determine the length of the query string
  532. //
  533. cchLength += wcslen(pwszObjectPath);
  534. if (NULL != pwszTargetClass)
  535. {
  536. cchLength += wcslen(pwszTargetClass);
  537. }
  538. //
  539. // If the query string is longer than our stack buffer, we need
  540. // to allocate a buffer off of the heap.
  541. //
  542. if (cchLength <= c_cchQueryBuffer)
  543. {
  544. //
  545. // The buffer is large enough. (Note that since the buffer on the
  546. // stack is one greater than the constant, the terminator is accounted
  547. // for.) Point our working pointer to the stack buffer.
  548. //
  549. pwszQuery = wszBuffer;
  550. }
  551. else
  552. {
  553. //
  554. // Allocate a sufficient buffer from the heap. The +1 is for the
  555. // terminating nul
  556. //
  557. pwszQuery = new OLECHAR[cchLength + 1];
  558. if (NULL == pwszQuery)
  559. {
  560. hr = E_OUTOFMEMORY;
  561. pwszQuery = wszBuffer;
  562. }
  563. }
  564. if (S_OK == hr)
  565. {
  566. //
  567. // Build the actual query string
  568. //
  569. if (NULL != pwszTargetClass)
  570. {
  571. swprintf(
  572. pwszQuery,
  573. L"%s%s%s%s",
  574. c_wszReferencesOf,
  575. pwszObjectPath,
  576. c_wszWhereResultClass,
  577. pwszTargetClass
  578. );
  579. }
  580. else
  581. {
  582. swprintf(
  583. pwszQuery,
  584. L"%s%s}",
  585. c_wszReferencesOf,
  586. pwszObjectPath
  587. );
  588. }
  589. *pBstr = SysAllocString(pwszQuery);
  590. if (NULL == *pBstr)
  591. {
  592. hr = E_OUTOFMEMORY;
  593. }
  594. }
  595. //
  596. // Free the query buffer, if necessary
  597. //
  598. if (wszBuffer != pwszQuery)
  599. {
  600. delete [] pwszQuery;
  601. }
  602. return hr;
  603. }
  604. HRESULT
  605. BuildSelectQueryBstr(
  606. BSTR *pBstr,
  607. LPCWSTR pwszProperties,
  608. LPCWSTR pwszFromClause,
  609. LPCWSTR pwszWhereClause
  610. )
  611. /*++
  612. Routine Description:
  613. Builds a WQL select query and places it into a BSTR. The returned
  614. query is
  615. SELECT wszProperties FROM wszFromClause [WHERE wszWhereClause]
  616. Arguments:
  617. pBstr - receives the built query. The caller is responsible for calling
  618. SysFreeString on this variable. Receives NULL on failure.
  619. pwszProperties - the properties the query should return
  620. pwszFromClause - the class the returned objects should be from
  621. pwszWhereClause - the constraints that the returned object must meet. If
  622. NULL, the query will not have a where clause.
  623. Return Value:
  624. Standard HRESULT
  625. --*/
  626. {
  627. HRESULT hr = S_OK;
  628. OLECHAR wszBuffer[c_cchQueryBuffer + 1];
  629. OLECHAR *pwszQuery = NULL;
  630. //
  631. // On debug builds, verify that our precomputed string lengths
  632. // match the actual lengths
  633. //
  634. _ASSERT(wcslen(c_wszSelect) == c_cchSelect);
  635. _ASSERT(wcslen(c_wszFrom) == c_cchFrom);
  636. _ASSERT(wcslen(c_wszWhere) == c_cchWhere);
  637. //
  638. // SELECT + 2 spaces (around properties) + FROM + space
  639. //
  640. ULONG cchLength = c_cchSelect + 2 + c_cchFrom + 1;
  641. _ASSERT(pwszProperties);
  642. _ASSERT(pwszFromClause);
  643. _ASSERT(pBstr);
  644. *pBstr = NULL;
  645. //
  646. // Determine the length of the query string
  647. //
  648. cchLength += wcslen(pwszProperties);
  649. cchLength += wcslen(pwszFromClause);
  650. if (pwszWhereClause)
  651. {
  652. //
  653. // space + WHERE + space
  654. //
  655. cchLength += 2 + c_cchWhere;
  656. cchLength += wcslen(pwszWhereClause);
  657. }
  658. //
  659. // If the query string is longer than our stack buffer, we need
  660. // to allocate a buffer off of the heap.
  661. //
  662. if (cchLength <= c_cchQueryBuffer)
  663. {
  664. //
  665. // The buffer is large enough. (Note that since the buffer on the
  666. // stack is one greater than the constant, the terminator is accounted
  667. // for.) Point our working pointer to the stack buffer.
  668. //
  669. pwszQuery = wszBuffer;
  670. }
  671. else
  672. {
  673. //
  674. // Allocate a sufficient buffer from the heap. The +1 is for the
  675. // terminating nul
  676. //
  677. pwszQuery = new OLECHAR[cchLength + 1];
  678. if (NULL == pwszQuery)
  679. {
  680. hr = E_OUTOFMEMORY;
  681. pwszQuery = wszBuffer;
  682. }
  683. }
  684. if (S_OK == hr)
  685. {
  686. //
  687. // Build the actual query string
  688. //
  689. if (pwszWhereClause)
  690. {
  691. swprintf(
  692. pwszQuery,
  693. L"%s %s %s %s %s %s",
  694. c_wszSelect,
  695. pwszProperties,
  696. c_wszFrom,
  697. pwszFromClause,
  698. c_wszWhere,
  699. pwszWhereClause
  700. );
  701. }
  702. else
  703. {
  704. swprintf(
  705. pwszQuery,
  706. L"%s %s %s %s",
  707. c_wszSelect,
  708. pwszProperties,
  709. c_wszFrom,
  710. pwszFromClause
  711. );
  712. }
  713. *pBstr = SysAllocString(pwszQuery);
  714. if (NULL == *pBstr)
  715. {
  716. hr = E_OUTOFMEMORY;
  717. }
  718. }
  719. //
  720. // Free the query buffer, if necessary
  721. //
  722. if (wszBuffer != pwszQuery)
  723. {
  724. delete [] pwszQuery;
  725. }
  726. return hr;
  727. }
  728. BOOLEAN
  729. ConnectionIsBoundToTcp(
  730. PIP_INTERFACE_INFO pIpInfoTable,
  731. GUID *pConnectionGuid
  732. )
  733. /*++
  734. Routine Description:
  735. Determines if a LAN connection is bound to TCP/IP. For the purposes of
  736. this routine, "bound to TCP/IP" is defines as there exists an IP
  737. adapter index for the connection.
  738. Arguments:
  739. pIpInfoTable - the IP interface table, obtained from a call to
  740. GetInterfaceInfo
  741. pConnectionGuid - a pointer to the guid for the connection
  742. Return Value:
  743. BOOLEAN - TRUE if the connection is bound to TCP/IP; FALSE otherwise.
  744. FALSE will be returned if an error occurs
  745. --*/
  746. {
  747. BOOLEAN fIsBound = FALSE;
  748. LPOLESTR pszGuid;
  749. HRESULT hr;
  750. ULONG cchGuid;
  751. ULONG cchName;
  752. PWCHAR pwchName;
  753. LONG l;
  754. _ASSERT(NULL != pIpInfoTable);
  755. _ASSERT(NULL != pConnectionGuid);
  756. //
  757. // Convert the guid to a string
  758. //
  759. hr = StringFromCLSID(*pConnectionGuid, &pszGuid);
  760. if (SUCCEEDED(hr))
  761. {
  762. cchGuid = wcslen(pszGuid);
  763. //
  764. // Walk the table, searching for the corresponding adapter
  765. //
  766. for (l = 0; l < pIpInfoTable->NumAdapters; l++)
  767. {
  768. cchName = wcslen(pIpInfoTable->Adapter[l].Name);
  769. if (cchName < cchGuid) { continue; }
  770. pwchName = pIpInfoTable->Adapter[l].Name + (cchName - cchGuid);
  771. if (0 == _wcsicmp(pszGuid, pwchName))
  772. {
  773. fIsBound = TRUE;
  774. break;
  775. }
  776. }
  777. CoTaskMemFree(pszGuid);
  778. }
  779. return fIsBound;
  780. } // ConnectionIsBoundToTcp
  781. HRESULT
  782. ConvertResponseRangeArrayToInstanceSafearray(
  783. IWbemServices *piwsNamespace,
  784. USHORT uscResponses,
  785. HNET_RESPONSE_RANGE rgResponses[],
  786. SAFEARRAY **ppsa
  787. )
  788. /*++
  789. Routine Description:
  790. Converts an array of HNET_RESPONSE_RANGE structures into a
  791. safearray of IUnknows that represent WMI instances of
  792. those response ranges.
  793. Arguments:
  794. piwsNamespace - the namespace to use
  795. uscResponses - the count of responses
  796. rgResponses - the response range structures
  797. ppsa - receives a pointer to the safearrays
  798. Return Value:
  799. Standard HRESULT
  800. --*/
  801. {
  802. HRESULT hr = S_OK;
  803. SAFEARRAY *psa;
  804. BSTR bstrPath;
  805. SAFEARRAYBOUND rgsabound[1];
  806. IWbemClassObject *pwcoClass = NULL;
  807. IWbemClassObject *pwcoInstance;
  808. IUnknown *pUnk;
  809. _ASSERT(NULL != piwsNamespace);
  810. _ASSERT(0 != uscResponses);
  811. _ASSERT(NULL != rgResponses);
  812. _ASSERT(NULL != ppsa);
  813. bstrPath = SysAllocString(c_wszHnetResponseRange);
  814. if (NULL == bstrPath)
  815. {
  816. hr = E_OUTOFMEMORY;
  817. }
  818. if (S_OK == hr)
  819. {
  820. //
  821. // Get the class for HNet_ResponseRange
  822. //
  823. pwcoClass = NULL;
  824. hr = piwsNamespace->GetObject(
  825. bstrPath,
  826. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  827. NULL,
  828. &pwcoClass,
  829. NULL
  830. );
  831. SysFreeString(bstrPath);
  832. }
  833. if (S_OK == hr)
  834. {
  835. //
  836. // Create the array to hold the response range instances
  837. //
  838. rgsabound[0].lLbound = 0;
  839. rgsabound[0].cElements = uscResponses;
  840. psa = SafeArrayCreate(VT_UNKNOWN, 1, rgsabound);
  841. if (NULL == psa)
  842. {
  843. hr = E_OUTOFMEMORY;
  844. }
  845. }
  846. if (S_OK == hr)
  847. {
  848. //
  849. // Process the passed in response ranges
  850. //
  851. for (USHORT i = 0; i < uscResponses; i++)
  852. {
  853. //
  854. // First, create an HNet_ResponseRange instance
  855. // for the entry
  856. //
  857. pwcoInstance = NULL;
  858. hr = pwcoClass->SpawnInstance(0, &pwcoInstance);
  859. if (WBEM_S_NO_ERROR != hr)
  860. {
  861. break;
  862. }
  863. //
  864. // Populate that instance
  865. //
  866. hr = CopyStructToResponseInstance(
  867. &rgResponses[i],
  868. pwcoInstance
  869. );
  870. if (FAILED(hr))
  871. {
  872. pwcoInstance->Release();
  873. break;
  874. }
  875. //
  876. // Get the IUnknown for the instance and put it
  877. // in the array
  878. //
  879. hr = pwcoInstance->QueryInterface(
  880. IID_PPV_ARG(IUnknown, &pUnk)
  881. );
  882. _ASSERT(S_OK == hr);
  883. LONG lIndex = i;
  884. hr = SafeArrayPutElement(
  885. psa,
  886. &lIndex,
  887. pUnk
  888. );
  889. pUnk->Release();
  890. pwcoInstance->Release();
  891. if (FAILED(hr))
  892. {
  893. SafeArrayDestroy(psa);
  894. break;
  895. }
  896. }
  897. }
  898. if (SUCCEEDED(hr))
  899. {
  900. *ppsa = psa;
  901. hr = S_OK;
  902. }
  903. if (pwcoClass) pwcoClass->Release();
  904. return hr;
  905. }
  906. HRESULT
  907. CopyResponseInstanceToStruct(
  908. IWbemClassObject *pwcoInstance,
  909. HNET_RESPONSE_RANGE *pResponse
  910. )
  911. /*++
  912. Routine Description:
  913. Converts an instance of an HNet_ResponseRange into the
  914. corresponding HNET_RESPONSE_RANGE
  915. Arguments:
  916. pwcoInstance - the HNet_ResponseRange instance
  917. pResponse - the HNET_RESPONSE_RANGE to fill
  918. Return Value:
  919. Standard HRESULT
  920. --*/
  921. {
  922. HRESULT hr = S_OK;
  923. VARIANT vt;
  924. _ASSERT(NULL != pwcoInstance);
  925. _ASSERT(NULL != pResponse);
  926. hr = pwcoInstance->Get(
  927. c_wszIPProtocol,
  928. 0,
  929. &vt,
  930. NULL,
  931. NULL
  932. );
  933. if (WBEM_S_NO_ERROR == hr)
  934. {
  935. _ASSERT(VT_UI1 == V_VT(&vt));
  936. pResponse->ucIPProtocol = V_UI1(&vt);
  937. VariantClear(&vt);
  938. }
  939. if (WBEM_S_NO_ERROR == hr)
  940. {
  941. hr = pwcoInstance->Get(
  942. c_wszStartPort,
  943. 0,
  944. &vt,
  945. NULL,
  946. NULL
  947. );
  948. if (WBEM_S_NO_ERROR == hr)
  949. {
  950. //
  951. // WMI returns uint16 properties as VT_I4
  952. //
  953. _ASSERT(VT_I4 == V_VT(&vt));
  954. pResponse->usStartPort = static_cast<USHORT>(V_I4(&vt));
  955. VariantClear(&vt);
  956. }
  957. }
  958. if (WBEM_S_NO_ERROR == hr)
  959. {
  960. hr = pwcoInstance->Get(
  961. c_wszEndPort,
  962. 0,
  963. &vt,
  964. NULL,
  965. NULL
  966. );
  967. if (WBEM_S_NO_ERROR == hr)
  968. {
  969. //
  970. // WMI returns uint16 properties as VT_I4
  971. //
  972. _ASSERT(VT_I4 == V_VT(&vt));
  973. pResponse->usEndPort = static_cast<USHORT>(V_I4(&vt));
  974. VariantClear(&vt);
  975. }
  976. }
  977. return hr;
  978. }
  979. HRESULT
  980. CopyStructToResponseInstance(
  981. HNET_RESPONSE_RANGE *pResponse,
  982. IWbemClassObject *pwcoInstance
  983. )
  984. /*++
  985. Routine Description:
  986. Converts an instance of an HNet_ResponseRange into the
  987. corresponding HNET_RESPONSE_RANGE
  988. Arguments:
  989. pResponse - the HNET_RESPONSE_RANGE to fill
  990. pwcoInstance - the HNet_ResponseRange instance to create
  991. Return Value:
  992. Standard HRESULT
  993. --*/
  994. {
  995. HRESULT hr = S_OK;
  996. VARIANT vt;
  997. _ASSERT(NULL != pResponse);
  998. _ASSERT(NULL != pwcoInstance);
  999. VariantInit(&vt);
  1000. V_VT(&vt) = VT_UI1;
  1001. V_UI1(&vt) = pResponse->ucIPProtocol;
  1002. hr = pwcoInstance->Put(
  1003. c_wszIPProtocol,
  1004. 0,
  1005. &vt,
  1006. NULL
  1007. );
  1008. if (WBEM_S_NO_ERROR == hr)
  1009. {
  1010. V_VT(&vt) = VT_I4;
  1011. V_I4(&vt) = pResponse->usStartPort;
  1012. hr = pwcoInstance->Put(
  1013. c_wszStartPort,
  1014. 0,
  1015. &vt,
  1016. NULL
  1017. );
  1018. }
  1019. if (WBEM_S_NO_ERROR == hr)
  1020. {
  1021. V_I4(&vt) = pResponse->usEndPort;
  1022. hr = pwcoInstance->Put(
  1023. c_wszEndPort,
  1024. 0,
  1025. &vt,
  1026. NULL
  1027. );
  1028. }
  1029. return hr;
  1030. }
  1031. HRESULT
  1032. DeleteWmiInstance(
  1033. IWbemServices *piwsNamespace,
  1034. IWbemClassObject *pwcoInstance
  1035. )
  1036. /*++
  1037. Routine Description:
  1038. Deletes an object instance from the WMI repository.
  1039. Arguments:
  1040. piwsNamespace - the namespace the object is in
  1041. pwcoInstance - the class object interface for the instance
  1042. Return Value:
  1043. Standard HRESULT
  1044. --*/
  1045. {
  1046. HRESULT hr = S_OK;
  1047. BSTR bstr;
  1048. _ASSERT(piwsNamespace);
  1049. _ASSERT(pwcoInstance);
  1050. hr = GetWmiPathFromObject(pwcoInstance, &bstr);
  1051. if (WBEM_S_NO_ERROR == hr)
  1052. {
  1053. hr = piwsNamespace->DeleteInstance(
  1054. bstr,
  1055. 0,
  1056. NULL,
  1057. NULL
  1058. );
  1059. SysFreeString(bstr);
  1060. }
  1061. return hr;
  1062. }
  1063. LPWSTR
  1064. EscapeString(
  1065. LPCWSTR pwsz
  1066. )
  1067. {
  1068. ULONG ulCount = 0;
  1069. LPWSTR wsz;
  1070. LPWSTR wszReturn;
  1071. wsz = const_cast<LPWSTR>(pwsz);
  1072. while (NULL != *wsz)
  1073. {
  1074. if (L'\\' == *wsz || L'\"' == *wsz)
  1075. {
  1076. //
  1077. // Need an extra character
  1078. //
  1079. ulCount += 1;
  1080. }
  1081. wsz += 1;
  1082. ulCount += 1;
  1083. }
  1084. //
  1085. // Allocate new string buffer
  1086. //
  1087. wszReturn = new OLECHAR[ulCount + 1];
  1088. if (NULL == wszReturn)
  1089. {
  1090. return wszReturn;
  1091. }
  1092. //
  1093. // Copy string over
  1094. //
  1095. wsz = wszReturn;
  1096. while (NULL != *pwsz)
  1097. {
  1098. if (L'\\' == *pwsz || L'\"' == *pwsz)
  1099. {
  1100. *wsz++ = L'\\';
  1101. }
  1102. *wsz++ = *pwsz++;
  1103. }
  1104. //
  1105. // Make sure everything is properly null terminated
  1106. //
  1107. *wsz = L'';
  1108. return wszReturn;
  1109. }
  1110. HRESULT
  1111. InitializeNetCfgForWrite(
  1112. OUT INetCfg **ppnetcfg,
  1113. OUT INetCfgLock **ppncfglock
  1114. )
  1115. /*++
  1116. Routine Description:
  1117. Initializes NetCfg for writing. If this function succeeds, the
  1118. caller must call UninitializeNetCfgForWrite() with the two
  1119. returned interface pointers when done.
  1120. Arguments:
  1121. ppnetcfg Receives an initialized INetCfg interface.
  1122. ppnetcfglock Receives an acquires INetCfgLock interface.
  1123. Return Value:
  1124. Status of the operation
  1125. --*/
  1126. {
  1127. HRESULT hr = S_OK;
  1128. *ppnetcfg = NULL;
  1129. *ppncfglock = NULL;
  1130. // Open our own NetCfg context
  1131. hr = CoCreateInstance(
  1132. CLSID_CNetCfg,
  1133. NULL,
  1134. CLSCTX_SERVER,
  1135. IID_PPV_ARG(INetCfg, ppnetcfg)
  1136. );
  1137. if ( SUCCEEDED(hr) )
  1138. {
  1139. //
  1140. // Get the lock interface
  1141. //
  1142. hr = (*ppnetcfg)->QueryInterface(
  1143. IID_PPV_ARG(INetCfgLock, ppncfglock)
  1144. );
  1145. if ( SUCCEEDED(hr) )
  1146. {
  1147. //
  1148. // Get the NetCfg lock
  1149. //
  1150. hr = (*ppncfglock)->AcquireWriteLock(
  1151. 5,
  1152. L"HNetCfg",
  1153. NULL
  1154. );
  1155. //
  1156. // S_FALSE is actually failure; it means NetCfg timed out
  1157. // trying to acquire the write lock
  1158. //
  1159. if( S_FALSE == hr )
  1160. {
  1161. // Turn into an error that will make sense up the call chain
  1162. hr = NETCFG_E_NO_WRITE_LOCK;
  1163. }
  1164. if ( SUCCEEDED(hr) )
  1165. {
  1166. //
  1167. // Must initialize NetCfg inside the lock
  1168. //
  1169. hr = (*ppnetcfg)->Initialize( NULL );
  1170. if( FAILED(hr) )
  1171. {
  1172. (*ppncfglock)->ReleaseWriteLock();
  1173. }
  1174. }
  1175. if( FAILED(hr) )
  1176. {
  1177. (*ppncfglock)->Release();
  1178. *ppncfglock = NULL;
  1179. }
  1180. }
  1181. if( FAILED(hr) )
  1182. {
  1183. (*ppnetcfg)->Release();
  1184. *ppnetcfg = NULL;
  1185. }
  1186. }
  1187. return hr;
  1188. }
  1189. void
  1190. UninitializeNetCfgForWrite(
  1191. IN INetCfg *pnetcfg,
  1192. IN INetCfgLock *pncfglock
  1193. )
  1194. /*++
  1195. Routine Description:
  1196. Uninitializes a NetCfg context created with InitializeNetCfgForWrite()
  1197. Arguments:
  1198. pnetcfg An INetCfg instance created by InitializeNetCfgForWrite()
  1199. pncfglock An INetCfgLock instance created by InitializeNetCfgForWrite()
  1200. Return Value:
  1201. Status of the operation
  1202. --*/
  1203. {
  1204. _ASSERT( (NULL != pnetcfg) && (NULL != pncfglock) );
  1205. pnetcfg->Uninitialize();
  1206. pncfglock->ReleaseWriteLock();
  1207. pncfglock->Release();
  1208. pnetcfg->Release();
  1209. }
  1210. HRESULT
  1211. FindAdapterByGUID(
  1212. IN INetCfg *pnetcfg,
  1213. IN GUID *pguid,
  1214. OUT INetCfgComponent **ppncfgcomp
  1215. )
  1216. /*++
  1217. Routine Description:
  1218. Retrieves an INetCfgComponent interface, if any, that corresponds
  1219. to the given device GUID. The GUID must correspond to a networking
  1220. component of class NET (i.e., a miniport).
  1221. E_FAIL is returned if the given GUID is not located.
  1222. Arguments:
  1223. pnetcfg An instance of INetCfg which has already had
  1224. its Initialize() method called
  1225. pguid The GUID to search for
  1226. ppncfgcomp Receives the resulting INetCfgComponent interface
  1227. pointer.
  1228. Return Value:
  1229. Status of the operation
  1230. --*/
  1231. {
  1232. HRESULT hr = S_OK;
  1233. GUID guidDevClass = GUID_DEVCLASS_NET;
  1234. IEnumNetCfgComponent *penumncfgcomp;
  1235. INetCfgComponent *pnetcfgcomp;
  1236. ULONG ulCount;
  1237. BOOLEAN fFound = FALSE;
  1238. //
  1239. // Get the list of NET (adapter) devices
  1240. //
  1241. hr = pnetcfg->EnumComponents( &guidDevClass, &penumncfgcomp );
  1242. if (S_OK == hr)
  1243. {
  1244. //
  1245. // Search for the designated adapter by GUID
  1246. //
  1247. while ( (FALSE == fFound) &&
  1248. (S_OK == penumncfgcomp->Next(1, &pnetcfgcomp, &ulCount) ) )
  1249. {
  1250. GUID guidThis;
  1251. hr = pnetcfgcomp->GetInstanceGuid( &guidThis );
  1252. if ( (S_OK == hr) && (InlineIsEqualGUID(guidThis,*pguid)) )
  1253. {
  1254. fFound = TRUE;
  1255. }
  1256. else
  1257. {
  1258. pnetcfgcomp->Release();
  1259. }
  1260. }
  1261. penumncfgcomp->Release();
  1262. }
  1263. if (fFound)
  1264. {
  1265. *ppncfgcomp = pnetcfgcomp;
  1266. }
  1267. else
  1268. {
  1269. hr = E_FAIL;
  1270. }
  1271. return hr;
  1272. }
  1273. HRESULT
  1274. FindINetConnectionByGuid(
  1275. GUID *pGuid,
  1276. INetConnection **ppNetCon
  1277. )
  1278. /*++
  1279. Routine Description:
  1280. Retrieves the INetConnection that corresponds to the given GUID.
  1281. Arguments:
  1282. pGuid - the guid of the connection
  1283. ppNetCon - receives the interface
  1284. Return Value:
  1285. standard HRESULT
  1286. --*/
  1287. {
  1288. HRESULT hr;
  1289. INetConnectionManager *pManager;
  1290. IEnumNetConnection *pEnum;
  1291. INetConnection *pConn;
  1292. _ASSERT(NULL != pGuid);
  1293. _ASSERT(NULL != ppNetCon);
  1294. //
  1295. // Get the net connections manager
  1296. //
  1297. hr = CoCreateInstance(
  1298. CLSID_ConnectionManager,
  1299. NULL,
  1300. CLSCTX_ALL,
  1301. IID_PPV_ARG(INetConnectionManager, &pManager)
  1302. );
  1303. if (S_OK == hr)
  1304. {
  1305. //
  1306. // Get the enumeration of connections
  1307. //
  1308. SetProxyBlanket(pManager);
  1309. hr = pManager->EnumConnections(NCME_DEFAULT, &pEnum);
  1310. pManager->Release();
  1311. }
  1312. if (S_OK == hr)
  1313. {
  1314. //
  1315. // Search for the connection with the correct guid
  1316. //
  1317. ULONG ulCount;
  1318. BOOLEAN fFound = FALSE;
  1319. SetProxyBlanket(pEnum);
  1320. do
  1321. {
  1322. NETCON_PROPERTIES *pProps;
  1323. hr = pEnum->Next(1, &pConn, &ulCount);
  1324. if (SUCCEEDED(hr) && 1 == ulCount)
  1325. {
  1326. SetProxyBlanket(pConn);
  1327. hr = pConn->GetProperties(&pProps);
  1328. if (S_OK == hr)
  1329. {
  1330. if (IsEqualGUID(pProps->guidId, *pGuid))
  1331. {
  1332. fFound = TRUE;
  1333. *ppNetCon = pConn;
  1334. (*ppNetCon)->AddRef();
  1335. }
  1336. NcFreeNetconProperties(pProps);
  1337. }
  1338. pConn->Release();
  1339. }
  1340. }
  1341. while (FALSE == fFound && SUCCEEDED(hr) && 1 == ulCount);
  1342. //
  1343. // Normalize hr
  1344. //
  1345. hr = (fFound ? S_OK : E_FAIL);
  1346. pEnum->Release();
  1347. }
  1348. return hr;
  1349. }
  1350. HRESULT
  1351. GetBridgeConnection(
  1352. IN IWbemServices *piwsHomenet,
  1353. OUT IHNetBridge **pphnetBridge
  1354. )
  1355. {
  1356. INetCfg *pnetcfg;
  1357. HRESULT hr;
  1358. if( NULL != pphnetBridge )
  1359. {
  1360. *pphnetBridge = NULL;
  1361. hr = CoCreateInstance(
  1362. CLSID_CNetCfg,
  1363. NULL,
  1364. CLSCTX_SERVER,
  1365. IID_PPV_ARG(INetCfg, &pnetcfg));
  1366. if( S_OK == hr )
  1367. {
  1368. hr = pnetcfg->Initialize( NULL );
  1369. if( S_OK == hr )
  1370. {
  1371. INetCfgComponent *pnetcfgcompBridge;
  1372. hr = pnetcfg->FindComponent( c_wszSBridgeMPID, &pnetcfgcompBridge );
  1373. if( S_OK == hr )
  1374. {
  1375. hr = GetIHNetConnectionForNetCfgComponent(
  1376. piwsHomenet,
  1377. pnetcfgcompBridge,
  1378. TRUE,
  1379. IID_PPV_ARG(IHNetBridge, pphnetBridge)
  1380. );
  1381. pnetcfgcompBridge->Release();
  1382. }
  1383. pnetcfg->Uninitialize();
  1384. }
  1385. pnetcfg->Release();
  1386. }
  1387. }
  1388. else
  1389. {
  1390. hr = E_POINTER;
  1391. }
  1392. // S_FALSE tends to get mishandled; return E_FAIL to signal the absence of a bridge.
  1393. if( S_FALSE == hr )
  1394. {
  1395. return E_FAIL;
  1396. }
  1397. return hr;
  1398. }
  1399. HRESULT
  1400. GetIHNetConnectionForNetCfgComponent(
  1401. IN IWbemServices *piwsHomenet,
  1402. IN INetCfgComponent *pnetcfgcomp,
  1403. IN BOOLEAN fLanConnection,
  1404. IN REFIID iid,
  1405. OUT PVOID *ppv
  1406. )
  1407. {
  1408. HRESULT hr;
  1409. if( NULL != ppv )
  1410. {
  1411. CComObject<CHNetCfgMgrChild> *pHNCfgMgrChild;
  1412. *ppv = NULL;
  1413. hr = CComObject<CHNetCfgMgrChild>::CreateInstance(&pHNCfgMgrChild);
  1414. if (SUCCEEDED(hr))
  1415. {
  1416. pHNCfgMgrChild->AddRef();
  1417. hr = pHNCfgMgrChild->Initialize(piwsHomenet);
  1418. if (SUCCEEDED(hr))
  1419. {
  1420. GUID guid;
  1421. hr = pnetcfgcomp->GetInstanceGuid( &guid );
  1422. if( S_OK == hr )
  1423. {
  1424. IHNetConnection *phnetcon;
  1425. hr = pHNCfgMgrChild->GetIHNetConnectionForGuid( &guid, fLanConnection, TRUE, &phnetcon );
  1426. if( S_OK == hr )
  1427. {
  1428. hr = phnetcon->GetControlInterface( iid, ppv );
  1429. phnetcon->Release();
  1430. }
  1431. }
  1432. }
  1433. pHNCfgMgrChild->Release();
  1434. }
  1435. }
  1436. else
  1437. {
  1438. hr = E_POINTER;
  1439. }
  1440. return hr;
  1441. }
  1442. HRESULT
  1443. BindOnlyToBridge(
  1444. IN INetCfgComponent *pnetcfgcomp
  1445. )
  1446. /*++
  1447. Routine Description:
  1448. Alters the bindings for the given INetCfgComponent so it is bound only
  1449. to the bridge protocol
  1450. c_pwszBridgeBindExceptions is a list of exceptions; if a binding path
  1451. involves a component listed in c_pwszBridgeBindExceptions, the path
  1452. will not be altered.
  1453. Arguments:
  1454. pnetcfgcomp The component whose bindings we wish to alter
  1455. Return Value:
  1456. standard HRESULT
  1457. --*/
  1458. {
  1459. HRESULT hr = S_OK;
  1460. INetCfgComponentBindings *pnetcfgBindings;
  1461. //
  1462. // Retrieve the ComponentBindings interface
  1463. //
  1464. hr = pnetcfgcomp->QueryInterface(
  1465. IID_PPV_ARG(INetCfgComponentBindings, &pnetcfgBindings)
  1466. );
  1467. if (S_OK == hr)
  1468. {
  1469. IEnumNetCfgBindingPath *penumPaths;
  1470. //
  1471. // Get the list of binding paths for this component
  1472. //
  1473. hr = pnetcfgBindings->EnumBindingPaths(
  1474. EBP_ABOVE,
  1475. &penumPaths
  1476. );
  1477. if (S_OK == hr)
  1478. {
  1479. ULONG ulCount1, ulCount2;
  1480. INetCfgBindingPath *pnetcfgPath;
  1481. while( (S_OK == penumPaths->Next(1, &pnetcfgPath, &ulCount1) ) )
  1482. {
  1483. INetCfgComponent *pnetcfgOwner;
  1484. //
  1485. // Get the owner of this path
  1486. //
  1487. hr = pnetcfgPath->GetOwner( &pnetcfgOwner );
  1488. if (S_OK == hr)
  1489. {
  1490. INetCfgComponentBindings *pnetcfgOwnerBindings;
  1491. hr = pnetcfgOwner->QueryInterface(
  1492. IID_PPV_ARG(INetCfgComponentBindings, &pnetcfgOwnerBindings)
  1493. );
  1494. if (S_OK == hr)
  1495. {
  1496. LPWSTR lpwstrId;
  1497. hr = pnetcfgOwner->GetId( &lpwstrId );
  1498. if (S_OK == hr)
  1499. {
  1500. BOOLEAN bIsBridge;
  1501. bIsBridge = ( _wcsicmp(lpwstrId, c_wszSBridgeSID) == 0 );
  1502. if( bIsBridge )
  1503. {
  1504. // This is the bridge component. Activate this binding path
  1505. hr = pnetcfgOwnerBindings->BindTo(pnetcfgcomp);
  1506. }
  1507. else
  1508. {
  1509. // Check if this is one of the bind exceptions
  1510. BOOLEAN bIsException = FALSE;
  1511. const WCHAR **ppwszException = c_pwszBridgeBindExceptions;
  1512. while( NULL != *ppwszException )
  1513. {
  1514. bIsException = ( _wcsicmp(lpwstrId, *ppwszException) == 0 );
  1515. if( bIsException )
  1516. {
  1517. break;
  1518. }
  1519. ppwszException++;
  1520. }
  1521. if( !bIsException )
  1522. {
  1523. hr = pnetcfgOwnerBindings->UnbindFrom(pnetcfgcomp);
  1524. }
  1525. // else this is an exception; leave the bind path as-is.
  1526. }
  1527. CoTaskMemFree(lpwstrId);
  1528. }
  1529. pnetcfgOwnerBindings->Release();
  1530. }
  1531. pnetcfgOwner->Release();
  1532. }
  1533. pnetcfgPath->Release();
  1534. }
  1535. penumPaths->Release();
  1536. }
  1537. pnetcfgBindings->Release();
  1538. }
  1539. return hr;
  1540. }
  1541. HRESULT
  1542. GetBooleanValue(
  1543. IWbemClassObject *pwcoInstance,
  1544. LPCWSTR pwszProperty,
  1545. BOOLEAN *pfBoolean
  1546. )
  1547. /*++
  1548. Routine Description:
  1549. Retrieves a boolean property from a Wbem object.
  1550. Arguments:
  1551. pwcoInstance - the object to get the property from
  1552. pwszProperty - the property to retrieve
  1553. pfBoolean - received the property value
  1554. Return Value:
  1555. standard HRESULT
  1556. --*/
  1557. {
  1558. HRESULT hr = S_OK;
  1559. VARIANT vt;
  1560. _ASSERT(NULL != pwcoInstance);
  1561. _ASSERT(NULL != pwszProperty);
  1562. _ASSERT(NULL != pfBoolean);
  1563. hr = pwcoInstance->Get(
  1564. pwszProperty,
  1565. 0,
  1566. &vt,
  1567. NULL,
  1568. NULL
  1569. );
  1570. if (WBEM_S_NO_ERROR == hr)
  1571. {
  1572. _ASSERT(VT_BOOL == V_VT(&vt) || VT_NULL == V_VT(&vt));
  1573. if (VT_BOOL == V_VT(&vt))
  1574. {
  1575. *pfBoolean = VARIANT_TRUE == V_BOOL(&vt);
  1576. }
  1577. else
  1578. {
  1579. //
  1580. // No value for this member was ever written to the store.
  1581. // Return FALSE, and set that value in the store. We don't
  1582. // pass along the error, if one occurs
  1583. //
  1584. *pfBoolean = FALSE;
  1585. SetBooleanValue(
  1586. pwcoInstance,
  1587. pwszProperty,
  1588. FALSE
  1589. );
  1590. }
  1591. VariantClear(&vt);
  1592. }
  1593. return hr;
  1594. }
  1595. HRESULT
  1596. GetConnectionInstanceByGuid(
  1597. IWbemServices *piwsNamespace,
  1598. BSTR bstrWQL,
  1599. GUID *pGuid,
  1600. IWbemClassObject **ppwcoConnection
  1601. )
  1602. /*++
  1603. Routine Description:
  1604. Retrieves the HNet_Connection instance for a INetConnection guid
  1605. Arguments:
  1606. piwsNamespace - WMI namespace
  1607. bstrWQL - a BSTR that corresponds to "WQL"
  1608. pGuid - the guid of the INetConnection (i.e., guidId in its properties)
  1609. ppwcoConnection - receives the HNet_Connection instance
  1610. Return Value:
  1611. standard HRESULT
  1612. --*/
  1613. {
  1614. HRESULT hr;
  1615. LPWSTR wsz;
  1616. BSTR bstrQuery;
  1617. LPOLESTR wszGuid;
  1618. IEnumWbemClassObject *pwcoEnum;
  1619. //
  1620. // Convert the guid to a string
  1621. //
  1622. hr = StringFromCLSID(*pGuid, &wszGuid);
  1623. if (S_OK == hr)
  1624. {
  1625. //
  1626. // Find the connection w/ name equal to that string
  1627. //
  1628. hr = BuildQuotedEqualsString(
  1629. &wsz,
  1630. c_wszGuid,
  1631. wszGuid
  1632. );
  1633. CoTaskMemFree(wszGuid);
  1634. if (S_OK == hr)
  1635. {
  1636. hr = BuildSelectQueryBstr(
  1637. &bstrQuery,
  1638. c_wszStar,
  1639. c_wszHnetConnection,
  1640. wsz
  1641. );
  1642. delete [] wsz;
  1643. }
  1644. if (S_OK == hr)
  1645. {
  1646. pwcoEnum = NULL;
  1647. hr = piwsNamespace->ExecQuery(
  1648. bstrWQL,
  1649. bstrQuery,
  1650. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
  1651. NULL,
  1652. &pwcoEnum
  1653. );
  1654. SysFreeString(bstrQuery);
  1655. }
  1656. }
  1657. if (WBEM_S_NO_ERROR == hr)
  1658. {
  1659. ULONG ulCount;
  1660. //
  1661. // Get the instance out of the enum
  1662. //
  1663. *ppwcoConnection = NULL;
  1664. hr = pwcoEnum->Next(
  1665. WBEM_INFINITE,
  1666. 1,
  1667. ppwcoConnection,
  1668. &ulCount
  1669. );
  1670. if (SUCCEEDED(hr) && 1 != ulCount)
  1671. {
  1672. hr = E_FAIL;
  1673. }
  1674. ValidateFinishedWCOEnum(piwsNamespace, pwcoEnum);
  1675. pwcoEnum->Release();
  1676. }
  1677. return hr;
  1678. }
  1679. HRESULT
  1680. GetConnAndPropInstancesByGuid(
  1681. IWbemServices *piwsNamespace,
  1682. GUID *pGuid,
  1683. IWbemClassObject **ppwcoConnection,
  1684. IWbemClassObject **ppwcoProperties
  1685. )
  1686. /*++
  1687. Routine Description:
  1688. Retrieves the HNet_Connection and HNet_ConnectionProperties instances
  1689. for a INetConnection guid
  1690. Arguments:
  1691. piwsNamespace - WMI namespace
  1692. pGuid - the guid of the INetConnection (i.e., guidId in its properties)
  1693. ppwcoConnection - receives the HNet_Connection instance
  1694. ppwcoProperties - receives the HNet_ConnectionProperties instance
  1695. Return Value:
  1696. standard HRESULT
  1697. --*/
  1698. {
  1699. HRESULT hr = S_OK;
  1700. BSTR bstrWQL = NULL;
  1701. _ASSERT(NULL != piwsNamespace);
  1702. _ASSERT(NULL != pGuid);
  1703. _ASSERT(NULL != ppwcoConnection);
  1704. _ASSERT(NULL != ppwcoProperties);
  1705. bstrWQL = SysAllocString(c_wszWQL);
  1706. if (NULL != bstrWQL)
  1707. {
  1708. hr = GetConnectionInstanceByGuid(
  1709. piwsNamespace,
  1710. bstrWQL,
  1711. pGuid,
  1712. ppwcoConnection
  1713. );
  1714. }
  1715. else
  1716. {
  1717. hr = E_OUTOFMEMORY;
  1718. }
  1719. if (SUCCEEDED(hr))
  1720. {
  1721. hr = GetPropInstanceFromConnInstance(
  1722. piwsNamespace,
  1723. *ppwcoConnection,
  1724. ppwcoProperties
  1725. );
  1726. if (FAILED(hr))
  1727. {
  1728. (*ppwcoConnection)->Release();
  1729. *ppwcoConnection = NULL;
  1730. }
  1731. }
  1732. if (NULL != bstrWQL)
  1733. {
  1734. SysFreeString(bstrWQL);
  1735. }
  1736. return hr;
  1737. }
  1738. HRESULT
  1739. GetConnAndPropInstancesForHNC(
  1740. IWbemServices *piwsNamespace,
  1741. IHNetConnection *pConn,
  1742. IWbemClassObject **ppwcoConnection,
  1743. IWbemClassObject **ppwcoProperties
  1744. )
  1745. /*++
  1746. Routine Description:
  1747. Retrieves the HNet_Connection and HNet_ConnectionProperties instances
  1748. for an IHNetConnection.
  1749. Arguments:
  1750. piwsNamespace - WMI namespace
  1751. pConn - the IHNetConnection
  1752. ppwcoConnection - receives the HNet_Connection instance
  1753. ppwcoProperties - receives the HNet_ConnectionProperties instance
  1754. Return Value:
  1755. standard HRESULT
  1756. --*/
  1757. {
  1758. HRESULT hr;
  1759. GUID *pGuid;
  1760. _ASSERT(NULL != piwsNamespace);
  1761. _ASSERT(NULL != pConn);
  1762. _ASSERT(NULL != ppwcoConnection);
  1763. _ASSERT(NULL != ppwcoProperties);
  1764. //
  1765. // Find the items by GUID
  1766. //
  1767. hr = pConn->GetGuid(&pGuid);
  1768. if (S_OK == hr)
  1769. {
  1770. hr = GetConnAndPropInstancesByGuid(
  1771. piwsNamespace,
  1772. pGuid,
  1773. ppwcoConnection,
  1774. ppwcoProperties
  1775. );
  1776. CoTaskMemFree(pGuid);
  1777. }
  1778. return hr;
  1779. }
  1780. HRESULT
  1781. GetPhonebookPathFromRasNetcon(
  1782. INetConnection *pConn,
  1783. LPWSTR *ppwstr
  1784. )
  1785. /*++
  1786. Routine Description:
  1787. Retrieves the phonebook path for an INetConnection that represents
  1788. a RAS connection
  1789. Arguments:
  1790. INetConnection - the RAS connection
  1791. ppwstr - receives the phonebook path. The caller must call CoTaskMemFree for
  1792. this pointer on success. On failure, the pointer receives NULL.
  1793. Return Value:
  1794. standard HRESULT
  1795. --*/
  1796. {
  1797. HRESULT hr;
  1798. INetRasConnection *pRasConn;
  1799. RASCON_INFO RasConInfo;
  1800. _ASSERT(NULL != pConn);
  1801. _ASSERT(NULL != ppwstr);
  1802. *ppwstr = NULL;
  1803. //
  1804. // QI for the INetRasConnection
  1805. //
  1806. hr = pConn->QueryInterface(
  1807. IID_PPV_ARG(INetRasConnection, &pRasConn)
  1808. );
  1809. if (SUCCEEDED(hr))
  1810. {
  1811. //
  1812. // Get the connection information
  1813. //
  1814. hr = pRasConn->GetRasConnectionInfo(&RasConInfo);
  1815. if (SUCCEEDED(hr))
  1816. {
  1817. *ppwstr = RasConInfo.pszwPbkFile;
  1818. //
  1819. // Free the name pointer. The caller is responsible for
  1820. // freeing the path pointer
  1821. //
  1822. CoTaskMemFree(RasConInfo.pszwEntryName);
  1823. }
  1824. pRasConn->Release();
  1825. }
  1826. return hr;
  1827. }
  1828. HRESULT
  1829. GetPortMappingBindingInstance(
  1830. IWbemServices *piwsNamespace,
  1831. BSTR bstrWQL,
  1832. BSTR bstrConnectionPath,
  1833. BSTR bstrProtocolPath,
  1834. USHORT usPublicPort,
  1835. IWbemClassObject **ppInstance
  1836. )
  1837. /*++
  1838. Routine Description:
  1839. Given the path to an HNet_Connection instance and and
  1840. HNet_PortMappingProtocol instance, checks to see if a
  1841. corresponding HNet_ConnectionPortMapping exists. If it
  1842. doesn't, the instance is created. The HNet_ConnectionPortMapping
  1843. instance -- existing or newly created -- is returned and must
  1844. be released by the caller.
  1845. Arguments:
  1846. piwsNamespace - the namespace to use
  1847. bstrWQL - a BSTR containing the string "WQL"
  1848. bstrConnectionPath - path to the HNet_Connection instance
  1849. bstrProtocolPath - path to the HNet_PortMappingProtocol instance
  1850. usPublicPort - the port of the port mapping protocol
  1851. ppInstance - receives the HNet_ConnectionPortMapping instance
  1852. Return Value:
  1853. Standard HRESULT
  1854. --*/
  1855. {
  1856. HRESULT hr;
  1857. IEnumWbemClassObject *pwcoEnum;
  1858. IWbemClassObject *pwcoInstance;
  1859. BSTR bstrQuery;
  1860. BSTR bstr;
  1861. LPWSTR wsz;
  1862. LPWSTR wszConClause;
  1863. LPWSTR wszProtClause;
  1864. _ASSERT(NULL != piwsNamespace);
  1865. _ASSERT(NULL != bstrWQL);
  1866. _ASSERT(NULL != bstrConnectionPath);
  1867. _ASSERT(NULL != bstrProtocolPath);
  1868. _ASSERT(NULL != ppInstance);
  1869. //
  1870. // Connection = "bstrConnectionPath" AND Protocol = "bstrProtocolPath"
  1871. //
  1872. hr = BuildEscapedQuotedEqualsString(
  1873. &wszConClause,
  1874. c_wszConnection,
  1875. bstrConnectionPath
  1876. );
  1877. if (S_OK == hr)
  1878. {
  1879. hr = BuildEscapedQuotedEqualsString(
  1880. &wszProtClause,
  1881. c_wszProtocol,
  1882. bstrProtocolPath
  1883. );
  1884. if (S_OK == hr)
  1885. {
  1886. hr = BuildAndString(
  1887. &wsz,
  1888. wszConClause,
  1889. wszProtClause
  1890. );
  1891. delete [] wszProtClause;
  1892. }
  1893. delete [] wszConClause;
  1894. }
  1895. if (S_OK == hr)
  1896. {
  1897. hr = BuildSelectQueryBstr(
  1898. &bstrQuery,
  1899. c_wszStar,
  1900. c_wszHnetConnectionPortMapping,
  1901. wsz
  1902. );
  1903. delete [] wsz;
  1904. }
  1905. if (S_OK == hr)
  1906. {
  1907. pwcoEnum = NULL;
  1908. hr = piwsNamespace->ExecQuery(
  1909. bstrWQL,
  1910. bstrQuery,
  1911. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
  1912. NULL,
  1913. &pwcoEnum
  1914. );
  1915. SysFreeString(bstrQuery);
  1916. }
  1917. if (WBEM_S_NO_ERROR == hr)
  1918. {
  1919. ULONG ulCount;
  1920. *ppInstance = NULL;
  1921. hr = pwcoEnum->Next(WBEM_INFINITE, 1, ppInstance, &ulCount);
  1922. if (FAILED(hr) || 1 != ulCount)
  1923. {
  1924. //
  1925. // Instance does not exist -- create now. However, first make
  1926. // sure that the protocol instance bstrProtocolPath refers to
  1927. // actually exists.
  1928. //
  1929. hr = GetWmiObjectFromPath(
  1930. piwsNamespace,
  1931. bstrProtocolPath,
  1932. ppInstance
  1933. );
  1934. if (WBEM_S_NO_ERROR == hr)
  1935. {
  1936. //
  1937. // The protocol object exists -- release it and
  1938. // continue with creating the new binding object.
  1939. //
  1940. (*ppInstance)->Release();
  1941. *ppInstance = NULL;
  1942. hr = SpawnNewInstance(
  1943. piwsNamespace,
  1944. c_wszHnetConnectionPortMapping,
  1945. ppInstance
  1946. );
  1947. }
  1948. if (WBEM_S_NO_ERROR == hr)
  1949. {
  1950. VARIANT vt;
  1951. //
  1952. // Fill out new instance information
  1953. //
  1954. V_VT(&vt) = VT_BSTR;
  1955. V_BSTR(&vt) = bstrConnectionPath;
  1956. hr = (*ppInstance)->Put(
  1957. c_wszConnection,
  1958. 0,
  1959. &vt,
  1960. NULL
  1961. );
  1962. if (WBEM_S_NO_ERROR == hr)
  1963. {
  1964. V_BSTR(&vt) = bstrProtocolPath;
  1965. hr = (*ppInstance)->Put(
  1966. c_wszProtocol,
  1967. 0,
  1968. &vt,
  1969. NULL
  1970. );
  1971. }
  1972. if (WBEM_S_NO_ERROR == hr)
  1973. {
  1974. hr = SetBooleanValue(
  1975. *ppInstance,
  1976. c_wszEnabled,
  1977. FALSE
  1978. );
  1979. }
  1980. if (WBEM_S_NO_ERROR == hr)
  1981. {
  1982. hr = SetBooleanValue(
  1983. *ppInstance,
  1984. c_wszNameActive,
  1985. FALSE
  1986. );
  1987. }
  1988. if (WBEM_S_NO_ERROR == hr)
  1989. {
  1990. V_VT(&vt) = VT_I4;
  1991. V_I4(&vt) = 0;
  1992. hr = (*ppInstance)->Put(
  1993. c_wszTargetIPAddress,
  1994. 0,
  1995. &vt,
  1996. NULL
  1997. );
  1998. }
  1999. if (WBEM_S_NO_ERROR == hr)
  2000. {
  2001. V_VT(&vt) = VT_BSTR;
  2002. V_BSTR(&vt) = SysAllocString(L" ");
  2003. if (NULL != V_BSTR(&vt))
  2004. {
  2005. hr = (*ppInstance)->Put(
  2006. c_wszTargetName,
  2007. 0,
  2008. &vt,
  2009. NULL
  2010. );
  2011. VariantClear(&vt);
  2012. }
  2013. else
  2014. {
  2015. hr = E_OUTOFMEMORY;
  2016. }
  2017. }
  2018. if (WBEM_S_NO_ERROR == hr)
  2019. {
  2020. V_VT(&vt) = VT_I4;
  2021. V_I4(&vt) = usPublicPort;
  2022. hr = (*ppInstance)->Put(
  2023. c_wszTargetPort,
  2024. 0,
  2025. &vt,
  2026. NULL
  2027. );
  2028. }
  2029. if (WBEM_S_NO_ERROR == hr)
  2030. {
  2031. IWbemCallResult *pResult;
  2032. //
  2033. // Write new instance to the store
  2034. //
  2035. pResult = NULL;
  2036. hr = piwsNamespace->PutInstance(
  2037. *ppInstance,
  2038. WBEM_FLAG_CREATE_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
  2039. NULL,
  2040. &pResult
  2041. );
  2042. if (WBEM_S_NO_ERROR == hr)
  2043. {
  2044. //
  2045. // Release the object, get the path from the result,
  2046. // and re-retrieve the object from the path
  2047. //
  2048. (*ppInstance)->Release();
  2049. *ppInstance = NULL;
  2050. hr = pResult->GetResultString(WBEM_INFINITE, &bstr);
  2051. if (WBEM_S_NO_ERROR == hr)
  2052. {
  2053. hr = GetWmiObjectFromPath(
  2054. piwsNamespace,
  2055. bstr,
  2056. ppInstance
  2057. );
  2058. SysFreeString(bstr);
  2059. }
  2060. pResult->Release();
  2061. }
  2062. }
  2063. }
  2064. }
  2065. else
  2066. {
  2067. //
  2068. // Normalize enum hresult
  2069. //
  2070. hr = S_OK;
  2071. }
  2072. ValidateFinishedWCOEnum(piwsNamespace, pwcoEnum);
  2073. pwcoEnum->Release();
  2074. }
  2075. return hr;
  2076. }
  2077. HRESULT
  2078. GetPropInstanceFromConnInstance(
  2079. IWbemServices *piwsNamespace,
  2080. IWbemClassObject *pwcoConnection,
  2081. IWbemClassObject **ppwcoProperties
  2082. )
  2083. /*++
  2084. Routine Description:
  2085. Retrieves the HNet_ConnectionProperties instance associated with
  2086. an HNet_Connection.
  2087. Arguments:
  2088. piwsNamespace - WMI namespace
  2089. bstrWQL - a BSTR that corresponds to "WQL"
  2090. pwcoConnection - the HNet_Connection instance
  2091. ppwcoProperties - receives the HNet_ConnectionProperties instance
  2092. Return Value:
  2093. standard HRESULT
  2094. --*/
  2095. {
  2096. HRESULT hr = S_OK;
  2097. OLECHAR wszBuffer[c_cchQueryBuffer + 1];
  2098. OLECHAR *pwszPath = NULL;
  2099. BSTR bstrPath;
  2100. VARIANT vt;
  2101. _ASSERT(NULL != piwsNamespace);
  2102. _ASSERT(NULL != pwcoConnection);
  2103. _ASSERT(NULL != ppwcoProperties);
  2104. //
  2105. // On debug builds, verify that our precomputed string lengths
  2106. // match the actual lengths
  2107. //
  2108. _ASSERT(wcslen(c_wszConnectionPropertiesPathFormat) == c_cchConnectionPropertiesPathFormat);
  2109. //
  2110. // Get the guid for the connection
  2111. //
  2112. hr = pwcoConnection->Get(
  2113. c_wszGuid,
  2114. 0,
  2115. &vt,
  2116. NULL,
  2117. NULL
  2118. );
  2119. if (WBEM_S_NO_ERROR == hr)
  2120. {
  2121. _ASSERT(VT_BSTR == V_VT(&vt));
  2122. //
  2123. // Determine how much space we need for the path and decide
  2124. // if we need to allocate a heap buffer.
  2125. //
  2126. ULONG cchLength =
  2127. c_cchConnectionPropertiesPathFormat + SysStringLen(V_BSTR(&vt)) + 1;
  2128. if (cchLength <= c_cchQueryBuffer)
  2129. {
  2130. //
  2131. // The buffer is large enough. (Note that since the buffer on the
  2132. // stack is one greater than the constant, the terminator is accounted
  2133. // for.) Point our working pointer to the stack buffer.
  2134. //
  2135. pwszPath = wszBuffer;
  2136. }
  2137. else
  2138. {
  2139. //
  2140. // Allocate a sufficient buffer from the heap. The +1 is for the
  2141. // terminating nul
  2142. //
  2143. pwszPath = new OLECHAR[cchLength + 1];
  2144. if (NULL == pwszPath)
  2145. {
  2146. hr = E_OUTOFMEMORY;
  2147. pwszPath = wszBuffer;
  2148. }
  2149. }
  2150. if (WBEM_S_NO_ERROR == hr)
  2151. {
  2152. //
  2153. // Build the path string
  2154. //
  2155. int iBytes =
  2156. _snwprintf(
  2157. pwszPath,
  2158. cchLength,
  2159. c_wszConnectionPropertiesPathFormat,
  2160. V_BSTR(&vt)
  2161. );
  2162. _ASSERT(iBytes >= 0);
  2163. //
  2164. // Convert that to a BSTR
  2165. //
  2166. bstrPath = SysAllocString(pwszPath);
  2167. if (NULL != bstrPath)
  2168. {
  2169. hr = GetWmiObjectFromPath(
  2170. piwsNamespace,
  2171. bstrPath,
  2172. ppwcoProperties
  2173. );
  2174. SysFreeString(bstrPath);
  2175. }
  2176. else
  2177. {
  2178. hr = E_OUTOFMEMORY;
  2179. }
  2180. }
  2181. VariantClear(&vt);
  2182. }
  2183. //
  2184. // Free the query buffer, if necessary
  2185. //
  2186. if (wszBuffer != pwszPath)
  2187. {
  2188. delete [] pwszPath;
  2189. }
  2190. return hr;
  2191. }
  2192. HRESULT
  2193. GetWmiObjectFromPath(
  2194. IWbemServices *piwsNamespace,
  2195. BSTR bstrPath,
  2196. IWbemClassObject **ppwcoInstance
  2197. )
  2198. /*++
  2199. Routine Description:
  2200. Retrieves the IWbemClassObject corresponding to an object path.
  2201. Arguments:
  2202. piwsNamespace - the WMI namespace the object lives in
  2203. bstrPath - the path to the object
  2204. ppwcoInstance - receives the object instance
  2205. Return Value:
  2206. standard HRESULT
  2207. --*/
  2208. {
  2209. HRESULT hr;
  2210. _ASSERT(NULL != piwsNamespace);
  2211. _ASSERT(NULL != bstrPath);
  2212. _ASSERT(NULL != ppwcoInstance);
  2213. *ppwcoInstance = NULL;
  2214. hr = piwsNamespace->GetObject(
  2215. bstrPath,
  2216. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  2217. NULL,
  2218. ppwcoInstance,
  2219. NULL
  2220. );
  2221. return hr;
  2222. }
  2223. HRESULT
  2224. GetWmiPathFromObject(
  2225. IWbemClassObject *pwcoInstance,
  2226. BSTR *pbstrPath
  2227. )
  2228. /*++
  2229. Routine Description:
  2230. Retrieves the object path corresponding to an IWbemClassObject instance.
  2231. Arguments:
  2232. pwcoInstance - the object instance to retrieve the path of
  2233. pbstrPath - receives the path to the object
  2234. Return Value:
  2235. standard HRESULT
  2236. --*/
  2237. {
  2238. HRESULT hr;
  2239. VARIANT vt;
  2240. _ASSERT(NULL != pwcoInstance);
  2241. _ASSERT(NULL != pbstrPath);
  2242. hr = pwcoInstance->Get(
  2243. c_wsz__Path,
  2244. 0,
  2245. &vt,
  2246. NULL,
  2247. NULL
  2248. );
  2249. if (WBEM_S_NO_ERROR == hr)
  2250. {
  2251. _ASSERT(VT_BSTR == V_VT(&vt));
  2252. *pbstrPath = V_BSTR(&vt);
  2253. //
  2254. // BSTR ownership transferred to caller
  2255. //
  2256. }
  2257. return hr;
  2258. }
  2259. HRESULT
  2260. HostAddrToIpPsz(
  2261. DWORD dwAddress,
  2262. LPWSTR* ppszwNewStr
  2263. )
  2264. // Converts IP Address from host by order to string
  2265. {
  2266. HRESULT hr = S_OK;
  2267. LPWSTR pszwStr;
  2268. *ppszwNewStr = NULL;
  2269. pszwStr = reinterpret_cast<LPWSTR>(CoTaskMemAlloc(sizeof(WCHAR) * 16));
  2270. if ( NULL == pszwStr )
  2271. {
  2272. hr = E_OUTOFMEMORY;
  2273. }
  2274. else
  2275. {
  2276. swprintf( pszwStr,
  2277. TEXT("%u.%u.%u.%u"),
  2278. (dwAddress&0xff),
  2279. ((dwAddress>>8)&0x0ff),
  2280. ((dwAddress>>16)&0x0ff),
  2281. ((dwAddress>>24)&0x0ff) );
  2282. *ppszwNewStr = pszwStr;
  2283. }
  2284. return hr;
  2285. }
  2286. DWORD
  2287. IpPszToHostAddr(
  2288. LPCWSTR cp
  2289. )
  2290. // Converts an IP address represented as a string to
  2291. // host byte order.
  2292. //
  2293. {
  2294. DWORD val, base, n;
  2295. TCHAR c;
  2296. DWORD parts[4], *pp = parts;
  2297. again:
  2298. // Collect number up to ``.''.
  2299. // Values are specified as for C:
  2300. // 0x=hex, 0=octal, other=decimal.
  2301. //
  2302. val = 0; base = 10;
  2303. if (*cp == TEXT('0'))
  2304. base = 8, cp++;
  2305. if (*cp == TEXT('x') || *cp == TEXT('X'))
  2306. base = 16, cp++;
  2307. while (c = *cp)
  2308. {
  2309. if ((c >= TEXT('0')) && (c <= TEXT('9')))
  2310. {
  2311. val = (val * base) + (c - TEXT('0'));
  2312. cp++;
  2313. continue;
  2314. }
  2315. if ((base == 16) &&
  2316. ( ((c >= TEXT('0')) && (c <= TEXT('9'))) ||
  2317. ((c >= TEXT('A')) && (c <= TEXT('F'))) ||
  2318. ((c >= TEXT('a')) && (c <= TEXT('f'))) ))
  2319. {
  2320. val = (val << 4) + (c + 10 - (
  2321. ((c >= TEXT('a')) && (c <= TEXT('f')))
  2322. ? TEXT('a')
  2323. : TEXT('A') ) );
  2324. cp++;
  2325. continue;
  2326. }
  2327. break;
  2328. }
  2329. if (*cp == TEXT('.'))
  2330. {
  2331. // Internet format:
  2332. // a.b.c.d
  2333. // a.b.c (with c treated as 16-bits)
  2334. // a.b (with b treated as 24 bits)
  2335. //
  2336. if (pp >= parts + 3)
  2337. return (DWORD) -1;
  2338. *pp++ = val, cp++;
  2339. goto again;
  2340. }
  2341. // Check for trailing characters.
  2342. //
  2343. if (*cp && (*cp != TEXT(' ')))
  2344. return 0xffffffff;
  2345. *pp++ = val;
  2346. // Concoct the address according to
  2347. // the number of parts specified.
  2348. //
  2349. n = (DWORD) (pp - parts);
  2350. switch (n)
  2351. {
  2352. case 1: // a -- 32 bits
  2353. val = parts[0];
  2354. break;
  2355. case 2: // a.b -- 8.24 bits
  2356. val = (parts[0] << 24) | (parts[1] & 0xffffff);
  2357. break;
  2358. case 3: // a.b.c -- 8.8.16 bits
  2359. val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
  2360. (parts[2] & 0xffff);
  2361. break;
  2362. case 4: // a.b.c.d -- 8.8.8.8 bits
  2363. val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
  2364. ((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
  2365. break;
  2366. default:
  2367. return 0xffffffff;
  2368. }
  2369. return val;
  2370. }
  2371. BOOLEAN
  2372. IsRoutingProtocolInstalled(
  2373. ULONG ulProtocolId
  2374. )
  2375. /*++
  2376. Routine Description:
  2377. This routine is invoked to determine whether the routing protocol
  2378. with the given protocol-ID is installed for Routing and Remote Access.
  2379. This is determined by examining the configuration for the service.
  2380. Arguments:
  2381. ulProtocolId - identifies the protocol to be found
  2382. Return Value:
  2383. TRUE if the protocol is installed, FALSE otherwise.
  2384. --*/
  2385. {
  2386. PUCHAR Buffer;
  2387. ULONG BufferLength;
  2388. HINSTANCE Hinstance;
  2389. PMPRCONFIGBUFFERFREE MprConfigBufferFree;
  2390. PMPRCONFIGSERVERCONNECT MprConfigServerConnect;
  2391. PMPRCONFIGSERVERDISCONNECT MprConfigServerDisconnect;
  2392. PMPRCONFIGTRANSPORTGETHANDLE MprConfigTransportGetHandle;
  2393. PMPRCONFIGTRANSPORTGETINFO MprConfigTransportGetInfo;
  2394. PMPRINFOBLOCKFIND MprInfoBlockFind;
  2395. HANDLE ServerHandle;
  2396. HANDLE TransportHandle;
  2397. //
  2398. // Load the MPRAPI.DLL module and retrieve the entrypoints
  2399. // to be used for examining the RRAS configuration.
  2400. //
  2401. if (!(Hinstance = LoadLibraryW(c_wszMprapiDll)) ||
  2402. !(MprConfigBufferFree =
  2403. (PMPRCONFIGBUFFERFREE)
  2404. GetProcAddress(Hinstance, c_szMprConfigBufferFree)) ||
  2405. !(MprConfigServerConnect =
  2406. (PMPRCONFIGSERVERCONNECT)
  2407. GetProcAddress(Hinstance, c_szMprConfigServerConnect)) ||
  2408. !(MprConfigServerDisconnect =
  2409. (PMPRCONFIGSERVERDISCONNECT)
  2410. GetProcAddress(Hinstance, c_szMprConfigServerDisconnect)) ||
  2411. !(MprConfigTransportGetHandle =
  2412. (PMPRCONFIGTRANSPORTGETHANDLE)
  2413. GetProcAddress(Hinstance, c_szMprConfigTransportGetHandle)) ||
  2414. !(MprConfigTransportGetInfo =
  2415. (PMPRCONFIGTRANSPORTGETINFO)
  2416. GetProcAddress(Hinstance, c_szMprConfigTransportGetInfo)) ||
  2417. !(MprInfoBlockFind =
  2418. (PMPRINFOBLOCKFIND)
  2419. GetProcAddress(Hinstance, c_szMprInfoBlockFind))) {
  2420. if (Hinstance) { FreeLibrary(Hinstance); }
  2421. return FALSE;
  2422. }
  2423. //
  2424. // Connect to the RRAS configuration, and retrieve the configuration
  2425. // for the IP transport-layer routing protocols. This should include
  2426. // the configuration for the routing-protocol in 'ProtocolId',
  2427. // if installed.
  2428. //
  2429. ServerHandle = NULL;
  2430. if (MprConfigServerConnect(NULL, &ServerHandle) != NO_ERROR ||
  2431. MprConfigTransportGetHandle(ServerHandle, PID_IP, &TransportHandle)
  2432. != NO_ERROR ||
  2433. MprConfigTransportGetInfo(
  2434. ServerHandle,
  2435. TransportHandle,
  2436. &Buffer,
  2437. &BufferLength,
  2438. NULL,
  2439. NULL,
  2440. NULL
  2441. ) != NO_ERROR) {
  2442. if (ServerHandle) { MprConfigServerDisconnect(ServerHandle); }
  2443. FreeLibrary(Hinstance);
  2444. return FALSE;
  2445. }
  2446. MprConfigServerDisconnect(ServerHandle);
  2447. //
  2448. // Look for the requested protocol's configuration,
  2449. // and return TRUE if it is found; otherwise, return FALSE.
  2450. //
  2451. if (MprInfoBlockFind(Buffer, ulProtocolId, NULL, NULL, NULL) == NO_ERROR) {
  2452. MprConfigBufferFree(Buffer);
  2453. FreeLibrary(Hinstance);
  2454. return TRUE;
  2455. }
  2456. MprConfigBufferFree(Buffer);
  2457. FreeLibrary(Hinstance);
  2458. return FALSE;
  2459. } // IsRoutingProtocolInstalled
  2460. BOOLEAN
  2461. IsServiceRunning(
  2462. LPCWSTR pwszServiceName
  2463. )
  2464. /*++
  2465. Routine Description:
  2466. Determines if a service is in a running state.
  2467. Arguments:
  2468. pwszServiceName - the service to check
  2469. Return Value:
  2470. TRUE if the service is in the running or start_pending state,
  2471. FALSE otherwise
  2472. --*/
  2473. {
  2474. BOOLEAN fServiceRunning = FALSE;
  2475. SC_HANDLE hScm;
  2476. SC_HANDLE hService;
  2477. SERVICE_STATUS Status;
  2478. hScm = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, GENERIC_READ);
  2479. if (NULL != hScm)
  2480. {
  2481. hService = OpenService(hScm, pwszServiceName, GENERIC_READ);
  2482. if (NULL != hService)
  2483. {
  2484. if (QueryServiceStatus(hService, &Status))
  2485. {
  2486. fServiceRunning =
  2487. (SERVICE_RUNNING == Status.dwCurrentState
  2488. || SERVICE_START_PENDING == Status.dwCurrentState);
  2489. }
  2490. CloseServiceHandle(hService);
  2491. }
  2492. CloseServiceHandle(hScm);
  2493. }
  2494. return fServiceRunning;
  2495. } // IsServiceRunning
  2496. HRESULT
  2497. MapGuidStringToAdapterIndex(
  2498. LPCWSTR pwszGuid,
  2499. ULONG *pulIndex
  2500. )
  2501. /*++
  2502. Routine Description:
  2503. This routine is called to match the GUID in the given string to
  2504. an adapter in the list returned by calling GetInterfaceInfo.
  2505. Arguments:
  2506. pwszGuid - identifies the GUID of the adapter to be found. The GUID string
  2507. must be in the format returned by RtlGuidToUnicodeString
  2508. pulIndex - receives the index of the adapter
  2509. Return Value:
  2510. standard HRESULT
  2511. --*/
  2512. {
  2513. HRESULT hr = S_OK;
  2514. ULONG ulError;
  2515. ULONG i;
  2516. ULONG GuidLength;
  2517. PIP_INTERFACE_INFO Info;
  2518. PWCHAR Name;
  2519. ULONG NameLength;
  2520. ULONG Size;
  2521. _ASSERT(NULL != pwszGuid);
  2522. _ASSERT(NULL != pulIndex);
  2523. Size = 0;
  2524. GuidLength = wcslen(pwszGuid);
  2525. ulError = GetInterfaceInfo(NULL, &Size);
  2526. if (ERROR_INSUFFICIENT_BUFFER == ulError)
  2527. {
  2528. Info = new IP_INTERFACE_INFO[Size];
  2529. if (NULL != Info)
  2530. {
  2531. ulError = GetInterfaceInfo(Info, &Size);
  2532. if (NO_ERROR == ulError)
  2533. {
  2534. for (i = 0; i < (ULONG)Info->NumAdapters; i++)
  2535. {
  2536. NameLength = wcslen(Info->Adapter[i].Name);
  2537. if (NameLength < GuidLength) { continue; }
  2538. Name = Info->Adapter[i].Name + (NameLength - GuidLength);
  2539. if (_wcsicmp(pwszGuid, Name) == 0)
  2540. {
  2541. *pulIndex = Info->Adapter[i].Index;
  2542. break;
  2543. }
  2544. }
  2545. }
  2546. else
  2547. {
  2548. hr = HRESULT_FROM_WIN32(ulError);
  2549. }
  2550. delete [] Info;
  2551. }
  2552. else
  2553. {
  2554. hr = E_OUTOFMEMORY;
  2555. }
  2556. }
  2557. else
  2558. {
  2559. hr = HRESULT_FROM_WIN32(ulError);
  2560. }
  2561. return hr;
  2562. }
  2563. HRESULT
  2564. OpenRegKey(
  2565. PHANDLE Key,
  2566. ACCESS_MASK DesiredAccess,
  2567. PCWSTR Name
  2568. )
  2569. /*++
  2570. Routine Description:
  2571. This routine is invoked to open a given registry key.
  2572. Arguments:
  2573. Key - receives the opened key
  2574. DesiredAccess - specifies the requested access
  2575. Name - specifies the key to be opened
  2576. Return Value:
  2577. HRESULT - NT status code.
  2578. --*/
  2579. {
  2580. OBJECT_ATTRIBUTES ObjectAttributes;
  2581. UNICODE_STRING UnicodeString;
  2582. RtlInitUnicodeString(&UnicodeString, Name);
  2583. InitializeObjectAttributes(
  2584. &ObjectAttributes,
  2585. &UnicodeString,
  2586. OBJ_CASE_INSENSITIVE,
  2587. NULL,
  2588. NULL
  2589. );
  2590. return NtOpenKey(Key, DesiredAccess, &ObjectAttributes);
  2591. } // OpenRegKey
  2592. BOOLEAN
  2593. PortMappingProtocolExists(
  2594. IWbemServices *piwsNamespace,
  2595. BSTR bstrWQL,
  2596. USHORT usPort,
  2597. UCHAR ucIPProtocol
  2598. )
  2599. /*++
  2600. Routine Description:
  2601. Checks if an port mapping protocol already exists that has the
  2602. specified protocol and port.
  2603. Arguments:
  2604. piwsNamespace - the namespace to use
  2605. bstrWQL - a BSTR containing "WQL"
  2606. ucProtocol - the protocol number to check for
  2607. usPort - the port to check for
  2608. Return Value:
  2609. BOOLEAN -- TRUE if the port mapping protocol exists; FALSE otherwise
  2610. --*/
  2611. {
  2612. BSTR bstr;
  2613. BOOLEAN fDuplicate = FALSE;
  2614. HRESULT hr = S_OK;
  2615. int iBytes;
  2616. IEnumWbemClassObject *pwcoEnum;
  2617. IWbemClassObject *pwcoInstance;
  2618. ULONG ulObjs;
  2619. OLECHAR wszWhereClause[c_cchQueryBuffer + 1];
  2620. _ASSERT(NULL != piwsNamespace);
  2621. _ASSERT(NULL != bstrWQL);
  2622. _ASSERT(0 == wcscmp(bstrWQL, L"WQL"));
  2623. //
  2624. // Build the query string
  2625. //
  2626. iBytes = _snwprintf(
  2627. wszWhereClause,
  2628. c_cchQueryBuffer,
  2629. c_wszPortMappingProtocolQueryFormat,
  2630. usPort,
  2631. ucIPProtocol
  2632. );
  2633. if (iBytes >= 0)
  2634. {
  2635. //
  2636. // String fit into buffer; make sure it's null terminated
  2637. //
  2638. wszWhereClause[c_cchQueryBuffer] = L'\0';
  2639. }
  2640. else
  2641. {
  2642. //
  2643. // For some reason the string didn't fit into the buffer...
  2644. //
  2645. hr = E_UNEXPECTED;
  2646. _ASSERT(FALSE);
  2647. }
  2648. if (S_OK == hr)
  2649. {
  2650. hr = BuildSelectQueryBstr(
  2651. &bstr,
  2652. c_wszStar,
  2653. c_wszHnetPortMappingProtocol,
  2654. wszWhereClause
  2655. );
  2656. }
  2657. if (S_OK == hr)
  2658. {
  2659. //
  2660. // Execute the query
  2661. //
  2662. pwcoEnum = NULL;
  2663. hr = piwsNamespace->ExecQuery(
  2664. bstrWQL,
  2665. bstr,
  2666. WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
  2667. NULL,
  2668. &pwcoEnum
  2669. );
  2670. SysFreeString(bstr);
  2671. }
  2672. if (S_OK == hr)
  2673. {
  2674. //
  2675. // Attempt to retrieve an item from the enum. If we're successful,
  2676. // this is a duplicate protocol.
  2677. //
  2678. pwcoInstance = NULL;
  2679. hr = pwcoEnum->Next(
  2680. WBEM_INFINITE,
  2681. 1,
  2682. &pwcoInstance,
  2683. &ulObjs
  2684. );
  2685. if (SUCCEEDED(hr) && 1 == ulObjs)
  2686. {
  2687. //
  2688. // It's a duplicate
  2689. //
  2690. fDuplicate = TRUE;
  2691. pwcoInstance->Release();
  2692. }
  2693. pwcoEnum->Release();
  2694. }
  2695. return fDuplicate;
  2696. } // PortMappingProtocolExists
  2697. HRESULT
  2698. QueryRegValueKey(
  2699. HANDLE Key,
  2700. const WCHAR ValueName[],
  2701. PKEY_VALUE_PARTIAL_INFORMATION* Information
  2702. )
  2703. /*++
  2704. Routine Description:
  2705. This routine is called to obtain the value of a registry key.
  2706. Arguments:
  2707. Key - the key to be queried
  2708. ValueName - the value to be queried
  2709. Information - receives a pointer to the information read. On success,
  2710. the caller must HeapFree this pointer
  2711. Return Value:
  2712. HRESULT - NT status code.
  2713. --*/
  2714. {
  2715. UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
  2716. ULONG InformationLength;
  2717. NTSTATUS status;
  2718. UNICODE_STRING UnicodeString;
  2719. RtlInitUnicodeString(&UnicodeString, ValueName);
  2720. *Information = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
  2721. InformationLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
  2722. //
  2723. // Read the value's size
  2724. //
  2725. status =
  2726. NtQueryValueKey(
  2727. Key,
  2728. &UnicodeString,
  2729. KeyValuePartialInformation,
  2730. *Information,
  2731. InformationLength,
  2732. &InformationLength
  2733. );
  2734. if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW &&
  2735. status != STATUS_BUFFER_TOO_SMALL) {
  2736. *Information = NULL;
  2737. return status;
  2738. }
  2739. //
  2740. // Allocate space for the value's size
  2741. //
  2742. *Information = (PKEY_VALUE_PARTIAL_INFORMATION) HeapAlloc(
  2743. GetProcessHeap(),
  2744. 0,
  2745. InformationLength+2
  2746. );
  2747. if (!*Information) { return STATUS_NO_MEMORY; }
  2748. //
  2749. // Read the value's data
  2750. //
  2751. status =
  2752. NtQueryValueKey(
  2753. Key,
  2754. &UnicodeString,
  2755. KeyValuePartialInformation,
  2756. *Information,
  2757. InformationLength,
  2758. &InformationLength
  2759. );
  2760. if (!NT_SUCCESS(status))
  2761. {
  2762. HeapFree(GetProcessHeap(), 0, *Information);
  2763. *Information = NULL;
  2764. }
  2765. return status;
  2766. } // QueryRegValueKey
  2767. HRESULT
  2768. ReadDhcpScopeSettings(
  2769. DWORD *pdwScopeAddress,
  2770. DWORD *pdwScopeMask
  2771. )
  2772. {
  2773. _ASSERT(NULL != pdwScopeAddress);
  2774. _ASSERT(NULL != pdwScopeMask);
  2775. //
  2776. // This routine never fails. Set default address/mask
  2777. // (192.168.0.1/255.255.255.255, in network order)
  2778. //
  2779. *pdwScopeAddress = 0x0100a8c0;
  2780. *pdwScopeMask = 0x00ffffff;
  2781. //
  2782. // $$TODO: Check to see if these values are overiddent
  2783. // through a registry entry
  2784. //
  2785. return S_OK;
  2786. }
  2787. HRESULT
  2788. RetrieveSingleInstance(
  2789. IWbemServices *piwsNamespace,
  2790. const OLECHAR *pwszClass,
  2791. BOOLEAN fCreate,
  2792. IWbemClassObject **ppwcoInstance
  2793. )
  2794. /*++
  2795. Routine Description:
  2796. Retrieves a single instance of a class from the WMI store. If there
  2797. are more than one instance, every instance after the first is deleted,
  2798. and an assertion is raised. If there are no instances, one is optionally
  2799. created.
  2800. Arguments:
  2801. piwsNamespace - WMI namespace
  2802. pwszClass - the class to retrieve the instance of
  2803. fCreate - create an instance if one does not already exist
  2804. ppwcoInstance - receive the instance
  2805. Return Value:
  2806. standard HRESULT
  2807. --*/
  2808. {
  2809. HRESULT hr = S_OK;
  2810. IEnumWbemClassObject *pwcoEnum = NULL;
  2811. BSTR bstrClass = NULL;
  2812. ULONG ulCount = 0;
  2813. _ASSERT(NULL != piwsNamespace);
  2814. _ASSERT(NULL != pwszClass);
  2815. _ASSERT(NULL != ppwcoInstance);
  2816. //
  2817. // Allocate the BSTR for the class name
  2818. //
  2819. bstrClass = SysAllocString(pwszClass);
  2820. if (NULL == bstrClass)
  2821. {
  2822. hr = E_OUTOFMEMORY;
  2823. }
  2824. //
  2825. // Query the WMI store for instances of the class
  2826. //
  2827. if (S_OK == hr)
  2828. {
  2829. pwcoEnum = NULL;
  2830. hr = piwsNamespace->CreateInstanceEnum(
  2831. bstrClass,
  2832. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
  2833. NULL,
  2834. &pwcoEnum
  2835. );
  2836. SysFreeString(bstrClass);
  2837. }
  2838. if (WBEM_S_NO_ERROR == hr)
  2839. {
  2840. //
  2841. // Attempt to retrieve an actual instance from the enumeration.
  2842. // Even if there are zero instances, WMI considers returning a
  2843. // zero-element enumerator success.
  2844. //
  2845. *ppwcoInstance = NULL;
  2846. hr = pwcoEnum->Next(
  2847. WBEM_INFINITE,
  2848. 1,
  2849. ppwcoInstance,
  2850. &ulCount
  2851. );
  2852. if (SUCCEEDED(hr) && 1 == ulCount)
  2853. {
  2854. //
  2855. // Normalize return value
  2856. //
  2857. hr = S_OK;
  2858. //
  2859. // Validate that enumeration is now empty
  2860. //
  2861. ValidateFinishedWCOEnum(piwsNamespace, pwcoEnum);
  2862. }
  2863. else
  2864. {
  2865. if (WBEM_S_FALSE == hr)
  2866. {
  2867. //
  2868. // No items in enumeration.
  2869. //
  2870. if (fCreate)
  2871. {
  2872. //
  2873. // Create a new object instance
  2874. //
  2875. hr = SpawnNewInstance(
  2876. piwsNamespace,
  2877. pwszClass,
  2878. ppwcoInstance
  2879. );
  2880. }
  2881. else
  2882. {
  2883. //
  2884. // Change this to an error code. This
  2885. // is deliberately not a WBEM error code.
  2886. //
  2887. hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND);
  2888. }
  2889. }
  2890. }
  2891. pwcoEnum->Release();
  2892. }
  2893. return hr;
  2894. }
  2895. HRESULT
  2896. SetBooleanValue(
  2897. IWbemClassObject *pwcoInstance,
  2898. LPCWSTR pwszProperty,
  2899. BOOLEAN fBoolean
  2900. )
  2901. /*++
  2902. Routine Description:
  2903. Retrieves a boolean property from a Wbem object.
  2904. Arguments:
  2905. pwcoInstance - the object to get the property from
  2906. pwszProperty - the property to retrieve
  2907. pfBoolean - received the property value
  2908. Return Value:
  2909. standard HRESULT
  2910. --*/
  2911. {
  2912. HRESULT hr = S_OK;
  2913. VARIANT vt;
  2914. _ASSERT(NULL != pwcoInstance);
  2915. _ASSERT(NULL != pwszProperty);
  2916. VariantInit(&vt);
  2917. V_VT(&vt) = VT_BOOL;
  2918. V_BOOL(&vt) = (fBoolean ? VARIANT_TRUE : VARIANT_FALSE);
  2919. hr = pwcoInstance->Put(
  2920. pwszProperty,
  2921. 0,
  2922. &vt,
  2923. NULL
  2924. );
  2925. return hr;
  2926. }
  2927. VOID
  2928. SetProxyBlanket(
  2929. IUnknown *pUnk
  2930. )
  2931. /*++
  2932. Routine Description:
  2933. Sets the standard COM security settings on the proxy for an
  2934. object.
  2935. Arguments:
  2936. pUnk - the object to set the proxy blanket on
  2937. Return Value:
  2938. None. Even if the CoSetProxyBlanket calls fail, pUnk remains
  2939. in a usable state. Failure is expected in certain contexts, such
  2940. as when, for example, we're being called w/in the netman process --
  2941. in this case, we have direct pointers to the netman objects, instead
  2942. of going through a proxy.
  2943. --*/
  2944. {
  2945. HRESULT hr;
  2946. _ASSERT(pUnk);
  2947. hr = CoSetProxyBlanket(
  2948. pUnk,
  2949. RPC_C_AUTHN_WINNT, // use NT default security
  2950. RPC_C_AUTHZ_NONE, // use NT default authentication
  2951. NULL, // must be null if default
  2952. RPC_C_AUTHN_LEVEL_CALL, // call
  2953. RPC_C_IMP_LEVEL_IMPERSONATE,
  2954. NULL, // use process token
  2955. EOAC_NONE
  2956. );
  2957. if (SUCCEEDED(hr))
  2958. {
  2959. IUnknown * pUnkSet = NULL;
  2960. hr = pUnk->QueryInterface(&pUnkSet);
  2961. if (SUCCEEDED(hr))
  2962. {
  2963. hr = CoSetProxyBlanket(
  2964. pUnkSet,
  2965. RPC_C_AUTHN_WINNT, // use NT default security
  2966. RPC_C_AUTHZ_NONE, // use NT default authentication
  2967. NULL, // must be null if default
  2968. RPC_C_AUTHN_LEVEL_CALL, // call
  2969. RPC_C_IMP_LEVEL_IMPERSONATE,
  2970. NULL, // use process token
  2971. EOAC_NONE
  2972. );
  2973. pUnkSet->Release();
  2974. }
  2975. }
  2976. }
  2977. HRESULT
  2978. SpawnNewInstance(
  2979. IWbemServices *piwsNamespace,
  2980. LPCWSTR wszClass,
  2981. IWbemClassObject **ppwcoInstance
  2982. )
  2983. /*++
  2984. Routine Description:
  2985. Creates a new instance of a class
  2986. Arguments:
  2987. piwsNamespace - the namespace the class is in
  2988. wszClass - the class to create the instance of
  2989. ppwcoInstance -- receives the created instance
  2990. Return Value:
  2991. standard HRESULT
  2992. --*/
  2993. {
  2994. HRESULT hr;
  2995. BSTR bstr;
  2996. IWbemClassObject *pwcoClass;
  2997. _ASSERT(NULL != piwsNamespace);
  2998. _ASSERT(NULL != wszClass);
  2999. _ASSERT(NULL != ppwcoInstance);
  3000. *ppwcoInstance = NULL;
  3001. bstr = SysAllocString(wszClass);
  3002. if (NULL != bstr)
  3003. {
  3004. pwcoClass = NULL;
  3005. hr = piwsNamespace->GetObject(
  3006. bstr,
  3007. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  3008. NULL,
  3009. &pwcoClass,
  3010. NULL
  3011. );
  3012. SysFreeString(bstr);
  3013. }
  3014. else
  3015. {
  3016. hr = E_OUTOFMEMORY;
  3017. }
  3018. if (WBEM_S_NO_ERROR == hr)
  3019. {
  3020. hr = pwcoClass->SpawnInstance(0, ppwcoInstance);
  3021. pwcoClass->Release();
  3022. }
  3023. return hr;
  3024. }
  3025. DWORD
  3026. StartOrUpdateService(
  3027. VOID
  3028. )
  3029. /*++
  3030. Routine Description:
  3031. This routine is invoked to start the SharedAccess service. It will
  3032. also mark the service as auto-start. If the service is already running,
  3033. it will send a IPNATHLP_CONTROL_UPDATE_CONNECTION notification
  3034. Arguments:
  3035. none.
  3036. Return Value:
  3037. ULONG - Win32 status code.
  3038. --*/
  3039. {
  3040. ULONG Error;
  3041. SC_HANDLE ScmHandle;
  3042. SC_HANDLE ServiceHandle;
  3043. SERVICE_STATUS ServiceStatus;
  3044. ULONG Timeout;
  3045. //
  3046. // Connect to the service control manager
  3047. //
  3048. ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  3049. if (!ScmHandle) { return GetLastError(); }
  3050. do {
  3051. //
  3052. // Open the shared access service
  3053. //
  3054. ServiceHandle =
  3055. OpenService(ScmHandle, c_wszSharedAccess, SERVICE_ALL_ACCESS);
  3056. if (!ServiceHandle) { Error = GetLastError(); break; }
  3057. //
  3058. // Mark it as auto-start
  3059. //
  3060. ChangeServiceConfig(
  3061. ServiceHandle,
  3062. SERVICE_NO_CHANGE,
  3063. SERVICE_AUTO_START,
  3064. SERVICE_NO_CHANGE,
  3065. NULL,
  3066. NULL,
  3067. NULL,
  3068. NULL,
  3069. NULL,
  3070. NULL,
  3071. NULL
  3072. );
  3073. // if we are in ICS Upgrade, don't start the SharedAccess service because the
  3074. // service may have problem in starting up during GUI Mode Setup.
  3075. HANDLE hIcsUpgradeEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, c_wszIcsUpgradeEventName);
  3076. if (NULL != hIcsUpgradeEvent)
  3077. {
  3078. CloseHandle(hIcsUpgradeEvent);
  3079. Error = NO_ERROR;
  3080. break;
  3081. }
  3082. //
  3083. // Attempt to start the service
  3084. //
  3085. if (!StartService(ServiceHandle, 0, NULL)) {
  3086. Error = GetLastError();
  3087. if (Error == ERROR_SERVICE_ALREADY_RUNNING)
  3088. {
  3089. //
  3090. // Send control notification
  3091. //
  3092. Error = NO_ERROR;
  3093. if (!ControlService(
  3094. ServiceHandle,
  3095. IPNATHLP_CONTROL_UPDATE_CONNECTION,
  3096. &ServiceStatus
  3097. ))
  3098. {
  3099. Error = GetLastError();
  3100. }
  3101. }
  3102. break;
  3103. }
  3104. //
  3105. // Wait for the service to start
  3106. //
  3107. Timeout = 30;
  3108. Error = ERROR_CAN_NOT_COMPLETE;
  3109. do {
  3110. //
  3111. // Query the service's state
  3112. //
  3113. if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) {
  3114. Error = GetLastError(); break;
  3115. }
  3116. //
  3117. // See if the service has started
  3118. //
  3119. if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
  3120. Error = NO_ERROR; break;
  3121. } else if (ServiceStatus.dwCurrentState == SERVICE_STOPPED ||
  3122. ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING) {
  3123. break;
  3124. }
  3125. //
  3126. // Wait a little longer
  3127. //
  3128. Sleep(1000);
  3129. } while(Timeout--);
  3130. } while(FALSE);
  3131. if (ServiceHandle) { CloseServiceHandle(ServiceHandle); }
  3132. CloseServiceHandle(ScmHandle);
  3133. return Error;
  3134. }
  3135. VOID
  3136. StopService(
  3137. VOID
  3138. )
  3139. /*++
  3140. Routine Description:
  3141. Stops the SharedAccess service, and marks it as demand start.
  3142. Arguments:
  3143. none.
  3144. Return Value:
  3145. none.
  3146. --*/
  3147. {
  3148. ULONG Error;
  3149. SC_HANDLE ScmHandle;
  3150. SC_HANDLE ServiceHandle;
  3151. SERVICE_STATUS ServiceStatus;
  3152. //
  3153. // Connect to the service control manager
  3154. //
  3155. ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  3156. if (!ScmHandle) { return; }
  3157. do {
  3158. //
  3159. // Open the shared access service
  3160. //
  3161. ServiceHandle =
  3162. OpenService(ScmHandle, c_wszSharedAccess, SERVICE_ALL_ACCESS);
  3163. if (!ServiceHandle) { Error = GetLastError(); break; }
  3164. //
  3165. // Mark it as demand-start
  3166. //
  3167. ChangeServiceConfig(
  3168. ServiceHandle,
  3169. SERVICE_NO_CHANGE,
  3170. SERVICE_DEMAND_START,
  3171. SERVICE_NO_CHANGE,
  3172. NULL,
  3173. NULL,
  3174. NULL,
  3175. NULL,
  3176. NULL,
  3177. NULL,
  3178. NULL
  3179. );
  3180. //
  3181. // Attempt to stop the service
  3182. //
  3183. ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus);
  3184. } while(FALSE);
  3185. if (ServiceHandle) { CloseServiceHandle(ServiceHandle); }
  3186. CloseServiceHandle(ScmHandle);
  3187. }
  3188. HRESULT
  3189. UpdateOrStopService(
  3190. IWbemServices *piwsNamespace,
  3191. BSTR bstrWQL,
  3192. DWORD dwControlCode
  3193. )
  3194. /*++
  3195. Routine Description:
  3196. Checks to see if there are any firewalled or ICS connections. If so,
  3197. an update request is sent to the SharedAccess service; if not, the
  3198. service is stopped
  3199. Arguments:
  3200. piwsNamespace - WMI namespace
  3201. bstrWQL - a BSTR that corresponds to "WQL"
  3202. dwControlCode - the kind of update to send
  3203. Return Value:
  3204. standard HRESULT
  3205. --*/
  3206. {
  3207. HRESULT hr = S_OK;
  3208. IEnumWbemClassObject *pwcoEnum;
  3209. BSTR bstrQuery;
  3210. _ASSERT(NULL != piwsNamespace);
  3211. _ASSERT(NULL != bstrWQL);
  3212. //
  3213. // See if we have any connections that are marked as
  3214. // * ICS public
  3215. // * ICS private
  3216. // * firewalled
  3217. //
  3218. // (We don't care about bridged connections, as the SharedAccess service
  3219. // doesn't have anything to do with the bridge.)
  3220. //
  3221. bstrQuery = SysAllocString(c_wszServiceCheckQuery);
  3222. if (NULL != bstrQuery)
  3223. {
  3224. pwcoEnum = NULL;
  3225. hr = piwsNamespace->ExecQuery(
  3226. bstrWQL,
  3227. bstrQuery,
  3228. WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
  3229. NULL,
  3230. &pwcoEnum
  3231. );
  3232. SysFreeString(bstrQuery);
  3233. }
  3234. else
  3235. {
  3236. hr = E_OUTOFMEMORY;
  3237. }
  3238. if (WBEM_S_NO_ERROR == hr)
  3239. {
  3240. ULONG ulCount;
  3241. IWbemClassObject *pwcoObj;
  3242. //
  3243. // Check to see if the query returned anything
  3244. //
  3245. pwcoObj = NULL;
  3246. hr = pwcoEnum->Next(WBEM_INFINITE, 1, &pwcoObj, &ulCount);
  3247. if (SUCCEEDED(hr))
  3248. {
  3249. if (1 == ulCount)
  3250. {
  3251. //
  3252. // Object retrieved -- need to update service
  3253. //
  3254. pwcoObj->Release();
  3255. UpdateService(dwControlCode);
  3256. }
  3257. else
  3258. {
  3259. //
  3260. // No object retrieved -- stop service
  3261. //
  3262. StopService();
  3263. }
  3264. }
  3265. pwcoEnum->Release();
  3266. }
  3267. return hr;
  3268. }
  3269. VOID
  3270. UpdateService(
  3271. DWORD dwControlCode
  3272. )
  3273. /*++
  3274. Routine Description:
  3275. Sends a control code to the SharedAccess service
  3276. Arguments:
  3277. dwControlCode - the code to send
  3278. Return Value:
  3279. none.
  3280. --*/
  3281. {
  3282. ULONG Error;
  3283. SC_HANDLE ScmHandle;
  3284. SC_HANDLE ServiceHandle;
  3285. SERVICE_STATUS ServiceStatus;
  3286. //
  3287. // Connect to the service control manager
  3288. //
  3289. ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  3290. if (!ScmHandle) { return; }
  3291. do {
  3292. //
  3293. // Open the shared access service
  3294. //
  3295. ServiceHandle =
  3296. OpenService(ScmHandle, c_wszSharedAccess, SERVICE_ALL_ACCESS);
  3297. if (!ServiceHandle) { Error = GetLastError(); break; }
  3298. //
  3299. // Send the control notification
  3300. //
  3301. ControlService(ServiceHandle, dwControlCode, &ServiceStatus);
  3302. } while(FALSE);
  3303. if (ServiceHandle) { CloseServiceHandle(ServiceHandle); }
  3304. CloseServiceHandle(ScmHandle);
  3305. }
  3306. VOID
  3307. ValidateFinishedWCOEnum(
  3308. IWbemServices *piwsNamespace,
  3309. IEnumWbemClassObject *pwcoEnum
  3310. )
  3311. /*++
  3312. Routine Description:
  3313. Checks to see that a WCO enumerator is finished (i.e., all objects
  3314. have been retrieved). If the enumerator is not finished, any object
  3315. instances that are retrieved will be deleted, and an assertion will
  3316. be raised on checked builds.
  3317. Arguments:
  3318. piwsNamespace - the namespace the enumeration is from
  3319. pwcoEnum - the enumeration to validate
  3320. Return Value:
  3321. None.
  3322. --*/
  3323. {
  3324. HRESULT hr;
  3325. IWbemClassObject *pwcoInstance = NULL;
  3326. ULONG ulCount = 0;
  3327. _ASSERT(piwsNamespace);
  3328. _ASSERT(pwcoEnum);
  3329. do
  3330. {
  3331. pwcoInstance = NULL;
  3332. hr = pwcoEnum->Next(
  3333. WBEM_INFINITE,
  3334. 1,
  3335. &pwcoInstance,
  3336. &ulCount
  3337. );
  3338. if (SUCCEEDED(hr) && 1 == ulCount)
  3339. {
  3340. //
  3341. // We got an unexpected instance.
  3342. //
  3343. _ASSERT(FALSE);
  3344. //
  3345. // Delete the instance. Don't care about return value.
  3346. //
  3347. DeleteWmiInstance(
  3348. piwsNamespace,
  3349. pwcoInstance
  3350. );
  3351. pwcoInstance->Release();
  3352. }
  3353. }
  3354. while (SUCCEEDED(hr) && 1 == ulCount);
  3355. }
  3356. HRESULT
  3357. SendPortMappingListChangeNotification()
  3358. {
  3359. HRESULT hr = S_OK;
  3360. ISharedAccessUpdate* pUpdate = NULL;
  3361. if ( IsServiceRunning(c_wszSharedAccess) )
  3362. {
  3363. hr = CoCreateInstance(
  3364. CLSID_SAUpdate,
  3365. NULL,
  3366. CLSCTX_SERVER,
  3367. IID_PPV_ARG( ISharedAccessUpdate, &pUpdate )
  3368. );
  3369. if ( SUCCEEDED(hr) )
  3370. {
  3371. hr = pUpdate->PortMappingListChanged();
  3372. pUpdate->Release();
  3373. }
  3374. }
  3375. return hr;
  3376. }
  3377. HRESULT
  3378. SignalModifiedConnection(
  3379. GUID *pGUID
  3380. )
  3381. /*++
  3382. Routine Description:
  3383. Signals a modification to a network connection (refreshes the UI)
  3384. Arguments:
  3385. pGUID The GUID of the modified connection
  3386. Return Value:
  3387. Result of the operation
  3388. --*/
  3389. {
  3390. HRESULT hr;
  3391. INetConnection *pConn;
  3392. hr = FindINetConnectionByGuid( pGUID, &pConn );
  3393. if( SUCCEEDED(hr) )
  3394. {
  3395. INetConnectionRefresh *pNetConRefresh;
  3396. hr = CoCreateInstance(
  3397. CLSID_ConnectionManager,
  3398. NULL,
  3399. CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
  3400. IID_PPV_ARG(INetConnectionRefresh, &pNetConRefresh)
  3401. );
  3402. if( SUCCEEDED(hr) )
  3403. {
  3404. SetProxyBlanket(pNetConRefresh);
  3405. hr = pNetConRefresh->ConnectionModified(pConn);
  3406. pNetConRefresh->Release();
  3407. }
  3408. pConn->Release();
  3409. }
  3410. return hr;
  3411. }
  3412. HRESULT
  3413. SignalNewConnection(
  3414. GUID *pGUID
  3415. )
  3416. /*++
  3417. Routine Description:
  3418. Signals that a new network connection has been created (refreshes the UI)
  3419. Arguments:
  3420. pGUID The GUID of the new connection
  3421. Return Value:
  3422. Result of the operation
  3423. --*/
  3424. {
  3425. HRESULT hr;
  3426. INetConnection *pConn;
  3427. hr = FindINetConnectionByGuid( pGUID, &pConn );
  3428. if( SUCCEEDED(hr) )
  3429. {
  3430. INetConnectionRefresh *pNetConRefresh;
  3431. hr = CoCreateInstance(
  3432. CLSID_ConnectionManager,
  3433. NULL,
  3434. CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
  3435. IID_PPV_ARG(INetConnectionRefresh, &pNetConRefresh)
  3436. );
  3437. if( SUCCEEDED(hr) )
  3438. {
  3439. SetProxyBlanket(pNetConRefresh);
  3440. hr = pNetConRefresh->ConnectionAdded(pConn);
  3441. pNetConRefresh->Release();
  3442. }
  3443. pConn->Release();
  3444. }
  3445. return hr;
  3446. }
  3447. HRESULT
  3448. SignalDeletedConnection(
  3449. GUID *pGUID
  3450. )
  3451. /*++
  3452. Routine Description:
  3453. Signals that a network connection has been deleted (refreshes the UI)
  3454. Arguments:
  3455. pGUID The GUID of the deleted connection
  3456. Return Value:
  3457. Result of the operation
  3458. --*/
  3459. {
  3460. HRESULT hr;
  3461. INetConnectionRefresh *pNetConRefresh;
  3462. hr = CoCreateInstance(
  3463. CLSID_ConnectionManager,
  3464. NULL,
  3465. CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
  3466. IID_PPV_ARG(INetConnectionRefresh, &pNetConRefresh)
  3467. );
  3468. if( SUCCEEDED(hr) )
  3469. {
  3470. hr = pNetConRefresh->ConnectionDeleted(pGUID);
  3471. pNetConRefresh->Release();
  3472. }
  3473. return hr;
  3474. }