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.
651 lines
19 KiB
651 lines
19 KiB
#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() throw();
|
|
~CConnectionPropPages() throw();
|
|
ULONG CntPages() throw() {return m_culPages;}
|
|
HPROPSHEETPAGE * PHPages() throw() {return m_rghPages;}
|
|
static BOOL FAddPropSheet(HPROPSHEETPAGE hPage, LPARAM lParam) throw();
|
|
|
|
private:
|
|
ULONG m_culPages;
|
|
ULONG m_ulPageBufferLen;
|
|
HPROPSHEETPAGE * m_rghPages;
|
|
};
|
|
|
|
CConnectionPropPages::CConnectionPropPages() throw()
|
|
{
|
|
m_culPages = 0;
|
|
m_ulPageBufferLen = 0;
|
|
m_rghPages = NULL;
|
|
}
|
|
|
|
CConnectionPropPages::~CConnectionPropPages() throw()
|
|
{
|
|
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(IN HPROPSHEETPAGE hPage, IN LPARAM lParam) throw()
|
|
{
|
|
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(
|
|
IN INetConnection * pconn,
|
|
IN REFIID riid,
|
|
OUT 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(IN INetConnection * pconn,
|
|
OUT 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(IN INetConnection * pconn) throw()
|
|
{
|
|
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(IN HWND hwnd,
|
|
IN UINT nStartPage,
|
|
IN 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_PTR 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(IN HRESULT hr, IN 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(IN HWND hwnd,
|
|
IN INetConnection * pconn,
|
|
IN 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;
|
|
}
|
|
|
|
|