Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4615 lines
98 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_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_DISABLE_AAA,
  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_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_DISABLE_AAA,
  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_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_DISABLE_AAA,
  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. BOOLEAN fBoundToBridge = FALSE;
  1460. HRESULT hr = S_OK;
  1461. INetCfgComponentBindings *pnetcfgBindings;
  1462. //
  1463. // Retrieve the ComponentBindings interface
  1464. //
  1465. hr = pnetcfgcomp->QueryInterface(
  1466. IID_PPV_ARG(INetCfgComponentBindings, &pnetcfgBindings)
  1467. );
  1468. if (S_OK == hr)
  1469. {
  1470. IEnumNetCfgBindingPath *penumPaths;
  1471. //
  1472. // Get the list of binding paths for this component
  1473. //
  1474. hr = pnetcfgBindings->EnumBindingPaths(
  1475. EBP_ABOVE,
  1476. &penumPaths
  1477. );
  1478. if (S_OK == hr)
  1479. {
  1480. ULONG ulCount1, ulCount2;
  1481. INetCfgBindingPath *pnetcfgPath;
  1482. while( (S_OK == penumPaths->Next(1, &pnetcfgPath, &ulCount1) ) )
  1483. {
  1484. INetCfgComponent *pnetcfgOwner;
  1485. //
  1486. // Get the owner of this path
  1487. //
  1488. hr = pnetcfgPath->GetOwner( &pnetcfgOwner );
  1489. if (S_OK == hr)
  1490. {
  1491. INetCfgComponentBindings *pnetcfgOwnerBindings;
  1492. hr = pnetcfgOwner->QueryInterface(
  1493. IID_PPV_ARG(INetCfgComponentBindings, &pnetcfgOwnerBindings)
  1494. );
  1495. if (S_OK == hr)
  1496. {
  1497. LPWSTR lpwstrId;
  1498. hr = pnetcfgOwner->GetId( &lpwstrId );
  1499. if (S_OK == hr)
  1500. {
  1501. BOOLEAN bIsBridge;
  1502. bIsBridge = ( _wcsicmp(lpwstrId, c_wszSBridgeSID) == 0 );
  1503. if( bIsBridge )
  1504. {
  1505. // This is the bridge component. Activate this binding path
  1506. hr = pnetcfgOwnerBindings->BindTo(pnetcfgcomp);
  1507. fBoundToBridge = (S_OK == hr);
  1508. }
  1509. else
  1510. {
  1511. // Check if this is one of the bind exceptions
  1512. BOOLEAN bIsException = FALSE;
  1513. const WCHAR **ppwszException = c_pwszBridgeBindExceptions;
  1514. while( NULL != *ppwszException )
  1515. {
  1516. bIsException = ( _wcsicmp(lpwstrId, *ppwszException) == 0 );
  1517. if( bIsException )
  1518. {
  1519. break;
  1520. }
  1521. ppwszException++;
  1522. }
  1523. if( !bIsException )
  1524. {
  1525. hr = pnetcfgOwnerBindings->UnbindFrom(pnetcfgcomp);
  1526. }
  1527. // else this is an exception; leave the bind path as-is.
  1528. }
  1529. CoTaskMemFree(lpwstrId);
  1530. }
  1531. pnetcfgOwnerBindings->Release();
  1532. }
  1533. pnetcfgOwner->Release();
  1534. }
  1535. pnetcfgPath->Release();
  1536. }
  1537. penumPaths->Release();
  1538. }
  1539. pnetcfgBindings->Release();
  1540. }
  1541. if (S_OK == hr && !fBoundToBridge)
  1542. {
  1543. //
  1544. // We didn't found a binding path between this component and
  1545. // the bridge protocol. This should never occur -- such
  1546. // components should not have shown up as bridgeable. Return
  1547. // and error and fire an assert.
  1548. //
  1549. _ASSERT(FALSE);
  1550. hr = E_FAIL;
  1551. }
  1552. return hr;
  1553. }
  1554. HRESULT
  1555. GetBooleanValue(
  1556. IWbemClassObject *pwcoInstance,
  1557. LPCWSTR pwszProperty,
  1558. BOOLEAN *pfBoolean
  1559. )
  1560. /*++
  1561. Routine Description:
  1562. Retrieves a boolean property from a Wbem object.
  1563. Arguments:
  1564. pwcoInstance - the object to get the property from
  1565. pwszProperty - the property to retrieve
  1566. pfBoolean - received the property value
  1567. Return Value:
  1568. standard HRESULT
  1569. --*/
  1570. {
  1571. HRESULT hr = S_OK;
  1572. VARIANT vt;
  1573. _ASSERT(NULL != pwcoInstance);
  1574. _ASSERT(NULL != pwszProperty);
  1575. _ASSERT(NULL != pfBoolean);
  1576. hr = pwcoInstance->Get(
  1577. pwszProperty,
  1578. 0,
  1579. &vt,
  1580. NULL,
  1581. NULL
  1582. );
  1583. if (WBEM_S_NO_ERROR == hr)
  1584. {
  1585. _ASSERT(VT_BOOL == V_VT(&vt) || VT_NULL == V_VT(&vt));
  1586. if (VT_BOOL == V_VT(&vt))
  1587. {
  1588. *pfBoolean = VARIANT_TRUE == V_BOOL(&vt);
  1589. }
  1590. else
  1591. {
  1592. //
  1593. // No value for this member was ever written to the store.
  1594. // Return FALSE, and set that value in the store. We don't
  1595. // pass along the error, if one occurs
  1596. //
  1597. *pfBoolean = FALSE;
  1598. SetBooleanValue(
  1599. pwcoInstance,
  1600. pwszProperty,
  1601. FALSE
  1602. );
  1603. }
  1604. VariantClear(&vt);
  1605. }
  1606. return hr;
  1607. }
  1608. HRESULT
  1609. GetConnectionInstanceByGuid(
  1610. IWbemServices *piwsNamespace,
  1611. BSTR bstrWQL,
  1612. GUID *pGuid,
  1613. IWbemClassObject **ppwcoConnection
  1614. )
  1615. /*++
  1616. Routine Description:
  1617. Retrieves the HNet_Connection instance for a INetConnection guid
  1618. Arguments:
  1619. piwsNamespace - WMI namespace
  1620. bstrWQL - a BSTR that corresponds to "WQL"
  1621. pGuid - the guid of the INetConnection (i.e., guidId in its properties)
  1622. ppwcoConnection - receives the HNet_Connection instance
  1623. Return Value:
  1624. standard HRESULT
  1625. --*/
  1626. {
  1627. HRESULT hr;
  1628. LPWSTR wsz;
  1629. BSTR bstrQuery;
  1630. LPOLESTR wszGuid;
  1631. IEnumWbemClassObject *pwcoEnum;
  1632. //
  1633. // Convert the guid to a string
  1634. //
  1635. hr = StringFromCLSID(*pGuid, &wszGuid);
  1636. if (S_OK == hr)
  1637. {
  1638. //
  1639. // Find the connection w/ name equal to that string
  1640. //
  1641. hr = BuildQuotedEqualsString(
  1642. &wsz,
  1643. c_wszGuid,
  1644. wszGuid
  1645. );
  1646. CoTaskMemFree(wszGuid);
  1647. if (S_OK == hr)
  1648. {
  1649. hr = BuildSelectQueryBstr(
  1650. &bstrQuery,
  1651. c_wszStar,
  1652. c_wszHnetConnection,
  1653. wsz
  1654. );
  1655. delete [] wsz;
  1656. }
  1657. if (S_OK == hr)
  1658. {
  1659. pwcoEnum = NULL;
  1660. hr = piwsNamespace->ExecQuery(
  1661. bstrWQL,
  1662. bstrQuery,
  1663. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
  1664. NULL,
  1665. &pwcoEnum
  1666. );
  1667. SysFreeString(bstrQuery);
  1668. }
  1669. }
  1670. if (WBEM_S_NO_ERROR == hr)
  1671. {
  1672. ULONG ulCount;
  1673. //
  1674. // Get the instance out of the enum
  1675. //
  1676. *ppwcoConnection = NULL;
  1677. hr = pwcoEnum->Next(
  1678. WBEM_INFINITE,
  1679. 1,
  1680. ppwcoConnection,
  1681. &ulCount
  1682. );
  1683. if (SUCCEEDED(hr) && 1 != ulCount)
  1684. {
  1685. hr = E_FAIL;
  1686. }
  1687. ValidateFinishedWCOEnum(piwsNamespace, pwcoEnum);
  1688. pwcoEnum->Release();
  1689. }
  1690. return hr;
  1691. }
  1692. HRESULT
  1693. GetConnAndPropInstancesByGuid(
  1694. IWbemServices *piwsNamespace,
  1695. GUID *pGuid,
  1696. IWbemClassObject **ppwcoConnection,
  1697. IWbemClassObject **ppwcoProperties
  1698. )
  1699. /*++
  1700. Routine Description:
  1701. Retrieves the HNet_Connection and HNet_ConnectionProperties instances
  1702. for a INetConnection guid
  1703. Arguments:
  1704. piwsNamespace - WMI namespace
  1705. pGuid - the guid of the INetConnection (i.e., guidId in its properties)
  1706. ppwcoConnection - receives the HNet_Connection instance
  1707. ppwcoProperties - receives the HNet_ConnectionProperties instance
  1708. Return Value:
  1709. standard HRESULT
  1710. --*/
  1711. {
  1712. HRESULT hr = S_OK;
  1713. BSTR bstrWQL = NULL;
  1714. _ASSERT(NULL != piwsNamespace);
  1715. _ASSERT(NULL != pGuid);
  1716. _ASSERT(NULL != ppwcoConnection);
  1717. _ASSERT(NULL != ppwcoProperties);
  1718. bstrWQL = SysAllocString(c_wszWQL);
  1719. if (NULL != bstrWQL)
  1720. {
  1721. hr = GetConnectionInstanceByGuid(
  1722. piwsNamespace,
  1723. bstrWQL,
  1724. pGuid,
  1725. ppwcoConnection
  1726. );
  1727. }
  1728. else
  1729. {
  1730. hr = E_OUTOFMEMORY;
  1731. }
  1732. if (SUCCEEDED(hr))
  1733. {
  1734. hr = GetPropInstanceFromConnInstance(
  1735. piwsNamespace,
  1736. *ppwcoConnection,
  1737. ppwcoProperties
  1738. );
  1739. if (FAILED(hr))
  1740. {
  1741. (*ppwcoConnection)->Release();
  1742. *ppwcoConnection = NULL;
  1743. }
  1744. }
  1745. if (NULL != bstrWQL)
  1746. {
  1747. SysFreeString(bstrWQL);
  1748. }
  1749. return hr;
  1750. }
  1751. HRESULT
  1752. GetConnAndPropInstancesForHNC(
  1753. IWbemServices *piwsNamespace,
  1754. IHNetConnection *pConn,
  1755. IWbemClassObject **ppwcoConnection,
  1756. IWbemClassObject **ppwcoProperties
  1757. )
  1758. /*++
  1759. Routine Description:
  1760. Retrieves the HNet_Connection and HNet_ConnectionProperties instances
  1761. for an IHNetConnection.
  1762. Arguments:
  1763. piwsNamespace - WMI namespace
  1764. pConn - the IHNetConnection
  1765. ppwcoConnection - receives the HNet_Connection instance
  1766. ppwcoProperties - receives the HNet_ConnectionProperties instance
  1767. Return Value:
  1768. standard HRESULT
  1769. --*/
  1770. {
  1771. HRESULT hr;
  1772. GUID *pGuid;
  1773. _ASSERT(NULL != piwsNamespace);
  1774. _ASSERT(NULL != pConn);
  1775. _ASSERT(NULL != ppwcoConnection);
  1776. _ASSERT(NULL != ppwcoProperties);
  1777. //
  1778. // Find the items by GUID
  1779. //
  1780. hr = pConn->GetGuid(&pGuid);
  1781. if (S_OK == hr)
  1782. {
  1783. hr = GetConnAndPropInstancesByGuid(
  1784. piwsNamespace,
  1785. pGuid,
  1786. ppwcoConnection,
  1787. ppwcoProperties
  1788. );
  1789. CoTaskMemFree(pGuid);
  1790. }
  1791. return hr;
  1792. }
  1793. HRESULT
  1794. GetPhonebookPathFromRasNetcon(
  1795. INetConnection *pConn,
  1796. LPWSTR *ppwstr
  1797. )
  1798. /*++
  1799. Routine Description:
  1800. Retrieves the phonebook path for an INetConnection that represents
  1801. a RAS connection
  1802. Arguments:
  1803. INetConnection - the RAS connection
  1804. ppwstr - receives the phonebook path. The caller must call CoTaskMemFree for
  1805. this pointer on success. On failure, the pointer receives NULL.
  1806. Return Value:
  1807. standard HRESULT
  1808. --*/
  1809. {
  1810. HRESULT hr;
  1811. INetRasConnection *pRasConn;
  1812. RASCON_INFO RasConInfo;
  1813. _ASSERT(NULL != pConn);
  1814. _ASSERT(NULL != ppwstr);
  1815. *ppwstr = NULL;
  1816. //
  1817. // QI for the INetRasConnection
  1818. //
  1819. hr = pConn->QueryInterface(
  1820. IID_PPV_ARG(INetRasConnection, &pRasConn)
  1821. );
  1822. if (SUCCEEDED(hr))
  1823. {
  1824. //
  1825. // Get the connection information
  1826. //
  1827. hr = pRasConn->GetRasConnectionInfo(&RasConInfo);
  1828. if (SUCCEEDED(hr))
  1829. {
  1830. *ppwstr = RasConInfo.pszwPbkFile;
  1831. //
  1832. // Free the name pointer. The caller is responsible for
  1833. // freeing the path pointer
  1834. //
  1835. CoTaskMemFree(RasConInfo.pszwEntryName);
  1836. }
  1837. pRasConn->Release();
  1838. }
  1839. return hr;
  1840. }
  1841. HRESULT
  1842. GetPortMappingBindingInstance(
  1843. IWbemServices *piwsNamespace,
  1844. BSTR bstrWQL,
  1845. BSTR bstrConnectionPath,
  1846. BSTR bstrProtocolPath,
  1847. USHORT usPublicPort,
  1848. IWbemClassObject **ppInstance
  1849. )
  1850. /*++
  1851. Routine Description:
  1852. Given the path to an HNet_Connection instance and and
  1853. HNet_PortMappingProtocol instance, checks to see if a
  1854. corresponding HNet_ConnectionPortMapping exists. If it
  1855. doesn't, the instance is created. The HNet_ConnectionPortMapping
  1856. instance -- existing or newly created -- is returned and must
  1857. be released by the caller.
  1858. Arguments:
  1859. piwsNamespace - the namespace to use
  1860. bstrWQL - a BSTR containing the string "WQL"
  1861. bstrConnectionPath - path to the HNet_Connection instance
  1862. bstrProtocolPath - path to the HNet_PortMappingProtocol instance
  1863. usPublicPort - the port of the port mapping protocol
  1864. ppInstance - receives the HNet_ConnectionPortMapping instance
  1865. Return Value:
  1866. Standard HRESULT
  1867. --*/
  1868. {
  1869. HRESULT hr;
  1870. IEnumWbemClassObject *pwcoEnum;
  1871. IWbemClassObject *pwcoInstance;
  1872. BSTR bstrQuery;
  1873. BSTR bstr;
  1874. LPWSTR wsz;
  1875. LPWSTR wszConClause;
  1876. LPWSTR wszProtClause;
  1877. _ASSERT(NULL != piwsNamespace);
  1878. _ASSERT(NULL != bstrWQL);
  1879. _ASSERT(NULL != bstrConnectionPath);
  1880. _ASSERT(NULL != bstrProtocolPath);
  1881. _ASSERT(NULL != ppInstance);
  1882. //
  1883. // Connection = "bstrConnectionPath" AND Protocol = "bstrProtocolPath"
  1884. //
  1885. hr = BuildEscapedQuotedEqualsString(
  1886. &wszConClause,
  1887. c_wszConnection,
  1888. bstrConnectionPath
  1889. );
  1890. if (S_OK == hr)
  1891. {
  1892. hr = BuildEscapedQuotedEqualsString(
  1893. &wszProtClause,
  1894. c_wszProtocol,
  1895. bstrProtocolPath
  1896. );
  1897. if (S_OK == hr)
  1898. {
  1899. hr = BuildAndString(
  1900. &wsz,
  1901. wszConClause,
  1902. wszProtClause
  1903. );
  1904. delete [] wszProtClause;
  1905. }
  1906. delete [] wszConClause;
  1907. }
  1908. if (S_OK == hr)
  1909. {
  1910. hr = BuildSelectQueryBstr(
  1911. &bstrQuery,
  1912. c_wszStar,
  1913. c_wszHnetConnectionPortMapping,
  1914. wsz
  1915. );
  1916. delete [] wsz;
  1917. }
  1918. if (S_OK == hr)
  1919. {
  1920. pwcoEnum = NULL;
  1921. hr = piwsNamespace->ExecQuery(
  1922. bstrWQL,
  1923. bstrQuery,
  1924. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
  1925. NULL,
  1926. &pwcoEnum
  1927. );
  1928. SysFreeString(bstrQuery);
  1929. }
  1930. if (WBEM_S_NO_ERROR == hr)
  1931. {
  1932. ULONG ulCount;
  1933. *ppInstance = NULL;
  1934. hr = pwcoEnum->Next(WBEM_INFINITE, 1, ppInstance, &ulCount);
  1935. if (FAILED(hr) || 1 != ulCount)
  1936. {
  1937. //
  1938. // Instance does not exist -- create now. However, first make
  1939. // sure that the protocol instance bstrProtocolPath refers to
  1940. // actually exists.
  1941. //
  1942. hr = GetWmiObjectFromPath(
  1943. piwsNamespace,
  1944. bstrProtocolPath,
  1945. ppInstance
  1946. );
  1947. if (WBEM_S_NO_ERROR == hr)
  1948. {
  1949. //
  1950. // The protocol object exists -- release it and
  1951. // continue with creating the new binding object.
  1952. //
  1953. (*ppInstance)->Release();
  1954. *ppInstance = NULL;
  1955. hr = SpawnNewInstance(
  1956. piwsNamespace,
  1957. c_wszHnetConnectionPortMapping,
  1958. ppInstance
  1959. );
  1960. }
  1961. if (WBEM_S_NO_ERROR == hr)
  1962. {
  1963. VARIANT vt;
  1964. //
  1965. // Fill out new instance information
  1966. //
  1967. V_VT(&vt) = VT_BSTR;
  1968. V_BSTR(&vt) = bstrConnectionPath;
  1969. hr = (*ppInstance)->Put(
  1970. c_wszConnection,
  1971. 0,
  1972. &vt,
  1973. NULL
  1974. );
  1975. if (WBEM_S_NO_ERROR == hr)
  1976. {
  1977. V_BSTR(&vt) = bstrProtocolPath;
  1978. hr = (*ppInstance)->Put(
  1979. c_wszProtocol,
  1980. 0,
  1981. &vt,
  1982. NULL
  1983. );
  1984. }
  1985. if (WBEM_S_NO_ERROR == hr)
  1986. {
  1987. hr = SetBooleanValue(
  1988. *ppInstance,
  1989. c_wszEnabled,
  1990. FALSE
  1991. );
  1992. }
  1993. if (WBEM_S_NO_ERROR == hr)
  1994. {
  1995. hr = SetBooleanValue(
  1996. *ppInstance,
  1997. c_wszNameActive,
  1998. FALSE
  1999. );
  2000. }
  2001. if (WBEM_S_NO_ERROR == hr)
  2002. {
  2003. V_VT(&vt) = VT_I4;
  2004. V_I4(&vt) = 0;
  2005. hr = (*ppInstance)->Put(
  2006. c_wszTargetIPAddress,
  2007. 0,
  2008. &vt,
  2009. NULL
  2010. );
  2011. }
  2012. if (WBEM_S_NO_ERROR == hr)
  2013. {
  2014. V_VT(&vt) = VT_BSTR;
  2015. V_BSTR(&vt) = SysAllocString(L" ");
  2016. if (NULL != V_BSTR(&vt))
  2017. {
  2018. hr = (*ppInstance)->Put(
  2019. c_wszTargetName,
  2020. 0,
  2021. &vt,
  2022. NULL
  2023. );
  2024. VariantClear(&vt);
  2025. }
  2026. else
  2027. {
  2028. hr = E_OUTOFMEMORY;
  2029. }
  2030. }
  2031. if (WBEM_S_NO_ERROR == hr)
  2032. {
  2033. V_VT(&vt) = VT_I4;
  2034. V_I4(&vt) = usPublicPort;
  2035. hr = (*ppInstance)->Put(
  2036. c_wszTargetPort,
  2037. 0,
  2038. &vt,
  2039. NULL
  2040. );
  2041. }
  2042. if (WBEM_S_NO_ERROR == hr)
  2043. {
  2044. IWbemCallResult *pResult;
  2045. //
  2046. // Write new instance to the store
  2047. //
  2048. pResult = NULL;
  2049. hr = piwsNamespace->PutInstance(
  2050. *ppInstance,
  2051. WBEM_FLAG_CREATE_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
  2052. NULL,
  2053. &pResult
  2054. );
  2055. if (WBEM_S_NO_ERROR == hr)
  2056. {
  2057. //
  2058. // Release the object, get the path from the result,
  2059. // and re-retrieve the object from the path
  2060. //
  2061. (*ppInstance)->Release();
  2062. *ppInstance = NULL;
  2063. hr = pResult->GetResultString(WBEM_INFINITE, &bstr);
  2064. if (WBEM_S_NO_ERROR == hr)
  2065. {
  2066. hr = GetWmiObjectFromPath(
  2067. piwsNamespace,
  2068. bstr,
  2069. ppInstance
  2070. );
  2071. SysFreeString(bstr);
  2072. }
  2073. pResult->Release();
  2074. }
  2075. }
  2076. }
  2077. }
  2078. else
  2079. {
  2080. //
  2081. // Normalize enum hresult
  2082. //
  2083. hr = S_OK;
  2084. }
  2085. ValidateFinishedWCOEnum(piwsNamespace, pwcoEnum);
  2086. pwcoEnum->Release();
  2087. }
  2088. return hr;
  2089. }
  2090. HRESULT
  2091. GetPropInstanceFromConnInstance(
  2092. IWbemServices *piwsNamespace,
  2093. IWbemClassObject *pwcoConnection,
  2094. IWbemClassObject **ppwcoProperties
  2095. )
  2096. /*++
  2097. Routine Description:
  2098. Retrieves the HNet_ConnectionProperties instance associated with
  2099. an HNet_Connection.
  2100. Arguments:
  2101. piwsNamespace - WMI namespace
  2102. bstrWQL - a BSTR that corresponds to "WQL"
  2103. pwcoConnection - the HNet_Connection instance
  2104. ppwcoProperties - receives the HNet_ConnectionProperties instance
  2105. Return Value:
  2106. standard HRESULT
  2107. --*/
  2108. {
  2109. HRESULT hr = S_OK;
  2110. OLECHAR wszBuffer[c_cchQueryBuffer + 1];
  2111. OLECHAR *pwszPath = NULL;
  2112. BSTR bstrPath;
  2113. VARIANT vt;
  2114. _ASSERT(NULL != piwsNamespace);
  2115. _ASSERT(NULL != pwcoConnection);
  2116. _ASSERT(NULL != ppwcoProperties);
  2117. //
  2118. // On debug builds, verify that our precomputed string lengths
  2119. // match the actual lengths
  2120. //
  2121. _ASSERT(wcslen(c_wszConnectionPropertiesPathFormat) == c_cchConnectionPropertiesPathFormat);
  2122. //
  2123. // Get the guid for the connection
  2124. //
  2125. hr = pwcoConnection->Get(
  2126. c_wszGuid,
  2127. 0,
  2128. &vt,
  2129. NULL,
  2130. NULL
  2131. );
  2132. if (WBEM_S_NO_ERROR == hr)
  2133. {
  2134. _ASSERT(VT_BSTR == V_VT(&vt));
  2135. //
  2136. // Determine how much space we need for the path and decide
  2137. // if we need to allocate a heap buffer.
  2138. //
  2139. ULONG cchLength =
  2140. c_cchConnectionPropertiesPathFormat + SysStringLen(V_BSTR(&vt)) + 1;
  2141. if (cchLength <= c_cchQueryBuffer)
  2142. {
  2143. //
  2144. // The buffer is large enough. (Note that since the buffer on the
  2145. // stack is one greater than the constant, the terminator is accounted
  2146. // for.) Point our working pointer to the stack buffer.
  2147. //
  2148. pwszPath = wszBuffer;
  2149. }
  2150. else
  2151. {
  2152. //
  2153. // Allocate a sufficient buffer from the heap. The +1 is for the
  2154. // terminating nul
  2155. //
  2156. pwszPath = new OLECHAR[cchLength + 1];
  2157. if (NULL == pwszPath)
  2158. {
  2159. hr = E_OUTOFMEMORY;
  2160. pwszPath = wszBuffer;
  2161. }
  2162. }
  2163. if (WBEM_S_NO_ERROR == hr)
  2164. {
  2165. //
  2166. // Build the path string
  2167. //
  2168. int iBytes =
  2169. _snwprintf(
  2170. pwszPath,
  2171. cchLength,
  2172. c_wszConnectionPropertiesPathFormat,
  2173. V_BSTR(&vt)
  2174. );
  2175. _ASSERT(iBytes >= 0);
  2176. //
  2177. // Convert that to a BSTR
  2178. //
  2179. bstrPath = SysAllocString(pwszPath);
  2180. if (NULL != bstrPath)
  2181. {
  2182. hr = GetWmiObjectFromPath(
  2183. piwsNamespace,
  2184. bstrPath,
  2185. ppwcoProperties
  2186. );
  2187. SysFreeString(bstrPath);
  2188. }
  2189. else
  2190. {
  2191. hr = E_OUTOFMEMORY;
  2192. }
  2193. }
  2194. VariantClear(&vt);
  2195. }
  2196. //
  2197. // Free the query buffer, if necessary
  2198. //
  2199. if (wszBuffer != pwszPath)
  2200. {
  2201. delete [] pwszPath;
  2202. }
  2203. return hr;
  2204. }
  2205. HRESULT
  2206. GetWmiObjectFromPath(
  2207. IWbemServices *piwsNamespace,
  2208. BSTR bstrPath,
  2209. IWbemClassObject **ppwcoInstance
  2210. )
  2211. /*++
  2212. Routine Description:
  2213. Retrieves the IWbemClassObject corresponding to an object path.
  2214. Arguments:
  2215. piwsNamespace - the WMI namespace the object lives in
  2216. bstrPath - the path to the object
  2217. ppwcoInstance - receives the object instance
  2218. Return Value:
  2219. standard HRESULT
  2220. --*/
  2221. {
  2222. HRESULT hr;
  2223. _ASSERT(NULL != piwsNamespace);
  2224. _ASSERT(NULL != bstrPath);
  2225. _ASSERT(NULL != ppwcoInstance);
  2226. *ppwcoInstance = NULL;
  2227. hr = piwsNamespace->GetObject(
  2228. bstrPath,
  2229. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  2230. NULL,
  2231. ppwcoInstance,
  2232. NULL
  2233. );
  2234. return hr;
  2235. }
  2236. HRESULT
  2237. GetWmiPathFromObject(
  2238. IWbemClassObject *pwcoInstance,
  2239. BSTR *pbstrPath
  2240. )
  2241. /*++
  2242. Routine Description:
  2243. Retrieves the object path corresponding to an IWbemClassObject instance.
  2244. Arguments:
  2245. pwcoInstance - the object instance to retrieve the path of
  2246. pbstrPath - receives the path to the object
  2247. Return Value:
  2248. standard HRESULT
  2249. --*/
  2250. {
  2251. HRESULT hr;
  2252. VARIANT vt;
  2253. _ASSERT(NULL != pwcoInstance);
  2254. _ASSERT(NULL != pbstrPath);
  2255. hr = pwcoInstance->Get(
  2256. c_wsz__Path,
  2257. 0,
  2258. &vt,
  2259. NULL,
  2260. NULL
  2261. );
  2262. if (WBEM_S_NO_ERROR == hr)
  2263. {
  2264. _ASSERT(VT_BSTR == V_VT(&vt));
  2265. *pbstrPath = V_BSTR(&vt);
  2266. //
  2267. // BSTR ownership transferred to caller
  2268. //
  2269. }
  2270. return hr;
  2271. }
  2272. HRESULT
  2273. HostAddrToIpPsz(
  2274. DWORD dwAddress,
  2275. LPWSTR* ppszwNewStr
  2276. )
  2277. // Converts IP Address from host by order to string
  2278. {
  2279. HRESULT hr = S_OK;
  2280. LPWSTR pszwStr;
  2281. *ppszwNewStr = NULL;
  2282. pszwStr = reinterpret_cast<LPWSTR>(CoTaskMemAlloc(sizeof(WCHAR) * 16));
  2283. if ( NULL == pszwStr )
  2284. {
  2285. hr = E_OUTOFMEMORY;
  2286. }
  2287. else
  2288. {
  2289. swprintf( pszwStr,
  2290. TEXT("%u.%u.%u.%u"),
  2291. (dwAddress&0xff),
  2292. ((dwAddress>>8)&0x0ff),
  2293. ((dwAddress>>16)&0x0ff),
  2294. ((dwAddress>>24)&0x0ff) );
  2295. *ppszwNewStr = pszwStr;
  2296. }
  2297. return hr;
  2298. }
  2299. DWORD
  2300. IpPszToHostAddr(
  2301. LPCWSTR cp
  2302. )
  2303. // Converts an IP address represented as a string to
  2304. // host byte order.
  2305. //
  2306. {
  2307. DWORD val, base, n;
  2308. TCHAR c;
  2309. DWORD parts[4], *pp = parts;
  2310. again:
  2311. // Collect number up to ``.''.
  2312. // Values are specified as for C:
  2313. // 0x=hex, 0=octal, other=decimal.
  2314. //
  2315. val = 0; base = 10;
  2316. if (*cp == TEXT('0'))
  2317. base = 8, cp++;
  2318. if (*cp == TEXT('x') || *cp == TEXT('X'))
  2319. base = 16, cp++;
  2320. while (c = *cp)
  2321. {
  2322. if ((c >= TEXT('0')) && (c <= TEXT('9')))
  2323. {
  2324. val = (val * base) + (c - TEXT('0'));
  2325. cp++;
  2326. continue;
  2327. }
  2328. if ((base == 16) &&
  2329. ( ((c >= TEXT('0')) && (c <= TEXT('9'))) ||
  2330. ((c >= TEXT('A')) && (c <= TEXT('F'))) ||
  2331. ((c >= TEXT('a')) && (c <= TEXT('f'))) ))
  2332. {
  2333. val = (val << 4) + (c + 10 - (
  2334. ((c >= TEXT('a')) && (c <= TEXT('f')))
  2335. ? TEXT('a')
  2336. : TEXT('A') ) );
  2337. cp++;
  2338. continue;
  2339. }
  2340. break;
  2341. }
  2342. if (*cp == TEXT('.'))
  2343. {
  2344. // Internet format:
  2345. // a.b.c.d
  2346. // a.b.c (with c treated as 16-bits)
  2347. // a.b (with b treated as 24 bits)
  2348. //
  2349. if (pp >= parts + 3)
  2350. return (DWORD) -1;
  2351. *pp++ = val, cp++;
  2352. goto again;
  2353. }
  2354. // Check for trailing characters.
  2355. //
  2356. if (*cp && (*cp != TEXT(' ')))
  2357. return 0xffffffff;
  2358. *pp++ = val;
  2359. // Concoct the address according to
  2360. // the number of parts specified.
  2361. //
  2362. n = (DWORD) (pp - parts);
  2363. switch (n)
  2364. {
  2365. case 1: // a -- 32 bits
  2366. val = parts[0];
  2367. break;
  2368. case 2: // a.b -- 8.24 bits
  2369. val = (parts[0] << 24) | (parts[1] & 0xffffff);
  2370. break;
  2371. case 3: // a.b.c -- 8.8.16 bits
  2372. val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
  2373. (parts[2] & 0xffff);
  2374. break;
  2375. case 4: // a.b.c.d -- 8.8.8.8 bits
  2376. val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
  2377. ((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
  2378. break;
  2379. default:
  2380. return 0xffffffff;
  2381. }
  2382. return val;
  2383. }
  2384. BOOLEAN
  2385. IsRrasConfigured()
  2386. /*++
  2387. Routine Description:
  2388. This routine is invoked to determine whether Routing and Remote Access
  2389. is configured.
  2390. Arguments:
  2391. None.
  2392. Return Value:
  2393. TRUE if RRAS is configured, FALSE otherwise.
  2394. --*/
  2395. {
  2396. DWORD dwType;
  2397. DWORD dwValue;
  2398. DWORD dwValueSize;
  2399. BOOLEAN fRrasConfigured = FALSE;
  2400. HKEY hKey;
  2401. LONG lError;
  2402. lError =
  2403. RegOpenKeyEx(
  2404. HKEY_LOCAL_MACHINE,
  2405. c_wszRrasConfigurationPath,
  2406. 0,
  2407. KEY_READ,
  2408. &hKey
  2409. );
  2410. if (ERROR_SUCCESS == lError)
  2411. {
  2412. dwValueSize = sizeof(dwValue);
  2413. lError =
  2414. RegQueryValueEx(
  2415. hKey,
  2416. c_wszRrasConfigurationValue,
  2417. NULL,
  2418. &dwType,
  2419. reinterpret_cast<LPBYTE>(&dwValue),
  2420. &dwValueSize
  2421. );
  2422. fRrasConfigured = (ERROR_SUCCESS == lError
  2423. && REG_DWORD == dwType
  2424. && 0 != dwValue);
  2425. RegCloseKey(hKey);
  2426. }
  2427. return fRrasConfigured;
  2428. } // IsRrasConfigured
  2429. BOOLEAN
  2430. IsServiceRunning(
  2431. LPCWSTR pwszServiceName
  2432. )
  2433. /*++
  2434. Routine Description:
  2435. Determines if a service is in a running state.
  2436. Arguments:
  2437. pwszServiceName - the service to check
  2438. Return Value:
  2439. TRUE if the service is in the running or start_pending state,
  2440. FALSE otherwise
  2441. --*/
  2442. {
  2443. BOOLEAN fServiceRunning = FALSE;
  2444. SC_HANDLE hScm;
  2445. SC_HANDLE hService;
  2446. SERVICE_STATUS Status;
  2447. hScm = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, GENERIC_READ);
  2448. if (NULL != hScm)
  2449. {
  2450. hService = OpenService(hScm, pwszServiceName, GENERIC_READ);
  2451. if (NULL != hService)
  2452. {
  2453. if (QueryServiceStatus(hService, &Status))
  2454. {
  2455. fServiceRunning =
  2456. (SERVICE_RUNNING == Status.dwCurrentState
  2457. || SERVICE_START_PENDING == Status.dwCurrentState);
  2458. }
  2459. CloseServiceHandle(hService);
  2460. }
  2461. CloseServiceHandle(hScm);
  2462. }
  2463. return fServiceRunning;
  2464. } // IsServiceRunning
  2465. HRESULT
  2466. MapGuidStringToAdapterIndex(
  2467. LPCWSTR pwszGuid,
  2468. ULONG *pulIndex
  2469. )
  2470. /*++
  2471. Routine Description:
  2472. This routine is called to match the GUID in the given string to
  2473. an adapter in the list returned by calling GetInterfaceInfo.
  2474. Arguments:
  2475. pwszGuid - identifies the GUID of the adapter to be found. The GUID string
  2476. must be in the format returned by RtlGuidToUnicodeString
  2477. pulIndex - receives the index of the adapter
  2478. Return Value:
  2479. standard HRESULT
  2480. --*/
  2481. {
  2482. HRESULT hr = S_OK;
  2483. ULONG ulError;
  2484. ULONG i;
  2485. ULONG GuidLength;
  2486. PIP_INTERFACE_INFO Info;
  2487. PWCHAR Name;
  2488. ULONG NameLength;
  2489. ULONG Size;
  2490. _ASSERT(NULL != pwszGuid);
  2491. _ASSERT(NULL != pulIndex);
  2492. Size = 0;
  2493. GuidLength = wcslen(pwszGuid);
  2494. ulError = GetInterfaceInfo(NULL, &Size);
  2495. if (ERROR_INSUFFICIENT_BUFFER == ulError)
  2496. {
  2497. Info = new IP_INTERFACE_INFO[Size];
  2498. if (NULL != Info)
  2499. {
  2500. ulError = GetInterfaceInfo(Info, &Size);
  2501. if (NO_ERROR == ulError)
  2502. {
  2503. for (i = 0; i < (ULONG)Info->NumAdapters; i++)
  2504. {
  2505. NameLength = wcslen(Info->Adapter[i].Name);
  2506. if (NameLength < GuidLength) { continue; }
  2507. Name = Info->Adapter[i].Name + (NameLength - GuidLength);
  2508. if (_wcsicmp(pwszGuid, Name) == 0)
  2509. {
  2510. *pulIndex = Info->Adapter[i].Index;
  2511. break;
  2512. }
  2513. }
  2514. }
  2515. else
  2516. {
  2517. hr = HRESULT_FROM_WIN32(ulError);
  2518. }
  2519. delete [] Info;
  2520. }
  2521. else
  2522. {
  2523. hr = E_OUTOFMEMORY;
  2524. }
  2525. }
  2526. else
  2527. {
  2528. hr = HRESULT_FROM_WIN32(ulError);
  2529. }
  2530. return hr;
  2531. }
  2532. HRESULT
  2533. OpenRegKey(
  2534. PHANDLE Key,
  2535. ACCESS_MASK DesiredAccess,
  2536. PCWSTR Name
  2537. )
  2538. /*++
  2539. Routine Description:
  2540. This routine is invoked to open a given registry key.
  2541. Arguments:
  2542. Key - receives the opened key
  2543. DesiredAccess - specifies the requested access
  2544. Name - specifies the key to be opened
  2545. Return Value:
  2546. HRESULT - NT status code.
  2547. --*/
  2548. {
  2549. OBJECT_ATTRIBUTES ObjectAttributes;
  2550. UNICODE_STRING UnicodeString;
  2551. RtlInitUnicodeString(&UnicodeString, Name);
  2552. InitializeObjectAttributes(
  2553. &ObjectAttributes,
  2554. &UnicodeString,
  2555. OBJ_CASE_INSENSITIVE,
  2556. NULL,
  2557. NULL
  2558. );
  2559. return NtOpenKey(Key, DesiredAccess, &ObjectAttributes);
  2560. } // OpenRegKey
  2561. BOOLEAN
  2562. PortMappingProtocolExists(
  2563. IWbemServices *piwsNamespace,
  2564. BSTR bstrWQL,
  2565. USHORT usPort,
  2566. UCHAR ucIPProtocol
  2567. )
  2568. /*++
  2569. Routine Description:
  2570. Checks if an port mapping protocol already exists that has the
  2571. specified protocol and port.
  2572. Arguments:
  2573. piwsNamespace - the namespace to use
  2574. bstrWQL - a BSTR containing "WQL"
  2575. ucProtocol - the protocol number to check for
  2576. usPort - the port to check for
  2577. Return Value:
  2578. BOOLEAN -- TRUE if the port mapping protocol exists; FALSE otherwise
  2579. --*/
  2580. {
  2581. BSTR bstr;
  2582. BOOLEAN fDuplicate = FALSE;
  2583. HRESULT hr = S_OK;
  2584. int iBytes;
  2585. IEnumWbemClassObject *pwcoEnum;
  2586. IWbemClassObject *pwcoInstance;
  2587. ULONG ulObjs;
  2588. OLECHAR wszWhereClause[c_cchQueryBuffer + 1];
  2589. _ASSERT(NULL != piwsNamespace);
  2590. _ASSERT(NULL != bstrWQL);
  2591. _ASSERT(0 == wcscmp(bstrWQL, L"WQL"));
  2592. //
  2593. // Build the query string
  2594. //
  2595. iBytes = _snwprintf(
  2596. wszWhereClause,
  2597. c_cchQueryBuffer,
  2598. c_wszPortMappingProtocolQueryFormat,
  2599. usPort,
  2600. ucIPProtocol
  2601. );
  2602. if (iBytes >= 0)
  2603. {
  2604. //
  2605. // String fit into buffer; make sure it's null terminated
  2606. //
  2607. wszWhereClause[c_cchQueryBuffer] = L'\0';
  2608. }
  2609. else
  2610. {
  2611. //
  2612. // For some reason the string didn't fit into the buffer...
  2613. //
  2614. hr = E_UNEXPECTED;
  2615. _ASSERT(FALSE);
  2616. }
  2617. if (S_OK == hr)
  2618. {
  2619. hr = BuildSelectQueryBstr(
  2620. &bstr,
  2621. c_wszStar,
  2622. c_wszHnetPortMappingProtocol,
  2623. wszWhereClause
  2624. );
  2625. }
  2626. if (S_OK == hr)
  2627. {
  2628. //
  2629. // Execute the query
  2630. //
  2631. pwcoEnum = NULL;
  2632. hr = piwsNamespace->ExecQuery(
  2633. bstrWQL,
  2634. bstr,
  2635. WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
  2636. NULL,
  2637. &pwcoEnum
  2638. );
  2639. SysFreeString(bstr);
  2640. }
  2641. if (S_OK == hr)
  2642. {
  2643. //
  2644. // Attempt to retrieve an item from the enum. If we're successful,
  2645. // this is a duplicate protocol.
  2646. //
  2647. pwcoInstance = NULL;
  2648. hr = pwcoEnum->Next(
  2649. WBEM_INFINITE,
  2650. 1,
  2651. &pwcoInstance,
  2652. &ulObjs
  2653. );
  2654. if (SUCCEEDED(hr) && 1 == ulObjs)
  2655. {
  2656. //
  2657. // It's a duplicate
  2658. //
  2659. fDuplicate = TRUE;
  2660. pwcoInstance->Release();
  2661. }
  2662. pwcoEnum->Release();
  2663. }
  2664. return fDuplicate;
  2665. } // PortMappingProtocolExists
  2666. HRESULT
  2667. QueryRegValueKey(
  2668. HANDLE Key,
  2669. const WCHAR ValueName[],
  2670. PKEY_VALUE_PARTIAL_INFORMATION* Information
  2671. )
  2672. /*++
  2673. Routine Description:
  2674. This routine is called to obtain the value of a registry key.
  2675. Arguments:
  2676. Key - the key to be queried
  2677. ValueName - the value to be queried
  2678. Information - receives a pointer to the information read. On success,
  2679. the caller must HeapFree this pointer
  2680. Return Value:
  2681. HRESULT - NT status code.
  2682. --*/
  2683. {
  2684. UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
  2685. ULONG InformationLength;
  2686. NTSTATUS status;
  2687. UNICODE_STRING UnicodeString;
  2688. RtlInitUnicodeString(&UnicodeString, ValueName);
  2689. *Information = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
  2690. InformationLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
  2691. //
  2692. // Read the value's size
  2693. //
  2694. status =
  2695. NtQueryValueKey(
  2696. Key,
  2697. &UnicodeString,
  2698. KeyValuePartialInformation,
  2699. *Information,
  2700. InformationLength,
  2701. &InformationLength
  2702. );
  2703. if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW &&
  2704. status != STATUS_BUFFER_TOO_SMALL) {
  2705. *Information = NULL;
  2706. return status;
  2707. }
  2708. //
  2709. // Allocate space for the value's size
  2710. //
  2711. *Information = (PKEY_VALUE_PARTIAL_INFORMATION) HeapAlloc(
  2712. GetProcessHeap(),
  2713. 0,
  2714. InformationLength+2
  2715. );
  2716. if (!*Information) { return STATUS_NO_MEMORY; }
  2717. //
  2718. // Read the value's data
  2719. //
  2720. status =
  2721. NtQueryValueKey(
  2722. Key,
  2723. &UnicodeString,
  2724. KeyValuePartialInformation,
  2725. *Information,
  2726. InformationLength,
  2727. &InformationLength
  2728. );
  2729. if (!NT_SUCCESS(status))
  2730. {
  2731. HeapFree(GetProcessHeap(), 0, *Information);
  2732. *Information = NULL;
  2733. }
  2734. return status;
  2735. } // QueryRegValueKey
  2736. HRESULT
  2737. ReadDhcpScopeSettings(
  2738. DWORD *pdwScopeAddress,
  2739. DWORD *pdwScopeMask
  2740. )
  2741. {
  2742. _ASSERT(NULL != pdwScopeAddress);
  2743. _ASSERT(NULL != pdwScopeMask);
  2744. //
  2745. // This routine never fails. Set default address/mask
  2746. // (192.168.0.1/255.255.255.255, in network order)
  2747. //
  2748. *pdwScopeAddress = 0x0100a8c0;
  2749. *pdwScopeMask = 0x00ffffff;
  2750. //
  2751. // $$TODO: Check to see if these values are overiddent
  2752. // through a registry entry
  2753. //
  2754. return S_OK;
  2755. }
  2756. HRESULT
  2757. RetrieveSingleInstance(
  2758. IWbemServices *piwsNamespace,
  2759. const OLECHAR *pwszClass,
  2760. BOOLEAN fCreate,
  2761. IWbemClassObject **ppwcoInstance
  2762. )
  2763. /*++
  2764. Routine Description:
  2765. Retrieves a single instance of a class from the WMI store. If there
  2766. are more than one instance, every instance after the first is deleted,
  2767. and an assertion is raised. If there are no instances, one is optionally
  2768. created.
  2769. Arguments:
  2770. piwsNamespace - WMI namespace
  2771. pwszClass - the class to retrieve the instance of
  2772. fCreate - create an instance if one does not already exist
  2773. ppwcoInstance - receive the instance
  2774. Return Value:
  2775. standard HRESULT
  2776. --*/
  2777. {
  2778. HRESULT hr = S_OK;
  2779. IEnumWbemClassObject *pwcoEnum = NULL;
  2780. BSTR bstrClass = NULL;
  2781. ULONG ulCount = 0;
  2782. _ASSERT(NULL != piwsNamespace);
  2783. _ASSERT(NULL != pwszClass);
  2784. _ASSERT(NULL != ppwcoInstance);
  2785. //
  2786. // Allocate the BSTR for the class name
  2787. //
  2788. bstrClass = SysAllocString(pwszClass);
  2789. if (NULL == bstrClass)
  2790. {
  2791. hr = E_OUTOFMEMORY;
  2792. }
  2793. //
  2794. // Query the WMI store for instances of the class
  2795. //
  2796. if (S_OK == hr)
  2797. {
  2798. pwcoEnum = NULL;
  2799. hr = piwsNamespace->CreateInstanceEnum(
  2800. bstrClass,
  2801. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
  2802. NULL,
  2803. &pwcoEnum
  2804. );
  2805. SysFreeString(bstrClass);
  2806. }
  2807. if (WBEM_S_NO_ERROR == hr)
  2808. {
  2809. //
  2810. // Attempt to retrieve an actual instance from the enumeration.
  2811. // Even if there are zero instances, WMI considers returning a
  2812. // zero-element enumerator success.
  2813. //
  2814. *ppwcoInstance = NULL;
  2815. hr = pwcoEnum->Next(
  2816. WBEM_INFINITE,
  2817. 1,
  2818. ppwcoInstance,
  2819. &ulCount
  2820. );
  2821. if (SUCCEEDED(hr) && 1 == ulCount)
  2822. {
  2823. //
  2824. // Normalize return value
  2825. //
  2826. hr = S_OK;
  2827. //
  2828. // Validate that enumeration is now empty
  2829. //
  2830. ValidateFinishedWCOEnum(piwsNamespace, pwcoEnum);
  2831. }
  2832. else
  2833. {
  2834. if (WBEM_S_FALSE == hr)
  2835. {
  2836. //
  2837. // No items in enumeration.
  2838. //
  2839. if (fCreate)
  2840. {
  2841. //
  2842. // Create a new object instance
  2843. //
  2844. hr = SpawnNewInstance(
  2845. piwsNamespace,
  2846. pwszClass,
  2847. ppwcoInstance
  2848. );
  2849. }
  2850. else
  2851. {
  2852. //
  2853. // Change this to an error code. This
  2854. // is deliberately not a WBEM error code.
  2855. //
  2856. hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND);
  2857. }
  2858. }
  2859. }
  2860. pwcoEnum->Release();
  2861. }
  2862. return hr;
  2863. }
  2864. HRESULT
  2865. SetBooleanValue(
  2866. IWbemClassObject *pwcoInstance,
  2867. LPCWSTR pwszProperty,
  2868. BOOLEAN fBoolean
  2869. )
  2870. /*++
  2871. Routine Description:
  2872. Retrieves a boolean property from a Wbem object.
  2873. Arguments:
  2874. pwcoInstance - the object to get the property from
  2875. pwszProperty - the property to retrieve
  2876. pfBoolean - received the property value
  2877. Return Value:
  2878. standard HRESULT
  2879. --*/
  2880. {
  2881. HRESULT hr = S_OK;
  2882. VARIANT vt;
  2883. _ASSERT(NULL != pwcoInstance);
  2884. _ASSERT(NULL != pwszProperty);
  2885. VariantInit(&vt);
  2886. V_VT(&vt) = VT_BOOL;
  2887. V_BOOL(&vt) = (fBoolean ? VARIANT_TRUE : VARIANT_FALSE);
  2888. hr = pwcoInstance->Put(
  2889. pwszProperty,
  2890. 0,
  2891. &vt,
  2892. NULL
  2893. );
  2894. return hr;
  2895. }
  2896. VOID
  2897. SetProxyBlanket(
  2898. IUnknown *pUnk
  2899. )
  2900. /*++
  2901. Routine Description:
  2902. Sets the standard COM security settings on the proxy for an
  2903. object.
  2904. Arguments:
  2905. pUnk - the object to set the proxy blanket on
  2906. Return Value:
  2907. None. Even if the CoSetProxyBlanket calls fail, pUnk remains
  2908. in a usable state. Failure is expected in certain contexts, such
  2909. as when, for example, we're being called w/in the netman process --
  2910. in this case, we have direct pointers to the netman objects, instead
  2911. of going through a proxy.
  2912. --*/
  2913. {
  2914. HRESULT hr;
  2915. _ASSERT(pUnk);
  2916. hr = CoSetProxyBlanket(
  2917. pUnk,
  2918. RPC_C_AUTHN_WINNT, // use NT default security
  2919. RPC_C_AUTHZ_NONE, // use NT default authentication
  2920. NULL, // must be null if default
  2921. RPC_C_AUTHN_LEVEL_CALL, // call
  2922. RPC_C_IMP_LEVEL_IMPERSONATE,
  2923. NULL, // use process token
  2924. EOAC_NONE
  2925. );
  2926. if (SUCCEEDED(hr))
  2927. {
  2928. IUnknown * pUnkSet = NULL;
  2929. hr = pUnk->QueryInterface(&pUnkSet);
  2930. if (SUCCEEDED(hr))
  2931. {
  2932. hr = CoSetProxyBlanket(
  2933. pUnkSet,
  2934. RPC_C_AUTHN_WINNT, // use NT default security
  2935. RPC_C_AUTHZ_NONE, // use NT default authentication
  2936. NULL, // must be null if default
  2937. RPC_C_AUTHN_LEVEL_CALL, // call
  2938. RPC_C_IMP_LEVEL_IMPERSONATE,
  2939. NULL, // use process token
  2940. EOAC_NONE
  2941. );
  2942. pUnkSet->Release();
  2943. }
  2944. }
  2945. }
  2946. HRESULT
  2947. SpawnNewInstance(
  2948. IWbemServices *piwsNamespace,
  2949. LPCWSTR wszClass,
  2950. IWbemClassObject **ppwcoInstance
  2951. )
  2952. /*++
  2953. Routine Description:
  2954. Creates a new instance of a class
  2955. Arguments:
  2956. piwsNamespace - the namespace the class is in
  2957. wszClass - the class to create the instance of
  2958. ppwcoInstance -- receives the created instance
  2959. Return Value:
  2960. standard HRESULT
  2961. --*/
  2962. {
  2963. HRESULT hr;
  2964. BSTR bstr;
  2965. IWbemClassObject *pwcoClass;
  2966. _ASSERT(NULL != piwsNamespace);
  2967. _ASSERT(NULL != wszClass);
  2968. _ASSERT(NULL != ppwcoInstance);
  2969. *ppwcoInstance = NULL;
  2970. bstr = SysAllocString(wszClass);
  2971. if (NULL != bstr)
  2972. {
  2973. pwcoClass = NULL;
  2974. hr = piwsNamespace->GetObject(
  2975. bstr,
  2976. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  2977. NULL,
  2978. &pwcoClass,
  2979. NULL
  2980. );
  2981. SysFreeString(bstr);
  2982. }
  2983. else
  2984. {
  2985. hr = E_OUTOFMEMORY;
  2986. }
  2987. if (WBEM_S_NO_ERROR == hr)
  2988. {
  2989. hr = pwcoClass->SpawnInstance(0, ppwcoInstance);
  2990. pwcoClass->Release();
  2991. }
  2992. return hr;
  2993. }
  2994. DWORD
  2995. StartOrUpdateService(
  2996. VOID
  2997. )
  2998. /*++
  2999. Routine Description:
  3000. This routine is invoked to start the SharedAccess service. It will
  3001. also mark the service as auto-start. If the service is already running,
  3002. it will send a IPNATHLP_CONTROL_UPDATE_CONNECTION notification
  3003. Arguments:
  3004. none.
  3005. Return Value:
  3006. ULONG - Win32 status code.
  3007. --*/
  3008. {
  3009. ULONG Error;
  3010. SC_HANDLE ScmHandle;
  3011. SC_HANDLE ServiceHandle;
  3012. SERVICE_STATUS ServiceStatus;
  3013. ULONG Timeout;
  3014. //
  3015. // Connect to the service control manager
  3016. //
  3017. ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  3018. if (!ScmHandle) { return GetLastError(); }
  3019. do {
  3020. //
  3021. // Open the shared access service
  3022. //
  3023. ServiceHandle =
  3024. OpenService(ScmHandle, c_wszSharedAccess, SERVICE_ALL_ACCESS);
  3025. if (!ServiceHandle) { Error = GetLastError(); break; }
  3026. //
  3027. // Mark it as auto-start
  3028. //
  3029. ChangeServiceConfig(
  3030. ServiceHandle,
  3031. SERVICE_NO_CHANGE,
  3032. SERVICE_AUTO_START,
  3033. SERVICE_NO_CHANGE,
  3034. NULL,
  3035. NULL,
  3036. NULL,
  3037. NULL,
  3038. NULL,
  3039. NULL,
  3040. NULL
  3041. );
  3042. // if we are in ICS Upgrade, don't start the SharedAccess service because the
  3043. // service may have problem in starting up during GUI Mode Setup.
  3044. HANDLE hIcsUpgradeEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, c_wszIcsUpgradeEventName);
  3045. if (NULL != hIcsUpgradeEvent)
  3046. {
  3047. CloseHandle(hIcsUpgradeEvent);
  3048. Error = NO_ERROR;
  3049. break;
  3050. }
  3051. //
  3052. // Attempt to start the service
  3053. //
  3054. if (!StartService(ServiceHandle, 0, NULL)) {
  3055. Error = GetLastError();
  3056. if (Error == ERROR_SERVICE_ALREADY_RUNNING)
  3057. {
  3058. //
  3059. // Send control notification
  3060. //
  3061. Error = NO_ERROR;
  3062. if (!ControlService(
  3063. ServiceHandle,
  3064. IPNATHLP_CONTROL_UPDATE_CONNECTION,
  3065. &ServiceStatus
  3066. ))
  3067. {
  3068. Error = GetLastError();
  3069. }
  3070. }
  3071. break;
  3072. }
  3073. //
  3074. // Wait for the service to start
  3075. //
  3076. Timeout = 50;
  3077. Error = ERROR_CAN_NOT_COMPLETE;
  3078. do {
  3079. //
  3080. // Query the service's state
  3081. //
  3082. if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) {
  3083. Error = GetLastError(); break;
  3084. }
  3085. //
  3086. // See if the service has started
  3087. //
  3088. if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
  3089. Error = NO_ERROR; break;
  3090. } else if (ServiceStatus.dwCurrentState == SERVICE_STOPPED ||
  3091. ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING) {
  3092. break;
  3093. }
  3094. //
  3095. // Wait a little longer
  3096. //
  3097. Sleep(1000);
  3098. } while(Timeout--);
  3099. } while(FALSE);
  3100. if (ServiceHandle) { CloseServiceHandle(ServiceHandle); }
  3101. CloseServiceHandle(ScmHandle);
  3102. return Error;
  3103. }
  3104. VOID
  3105. StopService(
  3106. VOID
  3107. )
  3108. /*++
  3109. Routine Description:
  3110. Stops the SharedAccess service, and marks it as demand start.
  3111. Arguments:
  3112. none.
  3113. Return Value:
  3114. none.
  3115. --*/
  3116. {
  3117. ULONG Error;
  3118. SC_HANDLE ScmHandle;
  3119. SC_HANDLE ServiceHandle;
  3120. SERVICE_STATUS ServiceStatus;
  3121. //
  3122. // Connect to the service control manager
  3123. //
  3124. ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  3125. if (!ScmHandle) { return; }
  3126. do {
  3127. //
  3128. // Open the shared access service
  3129. //
  3130. ServiceHandle =
  3131. OpenService(ScmHandle, c_wszSharedAccess, SERVICE_ALL_ACCESS);
  3132. if (!ServiceHandle) { Error = GetLastError(); break; }
  3133. //
  3134. // Mark it as demand-start
  3135. //
  3136. ChangeServiceConfig(
  3137. ServiceHandle,
  3138. SERVICE_NO_CHANGE,
  3139. SERVICE_DEMAND_START,
  3140. SERVICE_NO_CHANGE,
  3141. NULL,
  3142. NULL,
  3143. NULL,
  3144. NULL,
  3145. NULL,
  3146. NULL,
  3147. NULL
  3148. );
  3149. //
  3150. // Attempt to stop the service
  3151. //
  3152. ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus);
  3153. } while(FALSE);
  3154. if (ServiceHandle) { CloseServiceHandle(ServiceHandle); }
  3155. CloseServiceHandle(ScmHandle);
  3156. }
  3157. HRESULT
  3158. UpdateOrStopService(
  3159. IWbemServices *piwsNamespace,
  3160. BSTR bstrWQL,
  3161. DWORD dwControlCode
  3162. )
  3163. /*++
  3164. Routine Description:
  3165. Checks to see if there are any firewalled or ICS connections. If so,
  3166. an update request is sent to the SharedAccess service; if not, the
  3167. service is stopped
  3168. Arguments:
  3169. piwsNamespace - WMI namespace
  3170. bstrWQL - a BSTR that corresponds to "WQL"
  3171. dwControlCode - the kind of update to send
  3172. Return Value:
  3173. standard HRESULT
  3174. --*/
  3175. {
  3176. HRESULT hr = S_OK;
  3177. IEnumWbemClassObject *pwcoEnum;
  3178. BSTR bstrQuery;
  3179. _ASSERT(NULL != piwsNamespace);
  3180. _ASSERT(NULL != bstrWQL);
  3181. //
  3182. // See if we have any connections that are marked as
  3183. // * ICS public
  3184. // * ICS private
  3185. // * firewalled
  3186. //
  3187. // (We don't care about bridged connections, as the SharedAccess service
  3188. // doesn't have anything to do with the bridge.)
  3189. //
  3190. bstrQuery = SysAllocString(c_wszServiceCheckQuery);
  3191. if (NULL != bstrQuery)
  3192. {
  3193. pwcoEnum = NULL;
  3194. hr = piwsNamespace->ExecQuery(
  3195. bstrWQL,
  3196. bstrQuery,
  3197. WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
  3198. NULL,
  3199. &pwcoEnum
  3200. );
  3201. SysFreeString(bstrQuery);
  3202. }
  3203. else
  3204. {
  3205. hr = E_OUTOFMEMORY;
  3206. }
  3207. if (WBEM_S_NO_ERROR == hr)
  3208. {
  3209. ULONG ulCount;
  3210. IWbemClassObject *pwcoObj;
  3211. //
  3212. // Check to see if the query returned anything
  3213. //
  3214. pwcoObj = NULL;
  3215. hr = pwcoEnum->Next(WBEM_INFINITE, 1, &pwcoObj, &ulCount);
  3216. if (SUCCEEDED(hr))
  3217. {
  3218. if (1 == ulCount)
  3219. {
  3220. //
  3221. // Object retrieved -- need to update service
  3222. //
  3223. pwcoObj->Release();
  3224. UpdateService(dwControlCode);
  3225. }
  3226. else
  3227. {
  3228. //
  3229. // No object retrieved -- stop service
  3230. //
  3231. StopService();
  3232. }
  3233. }
  3234. pwcoEnum->Release();
  3235. }
  3236. return hr;
  3237. }
  3238. VOID
  3239. UpdateService(
  3240. DWORD dwControlCode
  3241. )
  3242. /*++
  3243. Routine Description:
  3244. Sends a control code to the SharedAccess service
  3245. Arguments:
  3246. dwControlCode - the code to send
  3247. Return Value:
  3248. none.
  3249. --*/
  3250. {
  3251. ULONG Error;
  3252. SC_HANDLE ScmHandle;
  3253. SC_HANDLE ServiceHandle;
  3254. SERVICE_STATUS ServiceStatus;
  3255. //
  3256. // Connect to the service control manager
  3257. //
  3258. ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  3259. if (!ScmHandle) { return; }
  3260. do {
  3261. //
  3262. // Open the shared access service
  3263. //
  3264. ServiceHandle =
  3265. OpenService(ScmHandle, c_wszSharedAccess, SERVICE_ALL_ACCESS);
  3266. if (!ServiceHandle) { Error = GetLastError(); break; }
  3267. //
  3268. // Send the control notification
  3269. //
  3270. ControlService(ServiceHandle, dwControlCode, &ServiceStatus);
  3271. } while(FALSE);
  3272. if (ServiceHandle) { CloseServiceHandle(ServiceHandle); }
  3273. CloseServiceHandle(ScmHandle);
  3274. }
  3275. VOID
  3276. ValidateFinishedWCOEnum(
  3277. IWbemServices *piwsNamespace,
  3278. IEnumWbemClassObject *pwcoEnum
  3279. )
  3280. /*++
  3281. Routine Description:
  3282. Checks to see that a WCO enumerator is finished (i.e., all objects
  3283. have been retrieved). If the enumerator is not finished, any object
  3284. instances that are retrieved will be deleted, and an assertion will
  3285. be raised on checked builds.
  3286. Arguments:
  3287. piwsNamespace - the namespace the enumeration is from
  3288. pwcoEnum - the enumeration to validate
  3289. Return Value:
  3290. None.
  3291. --*/
  3292. {
  3293. HRESULT hr;
  3294. IWbemClassObject *pwcoInstance = NULL;
  3295. ULONG ulCount = 0;
  3296. _ASSERT(piwsNamespace);
  3297. _ASSERT(pwcoEnum);
  3298. do
  3299. {
  3300. pwcoInstance = NULL;
  3301. hr = pwcoEnum->Next(
  3302. WBEM_INFINITE,
  3303. 1,
  3304. &pwcoInstance,
  3305. &ulCount
  3306. );
  3307. if (SUCCEEDED(hr) && 1 == ulCount)
  3308. {
  3309. //
  3310. // We got an unexpected instance.
  3311. //
  3312. _ASSERT(FALSE);
  3313. //
  3314. // Delete the instance. Don't care about return value.
  3315. //
  3316. DeleteWmiInstance(
  3317. piwsNamespace,
  3318. pwcoInstance
  3319. );
  3320. pwcoInstance->Release();
  3321. }
  3322. }
  3323. while (SUCCEEDED(hr) && 1 == ulCount);
  3324. }
  3325. HRESULT
  3326. SendPortMappingListChangeNotification()
  3327. {
  3328. HRESULT hr = S_OK;
  3329. ISharedAccessUpdate* pUpdate = NULL;
  3330. if ( IsServiceRunning(c_wszSharedAccess) )
  3331. {
  3332. hr = CoCreateInstance(
  3333. CLSID_SAUpdate,
  3334. NULL,
  3335. CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_DISABLE_AAA,
  3336. IID_PPV_ARG( ISharedAccessUpdate, &pUpdate )
  3337. );
  3338. if ( SUCCEEDED(hr) )
  3339. {
  3340. hr = pUpdate->PortMappingListChanged();
  3341. pUpdate->Release();
  3342. }
  3343. }
  3344. return hr;
  3345. }
  3346. HRESULT
  3347. SignalModifiedConnection(
  3348. GUID *pGUID
  3349. )
  3350. /*++
  3351. Routine Description:
  3352. Signals a modification to a network connection (refreshes the UI)
  3353. Arguments:
  3354. pGUID The GUID of the modified connection
  3355. Return Value:
  3356. Result of the operation
  3357. --*/
  3358. {
  3359. HRESULT hr;
  3360. INetConnection *pConn;
  3361. hr = FindINetConnectionByGuid( pGUID, &pConn );
  3362. if( SUCCEEDED(hr) )
  3363. {
  3364. INetConnectionRefresh *pNetConRefresh;
  3365. hr = CoCreateInstance(
  3366. CLSID_ConnectionManager,
  3367. NULL,
  3368. CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_DISABLE_AAA | CLSCTX_NO_CODE_DOWNLOAD,
  3369. IID_PPV_ARG(INetConnectionRefresh, &pNetConRefresh)
  3370. );
  3371. if( SUCCEEDED(hr) )
  3372. {
  3373. SetProxyBlanket(pNetConRefresh);
  3374. hr = pNetConRefresh->ConnectionModified(pConn);
  3375. pNetConRefresh->Release();
  3376. }
  3377. pConn->Release();
  3378. }
  3379. return hr;
  3380. }
  3381. HRESULT
  3382. SignalNewConnection(
  3383. GUID *pGUID
  3384. )
  3385. /*++
  3386. Routine Description:
  3387. Signals that a new network connection has been created (refreshes the UI)
  3388. Arguments:
  3389. pGUID The GUID of the new connection
  3390. Return Value:
  3391. Result of the operation
  3392. --*/
  3393. {
  3394. HRESULT hr;
  3395. INetConnection *pConn;
  3396. hr = FindINetConnectionByGuid( pGUID, &pConn );
  3397. if( SUCCEEDED(hr) )
  3398. {
  3399. INetConnectionRefresh *pNetConRefresh;
  3400. hr = CoCreateInstance(
  3401. CLSID_ConnectionManager,
  3402. NULL,
  3403. CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_DISABLE_AAA | CLSCTX_NO_CODE_DOWNLOAD,
  3404. IID_PPV_ARG(INetConnectionRefresh, &pNetConRefresh)
  3405. );
  3406. if( SUCCEEDED(hr) )
  3407. {
  3408. SetProxyBlanket(pNetConRefresh);
  3409. hr = pNetConRefresh->ConnectionAdded(pConn);
  3410. pNetConRefresh->Release();
  3411. }
  3412. pConn->Release();
  3413. }
  3414. return hr;
  3415. }
  3416. HRESULT
  3417. SignalDeletedConnection(
  3418. GUID *pGUID
  3419. )
  3420. /*++
  3421. Routine Description:
  3422. Signals that a network connection has been deleted (refreshes the UI)
  3423. Arguments:
  3424. pGUID The GUID of the deleted connection
  3425. Return Value:
  3426. Result of the operation
  3427. --*/
  3428. {
  3429. HRESULT hr;
  3430. INetConnectionRefresh *pNetConRefresh;
  3431. hr = CoCreateInstance(
  3432. CLSID_ConnectionManager,
  3433. NULL,
  3434. CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_DISABLE_AAA | CLSCTX_NO_CODE_DOWNLOAD,
  3435. IID_PPV_ARG(INetConnectionRefresh, &pNetConRefresh)
  3436. );
  3437. if( SUCCEEDED(hr) )
  3438. {
  3439. hr = pNetConRefresh->ConnectionDeleted(pGUID);
  3440. pNetConRefresh->Release();
  3441. }
  3442. return hr;
  3443. }