Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1898 lines
61 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997-2001.
  5. //
  6. // File: C O N M A N . C P P
  7. //
  8. // Contents: Connection manager.
  9. //
  10. // Notes:
  11. //
  12. // Author: shaunco 21 Sep 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include <dbt.h>
  18. #include <ndisguid.h>
  19. #include "conman.h"
  20. #include "dialup.h"
  21. #include "enum.h"
  22. #include "enumw.h"
  23. #include "ncnetcon.h"
  24. #include "ncreg.h"
  25. #include "nminit.h"
  26. #if DBG
  27. #include "ncras.h"
  28. #endif // DBG
  29. #include <wmium.h>
  30. #include "cmutil.h"
  31. #include <shlwapi.h>
  32. #include <shfolder.h>
  33. #include "cobase.h"
  34. #define SECURITY_WIN32
  35. #include <security.h>
  36. #include <wzcsvc.h>
  37. bool operator < (const GUID& rguid1, const GUID& rguid2)
  38. {
  39. return memcmp(&rguid1, &rguid2, sizeof(GUID)) < 0;
  40. }
  41. static const WCHAR c_szRegKeyClassManagers [] = L"System\\CurrentControlSet\\Control\\Network\\Connections";
  42. static const WCHAR c_szRegValClassManagers [] = L"ClassManagers";
  43. volatile CConnectionManager* CConnectionManager::g_pConMan = NULL;
  44. volatile BOOL CConnectionManager::g_fInUse = FALSE;
  45. bool operator == (const NETCON_PROPERTIES& rProps1, const NETCON_PROPERTIES& rProps2)
  46. {
  47. return (IsEqualGUID(rProps1.clsidThisObject, rProps2.clsidThisObject) &&
  48. IsEqualGUID(rProps1.clsidUiObject, rProps2.clsidUiObject) &&
  49. (rProps1.dwCharacter == rProps2.dwCharacter) &&
  50. IsEqualGUID(rProps1.guidId, rProps2.guidId) &&
  51. (rProps1.MediaType == rProps2.MediaType) &&
  52. (rProps1.pszwDeviceName == rProps2.pszwDeviceName) &&
  53. (rProps1.pszwName == rProps2.pszwName) &&
  54. (rProps1.Status == rProps2.Status));
  55. }
  56. const DWORD MAX_DISABLE_EVENT_TIMEOUT = 0xFFFF;
  57. //static
  58. BOOL
  59. CConnectionManager::FHasActiveConnectionPoints ()
  60. {
  61. BOOL fRet = FALSE;
  62. // Note our intent to use g_pConMan. We may find out that it is not
  63. // available for use, but setting g_fInUse to TRUE prevents FinalRelease
  64. // from allowing the object to be destroyed while we are using it.
  65. //
  66. g_fInUse = TRUE;
  67. // Save g_pConMan into a local variable since we have to test and use
  68. // it atomically. If we tested g_pConMan directly and then used it
  69. // directly, it may have been set to NULL by FinalRelease in between
  70. // our test and use. (Uh, which would be bad.)
  71. //
  72. // The const_cast is because g_pConMan is declared volatile.
  73. //
  74. CConnectionManager* pConMan = const_cast<CConnectionManager*>(g_pConMan);
  75. if (pConMan)
  76. {
  77. pConMan->Lock();
  78. IUnknown** ppUnk;
  79. for (ppUnk = pConMan->m_vec.begin();
  80. ppUnk < pConMan->m_vec.end();
  81. ppUnk++)
  82. {
  83. if (ppUnk && *ppUnk)
  84. {
  85. fRet = TRUE;
  86. break;
  87. }
  88. }
  89. pConMan->Unlock();
  90. }
  91. // Now that we are finished using the object, indicate so. FinalRelease
  92. // may be waiting for this condition in which case the object will soon
  93. // be destroyed.
  94. //
  95. g_fInUse = FALSE;
  96. return fRet;
  97. }
  98. //+---------------------------------------------------------------------------
  99. //
  100. // Member: CConnectionManager::FinalRelease
  101. //
  102. // Purpose: COM destructor
  103. //
  104. // Arguments:
  105. // (none)
  106. //
  107. // Returns: nothing
  108. //
  109. // Author: shaunco 21 Sep 1997
  110. //
  111. // Notes:
  112. //
  113. VOID
  114. CConnectionManager::FinalRelease ()
  115. {
  116. TraceFileFunc(ttidConman);
  117. if (m_hRegClassManagerKey)
  118. {
  119. RegCloseKey(m_hRegClassManagerKey);
  120. m_hRegClassManagerKey = NULL;
  121. }
  122. NTSTATUS Status = RtlDeregisterWait(m_hRegNotifyWait);
  123. if (!NT_SUCCESS(Status))
  124. {
  125. TraceError("Could not deregister Registry Change Notification", HrFromLastWin32Error());
  126. }
  127. m_hRegNotifyWait = NULL;
  128. if (m_hRegNotify)
  129. {
  130. CloseHandle(m_hRegNotify);
  131. m_hRegNotify = NULL;
  132. }
  133. // Unregister for PnP device events if we successfully registered for
  134. // them.
  135. //
  136. if (m_hDevNotify)
  137. {
  138. TraceTag (ttidConman, "Calling UnregisterDeviceNotification...");
  139. if (!UnregisterDeviceNotification (m_hDevNotify))
  140. {
  141. TraceHr (ttidError, FAL, HrFromLastWin32Error(), FALSE,
  142. "UnregisterDeviceNotification");
  143. }
  144. }
  145. (VOID) HrEnsureRegisteredOrDeregisteredWithWmi (FALSE);
  146. // Revoke the global connection manager pointer so that subsequent calls
  147. // to NotifyClientsOfEvent on other threads will do nothing.
  148. //
  149. g_pConMan = NULL;
  150. // Wait for g_fInUse to become FALSE. NotifyClientsOfEvent will set
  151. // this to TRUE while it is using us.
  152. // Keep track of the number of times we sleep and trace it for
  153. // informational purposes. If we see that we are waiting quite a few
  154. // number of times, increase the wait period.
  155. //
  156. #ifdef ENABLETRACE
  157. if (g_fInUse)
  158. {
  159. TraceTag (ttidConman, "CConnectionManager::FinalRelease is waiting "
  160. "for NotifyClientsOfEvent to finish...");
  161. }
  162. #endif
  163. ULONG cSleeps = 0;
  164. const DWORD nMilliseconds = 0;
  165. while (g_fInUse)
  166. {
  167. cSleeps++;
  168. Sleep (nMilliseconds);
  169. }
  170. #ifdef ENABLETRACE
  171. if (cSleeps)
  172. {
  173. TraceTag (ttidConman, "CConnectionManager::FinalRelease slept %d "
  174. "times. (%d ms each time.)",
  175. cSleeps, nMilliseconds);
  176. }
  177. #endif
  178. // Release our class managers.
  179. //
  180. for (CLASSMANAGERMAP::iterator iter = m_mapClassManagers.begin(); iter != m_mapClassManagers.end(); iter++)
  181. {
  182. ReleaseObj (iter->second);
  183. }
  184. TraceTag (ttidConman, "Connection manager being destroyed");
  185. }
  186. inline
  187. LPVOID OffsetToPointer(LPVOID pStart, DWORD dwNumBytes)
  188. {
  189. DWORD_PTR dwPtr;
  190. dwPtr = reinterpret_cast<DWORD_PTR>(pStart);
  191. dwPtr += dwNumBytes;
  192. return reinterpret_cast<LPVOID>(dwPtr);
  193. }
  194. //
  195. // Must match type of NOTIFICATIONCALLBACK
  196. //
  197. VOID
  198. WINAPI
  199. WmiEventCallback (
  200. PWNODE_HEADER Wnode,
  201. UINT_PTR NotificationContext)
  202. {
  203. TraceTag (ttidConman,
  204. "WmiEventCallback called...");
  205. TraceTag(ttidEvents, "Flags: %d", Wnode->Flags);
  206. if (WNODE_FLAG_SINGLE_INSTANCE == (WNODE_FLAG_SINGLE_INSTANCE & Wnode->Flags))
  207. {
  208. PWNODE_SINGLE_INSTANCE pInstance = reinterpret_cast<PWNODE_SINGLE_INSTANCE>(Wnode);
  209. LPCWSTR lpszDevice = NULL;
  210. LPWSTR lpszGuid;
  211. GUID guidAdapter;
  212. lpszDevice = reinterpret_cast<LPCWSTR>(OffsetToPointer(pInstance, pInstance->DataBlockOffset));
  213. lpszGuid = wcsrchr(lpszDevice, L'{');
  214. TraceTag(ttidEvents, "Adapter Guid From NDIS for Media Status Change Event: %S", lpszGuid);
  215. if (SUCCEEDED(CLSIDFromString(lpszGuid, &guidAdapter)))
  216. {
  217. CONMAN_EVENT* pEvent;
  218. pEvent = new CONMAN_EVENT;
  219. if(pEvent)
  220. {
  221. pEvent->ConnectionManager = CONMAN_LAN;
  222. pEvent->guidId = guidAdapter;
  223. pEvent->Type = CONNECTION_STATUS_CHANGE;
  224. if (IsEqualGUID(Wnode->Guid, GUID_NDIS_STATUS_MEDIA_CONNECT))
  225. {
  226. pEvent->Status = NCS_CONNECTED;
  227. }
  228. else if (IsEqualGUID(Wnode->Guid, GUID_NDIS_STATUS_MEDIA_DISCONNECT))
  229. {
  230. pEvent->Status = NCS_MEDIA_DISCONNECTED;
  231. }
  232. else
  233. {
  234. AssertSz(FALSE, "We never registered for this event ... WMI may be having internal issues.");
  235. MemFree(pEvent);
  236. return;
  237. }
  238. if (!QueueUserWorkItemInThread(LanEventWorkItem, reinterpret_cast<PVOID>(pEvent), EVENTMGR_CONMAN))
  239. {
  240. FreeConmanEvent(pEvent);
  241. }
  242. }
  243. }
  244. }
  245. else
  246. {
  247. LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
  248. }
  249. }
  250. HRESULT
  251. CConnectionManager::HrEnsureRegisteredOrDeregisteredWithWmi (
  252. BOOL fRegister)
  253. {
  254. // Already registered or deregistered?
  255. //
  256. if (!!m_fRegisteredWithWmi == !!fRegister)
  257. {
  258. return S_OK;
  259. }
  260. m_fRegisteredWithWmi = !!fRegister;
  261. HRESULT hr = S_OK;
  262. DWORD dwErr;
  263. INT i;
  264. const GUID* apguid [] =
  265. {
  266. &GUID_NDIS_STATUS_MEDIA_CONNECT,
  267. &GUID_NDIS_STATUS_MEDIA_DISCONNECT,
  268. };
  269. TraceTag (ttidConman,
  270. "Calling WmiNotificationRegistration to %s for NDIS media events...",
  271. (fRegister) ? "register" : "unregister");
  272. for (i = 0; i < celems(apguid); i++)
  273. {
  274. dwErr = WmiNotificationRegistration (
  275. const_cast<GUID*>(apguid[i]),
  276. !!fRegister, // !! for BOOL to BOOLEAN
  277. WmiEventCallback,
  278. 0,
  279. NOTIFICATION_CALLBACK_DIRECT);
  280. hr = HRESULT_FROM_WIN32 (dwErr);
  281. TraceHr (ttidError, FAL, hr, FALSE, "WmiNotificationRegistration");
  282. }
  283. TraceHr (ttidError, FAL, hr, FALSE, "HrEnsureRegisteredOrDeregisteredWithWmi");
  284. return hr;
  285. }
  286. //+---------------------------------------------------------------------------
  287. //
  288. // Member: CConnectionManager::NotifyClientsOfEvent
  289. //
  290. // Purpose: Notify our connection points that this object has changed
  291. // state in some way and that a re-enumeration is needed.
  292. //
  293. // Arguments:
  294. // (none)
  295. //
  296. // Returns: nothing
  297. //
  298. // Author: shaunco 20 Mar 1998
  299. //
  300. // Notes: This is a static function. No this pointer is passed.
  301. //
  302. // static
  303. VOID CConnectionManager::NotifyClientsOfEvent (
  304. CONMAN_EVENT* pEvent)
  305. {
  306. HRESULT hr;
  307. // Let's be sure we only do work if the service state is still running.
  308. // If we have a stop pending for example, we don't need to do anything.
  309. //
  310. if (SERVICE_RUNNING != _Module.DwServiceStatus ())
  311. {
  312. return;
  313. }
  314. // Note our intent to use g_pConMan. We may find out that it is not
  315. // available for use, but setting g_fInUse to TRUE prevents FinalRelease
  316. // from allowing the object to be destroyed while we are using it.
  317. //
  318. g_fInUse = TRUE;
  319. // Save g_pConMan into a local variable since we have to test and use
  320. // it atomically. If we tested g_pConMan directly and then used it
  321. // directly, it may have been set to NULL by FinalRelease in between
  322. // our test and use. (Uh, which would be bad.)
  323. //
  324. // The const_cast is because g_pConMan is declared volatile.
  325. //
  326. CConnectionManager* pConMan = const_cast<CConnectionManager*>(g_pConMan);
  327. if (pConMan)
  328. {
  329. ULONG cpUnk;
  330. IUnknown** apUnk;
  331. hr = HrCopyIUnknownArrayWhileLocked (
  332. pConMan,
  333. &pConMan->m_vec,
  334. &cpUnk,
  335. &apUnk);
  336. if (SUCCEEDED(hr) && cpUnk && apUnk)
  337. {
  338. #ifdef DBG
  339. CHAR szClientList[MAX_PATH];
  340. ZeroMemory(szClientList, MAX_PATH);
  341. LPSTR pszClientList = szClientList;
  342. ITERUSERNOTIFYMAP iter;
  343. for (iter = pConMan->m_mapNotify.begin(); iter != pConMan->m_mapNotify.end(); iter++)
  344. {
  345. pszClientList += sprintf(pszClientList, "%d ", iter->second->dwCookie);
  346. if (pszClientList > (szClientList + MAX_PATH-50) )
  347. {
  348. break;
  349. }
  350. }
  351. if (iter != pConMan->m_mapNotify.end())
  352. {
  353. pszClientList += sprintf(pszClientList, "(more)");
  354. }
  355. TraceTag (ttidConman,
  356. "NotifyClientsOfEvent: Notifying %d clients. Cookies: %s)",
  357. cpUnk, szClientList);
  358. #endif
  359. for (ULONG i = 0; i < cpUnk; i++)
  360. {
  361. INetConnectionNotifySink* pSink = NULL;
  362. BOOL fFireEventOnSink = FALSE;
  363. hr = apUnk[i]->QueryInterface(IID_INetConnectionNotifySink, reinterpret_cast<LPVOID*>(&pSink));
  364. ReleaseObj(apUnk[i]);
  365. if (SUCCEEDED(hr))
  366. {
  367. hr = CoSetProxyBlanket (
  368. pSink,
  369. RPC_C_AUTHN_WINNT, // use NT default security
  370. RPC_C_AUTHZ_NONE, // use NT default authentication
  371. NULL, // must be null if default
  372. RPC_C_AUTHN_LEVEL_CALL, // call
  373. RPC_C_IMP_LEVEL_IDENTIFY,
  374. NULL, // use process token
  375. EOAC_DEFAULT);
  376. switch (pEvent->Type)
  377. {
  378. case CONNECTION_ADDED:
  379. Assert (pEvent);
  380. Assert (pEvent->pPropsEx);
  381. TraceTag(ttidEvents, "Characteristics: %s", DbgNccf(pEvent->pPropsEx->dwCharacter));
  382. if (!(NCCF_ALL_USERS == (pEvent->pPropsEx->dwCharacter & NCCF_ALL_USERS)))
  383. {
  384. const WCHAR* pchw = reinterpret_cast<const WCHAR*>(pEvent->pPropsEx->bstrPersistData);
  385. const WCHAR* pchwMax;
  386. PCWSTR pszwPhonebook;
  387. WCHAR LeadWord = PersistDataLead;
  388. WCHAR TrailWord = PersistDataTrail;
  389. IUnknown* pUnkSink = NULL;
  390. hr = pSink->QueryInterface(IID_IUnknown, reinterpret_cast<LPVOID*>(&pUnkSink));
  391. AssertSz(SUCCEEDED(hr), "Please explain how this happened...");
  392. if (SUCCEEDED(hr))
  393. {
  394. // The last valid pointer for the embedded strings.
  395. //
  396. pchwMax = reinterpret_cast<const WCHAR*>(pEvent->pbPersistData + pEvent->cbPersistData
  397. - (sizeof (GUID) +
  398. sizeof (BOOL) +
  399. sizeof (TrailWord)));
  400. if (pchw && (LeadWord == *pchw))
  401. {
  402. TraceTag(ttidEvents, "Found Correct Lead Character.");
  403. // Skip past our lead byte.
  404. //
  405. pchw++;
  406. // Get PhoneBook path. Search for the terminating null and make sure
  407. // we find it before the end of the buffer. Using lstrlen to skip
  408. // the string can result in an an AV in the event the string is
  409. // not actually null-terminated.
  410. //
  411. for (pszwPhonebook = pchw; *pchw != L'\0' ; pchw++)
  412. {
  413. if (pchw >= pchwMax)
  414. {
  415. pszwPhonebook = NULL;
  416. break;
  417. }
  418. }
  419. TraceTag(ttidEvents, "Found Valid Phonebook: %S", (pszwPhonebook) ? L"TRUE" : L"FALSE");
  420. if (pszwPhonebook)
  421. {
  422. ITERUSERNOTIFYMAP iter = pConMan->m_mapNotify.find(pUnkSink);
  423. if (iter != pConMan->m_mapNotify.end())
  424. {
  425. tstring& strUserDataPath = iter->second->szUserProfilesPath;
  426. TraceTag(ttidEvents, "Comparing stored Path: %S to Phonebook Path: %S",
  427. strUserDataPath.c_str(), pszwPhonebook);
  428. if (_wcsnicmp(pszwPhonebook, strUserDataPath.c_str(), strUserDataPath.length()) == 0)
  429. {
  430. fFireEventOnSink = TRUE;
  431. }
  432. }
  433. else
  434. {
  435. TraceTag(ttidError, "Could not find Path for NotifySink: 0x%08x", pUnkSink);
  436. }
  437. }
  438. }
  439. else
  440. {
  441. // Some other devices do not use this Format, but need to be sent events.
  442. fFireEventOnSink = TRUE;
  443. }
  444. ReleaseObj(pUnkSink);
  445. }
  446. }
  447. else
  448. {
  449. TraceTag(ttidEvents, "All User Connection");
  450. fFireEventOnSink = TRUE;
  451. }
  452. if (fFireEventOnSink)
  453. {
  454. TraceTag (ttidEvents,
  455. "Notifying ConnectionAdded... (pSink=0x%p)",
  456. pSink);
  457. hr = pSink->ConnectionAdded (
  458. pEvent->pPropsEx);
  459. }
  460. break;
  461. case CONNECTION_BANDWIDTH_CHANGE:
  462. TraceTag (ttidEvents,
  463. "Notifying ConnectionBandWidthChange... (pSink=0x%p)",
  464. pSink);
  465. hr = pSink->ConnectionBandWidthChange (&pEvent->guidId);
  466. break;
  467. case CONNECTION_DELETED:
  468. TraceTag (ttidEvents,
  469. "Notifying ConnectionDeleted... (pSink=0x%p)",
  470. pSink);
  471. hr = pSink->ConnectionDeleted (&pEvent->guidId);
  472. break;
  473. case CONNECTION_MODIFIED:
  474. Assert (pEvent->pPropsEx);
  475. TraceTag (ttidEvents,
  476. "Notifying ConnectionModified... (pSink=0x%p)",
  477. pSink);
  478. hr = pSink->ConnectionModified (pEvent->pPropsEx);
  479. break;
  480. case CONNECTION_RENAMED:
  481. TraceTag (ttidEvents,
  482. "Notifying ConnectionRenamed... (pSink=0x%p)",
  483. pSink);
  484. hr = pSink->ConnectionRenamed (&pEvent->guidId,
  485. pEvent->szNewName);
  486. break;
  487. case CONNECTION_STATUS_CHANGE:
  488. TraceTag (ttidEvents,
  489. "Notifying ConnectionStatusChange... (pSink=0x%p)",
  490. pSink);
  491. TraceTag(ttidEvents, "Status changed to: %s", DbgNcs(pEvent->Status));
  492. hr = pSink->ConnectionStatusChange (&pEvent->guidId,
  493. pEvent->Status);
  494. break;
  495. case REFRESH_ALL:
  496. TraceTag (ttidEvents,
  497. "Notifying RefreshAll... (pSink=0x%p)",
  498. pSink);
  499. hr = pSink->RefreshAll ();
  500. break;
  501. case CONNECTION_ADDRESS_CHANGE:
  502. TraceTag (ttidEvents,
  503. "Notifying ConnectionAddressChange... (pSink=0x%p)",
  504. pSink);
  505. hr = pSink->ConnectionAddressChange(&pEvent->guidId);
  506. break;
  507. case CONNECTION_BALLOON_POPUP:
  508. TraceTag (ttidEvents,
  509. "Notifying ConnectionStatusChange... (pSink=0x%p)",
  510. pSink);
  511. hr = pSink->ShowBalloon(&pEvent->guidId, pEvent->szCookie, pEvent->szBalloonText);
  512. break;
  513. case DISABLE_EVENTS:
  514. TraceTag (ttidEvents,
  515. "Notifying DisableEvents... (pSink=0x%p)",
  516. pSink);
  517. hr = pSink->DisableEvents(pEvent->fDisable, pEvent->ulDisableTimeout);
  518. break;
  519. default:
  520. TraceTag(ttidEvents, "Event Type Passed: %d", pEvent->Type);
  521. AssertSz (FALSE, "Invalid Type specified in pEvent");
  522. break;
  523. }
  524. TraceErrorOptional("pSink call failed: ", hr, (S_FALSE == hr) );
  525. if ( (HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) == hr) ||
  526. (HRESULT_FROM_WIN32(RPC_S_CALL_FAILED_DNE) == hr) ||
  527. (RPC_E_SERVER_DIED == hr) ||
  528. (RPC_E_DISCONNECTED == hr) ||
  529. (HRESULT_FROM_WIN32(RPC_S_CALL_FAILED) == hr) )
  530. {
  531. IUnknown* pUnkSink = NULL;
  532. HRESULT hrT = pSink->QueryInterface(IID_IUnknown, reinterpret_cast<LPVOID*>(&pUnkSink));
  533. if (SUCCEEDED(hrT))
  534. {
  535. ITERUSERNOTIFYMAP iter = pConMan->m_mapNotify.find(pUnkSink);
  536. if (iter != pConMan->m_mapNotify.end())
  537. {
  538. TraceTag(ttidError, "Dead client detected. Removing notify advise for: %S", iter->second->szUserName.c_str());
  539. hrT = pConMan->Unadvise(iter->second->dwCookie);
  540. }
  541. ReleaseObj(pUnkSink);
  542. }
  543. TraceHr (ttidError, FAL, hrT, S_FALSE == hrT, "Error removing notify advise.");
  544. }
  545. ReleaseObj(pSink);
  546. }
  547. }
  548. MemFree (apUnk);
  549. }
  550. }
  551. // Now that we are finished using the object, indicate so. FinalRelease
  552. // may be waiting for this condition in which case the object will soon
  553. // be destroyed.
  554. //
  555. g_fInUse = FALSE;
  556. }
  557. //+---------------------------------------------------------------------------
  558. //
  559. // Member: CConnectionManager::HrEnsureClassManagersLoaded
  560. //
  561. // Purpose: Loads the class managers if they have not been loaded yet.
  562. //
  563. // Arguments:
  564. // (none)
  565. //
  566. // Returns: S_OK or an error code.
  567. //
  568. // Author: shaunco 10 Dec 1997
  569. //
  570. // Notes:
  571. //
  572. HRESULT
  573. CConnectionManager::HrEnsureClassManagersLoaded ()
  574. {
  575. HRESULT hr = S_OK;
  576. // Need to protect m_mapClassManagers for the case that two clients
  577. // get our object simultaneously and call a method which invokes
  578. // this method. Need to transition m_mapClassManagers from being
  579. // empty to being full in one atomic operation.
  580. //
  581. CExceptionSafeComObjectLock EsLock (this);
  582. // If our vector of class managers is emtpy, try to load them.
  583. // This will certainly be the case if we haven't tried to load them yet.
  584. // If will also be the case when no class managers are registered.
  585. // This isn't likely because we register them in hivesys.inf, but it
  586. // shouldn't hurt to keep trying if they're really are none registered.
  587. //
  588. if (m_mapClassManagers.empty())
  589. {
  590. TraceTag (ttidConman, "Loading class managers...");
  591. // Load the registered class managers.
  592. //
  593. // Open the registry key where the class managers are registered.
  594. //
  595. HKEY hkey;
  596. hr = HrRegOpenKeyEx (HKEY_LOCAL_MACHINE,
  597. c_szRegKeyClassManagers, KEY_READ, &hkey);
  598. if (SUCCEEDED(hr))
  599. {
  600. // Read the multi-sz of class manager CLSIDs.
  601. //
  602. PWSTR pmsz;
  603. hr = HrRegQueryMultiSzWithAlloc (hkey, c_szRegValClassManagers,
  604. &pmsz);
  605. if (S_OK == hr)
  606. {
  607. (VOID) HrNmWaitForClassObjectsToBeRegistered ();
  608. // For each CLSID, create the object and request its
  609. // INetConnectionManager interface.
  610. //
  611. for (PCWSTR pszClsid = pmsz;
  612. *pszClsid;
  613. pszClsid += wcslen (pszClsid) + 1)
  614. {
  615. // Convert the string to a CLSID. If it fails, skip it.
  616. //
  617. CLSID clsid;
  618. if (FAILED(CLSIDFromString ((LPOLESTR)pszClsid, &clsid)))
  619. {
  620. TraceTag (ttidConman, "Skipping bogus CLSID (%S)",
  621. pszClsid);
  622. continue;
  623. }
  624. // Create the class manager and add it to our list.
  625. //
  626. INetConnectionManager* pConMan;
  627. hr = CoCreateInstance (
  628. clsid, NULL,
  629. CLSCTX_ALL | CLSCTX_NO_CODE_DOWNLOAD,
  630. IID_INetConnectionManager,
  631. reinterpret_cast<VOID**>(&pConMan));
  632. TraceHr (ttidError, FAL, hr, FALSE,
  633. "CConnectionManager::HrEnsureClassManagersLoaded: "
  634. "CoCreateInstance failed for class manager %S.",
  635. pszClsid);
  636. if (SUCCEEDED(hr))
  637. {
  638. TraceTag (ttidConman, "Loaded class manager %S",
  639. pszClsid);
  640. Assert (pConMan);
  641. if (m_mapClassManagers.find(clsid) != m_mapClassManagers.end())
  642. {
  643. AssertSz(FALSE, "Attempting to insert the same class manager twice!");
  644. }
  645. else
  646. {
  647. m_mapClassManagers[clsid] = pConMan;
  648. }
  649. }
  650. /*
  651. // If CoCreateInstance starts failing again on retail builds, this can
  652. // be helpful.
  653. else
  654. {
  655. CHAR psznBuf [512];
  656. wsprintfA (psznBuf, "NETCFG: CoCreateInstance failed "
  657. "(0x%08x) on class manager %i.\n",
  658. hr, m_mapClassManagers.size ());
  659. OutputDebugStringA (psznBuf);
  660. }
  661. */
  662. }
  663. MemFree (pmsz);
  664. }
  665. RegCloseKey (hkey);
  666. }
  667. TraceTag (ttidConman, "Loaded %i class managers",
  668. m_mapClassManagers.size ());
  669. }
  670. TraceErrorOptional ("CConnectionManager::HrEnsureClassManagersLoaded", hr, (S_FALSE == hr));
  671. return hr;
  672. }
  673. VOID NTAPI CConnectionManager::RegChangeNotifyHandler(IN LPVOID pContext, IN BOOLEAN fTimerFired)
  674. {
  675. TraceTag(ttidConman, "CConnectionManager::RegChangeNotifyHandler (%d)", fTimerFired);
  676. CConnectionManager *pThis = reinterpret_cast<CConnectionManager *>(pContext);
  677. CExceptionSafeComObjectLock EsLock (pThis);
  678. list<GUID> lstRegisteredGuids;
  679. HKEY hkey;
  680. HRESULT hr = HrRegOpenKeyEx (HKEY_LOCAL_MACHINE, c_szRegKeyClassManagers, KEY_READ, &hkey);
  681. if (SUCCEEDED(hr))
  682. {
  683. // Read the multi-sz of class manager CLSIDs.
  684. //
  685. PWSTR pmsz;
  686. hr = HrRegQueryMultiSzWithAlloc (hkey, c_szRegValClassManagers,
  687. &pmsz);
  688. if (S_OK == hr)
  689. {
  690. for (PCWSTR pszClsid = pmsz;
  691. *pszClsid;
  692. pszClsid += wcslen (pszClsid) + 1)
  693. {
  694. CLSID clsid;
  695. if (FAILED(CLSIDFromString ((LPOLESTR)pszClsid, &clsid)))
  696. {
  697. TraceTag (ttidConman, "Skipping bogus CLSID (%S)", pszClsid);
  698. continue;
  699. }
  700. lstRegisteredGuids.push_back(clsid);
  701. }
  702. }
  703. RegCloseKey(hkey);
  704. BOOL bFound;
  705. do
  706. {
  707. bFound = FALSE;
  708. CLASSMANAGERMAP::iterator iterClassMgr;
  709. for (iterClassMgr = pThis->m_mapClassManagers.begin(); iterClassMgr != pThis->m_mapClassManagers.end(); iterClassMgr++)
  710. {
  711. if (find(lstRegisteredGuids.begin(), lstRegisteredGuids.end(), iterClassMgr->first) == lstRegisteredGuids.end())
  712. {
  713. // Class manager key has been removed
  714. TraceTag(ttidConman, "Removing class manager");
  715. bFound = TRUE;
  716. break;
  717. }
  718. }
  719. if (bFound)
  720. {
  721. ULONG uRefCount = iterClassMgr->second->Release();
  722. TraceTag(ttidConman, "Releasing class manager - Refcount = %d", uRefCount);
  723. pThis->m_mapClassManagers.erase(iterClassMgr);
  724. }
  725. } while (bFound);
  726. for (list<GUID>::iterator iter = lstRegisteredGuids.begin(); iter != lstRegisteredGuids.end(); iter++)
  727. {
  728. if (pThis->m_mapClassManagers.find(*iter) == pThis->m_mapClassManagers.end())
  729. {
  730. // Class manager key has been added
  731. TraceTag(ttidConman, "Adding class manager");
  732. INetConnectionManager* pConMan;
  733. hr = CoCreateInstance (
  734. *iter,
  735. NULL,
  736. CLSCTX_ALL | CLSCTX_NO_CODE_DOWNLOAD,
  737. IID_INetConnectionManager,
  738. reinterpret_cast<VOID**>(&pConMan));
  739. TraceHr (ttidError, FAL, hr, FALSE,
  740. "CConnectionManager::RegChangeNotifyHandler: CoCreateInstance failed for class manager.");
  741. if (SUCCEEDED(hr))
  742. {
  743. TraceTag (ttidConman, "Loaded class manager");
  744. Assert (pConMan);
  745. if (pThis->m_mapClassManagers.find(*iter) != pThis->m_mapClassManagers.end())
  746. {
  747. AssertSz(FALSE, "Attempting to insert the same class manager twice!");
  748. }
  749. else
  750. {
  751. pThis->m_mapClassManagers[*iter] = pConMan;
  752. }
  753. }
  754. }
  755. }
  756. }
  757. else
  758. {
  759. TraceError("Could not open registry key", HrFromLastWin32Error());
  760. }
  761. TraceError("RegChangeNotifyHandler", hr);
  762. LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
  763. RegNotifyChangeKeyValue(pThis->m_hRegClassManagerKey, FALSE, REG_NOTIFY_CHANGE_LAST_SET, pThis->m_hRegNotify, TRUE);
  764. }
  765. //+---------------------------------------------------------------------------
  766. // INetConnectionManager
  767. //
  768. //+---------------------------------------------------------------------------
  769. //
  770. // Member: CConnectionManager::EnumConnections
  771. //
  772. // Purpose: Return an INetConnection enumerator.
  773. //
  774. // Arguments:
  775. // Flags [in]
  776. // ppEnum [out] The enumerator.
  777. //
  778. // Returns: S_OK or an error code.
  779. //
  780. // Author: shaunco 21 Sep 1997
  781. //
  782. // Notes:
  783. //
  784. STDMETHODIMP
  785. CConnectionManager::EnumConnections (
  786. NETCONMGR_ENUM_FLAGS Flags,
  787. IEnumNetConnection** ppEnum)
  788. {
  789. HRESULT hr = S_OK;
  790. {
  791. CExceptionSafeComObjectLock EsLock (this);
  792. Assert(FImplies(m_hRegNotify, m_hRegClassManagerKey));
  793. if (!m_hRegNotify)
  794. {
  795. m_hRegNotify = CreateEvent(NULL, FALSE, FALSE, NULL);
  796. if (m_hRegNotify)
  797. {
  798. NTSTATUS Status = RtlRegisterWait(&m_hRegNotifyWait, m_hRegNotify, &CConnectionManager::RegChangeNotifyHandler, this, INFINITE, WT_EXECUTEDEFAULT);
  799. if (!NT_SUCCESS(Status))
  800. {
  801. hr = HRESULT_FROM_NT(Status);
  802. }
  803. else
  804. {
  805. hr = HrRegOpenKeyEx (HKEY_LOCAL_MACHINE, c_szRegKeyClassManagers, KEY_READ, &m_hRegClassManagerKey);
  806. if (SUCCEEDED(hr))
  807. {
  808. hr = RegNotifyChangeKeyValue(m_hRegClassManagerKey, FALSE, REG_NOTIFY_CHANGE_LAST_SET, m_hRegNotify, TRUE);
  809. if (FAILED(hr))
  810. {
  811. RegCloseKey(m_hRegClassManagerKey);
  812. m_hRegClassManagerKey = NULL;
  813. }
  814. }
  815. if (FAILED(hr))
  816. {
  817. Status = RtlDeregisterWait(m_hRegNotifyWait);
  818. if (!NT_SUCCESS(Status))
  819. {
  820. hr = HRESULT_FROM_NT(Status);
  821. }
  822. m_hRegNotifyWait = NULL;
  823. }
  824. }
  825. if (FAILED(hr))
  826. {
  827. CloseHandle(m_hRegNotify);
  828. m_hRegNotify = NULL;
  829. }
  830. }
  831. else
  832. {
  833. hr = HrFromLastWin32Error();
  834. }
  835. }
  836. if (SUCCEEDED(hr))
  837. {
  838. // Create and return the enumerator.
  839. //
  840. hr = HrEnsureClassManagersLoaded ();
  841. }
  842. }
  843. if(SUCCEEDED(hr))
  844. {
  845. hr = CConnectionManagerEnumConnection::CreateInstance (
  846. Flags,
  847. m_mapClassManagers,
  848. IID_IEnumNetConnection,
  849. reinterpret_cast<VOID**>(ppEnum));
  850. }
  851. TraceErrorOptional ("CConnectionManager::EnumConnections", hr, (S_FALSE == hr));
  852. return hr;
  853. }
  854. //+---------------------------------------------------------------------------
  855. // INetConnectionRefresh
  856. //
  857. STDMETHODIMP
  858. CConnectionManager::RefreshAll()
  859. {
  860. LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
  861. return S_OK;
  862. }
  863. //+---------------------------------------------------------------------------
  864. //
  865. // Function: CConnectionManager::ConnectionAdded
  866. //
  867. // Purpose: Notifies event sinks that a new connection has been added.
  868. //
  869. // Arguments:
  870. // pConnection [in] INetConnection* for new connection.
  871. //
  872. // Returns: Standard HRESULT
  873. //
  874. // Author: deonb 22 Mar 2001
  875. //
  876. // Notes:
  877. //
  878. STDMETHODIMP
  879. CConnectionManager::ConnectionAdded(
  880. IN INetConnection* pConnection)
  881. {
  882. HRESULT hr = S_OK;
  883. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  884. if (pEvent)
  885. {
  886. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  887. pEvent->Type = CONNECTION_ADDED;
  888. hr = HrGetPropertiesExFromINetConnection(pConnection, &pEvent->pPropsEx);
  889. if (SUCCEEDED(hr))
  890. {
  891. if (QueueUserWorkItemInThread(ConmanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  892. {
  893. return hr;
  894. }
  895. hr = E_FAIL;
  896. }
  897. FreeConmanEvent(pEvent);
  898. }
  899. else
  900. {
  901. hr = E_OUTOFMEMORY;
  902. }
  903. return hr;
  904. }
  905. //+---------------------------------------------------------------------------
  906. //
  907. // Function: CConnectionManager::ConnectionDeleted
  908. //
  909. // Purpose: Sends an event to notify of a connection being deleted.
  910. //
  911. // Arguments:
  912. // pguidId [in] GUID of the connectoid
  913. //
  914. // Returns: Standard HRESULT
  915. //
  916. // Author: ckotze 18 Apr 2001
  917. //
  918. // Notes:
  919. //
  920. STDMETHODIMP
  921. CConnectionManager::ConnectionDeleted(
  922. IN const GUID* pguidId)
  923. {
  924. HRESULT hr = S_OK;
  925. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  926. if (pEvent)
  927. {
  928. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  929. pEvent->Type = CONNECTION_DELETED;
  930. pEvent->guidId = *pguidId;
  931. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, reinterpret_cast<PVOID>(pEvent), EVENTMGR_CONMAN))
  932. {
  933. hr = E_FAIL;
  934. FreeConmanEvent(pEvent);
  935. }
  936. }
  937. else
  938. {
  939. hr = E_OUTOFMEMORY;
  940. }
  941. return hr;
  942. }
  943. //+---------------------------------------------------------------------------
  944. //
  945. // Function: CConnectionManager::ConnectionRenamed
  946. //
  947. // Purpose: Notifies the event sinks of a connection being renamed.
  948. //
  949. // Arguments:
  950. // pConnection [in] INetConnection* for new connection.
  951. //
  952. // Returns: Standard HRESULT
  953. //
  954. // Author: ckotze 19 Apr 2001
  955. //
  956. // Notes:
  957. //
  958. STDMETHODIMP
  959. CConnectionManager::ConnectionRenamed(
  960. IN INetConnection* pConnection)
  961. {
  962. HRESULT hr = S_OK;
  963. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  964. if (pEvent)
  965. {
  966. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  967. pEvent->Type = CONNECTION_RENAMED;
  968. hr = HrGetPropertiesExFromINetConnection(pConnection, &pEvent->pPropsEx);
  969. if (SUCCEEDED(hr))
  970. {
  971. lstrcpynW (pEvent->szNewName, pEvent->pPropsEx->bstrName, celems(pEvent->szNewName) );
  972. pEvent->guidId = pEvent->pPropsEx->guidId;
  973. if (QueueUserWorkItemInThread(ConmanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  974. {
  975. return hr;
  976. }
  977. hr = E_FAIL;
  978. }
  979. FreeConmanEvent(pEvent);
  980. }
  981. else
  982. {
  983. hr = E_OUTOFMEMORY;
  984. }
  985. return hr;
  986. }
  987. //+---------------------------------------------------------------------------
  988. //
  989. // Function: CConnectionManager::ConnectionModified
  990. //
  991. // Purpose: Sends an event to notify clients that the connection has been
  992. // Modified.
  993. // Arguments:
  994. // pConnection [in] INetConnection* for new connection.
  995. //
  996. // Returns: Standard HRESULT
  997. //
  998. // Author: ckotze 22 Mar 2001
  999. //
  1000. // Notes:
  1001. //
  1002. STDMETHODIMP
  1003. CConnectionManager::ConnectionModified(INetConnection* pConnection)
  1004. {
  1005. HRESULT hr = S_OK;
  1006. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1007. if (pEvent)
  1008. {
  1009. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1010. pEvent->Type = CONNECTION_MODIFIED;
  1011. hr = HrGetPropertiesExFromINetConnection(pConnection, &pEvent->pPropsEx);
  1012. if (SUCCEEDED(hr))
  1013. {
  1014. if (QueueUserWorkItemInThread(ConmanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  1015. {
  1016. return hr;
  1017. }
  1018. hr = E_FAIL;
  1019. }
  1020. FreeConmanEvent(pEvent);
  1021. }
  1022. else
  1023. {
  1024. hr = E_OUTOFMEMORY;
  1025. }
  1026. return hr;
  1027. }
  1028. //+---------------------------------------------------------------------------
  1029. //
  1030. // Function: CConnectionManager::ConnectionStatusChanged
  1031. //
  1032. // Purpose: Sends the ShowBalloon event to each applicable netshell
  1033. //
  1034. // Arguments:
  1035. // pguidId [in] GUID of the connectoid
  1036. // ncs [in] New status of the connectoid
  1037. //
  1038. // Returns: Standard HRESULT
  1039. //
  1040. // Author: deonb 22 Mar 2001
  1041. //
  1042. // Notes:
  1043. //
  1044. STDMETHODIMP
  1045. CConnectionManager::ConnectionStatusChanged(
  1046. IN const GUID* pguidId,
  1047. IN const NETCON_STATUS ncs)
  1048. {
  1049. HRESULT hr = S_OK;
  1050. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1051. if (pEvent)
  1052. {
  1053. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1054. pEvent->Type = CONNECTION_STATUS_CHANGE;
  1055. pEvent->guidId = *pguidId;
  1056. pEvent->Status = ncs;
  1057. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, reinterpret_cast<PVOID>(pEvent), EVENTMGR_CONMAN))
  1058. {
  1059. FreeConmanEvent(pEvent);
  1060. hr = E_FAIL;
  1061. }
  1062. }
  1063. else
  1064. {
  1065. hr = E_OUTOFMEMORY;
  1066. }
  1067. return hr;
  1068. }
  1069. //+---------------------------------------------------------------------------
  1070. //
  1071. // Function: CConnectionManager::ShowBalloon
  1072. //
  1073. // Purpose: Sends the ShowBalloon event to each applicable netshell
  1074. //
  1075. // Arguments:
  1076. // pguidId [in] GUID of the connectoid
  1077. // szCookie [in] A specified cookie that will end up at netshell
  1078. // szBalloonText [in] The balloon text
  1079. //
  1080. // Returns: Standard HRESULT
  1081. //
  1082. // Author: deonb 22 Mar 2001
  1083. //
  1084. // Notes:
  1085. //
  1086. STDMETHODIMP
  1087. CConnectionManager::ShowBalloon(
  1088. IN const GUID *pguidId,
  1089. IN const BSTR szCookie,
  1090. IN const BSTR szBalloonText)
  1091. {
  1092. HRESULT hr = S_OK;
  1093. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1094. if (pEvent)
  1095. {
  1096. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1097. pEvent->Type = CONNECTION_BALLOON_POPUP;
  1098. pEvent->guidId = *pguidId;
  1099. pEvent->szCookie = SysAllocStringByteLen(reinterpret_cast<LPCSTR>(szCookie), SysStringByteLen(szCookie));
  1100. pEvent->szBalloonText = SysAllocString(szBalloonText);
  1101. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, reinterpret_cast<PVOID>(pEvent), EVENTMGR_CONMAN))
  1102. {
  1103. hr = E_FAIL;
  1104. FreeConmanEvent(pEvent);
  1105. }
  1106. }
  1107. else
  1108. {
  1109. hr = E_OUTOFMEMORY;
  1110. }
  1111. return hr;
  1112. }
  1113. //+---------------------------------------------------------------------------
  1114. //
  1115. // Function: CConnectionManager::DisableEvents
  1116. //
  1117. // Purpose: Disable netshell processing of events for x milliseconds
  1118. //
  1119. // Arguments:
  1120. // fDisable [in] TRUE to disable EVENT processing, FALSE to renable
  1121. // ulDisableTimeout [in] Number of milliseconds to disable event processing for
  1122. //
  1123. // Returns: Standard HRESULT
  1124. //
  1125. // Author: deonb 10 April 2001
  1126. //
  1127. // Notes:
  1128. //
  1129. STDMETHODIMP CConnectionManager::DisableEvents(IN const BOOL fDisable, IN const ULONG ulDisableTimeout)
  1130. {
  1131. HRESULT hr = S_OK;
  1132. if (ulDisableTimeout > MAX_DISABLE_EVENT_TIMEOUT)
  1133. {
  1134. return E_INVALIDARG;
  1135. }
  1136. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1137. if (pEvent)
  1138. {
  1139. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1140. pEvent->Type = DISABLE_EVENTS;
  1141. pEvent->fDisable = fDisable;
  1142. // We set the high bit to let netshell know that this is coming from our private interface.
  1143. pEvent->ulDisableTimeout = 0x80000000 | ulDisableTimeout;
  1144. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, reinterpret_cast<PVOID>(pEvent), EVENTMGR_CONMAN))
  1145. {
  1146. hr = E_FAIL;
  1147. FreeConmanEvent(pEvent);
  1148. }
  1149. }
  1150. else
  1151. {
  1152. hr = E_OUTOFMEMORY;
  1153. }
  1154. return hr;
  1155. }
  1156. //+---------------------------------------------------------------------------
  1157. //
  1158. // Function: CConnectionManager::RefreshConnections
  1159. //
  1160. // Purpose: Refreshes the connections in the connections folder
  1161. //
  1162. // Arguments:
  1163. // None.
  1164. //
  1165. //
  1166. // Returns: Standard HRESULT
  1167. //
  1168. // Author: ckotze 19 April 2001
  1169. //
  1170. // Notes: This is a public interface that we are providing in order to
  1171. // allow other components/companies to have some control over
  1172. // the Connections Folder.
  1173. STDMETHODIMP CConnectionManager::RefreshConnections()
  1174. {
  1175. HRESULT hr = S_OK;
  1176. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1177. if (pEvent)
  1178. {
  1179. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1180. pEvent->Type = REFRESH_ALL;
  1181. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, reinterpret_cast<PVOID>(pEvent), EVENTMGR_CONMAN))
  1182. {
  1183. hr = E_FAIL;
  1184. FreeConmanEvent(pEvent);
  1185. }
  1186. }
  1187. else
  1188. {
  1189. hr = E_OUTOFMEMORY;
  1190. }
  1191. return hr;
  1192. }
  1193. //+---------------------------------------------------------------------------
  1194. //
  1195. // Function: CConnectionManager::Enable
  1196. //
  1197. // Purpose: Enables events to be fired once more in the connections folder
  1198. //
  1199. // Arguments:
  1200. // None.
  1201. //
  1202. // Returns: Standard HRESULT
  1203. //
  1204. // Author: ckotze 19 April 2001
  1205. //
  1206. // Notes: This is a public interface that we are providing in order to
  1207. // allow other components/companies to have some control over
  1208. // the Connections Folder.
  1209. // Since this is a public interface, we are only allowing the
  1210. // INVALID_ADDRESS notification to be disabled
  1211. // (this will take place in netshell.dll).
  1212. //
  1213. STDMETHODIMP CConnectionManager::Enable()
  1214. {
  1215. HRESULT hr = S_OK;
  1216. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1217. if (pEvent)
  1218. {
  1219. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1220. pEvent->Type = DISABLE_EVENTS;
  1221. pEvent->fDisable = FALSE;
  1222. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, reinterpret_cast<PVOID>(pEvent), EVENTMGR_CONMAN))
  1223. {
  1224. hr = E_FAIL;
  1225. FreeConmanEvent(pEvent);
  1226. }
  1227. }
  1228. else
  1229. {
  1230. hr = E_OUTOFMEMORY;
  1231. }
  1232. return hr;
  1233. }
  1234. //+---------------------------------------------------------------------------
  1235. //
  1236. // Function: CConnectionManager::Disable
  1237. //
  1238. // Purpose: Disable netshell processing of events for x milliseconds
  1239. //
  1240. // Arguments:
  1241. // ulDisableTimeout [in] Number of milliseconds to disable event
  1242. // processing for. Max is 60000 (1 minute)
  1243. //
  1244. // Returns: Standard HRESULT
  1245. //
  1246. // Author: ckotze 19 April 2001
  1247. //
  1248. // Notes: This is a public interface that we are providing in order to
  1249. // allow other components/companies to have some control over
  1250. // the Connections Folder.
  1251. // Since this is a public interface, we are only allowing the
  1252. // INVALID_ADDRESS notification to be disabled
  1253. // (this will take place in netshell.dll).
  1254. //
  1255. STDMETHODIMP CConnectionManager::Disable(IN const ULONG ulDisableTimeout)
  1256. {
  1257. HRESULT hr = S_OK;
  1258. if (ulDisableTimeout > MAX_DISABLE_EVENT_TIMEOUT)
  1259. {
  1260. return E_INVALIDARG;
  1261. }
  1262. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  1263. if (pEvent)
  1264. {
  1265. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  1266. pEvent->Type = DISABLE_EVENTS;
  1267. pEvent->fDisable = TRUE;
  1268. pEvent->ulDisableTimeout = ulDisableTimeout;
  1269. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, reinterpret_cast<PVOID>(pEvent), EVENTMGR_CONMAN))
  1270. {
  1271. hr = E_FAIL;
  1272. FreeConmanEvent(pEvent);
  1273. }
  1274. }
  1275. else
  1276. {
  1277. hr = E_OUTOFMEMORY;
  1278. }
  1279. return hr;
  1280. }
  1281. //+---------------------------------------------------------------------------
  1282. // INetConnectionCMUtil
  1283. //
  1284. //+---------------------------------------------------------------------------
  1285. //
  1286. // Function: MapCMHiddenConnectionToOwner
  1287. //
  1288. // Purpose: Maps a child connection to its parent connection.
  1289. //
  1290. // Connection Manager has two stages: Dialup and VPN.
  1291. // For the Dialup it creates a hidden connectoid that the
  1292. // folder (netshell) does not see. However netman caches
  1293. // the name, guid and status of this connectedoid. Both
  1294. // the parent and child connectoid have the same name. When
  1295. // the status of the hidden connectiod is updated the folder
  1296. // recives the guid of the hidden connectoid and maps the
  1297. // connectiod to it parent (Connection Manager) by searching
  1298. // netmans cache for the name of the hidden connectoid. Then it
  1299. // searches the connections in the folder for that name and thus
  1300. // gets the guid of the parent connectoid.
  1301. //
  1302. // When the folder gets a notify message from netman for the hidden
  1303. // connection it uses this function to find the parent and update the
  1304. // parent's status. The hidden connection is not displayed.
  1305. //
  1306. // Arguments:
  1307. // guidHidden [in] GUID of the hidden connectiod
  1308. // pguidOwner [out] GUID of the parent connectiod
  1309. //
  1310. // Returns: S_OK -- Found hidden connection
  1311. // else not found
  1312. //
  1313. // Author: omiller 1 Jun 2000
  1314. //
  1315. // Notes:
  1316. //
  1317. STDMETHODIMP
  1318. CConnectionManager::MapCMHiddenConnectionToOwner (
  1319. /*[in]*/ REFGUID guidHidden,
  1320. /*[out]*/ GUID * pguidOwner)
  1321. {
  1322. HRESULT hr = S_OK;
  1323. bool bFound = false;
  1324. hr = HrEnsureClassManagersLoaded ();
  1325. if (SUCCEEDED(hr))
  1326. {
  1327. // Impersonate the user so that we see all of the connections displayed in the folder
  1328. //
  1329. hr = CoImpersonateClient();
  1330. if (SUCCEEDED(hr))
  1331. {
  1332. // Find the hidden connection with this guid
  1333. //
  1334. CMEntry cm;
  1335. hr = CCMUtil::Instance().HrGetEntry(guidHidden, cm);
  1336. // Did we find the hidden connection?
  1337. if( S_OK == hr )
  1338. {
  1339. // Enumerate through all of the connections and find connection with the same name as the
  1340. // hidden connection
  1341. //
  1342. IEnumNetConnection * pEnum = NULL;
  1343. hr = CWanConnectionManagerEnumConnection::CreateInstance(NCME_DEFAULT, IID_IEnumNetConnection, reinterpret_cast<LPVOID *>(&pEnum));
  1344. if (SUCCEEDED(hr))
  1345. {
  1346. INetConnection * pNetCon;
  1347. NETCON_PROPERTIES * pProps;
  1348. while(!bFound)
  1349. {
  1350. // Get the nect connection
  1351. //
  1352. hr = pEnum->Next(1, &pNetCon, NULL);
  1353. if(S_OK != hr)
  1354. {
  1355. // Ooops encountered some error, stop searching
  1356. //
  1357. break;
  1358. }
  1359. // Get the properties of the connection
  1360. //
  1361. hr = pNetCon->GetProperties(&pProps);
  1362. if(SUCCEEDED(hr))
  1363. {
  1364. if(lstrcmp(cm.m_szEntryName, pProps->pszwName) == 0)
  1365. {
  1366. // Found the connection that has the same name a the hidden connection
  1367. // Stop searching!!
  1368. *pguidOwner = pProps->guidId;
  1369. bFound = true;
  1370. }
  1371. FreeNetconProperties(pProps);
  1372. }
  1373. ReleaseObj(pNetCon);
  1374. }
  1375. ReleaseObj(pEnum);
  1376. }
  1377. }
  1378. // Stop Impersonating the user
  1379. //
  1380. CoRevertToSelf();
  1381. }
  1382. }
  1383. return bFound ? S_OK : S_FALSE;
  1384. }
  1385. //+---------------------------------------------------------------------------
  1386. // IConnectionPoint overrides netman!CConnectionManager__Advise
  1387. //
  1388. STDMETHODIMP
  1389. CConnectionManager::Advise (
  1390. IUnknown* pUnkSink,
  1391. DWORD* pdwCookie)
  1392. {
  1393. HRESULT hr = S_OK;
  1394. TraceFileFunc(ttidConman);
  1395. Assert(!FBadInPtr(pUnkSink));
  1396. // Set our cloaked identity to be used when we call back on this
  1397. // advise interface. It's important to do this for security. Since
  1398. // we run as LocalSystem, if we were to call back without identify
  1399. // impersonation only, the client could impersonate us and get a free
  1400. // LocalSystem context which could be used for malicious purposes.
  1401. //
  1402. //
  1403. CoSetProxyBlanket (
  1404. pUnkSink,
  1405. RPC_C_AUTHN_WINNT, // use NT default security
  1406. RPC_C_AUTHZ_NONE, // use NT default authentication
  1407. NULL, // must be null if default
  1408. RPC_C_AUTHN_LEVEL_CALL, // call
  1409. RPC_C_IMP_LEVEL_IDENTIFY,
  1410. NULL, // use process token
  1411. EOAC_DEFAULT);
  1412. TraceHr(ttidError, FAL, hr, FALSE, "CoSetProxyBlanket");
  1413. if (S_OK == hr)
  1414. {
  1415. // Initialize our event handler if it has not already been done.
  1416. hr = HrEnsureEventHandlerInitialized();
  1417. if (SUCCEEDED(hr))
  1418. {
  1419. // We still work for other events if this fails.
  1420. hr = HrEnsureRegisteredWithNla();
  1421. TraceErrorOptional("Could not register with Nla", hr, (S_FALSE == hr));
  1422. // Call the underlying ATL implementation of Advise.
  1423. //
  1424. hr = IConnectionPointImpl<
  1425. CConnectionManager,
  1426. &IID_INetConnectionNotifySink>::Advise(pUnkSink, pdwCookie);
  1427. TraceTag (ttidConman,
  1428. "CConnectionManager::Advise called... pUnkSink=0x%p, cookie=%d",
  1429. pUnkSink,
  1430. *pdwCookie);
  1431. TraceHr (ttidError, FAL, hr, FALSE, "IConnectionPointImpl::Advise");
  1432. if (SUCCEEDED(hr))
  1433. {
  1434. WCHAR szUserAppData[MAX_PATH];
  1435. HRESULT hrT = S_OK;
  1436. HRESULT hrImpersonate = S_OK;
  1437. if (SUCCEEDED(hrT))
  1438. {
  1439. // We ignore this HRESULT because we can be called inproc and that would definitely fail.
  1440. // Instead we just make sure that it succeeded when befor call CoRevertToSelf. This is
  1441. // fine because we'll still get a valid User App data path, it will just be something like
  1442. // LocalService or LocalSystem and we can still determine which sinks to send events to.
  1443. BOOLEAN fNotifyWZC = FALSE;
  1444. WCHAR szUserName[MAX_PATH];
  1445. CNotifySourceInfo* pNotifySourceInfo = new CNotifySourceInfo();
  1446. if (!pNotifySourceInfo)
  1447. {
  1448. hr = E_OUTOFMEMORY;
  1449. }
  1450. else
  1451. {
  1452. pNotifySourceInfo->dwCookie = *pdwCookie;
  1453. hrImpersonate = CoImpersonateClient();
  1454. if (SUCCEEDED(hrImpersonate) || (RPC_E_CALL_COMPLETE == hrImpersonate))
  1455. {
  1456. hrT = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, szUserAppData);
  1457. if (SUCCEEDED(hrT))
  1458. {
  1459. pNotifySourceInfo->szUserProfilesPath = szUserAppData;
  1460. TraceTag(ttidEvents, "Adding IUnknown for Sink to Map: 0x%08x. Path: %S", reinterpret_cast<DWORD_PTR>(pUnkSink), szUserAppData);
  1461. TraceTag(ttidEvents, "Number of Items in Map: %d", m_mapNotify.size());
  1462. }
  1463. else
  1464. {
  1465. TraceError("Unable to get Folder Path", hrT);
  1466. }
  1467. ZeroMemory(szUserName, celems(szUserName));
  1468. ULONG nSize = celems(szUserName);
  1469. if (GetUserNameEx(NameSamCompatible, szUserName, &nSize) && *szUserName)
  1470. {
  1471. pNotifySourceInfo->szUserName = szUserName;
  1472. fNotifyWZC = TRUE;
  1473. }
  1474. else
  1475. {
  1476. pNotifySourceInfo->szUserName = L"System";
  1477. TraceError("Unable to get the user name", HrFromLastWin32Error());
  1478. }
  1479. }
  1480. Lock();
  1481. m_mapNotify[pUnkSink] = pNotifySourceInfo;
  1482. Unlock();
  1483. #ifdef DBG
  1484. LPWSTR* ppszAdviseUsers;
  1485. DWORD dwCount;
  1486. HRESULT hrT = GetClientAdvises(&ppszAdviseUsers, &dwCount);
  1487. if (SUCCEEDED(hrT))
  1488. {
  1489. Assert(dwCount);
  1490. TraceTag(ttidConman, "Advise client list after ::Advise:");
  1491. for (DWORD x = 0; x < dwCount; x++)
  1492. {
  1493. LPWSTR szUserName = ppszAdviseUsers[x];
  1494. TraceTag(ttidConman, "%x: %S", x, szUserName);
  1495. }
  1496. CoTaskMemFree(ppszAdviseUsers);
  1497. }
  1498. #endif
  1499. }
  1500. if (SUCCEEDED(hrImpersonate))
  1501. {
  1502. CoRevertToSelf();
  1503. }
  1504. if (fNotifyWZC)
  1505. {
  1506. WZCTrayIconReady(szUserName);
  1507. }
  1508. }
  1509. if (!m_lRegisteredOneTime)
  1510. {
  1511. // Do an explicit interlocked exchange to only let one thread
  1512. // through to do the registration.
  1513. //
  1514. if (0 == InterlockedExchange (&m_lRegisteredOneTime, 1))
  1515. {
  1516. // Register for device notifications. Specifically, we're
  1517. // interested in network adapters coming and going. If this
  1518. // fails, we proceed anyway.
  1519. //
  1520. TraceTag (ttidConman, "Calling RegisterDeviceNotification...");
  1521. DEV_BROADCAST_DEVICEINTERFACE PnpFilter;
  1522. ZeroMemory (&PnpFilter, sizeof(PnpFilter));
  1523. PnpFilter.dbcc_size = sizeof(PnpFilter);
  1524. PnpFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  1525. PnpFilter.dbcc_classguid = GUID_NDIS_LAN_CLASS;
  1526. m_hDevNotify = RegisterDeviceNotification (
  1527. (HANDLE)_Module.m_hStatus,
  1528. &PnpFilter,
  1529. DEVICE_NOTIFY_SERVICE_HANDLE);
  1530. if (!m_hDevNotify)
  1531. {
  1532. TraceHr (ttidError, FAL, HrFromLastWin32Error(), FALSE,
  1533. "RegisterDeviceNotification");
  1534. }
  1535. (VOID) HrEnsureRegisteredOrDeregisteredWithWmi (TRUE);
  1536. }
  1537. }
  1538. }
  1539. }
  1540. }
  1541. TraceErrorOptional ("CConnectionManager::Advise", hr, (S_FALSE == hr));
  1542. return hr;
  1543. }
  1544. STDMETHODIMP
  1545. CConnectionManager::Unadvise(DWORD dwCookie)
  1546. {
  1547. HRESULT hr = S_OK;
  1548. TraceFileFunc(ttidConman);
  1549. hr = IConnectionPointImpl<CConnectionManager, &IID_INetConnectionNotifySink>::Unadvise(dwCookie);
  1550. Lock();
  1551. BOOL fFound = FALSE;
  1552. for (ITERUSERNOTIFYMAP iter = m_mapNotify.begin(); iter != m_mapNotify.end(); iter++)
  1553. {
  1554. if (iter->second->dwCookie == dwCookie)
  1555. {
  1556. fFound = TRUE;
  1557. delete iter->second;
  1558. m_mapNotify.erase(iter);
  1559. break;
  1560. }
  1561. }
  1562. Unlock();
  1563. if (!fFound)
  1564. {
  1565. TraceTag(ttidError, "Unadvise cannot find advise for cookie 0x%08x in notify map", dwCookie);
  1566. }
  1567. #ifdef DBG
  1568. LPWSTR* ppszAdviseUsers;
  1569. DWORD dwCount;
  1570. HRESULT hrT = GetClientAdvises(&ppszAdviseUsers, &dwCount);
  1571. if (SUCCEEDED(hrT))
  1572. {
  1573. if (!dwCount)
  1574. {
  1575. TraceTag(ttidConman, "Unadvise removed the last advise client");
  1576. }
  1577. else
  1578. {
  1579. TraceTag(ttidConman, "Advise client list after ::Unadvise:");
  1580. }
  1581. for (DWORD x = 0; x < dwCount; x++)
  1582. {
  1583. LPWSTR szUserName = ppszAdviseUsers[x];
  1584. TraceTag(ttidConman, "%x: %S", x, szUserName);
  1585. }
  1586. CoTaskMemFree(ppszAdviseUsers);
  1587. }
  1588. #endif
  1589. return hr;
  1590. }
  1591. #if DBG
  1592. //+---------------------------------------------------------------------------
  1593. // INetConnectionManagerDebug
  1594. //
  1595. DWORD
  1596. WINAPI
  1597. ConmanNotifyTest (
  1598. PVOID pvContext
  1599. )
  1600. {
  1601. HRESULT hr;
  1602. RASENUMENTRYDETAILS* pDetails;
  1603. DWORD cDetails;
  1604. hr = HrRasEnumAllEntriesWithDetails (NULL,
  1605. &pDetails, &cDetails);
  1606. if (SUCCEEDED(hr))
  1607. {
  1608. RASEVENT Event;
  1609. for (DWORD i = 0; i < cDetails; i++)
  1610. {
  1611. Event.Type = ENTRY_ADDED;
  1612. Event.Details = pDetails[i];
  1613. RasEventNotify (&Event);
  1614. Event.Type = ENTRY_MODIFIED;
  1615. RasEventNotify (&Event);
  1616. Event.Type = ENTRY_CONNECTED;
  1617. Event.guidId = pDetails[i].guidId;
  1618. RasEventNotify (&Event);
  1619. Event.Type = ENTRY_DISCONNECTED;
  1620. Event.guidId = pDetails[i].guidId;
  1621. RasEventNotify (&Event);
  1622. Event.Type = ENTRY_RENAMED;
  1623. lstrcpyW (Event.pszwNewName, L"foobar");
  1624. RasEventNotify (&Event);
  1625. Event.Type = ENTRY_DELETED;
  1626. Event.guidId = pDetails[i].guidId;
  1627. RasEventNotify (&Event);
  1628. }
  1629. MemFree (pDetails);
  1630. }
  1631. LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
  1632. TraceErrorOptional ("ConmanNotifyTest", hr, (S_FALSE == hr));
  1633. return hr;
  1634. }
  1635. STDMETHODIMP
  1636. CConnectionManager::NotifyTestStart ()
  1637. {
  1638. HRESULT hr = S_OK;
  1639. if (!QueueUserWorkItem (ConmanNotifyTest, NULL, WT_EXECUTEDEFAULT))
  1640. {
  1641. hr = HrFromLastWin32Error ();
  1642. }
  1643. TraceErrorOptional ("CConnectionManager::NotifyTestStart", hr, (S_FALSE == hr));
  1644. return hr;
  1645. }
  1646. STDMETHODIMP
  1647. CConnectionManager::NotifyTestStop ()
  1648. {
  1649. return S_OK;
  1650. }
  1651. #endif // DBG