windows-nt/Source/XPSP1/NT/net/config/shell/folder/conprops.cpp
2020-09-26 16:20:57 +08:00

648 lines
18 KiB
C++

#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<CConnectionPropPages*>(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<void**>(&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<void**>(&pPUI2));
if (SUCCEEDED(hr))
{
pPUI = dynamic_cast<INetConnectionPropertyUi *>(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 <Unknown Application>
//
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<INetConnectionPropertyUi2> pUI2;
HICON hIcon = NULL;
DWORD dwDisplayIcon = 0;
hr = pPUI->QueryInterface(IID_INetConnectionPropertyUi2, reinterpret_cast<LPVOID *>(&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<LPARAM>(&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<void**>(&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;
}