#include "pch.h" #pragma hdrstop #include "foldinc.h" // Standard shell\folder includes #include "conprops.h" #include "ncnetcon.h" #include "foldres.h" class CConnectionPropPages { public: CConnectionPropPages(); ~CConnectionPropPages(); ULONG CntPages() {return m_culPages;} HPROPSHEETPAGE * PHPages() {return m_rghPages;} static BOOL FAddPropSheet(HPROPSHEETPAGE hPage, LPARAM lParam); private: ULONG m_culPages; ULONG m_ulPageBufferLen; HPROPSHEETPAGE * m_rghPages; }; CConnectionPropPages::CConnectionPropPages() { m_culPages = 0; m_ulPageBufferLen = 0; m_rghPages = NULL; } CConnectionPropPages::~CConnectionPropPages() { delete [] (BYTE *)(m_rghPages); } // // Function: CConnectionPropPages::FAddPropSheet // // Purpose: Callback function for the AddPages API used to accept // connection property pages handed back from a provider. // // Parameters: hPage [IN] - The page to add // lParam [IN] - 'this' casted to an LPARAM // // Returns: BOOL, TRUE if the page was successfully added. // BOOL CConnectionPropPages::FAddPropSheet(HPROPSHEETPAGE hPage, LPARAM lParam) { CConnectionPropPages * pCPP = NULL; // Validate the input parameters // if ((0L == lParam) || (NULL == hPage)) { Assert(lParam); Assert(hPage); TraceHr(ttidShellFolder, FAL, E_INVALIDARG, FALSE, "CConnectionPropPages::FAddPropSheet"); return FALSE; } pCPP = reinterpret_cast(lParam); // Grow the buffer if necessary // if (pCPP->m_culPages == pCPP->m_ulPageBufferLen) { HPROPSHEETPAGE* rghPages = NULL; rghPages = (HPROPSHEETPAGE*)(new BYTE[sizeof(HPROPSHEETPAGE) * (pCPP->m_ulPageBufferLen + 10)]); if (NULL == rghPages) { TraceHr(ttidShellFolder, FAL, E_OUTOFMEMORY, FALSE, "CConnectionPropPages::FAddPropSheet"); return FALSE; } // Copy the existing pages to the new buffer // memcpy(rghPages, pCPP->m_rghPages, sizeof(HPROPSHEETPAGE) * pCPP->m_ulPageBufferLen); delete [] (BYTE *)(pCPP->m_rghPages); pCPP->m_rghPages = rghPages; pCPP->m_ulPageBufferLen += 10; } // Retain the new page // pCPP->m_rghPages[pCPP->m_culPages++] = hPage; return TRUE; } //+--------------------------------------------------------------------------- // // Function: HrUIInterfaceFromNetCon // // Purpose: Get the INetConnectionPropertyUI interface from an // INetConnection pointer. // // Arguments: // pconn [in] Valid INetConnection * // riid [in] IID of desired interface // ppv [out] Returned pointer to the interface // // Returns: // // Author: jeffspr 12 Nov 1997 // // Notes: // HRESULT HrUIInterfaceFromNetCon( INetConnection * pconn, REFIID riid, LPVOID * ppv) { HRESULT hr = S_OK; CLSID clsid; Assert(pconn); Assert(ppv); // Validate the parameters. // if ((NULL == pconn) || (NULL == ppv)) { hr = E_INVALIDARG; goto Error; } // Initailize the output parameter. // *ppv = NULL; // Get the CLSID of the object which can provide the particular interface. // hr = pconn->GetUiObjectClassId(&clsid); if (FAILED(hr)) { goto Error; } // Create this object asking for the specified interface. // hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER | CLSCTX_NO_CODE_DOWNLOAD, riid, ppv); Error: TraceHr(ttidError, FAL, hr, (E_NOINTERFACE == hr), "HrUIInterfaceFromNetCon"); return hr; } //+--------------------------------------------------------------------------- // // Function: HrGetPropertiesCaption // // Purpose: Generate the caption for a property page // // Arguments: // pconn [in] Connection pointer passed in from the shell // ppszCaption [out] Resultant property page caption if successful // // Returns: // // Notes: // HRESULT HrGetPropertiesCaption(INetConnection * pconn, PWSTR * ppszCaption) { HRESULT hr; Assert(pconn); Assert(ppszCaption); // Try to get the connection name // NETCON_PROPERTIES* pProps; hr = pconn->GetProperties(&pProps); if (SUCCEEDED(hr)) { Assert (pProps->pszwName); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, SzLoadIds(IDS_CONPROP_CAPTION), 0, 0, (PWSTR)ppszCaption, 0, (va_list *)&pProps->pszwName); FreeNetconProperties(pProps); } TraceHr(ttidError, FAL, hr, FALSE,"HrGetPropertiesCaption"); return hr; } //+--------------------------------------------------------------------------- // // Function: ActivatePropertyDialog // // Purpose: Try to locate a property dialog associated with pconn // then bring it to the foreground. // // Arguments: // pconn [in] Connection pointer passed in from the shell // // Returns: // // Notes: // VOID ActivatePropertyDialog(INetConnection * pconn) { PWSTR pszCaption = NULL; if (SUCCEEDED(HrGetPropertiesCaption(pconn, &pszCaption))) { Assert(pszCaption); // Find the dialog with this caption // HWND hwnd = FindWindow(NULL, pszCaption); if (IsWindow(hwnd)) { SetForegroundWindow(hwnd); } LocalFree (pszCaption); } } //+--------------------------------------------------------------------------- // // Function: HrSetPropertiesTaskbarIcon // // Purpose: Setup the dialog property sheet's taskbar icon. // // Arguments: // hwndDlg [in] Dialog handle // uMsg [in] Message value // lparam [in] Long parameter // // Returns: 0 // // Notes: A standard Win32 commctrl PropSheetProc always return 0. // See MSDN documentation. // int CALLBACK HrSetPropertiesTaskbarIcon( IN HWND hwndDlg, IN UINT uMsg, IN LPARAM lparam) { switch (uMsg) { case PSCB_INITIALIZED: // Set the dialog window's icon // NTRAID#NTBUG9-366302-2001/04/11-roelfc Alt-tab icon // This requires a re-architecture in order to be able to retrieve // the appropiate icon for the property page through the // IID_INetConnectionPropertyUi2 interface. // In the mean time, we query the small icon through the only link we have, // the dialog handle, and assign it as the big icon as well. Stretching the // small icon is better than nothing at all... HICON hIcon; hIcon = (HICON)SendMessage(hwndDlg, WM_GETICON, ICON_SMALL, 0); Assert(hIcon); if (hIcon) { SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon); } break; default: break; } return 0; } //+--------------------------------------------------------------------------- // // Function: HrRaiseConnectionPropertiesInternal // // Purpose: Bring up the propsheet page UI for the passed in connection // // Arguments: // hwnd [in] Owner hwnd // pconn [in] Connection pointer passed in from the shell // // Returns: // // Author: jeffspr 12 Nov 1997 // // Notes: // HRESULT HrRaiseConnectionPropertiesInternal(HWND hwnd, UINT nStartPage, INetConnection * pconn) { HRESULT hr = NOERROR; INetConnectionPropertyUi * pPUI = NULL; PWSTR pszCaption = NULL; Assert(pconn); hr = HrUIInterfaceFromNetCon(pconn, IID_INetConnectionPropertyUi, reinterpret_cast(&pPUI)); if (E_NOINTERFACE == hr) { // What we want to check for here, is an object that when QI'd doesn't support IID_INetConnectionPropertyUi // but support IID_INetConnectionPropertyUi2. // // A reinterpret style-downcast directly from the QI would have been ok since INetConnectionPropertyUi2 inherit from // INetConnectionPropertyUi. Hence an object can't multi-inherit from both, so we'll never have both vtable entries. // We could simply get the INetConnectionPropertyUi2 vtable entry and treat it like an INetConnectionPropertyUi. // // However, I'm doing the dynamic cast anyway since a cast-to-wrong-vtable is one of the most difficult // bugs to spot. INetConnectionPropertyUi2 *pPUI2 = NULL; hr = HrUIInterfaceFromNetCon(pconn, IID_INetConnectionPropertyUi2, reinterpret_cast(&pPUI2)); if (SUCCEEDED(hr)) { pPUI = dynamic_cast(pPUI2); } } if (SUCCEEDED(hr)) { INetConnectionUiLock * pUiLock = NULL; // Try to get the connection name // (VOID)HrGetPropertiesCaption(pconn, &pszCaption); Assert(pPUI); hr = pPUI->QueryInterface(IID_INetConnectionUiLock, (LPVOID *)&pUiLock); if (SUCCEEDED(hr)) { // If the interface exists, we have work to do. PWSTR pszwMsg = NULL; hr = pUiLock->QueryLock(&pszwMsg); ReleaseObj(pUiLock); if (S_FALSE == hr) { // Format the error text // PWSTR pszText = NULL; PCWSTR pcszwTemp = pszwMsg; if (NULL == pcszwTemp) { // Load // pcszwTemp = SzLoadIds(IDS_CONPROP_GENERIC_COMP); } Assert(pcszwTemp); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, SzLoadIds(IDS_CONPROP_NO_WRITE_LOCK), 0, 0, (PWSTR)&pszText, 0, (va_list *)&pcszwTemp); if (pszwMsg) { CoTaskMemFree(pszwMsg); } // No UI, couldn't acquire the lock // if (pszText) { MessageBox(hwnd, pszText, (pszCaption ? pszCaption : c_szEmpty), MB_OK | MB_ICONERROR); LocalFree(pszText); } goto Error; } else if (FAILED(hr)) { goto Error; } } BOOL fShouldDestroyIcon = FALSE; hr = pPUI->SetConnection(pconn); if (SUCCEEDED(hr)) { CComPtr pUI2; HICON hIcon = NULL; DWORD dwDisplayIcon = 0; hr = pPUI->QueryInterface(IID_INetConnectionPropertyUi2, reinterpret_cast(&pUI2) ); if (SUCCEEDED(hr)) { Assert(GetSystemMetrics(SM_CXSMICON) == GetSystemMetrics(SM_CYSMICON)); hr = pUI2->GetIcon(GetSystemMetrics(SM_CXSMICON), &hIcon); if (SUCCEEDED(hr)) { fShouldDestroyIcon = TRUE; dwDisplayIcon = PSH_USEHICON; } else { hIcon = NULL; } } else { TraceTag(ttidError, "QI for INetConnectionPropertyUi2 failed using Default Icon"); hIcon = LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_CONNECTIONS_FOLDER_LARGE2)); if (hIcon) { dwDisplayIcon = PSH_USEHICON; } } Assert(hIcon); CConnectionPropPages CPP; // Get the pages from the provider hr = pPUI->AddPages(hwnd, CConnectionPropPages::FAddPropSheet, reinterpret_cast(&CPP)); // If any pages were returned, display them if (SUCCEEDED(hr) && CPP.CntPages()) { PROPSHEETHEADER psh; ZeroMemory (&psh, sizeof(psh)); psh.dwSize = sizeof( PROPSHEETHEADER ); psh.dwFlags = PSH_NOAPPLYNOW | PSH_USECALLBACK | dwDisplayIcon; psh.hwndParent = hwnd; psh.hInstance = _Module.GetResourceInstance(); psh.pszCaption = pszCaption; psh.nPages = CPP.CntPages(); psh.phpage = CPP.PHPages(); psh.hIcon = hIcon; psh.nStartPage = nStartPage; psh.pfnCallback = HrSetPropertiesTaskbarIcon; // nRet used for debugging only // int nRet = PropertySheet(&psh); if (fShouldDestroyIcon) { DestroyIcon(hIcon); } } } Error: ReleaseObj(pPUI); } // Cleanup // if (pszCaption) { LocalFree (pszCaption); } TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrRaiseConnectionProperties"); return hr; } //+--------------------------------------------------------------------------- // // Function: HrHandleDisconnectHResult // // Purpose: Put up the message box assocated with an HRESULT from // a diconnect operation if the HRESULT represents a failure. // Also translate any success codes back to S_OK as needed. // // Arguments: // hr [in] The HRESULT returned from a connection disconnect method. // pconn [in] INetConnection* for checking if this is a LAN or RAS connection. // // Returns: The translated HRESULT if needed // // Author: shaunco 3 Jun 1999 // HRESULT HrHandleDisconnectHResult(HRESULT hr, INetConnection * pconn) { if (FAILED(hr)) { NETCON_PROPERTIES* pProps = NULL; UINT nFailureCaptionID; UINT nFailureMessageID; TraceHr(ttidShellFolder, FAL, hr, FALSE, "pNetCon->Disconnect() failed"); // Assume that is is a RAS/DIALUP connection unless we find otherwise nFailureCaptionID = IDS_CONFOLD_DISCONNECT_FAILURE_CAPTION; nFailureMessageID = IDS_CONFOLD_DISCONNECT_FAILURE; hr = pconn->GetProperties(&pProps); if (SUCCEEDED(hr)) { if (NCM_LAN == pProps->MediaType) { nFailureCaptionID = IDS_CONFOLD_DISABLE_FAILURE_CAPTION; nFailureMessageID = IDS_CONFOLD_DISABLE_FAILURE; } FreeNetconProperties(pProps); } // Ignore the return from this, since we only allow OK // (void) NcMsgBox( _Module.GetResourceInstance(), NULL, nFailureCaptionID, nFailureMessageID, MB_OK | MB_ICONEXCLAMATION); } else { // If we get the object_nlv return, it means that the connection // is deleted on disconnect and we shouldn't perform an update of // that connection. We can normalize this for now, as we'll let the // notifysink take care of the delete update. // if (S_OBJECT_NO_LONGER_VALID == hr) { hr = S_OK; } } return hr; } //+--------------------------------------------------------------------------- // // Function: HrConnectOrDisconnectNetConObject // // Purpose: Bring up the connection UI and make the connection for the // passed in connection. // // Arguments: // hwnd [in] Owner hwnd // pconn [in] Connection pointer passed in from the shell // Flag [in] CD_CONNECT or CD_DISCONNECT. // // Returns: // // Author: jeffspr 12 Nov 1997 // // Notes: // HRESULT HrConnectOrDisconnectNetConObject(HWND hwnd, INetConnection * pconn, CDFLAG Flag) { HRESULT hr = NOERROR; INetConnectionConnectUi * pCUI = NULL; Assert(pconn); // Get the INetConnectionConnectUi interface from the connection // hr = HrUIInterfaceFromNetCon(pconn, IID_INetConnectionConnectUi, reinterpret_cast(&pCUI)); if (SUCCEEDED(hr)) { Assert(pCUI); // Set the connection on the UI object // hr = pCUI->SetConnection(pconn); if (SUCCEEDED(hr)) { if (CD_CONNECT == Flag) { // Connect, dangit! // hr = pCUI->Connect(hwnd, NCUC_DEFAULT); if (SUCCEEDED(hr)) { // heh heh, uhhhh, heh heh. Cool. } else if (HRESULT_FROM_WIN32(ERROR_NOT_CONNECTED) == hr) { // Ignore the return from this, since we only allow OK // (void) NcMsgBox( _Module.GetResourceInstance(), hwnd, IDS_CONFOLD_CONNECT_FAILURE_CAPTION, IDS_CONFOLD_CONNECT_FAILURE, MB_OK | MB_ICONEXCLAMATION); } } else { // Disconnect the connection object // hr = pCUI->Disconnect(hwnd, NCUC_DEFAULT); hr = HrHandleDisconnectHResult(hr, pconn); } } ReleaseObj(pCUI); } else if ((E_NOINTERFACE == hr) && (CD_DISCONNECT == Flag)) { // Incoming connection objects do not have a UI interface // so we disconect them on the object itself. // hr = pconn->Disconnect (); hr = HrHandleDisconnectHResult(hr, pconn); } AssertSz(E_NOINTERFACE != hr, "Should not have been able to attempt connection on object that doesn't support this interface"); TraceHr(ttidShellFolder, FAL, hr, (E_NOINTERFACE == hr), "HrConnectOrDisconnectNetConObject"); return hr; }