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.

647 lines
18 KiB

  1. #include "pch.h"
  2. #pragma hdrstop
  3. #include "foldinc.h" // Standard shell\folder includes
  4. #include "conprops.h"
  5. #include "ncnetcon.h"
  6. #include "foldres.h"
  7. class CConnectionPropPages
  8. {
  9. public:
  10. CConnectionPropPages();
  11. ~CConnectionPropPages();
  12. ULONG CntPages() {return m_culPages;}
  13. HPROPSHEETPAGE * PHPages() {return m_rghPages;}
  14. static BOOL FAddPropSheet(HPROPSHEETPAGE hPage, LPARAM lParam);
  15. private:
  16. ULONG m_culPages;
  17. ULONG m_ulPageBufferLen;
  18. HPROPSHEETPAGE * m_rghPages;
  19. };
  20. CConnectionPropPages::CConnectionPropPages()
  21. {
  22. m_culPages = 0;
  23. m_ulPageBufferLen = 0;
  24. m_rghPages = NULL;
  25. }
  26. CConnectionPropPages::~CConnectionPropPages()
  27. {
  28. delete [] (BYTE *)(m_rghPages);
  29. }
  30. //
  31. // Function: CConnectionPropPages::FAddPropSheet
  32. //
  33. // Purpose: Callback function for the AddPages API used to accept
  34. // connection property pages handed back from a provider.
  35. //
  36. // Parameters: hPage [IN] - The page to add
  37. // lParam [IN] - 'this' casted to an LPARAM
  38. //
  39. // Returns: BOOL, TRUE if the page was successfully added.
  40. //
  41. BOOL
  42. CConnectionPropPages::FAddPropSheet(HPROPSHEETPAGE hPage, LPARAM lParam)
  43. {
  44. CConnectionPropPages * pCPP = NULL;
  45. // Validate the input parameters
  46. //
  47. if ((0L == lParam) || (NULL == hPage))
  48. {
  49. Assert(lParam);
  50. Assert(hPage);
  51. TraceHr(ttidShellFolder, FAL, E_INVALIDARG, FALSE, "CConnectionPropPages::FAddPropSheet");
  52. return FALSE;
  53. }
  54. pCPP = reinterpret_cast<CConnectionPropPages*>(lParam);
  55. // Grow the buffer if necessary
  56. //
  57. if (pCPP->m_culPages == pCPP->m_ulPageBufferLen)
  58. {
  59. HPROPSHEETPAGE* rghPages = NULL;
  60. rghPages = (HPROPSHEETPAGE*)(new BYTE[sizeof(HPROPSHEETPAGE) *
  61. (pCPP->m_ulPageBufferLen + 10)]);
  62. if (NULL == rghPages)
  63. {
  64. TraceHr(ttidShellFolder, FAL, E_OUTOFMEMORY, FALSE, "CConnectionPropPages::FAddPropSheet");
  65. return FALSE;
  66. }
  67. // Copy the existing pages to the new buffer
  68. //
  69. memcpy(rghPages, pCPP->m_rghPages,
  70. sizeof(HPROPSHEETPAGE) * pCPP->m_ulPageBufferLen);
  71. delete [] (BYTE *)(pCPP->m_rghPages);
  72. pCPP->m_rghPages = rghPages;
  73. pCPP->m_ulPageBufferLen += 10;
  74. }
  75. // Retain the new page
  76. //
  77. pCPP->m_rghPages[pCPP->m_culPages++] = hPage;
  78. return TRUE;
  79. }
  80. //+---------------------------------------------------------------------------
  81. //
  82. // Function: HrUIInterfaceFromNetCon
  83. //
  84. // Purpose: Get the INetConnectionPropertyUI interface from an
  85. // INetConnection pointer.
  86. //
  87. // Arguments:
  88. // pconn [in] Valid INetConnection *
  89. // riid [in] IID of desired interface
  90. // ppv [out] Returned pointer to the interface
  91. //
  92. // Returns:
  93. //
  94. // Author: jeffspr 12 Nov 1997
  95. //
  96. // Notes:
  97. //
  98. HRESULT HrUIInterfaceFromNetCon(
  99. INetConnection * pconn,
  100. REFIID riid,
  101. LPVOID * ppv)
  102. {
  103. HRESULT hr = S_OK;
  104. CLSID clsid;
  105. Assert(pconn);
  106. Assert(ppv);
  107. // Validate the parameters.
  108. //
  109. if ((NULL == pconn) || (NULL == ppv))
  110. {
  111. hr = E_INVALIDARG;
  112. goto Error;
  113. }
  114. // Initailize the output parameter.
  115. //
  116. *ppv = NULL;
  117. // Get the CLSID of the object which can provide the particular interface.
  118. //
  119. hr = pconn->GetUiObjectClassId(&clsid);
  120. if (FAILED(hr))
  121. {
  122. goto Error;
  123. }
  124. // Create this object asking for the specified interface.
  125. //
  126. hr = CoCreateInstance(clsid, NULL,
  127. CLSCTX_INPROC_SERVER | CLSCTX_NO_CODE_DOWNLOAD, riid, ppv);
  128. Error:
  129. TraceHr(ttidError, FAL, hr, (E_NOINTERFACE == hr),
  130. "HrUIInterfaceFromNetCon");
  131. return hr;
  132. }
  133. //+---------------------------------------------------------------------------
  134. //
  135. // Function: HrGetPropertiesCaption
  136. //
  137. // Purpose: Generate the caption for a property page
  138. //
  139. // Arguments:
  140. // pconn [in] Connection pointer passed in from the shell
  141. // ppszCaption [out] Resultant property page caption if successful
  142. //
  143. // Returns:
  144. //
  145. // Notes:
  146. //
  147. HRESULT HrGetPropertiesCaption(INetConnection * pconn, PWSTR * ppszCaption)
  148. {
  149. HRESULT hr;
  150. Assert(pconn);
  151. Assert(ppszCaption);
  152. // Try to get the connection name
  153. //
  154. NETCON_PROPERTIES* pProps;
  155. hr = pconn->GetProperties(&pProps);
  156. if (SUCCEEDED(hr))
  157. {
  158. Assert (pProps->pszwName);
  159. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  160. FORMAT_MESSAGE_FROM_STRING |
  161. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  162. SzLoadIds(IDS_CONPROP_CAPTION),
  163. 0, 0, (PWSTR)ppszCaption, 0,
  164. (va_list *)&pProps->pszwName);
  165. FreeNetconProperties(pProps);
  166. }
  167. TraceHr(ttidError, FAL, hr, FALSE,"HrGetPropertiesCaption");
  168. return hr;
  169. }
  170. //+---------------------------------------------------------------------------
  171. //
  172. // Function: ActivatePropertyDialog
  173. //
  174. // Purpose: Try to locate a property dialog associated with pconn
  175. // then bring it to the foreground.
  176. //
  177. // Arguments:
  178. // pconn [in] Connection pointer passed in from the shell
  179. //
  180. // Returns:
  181. //
  182. // Notes:
  183. //
  184. VOID ActivatePropertyDialog(INetConnection * pconn)
  185. {
  186. PWSTR pszCaption = NULL;
  187. if (SUCCEEDED(HrGetPropertiesCaption(pconn, &pszCaption)))
  188. {
  189. Assert(pszCaption);
  190. // Find the dialog with this caption
  191. //
  192. HWND hwnd = FindWindow(NULL, pszCaption);
  193. if (IsWindow(hwnd))
  194. {
  195. SetForegroundWindow(hwnd);
  196. }
  197. LocalFree (pszCaption);
  198. }
  199. }
  200. //+---------------------------------------------------------------------------
  201. //
  202. // Function: HrSetPropertiesTaskbarIcon
  203. //
  204. // Purpose: Setup the dialog property sheet's taskbar icon.
  205. //
  206. // Arguments:
  207. // hwndDlg [in] Dialog handle
  208. // uMsg [in] Message value
  209. // lparam [in] Long parameter
  210. //
  211. // Returns: 0
  212. //
  213. // Notes: A standard Win32 commctrl PropSheetProc always return 0.
  214. // See MSDN documentation.
  215. //
  216. int CALLBACK HrSetPropertiesTaskbarIcon(
  217. IN HWND hwndDlg,
  218. IN UINT uMsg,
  219. IN LPARAM lparam)
  220. {
  221. switch (uMsg)
  222. {
  223. case PSCB_INITIALIZED:
  224. // Set the dialog window's icon
  225. // NTRAID#NTBUG9-366302-2001/04/11-roelfc Alt-tab icon
  226. // This requires a re-architecture in order to be able to retrieve
  227. // the appropiate icon for the property page through the
  228. // IID_INetConnectionPropertyUi2 interface.
  229. // In the mean time, we query the small icon through the only link we have,
  230. // the dialog handle, and assign it as the big icon as well. Stretching the
  231. // small icon is better than nothing at all...
  232. HICON hIcon;
  233. hIcon = (HICON)SendMessage(hwndDlg,
  234. WM_GETICON,
  235. ICON_SMALL,
  236. 0);
  237. Assert(hIcon);
  238. if (hIcon)
  239. {
  240. SendMessage(hwndDlg,
  241. WM_SETICON,
  242. ICON_BIG,
  243. (LPARAM)hIcon);
  244. }
  245. break;
  246. default:
  247. break;
  248. }
  249. return 0;
  250. }
  251. //+---------------------------------------------------------------------------
  252. //
  253. // Function: HrRaiseConnectionPropertiesInternal
  254. //
  255. // Purpose: Bring up the propsheet page UI for the passed in connection
  256. //
  257. // Arguments:
  258. // hwnd [in] Owner hwnd
  259. // pconn [in] Connection pointer passed in from the shell
  260. //
  261. // Returns:
  262. //
  263. // Author: jeffspr 12 Nov 1997
  264. //
  265. // Notes:
  266. //
  267. HRESULT HrRaiseConnectionPropertiesInternal(HWND hwnd, UINT nStartPage, INetConnection * pconn)
  268. {
  269. HRESULT hr = NOERROR;
  270. INetConnectionPropertyUi * pPUI = NULL;
  271. PWSTR pszCaption = NULL;
  272. Assert(pconn);
  273. hr = HrUIInterfaceFromNetCon(pconn, IID_INetConnectionPropertyUi,
  274. reinterpret_cast<void**>(&pPUI));
  275. if (E_NOINTERFACE == hr)
  276. {
  277. // What we want to check for here, is an object that when QI'd doesn't support IID_INetConnectionPropertyUi
  278. // but support IID_INetConnectionPropertyUi2.
  279. //
  280. // A reinterpret style-downcast directly from the QI would have been ok since INetConnectionPropertyUi2 inherit from
  281. // INetConnectionPropertyUi. Hence an object can't multi-inherit from both, so we'll never have both vtable entries.
  282. // We could simply get the INetConnectionPropertyUi2 vtable entry and treat it like an INetConnectionPropertyUi.
  283. //
  284. // However, I'm doing the dynamic cast anyway since a cast-to-wrong-vtable is one of the most difficult
  285. // bugs to spot.
  286. INetConnectionPropertyUi2 *pPUI2 = NULL;
  287. hr = HrUIInterfaceFromNetCon(pconn, IID_INetConnectionPropertyUi2,
  288. reinterpret_cast<void**>(&pPUI2));
  289. if (SUCCEEDED(hr))
  290. {
  291. pPUI = dynamic_cast<INetConnectionPropertyUi *>(pPUI2);
  292. }
  293. }
  294. if (SUCCEEDED(hr))
  295. {
  296. INetConnectionUiLock * pUiLock = NULL;
  297. // Try to get the connection name
  298. //
  299. (VOID)HrGetPropertiesCaption(pconn, &pszCaption);
  300. Assert(pPUI);
  301. hr = pPUI->QueryInterface(IID_INetConnectionUiLock, (LPVOID *)&pUiLock);
  302. if (SUCCEEDED(hr))
  303. {
  304. // If the interface exists, we have work to do.
  305. PWSTR pszwMsg = NULL;
  306. hr = pUiLock->QueryLock(&pszwMsg);
  307. ReleaseObj(pUiLock);
  308. if (S_FALSE == hr)
  309. {
  310. // Format the error text
  311. //
  312. PWSTR pszText = NULL;
  313. PCWSTR pcszwTemp = pszwMsg;
  314. if (NULL == pcszwTemp)
  315. {
  316. // Load <Unknown Application>
  317. //
  318. pcszwTemp = SzLoadIds(IDS_CONPROP_GENERIC_COMP);
  319. }
  320. Assert(pcszwTemp);
  321. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  322. FORMAT_MESSAGE_FROM_STRING |
  323. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  324. SzLoadIds(IDS_CONPROP_NO_WRITE_LOCK),
  325. 0, 0, (PWSTR)&pszText, 0,
  326. (va_list *)&pcszwTemp);
  327. if (pszwMsg)
  328. {
  329. CoTaskMemFree(pszwMsg);
  330. }
  331. // No UI, couldn't acquire the lock
  332. //
  333. if (pszText)
  334. {
  335. MessageBox(hwnd, pszText,
  336. (pszCaption ? pszCaption : c_szEmpty),
  337. MB_OK | MB_ICONERROR);
  338. LocalFree(pszText);
  339. }
  340. goto Error;
  341. }
  342. else if (FAILED(hr))
  343. {
  344. goto Error;
  345. }
  346. }
  347. BOOL fShouldDestroyIcon = FALSE;
  348. hr = pPUI->SetConnection(pconn);
  349. if (SUCCEEDED(hr))
  350. {
  351. CComPtr<INetConnectionPropertyUi2> pUI2;
  352. HICON hIcon = NULL;
  353. DWORD dwDisplayIcon = 0;
  354. hr = pPUI->QueryInterface(IID_INetConnectionPropertyUi2, reinterpret_cast<LPVOID *>(&pUI2) );
  355. if (SUCCEEDED(hr))
  356. {
  357. Assert(GetSystemMetrics(SM_CXSMICON) == GetSystemMetrics(SM_CYSMICON));
  358. hr = pUI2->GetIcon(GetSystemMetrics(SM_CXSMICON), &hIcon);
  359. if (SUCCEEDED(hr))
  360. {
  361. fShouldDestroyIcon = TRUE;
  362. dwDisplayIcon = PSH_USEHICON;
  363. }
  364. else
  365. {
  366. hIcon = NULL;
  367. }
  368. }
  369. else
  370. {
  371. TraceTag(ttidError, "QI for INetConnectionPropertyUi2 failed using Default Icon");
  372. hIcon = LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_CONNECTIONS_FOLDER_LARGE2));
  373. if (hIcon)
  374. {
  375. dwDisplayIcon = PSH_USEHICON;
  376. }
  377. }
  378. Assert(hIcon);
  379. CConnectionPropPages CPP;
  380. // Get the pages from the provider
  381. hr = pPUI->AddPages(hwnd,
  382. CConnectionPropPages::FAddPropSheet,
  383. reinterpret_cast<LPARAM>(&CPP));
  384. // If any pages were returned, display them
  385. if (SUCCEEDED(hr) && CPP.CntPages())
  386. {
  387. PROPSHEETHEADER psh;
  388. ZeroMemory (&psh, sizeof(psh));
  389. psh.dwSize = sizeof( PROPSHEETHEADER );
  390. psh.dwFlags = PSH_NOAPPLYNOW | PSH_USECALLBACK | dwDisplayIcon;
  391. psh.hwndParent = hwnd;
  392. psh.hInstance = _Module.GetResourceInstance();
  393. psh.pszCaption = pszCaption;
  394. psh.nPages = CPP.CntPages();
  395. psh.phpage = CPP.PHPages();
  396. psh.hIcon = hIcon;
  397. psh.nStartPage = nStartPage;
  398. psh.pfnCallback = HrSetPropertiesTaskbarIcon;
  399. // nRet used for debugging only
  400. //
  401. int nRet = PropertySheet(&psh);
  402. if (fShouldDestroyIcon)
  403. {
  404. DestroyIcon(hIcon);
  405. }
  406. }
  407. }
  408. Error:
  409. ReleaseObj(pPUI);
  410. }
  411. // Cleanup
  412. //
  413. if (pszCaption)
  414. {
  415. LocalFree (pszCaption);
  416. }
  417. TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrRaiseConnectionProperties");
  418. return hr;
  419. }
  420. //+---------------------------------------------------------------------------
  421. //
  422. // Function: HrHandleDisconnectHResult
  423. //
  424. // Purpose: Put up the message box assocated with an HRESULT from
  425. // a diconnect operation if the HRESULT represents a failure.
  426. // Also translate any success codes back to S_OK as needed.
  427. //
  428. // Arguments:
  429. // hr [in] The HRESULT returned from a connection disconnect method.
  430. // pconn [in] INetConnection* for checking if this is a LAN or RAS connection.
  431. //
  432. // Returns: The translated HRESULT if needed
  433. //
  434. // Author: shaunco 3 Jun 1999
  435. //
  436. HRESULT HrHandleDisconnectHResult(HRESULT hr, INetConnection * pconn)
  437. {
  438. if (FAILED(hr))
  439. {
  440. NETCON_PROPERTIES* pProps = NULL;
  441. UINT nFailureCaptionID;
  442. UINT nFailureMessageID;
  443. TraceHr(ttidShellFolder, FAL, hr, FALSE, "pNetCon->Disconnect() failed");
  444. // Assume that is is a RAS/DIALUP connection unless we find otherwise
  445. nFailureCaptionID = IDS_CONFOLD_DISCONNECT_FAILURE_CAPTION;
  446. nFailureMessageID = IDS_CONFOLD_DISCONNECT_FAILURE;
  447. hr = pconn->GetProperties(&pProps);
  448. if (SUCCEEDED(hr))
  449. {
  450. if (NCM_LAN == pProps->MediaType)
  451. {
  452. nFailureCaptionID = IDS_CONFOLD_DISABLE_FAILURE_CAPTION;
  453. nFailureMessageID = IDS_CONFOLD_DISABLE_FAILURE;
  454. }
  455. FreeNetconProperties(pProps);
  456. }
  457. // Ignore the return from this, since we only allow OK
  458. //
  459. (void) NcMsgBox(
  460. _Module.GetResourceInstance(),
  461. NULL,
  462. nFailureCaptionID,
  463. nFailureMessageID,
  464. MB_OK | MB_ICONEXCLAMATION);
  465. }
  466. else
  467. {
  468. // If we get the object_nlv return, it means that the connection
  469. // is deleted on disconnect and we shouldn't perform an update of
  470. // that connection. We can normalize this for now, as we'll let the
  471. // notifysink take care of the delete update.
  472. //
  473. if (S_OBJECT_NO_LONGER_VALID == hr)
  474. {
  475. hr = S_OK;
  476. }
  477. }
  478. return hr;
  479. }
  480. //+---------------------------------------------------------------------------
  481. //
  482. // Function: HrConnectOrDisconnectNetConObject
  483. //
  484. // Purpose: Bring up the connection UI and make the connection for the
  485. // passed in connection.
  486. //
  487. // Arguments:
  488. // hwnd [in] Owner hwnd
  489. // pconn [in] Connection pointer passed in from the shell
  490. // Flag [in] CD_CONNECT or CD_DISCONNECT.
  491. //
  492. // Returns:
  493. //
  494. // Author: jeffspr 12 Nov 1997
  495. //
  496. // Notes:
  497. //
  498. HRESULT HrConnectOrDisconnectNetConObject(HWND hwnd, INetConnection * pconn,
  499. CDFLAG Flag)
  500. {
  501. HRESULT hr = NOERROR;
  502. INetConnectionConnectUi * pCUI = NULL;
  503. Assert(pconn);
  504. // Get the INetConnectionConnectUi interface from the connection
  505. //
  506. hr = HrUIInterfaceFromNetCon(pconn, IID_INetConnectionConnectUi,
  507. reinterpret_cast<void**>(&pCUI));
  508. if (SUCCEEDED(hr))
  509. {
  510. Assert(pCUI);
  511. // Set the connection on the UI object
  512. //
  513. hr = pCUI->SetConnection(pconn);
  514. if (SUCCEEDED(hr))
  515. {
  516. if (CD_CONNECT == Flag)
  517. {
  518. // Connect, dangit!
  519. //
  520. hr = pCUI->Connect(hwnd, NCUC_DEFAULT);
  521. if (SUCCEEDED(hr))
  522. {
  523. // heh heh, uhhhh, heh heh. Cool.
  524. }
  525. else if (HRESULT_FROM_WIN32(ERROR_NOT_CONNECTED) == hr)
  526. {
  527. // Ignore the return from this, since we only allow OK
  528. //
  529. (void) NcMsgBox(
  530. _Module.GetResourceInstance(),
  531. hwnd,
  532. IDS_CONFOLD_CONNECT_FAILURE_CAPTION,
  533. IDS_CONFOLD_CONNECT_FAILURE,
  534. MB_OK | MB_ICONEXCLAMATION);
  535. }
  536. }
  537. else
  538. {
  539. // Disconnect the connection object
  540. //
  541. hr = pCUI->Disconnect(hwnd, NCUC_DEFAULT);
  542. hr = HrHandleDisconnectHResult(hr, pconn);
  543. }
  544. }
  545. ReleaseObj(pCUI);
  546. }
  547. else if ((E_NOINTERFACE == hr) && (CD_DISCONNECT == Flag))
  548. {
  549. // Incoming connection objects do not have a UI interface
  550. // so we disconect them on the object itself.
  551. //
  552. hr = pconn->Disconnect ();
  553. hr = HrHandleDisconnectHResult(hr, pconn);
  554. }
  555. AssertSz(E_NOINTERFACE != hr,
  556. "Should not have been able to attempt connection on object that doesn't support this interface");
  557. TraceHr(ttidShellFolder, FAL, hr, (E_NOINTERFACE == hr),
  558. "HrConnectOrDisconnectNetConObject");
  559. return hr;
  560. }