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.
 
 
 
 
 
 

3180 lines
98 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: O N C O M M A N D . C P P
//
// Contents: Command handlers for the context menus, etc.
//
// Notes:
//
// Author: jeffspr 4 Nov 1997
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "foldinc.h" // Standard shell\folder includes
#include "advcfg.h"
#include "conprops.h"
#include "foldres.h"
#include "oncommand.h"
#if DBG // Debug menu commands
#include "oncommand_dbg.h" //
#endif
#include "shutil.h"
#include "ncras.h"
#include "traymsgs.h"
#include <ncnetcon.h>
#include <nsres.h>
#include <wizentry.h>
#include "disconnect.h"
#include "ncperms.h"
#include "smcent.h"
#include "cfutils.h"
#include "HNetCfg.h"
#include "..\lanui\lanui.h"
#include "repair.h"
#include "iconhandler.h"
#include "wzcdlg.h"
//---[ Externs ]--------------------------------------------------------------
extern HWND g_hwndTray;
extern const WCHAR c_szNetShellDll[];
//---[ Constants ]------------------------------------------------------------
// Command-line for the control-panel applet.
//
static const WCHAR c_szRunDll32[] = L"rundll32.exe";
static const WCHAR c_szNetworkIdCmdLine[] = L"shell32.dll,Control_RunDLL sysdm.cpl,,1";
//---[ Local functions ]------------------------------------------------------
// None
class CCommandHandlerParams
{
public:
const PCONFOLDPIDLVEC* apidl;
HWND hwndOwner;
LPSHELLFOLDER psf;
UINT_PTR nAdditionalParam;
} ;
HRESULT HrCommandHandlerThread(
FOLDERONCOMMANDPROC pfnCommandHandler,
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
PCONFOLDPIDLVEC apidlCopy;
// If there are pidls to copy, copy them
//
if (!apidl.empty())
{
hr = HrCloneRgIDL(apidl, FALSE, TRUE, apidlCopy);
}
// If either there were no pidls, or the Clone succeeded, then we want to continue
//
if (SUCCEEDED(hr))
{
PCONFOLDONCOMMANDPARAMS pcfocp = new CONFOLDONCOMMANDPARAMS;
if (pcfocp)
{
pcfocp->pfnfocp = pfnCommandHandler;
pcfocp->apidl = apidlCopy;
pcfocp->hwndOwner = hwndOwner;
pcfocp->psf = psf;
pcfocp->hInstNetShell = NULL;
// This should be Release'd in the thread called.
//
psf->AddRef();
// This will always succeed in retail, but will test the flag in debug
//
if (!FIsDebugFlagSet (dfidDisableShellThreading))
{
// Run in a thread using the QueueUserWorkItem
//
HANDLE hthrd = NULL;
HINSTANCE hInstNetShell = LoadLibrary(c_szNetShellDll);
if (hInstNetShell)
{
pcfocp->hInstNetShell = hInstNetShell;
DWORD dwThreadId;
hthrd = CreateThread(NULL, STACK_SIZE_DEFAULT,
(LPTHREAD_START_ROUTINE)FolderCommandHandlerThreadProc,
(LPVOID)pcfocp, 0, &dwThreadId);
}
if (NULL != hthrd)
{
CloseHandle(hthrd);
}
else
{
pcfocp->hInstNetShell = NULL;
FolderCommandHandlerThreadProc(pcfocp);
}
}
else
{
// Run directly in this same thread
//
FolderCommandHandlerThreadProc((PVOID) pcfocp);
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
// Don't release the psf here. This should have been taken care of by the called ThreadProc
//
return hr;
}
DWORD WINAPI FolderCommandHandlerThreadProc(LPVOID lpParam)
{
HRESULT hr = S_OK;
PCONFOLDONCOMMANDPARAMS pcfocp = (PCONFOLDONCOMMANDPARAMS) lpParam;
BOOL fCoInited = FALSE;
IUnknown * punkExplorerProcess = NULL;
Assert(pcfocp);
SHGetInstanceExplorer(&punkExplorerProcess);
hr = CoInitializeEx (NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED);
if (SUCCEEDED(hr))
{
// We don't care if this is S_FALSE or not, since we'll soon
// overwrite the hr. If it's already initialized, great...
fCoInited = TRUE;
// Call the specific handler
//
hr = pcfocp->pfnfocp(
pcfocp->apidl,
pcfocp->hwndOwner,
pcfocp->psf);
}
// Remove the ref that we have on this object. The thread handler would have addref'd
// this before queueing our action
//
if (pcfocp->psf)
{
ReleaseObj(pcfocp->psf);
}
// Remove this object. We're responsible for this now.
//
HINSTANCE hInstNetShell = pcfocp->hInstNetShell;
pcfocp->hInstNetShell = NULL;
delete pcfocp;
if (fCoInited)
{
CoUninitialize();
}
::ReleaseObj(punkExplorerProcess);
if (hInstNetShell)
FreeLibraryAndExitThread(hInstNetShell, hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrCommandHomeNetWizard
//
// Purpose: Command handler to start the home networking wizard
//
// Arguments: none
//
// Returns: S_OK if succeeded
// E_FAIL otherwise
//
// Author: deonb 10 Feb 2001
//
// Notes:
//
HRESULT HrCommandHomeNetWizard()
{
// ShellExecute returns <32 if an error
if (ShellExecute(NULL, NULL, L"rundll32.exe", L"hnetwiz.dll,HomeNetWizardRunDll", NULL, SW_SHOWNORMAL) > reinterpret_cast<HINSTANCE>(32))
{
return S_OK;
}
else
{
return E_FAIL;
}
}
//
//
//
LONG
TotalValidSelectedConnectionsForBridge(
IN const PCONFOLDPIDLVEC& apidlSelected
)
{
int nTotalValidCandidateForBridge = 0;
//
// Loop through each of the selected objects
//
for ( PCONFOLDPIDLVEC::const_iterator iterObjectLoop = apidlSelected.begin(); iterObjectLoop != apidlSelected.end(); iterObjectLoop++ )
{
// Validate the pidls
//
const PCONFOLDPIDL& pcfp = *iterObjectLoop;
if ( !pcfp.empty() )
{
//
// needs to be a LAN Adapter and NOT (Firewalled/Shared or Bridge)
//
if ( (NCM_LAN == pcfp->ncm) )
if ( !( (NCCF_BRIDGED|NCCF_FIREWALLED|NCCF_SHARED) & pcfp->dwCharacteristics ) )
{
//
// Ok we have a winner it's a nice clean adapter
//
nTotalValidCandidateForBridge ++;
}
}
}
return nTotalValidCandidateForBridge;
}
//+---------------------------------------------------------------------------
//
// Function: HrCommandNetworkDiagnostics
//
// Purpose: Command handler to start the Network Diagnostics page
//
// Arguments: none
//
// Returns: S_OK if succeeded
// E_FAIL otherwise
//
// Author: deonb 10 Feb 2001
//
// Notes:
//
HRESULT HrCommandNetworkDiagnostics()
{
// ShellExecute returns <32 if an error
if (ShellExecute(NULL, NULL, L"hcp://system/netdiag/dglogs.htm", L"", NULL, SW_SHOWNORMAL) > reinterpret_cast<HINSTANCE>(32))
{
return S_OK;
}
else
{
return E_FAIL;
}
}
//+---------------------------------------------------------------------------
//
// Function: HrCommandNetworkTroubleShoot
//
// Purpose: Command handler to start the Network Troubleshooter page
//
// Arguments: none
//
// Returns: S_OK if succeeded
// E_FAIL otherwise
//
// Author: deonb 4 April 2001
//
// Notes:
//
HRESULT HrCommandNetworkTroubleShoot()
{
// ShellExecute returns <32 if an error
if (ShellExecute(NULL, NULL, L"hcp://system/panels/Topics.htm?path=TopLevelBucket_4/Fixing_a_problem/Home_Networking_and_network_problems", L"", NULL, SW_SHOWNORMAL) > reinterpret_cast<HINSTANCE>(32))
{
return S_OK;
}
else
{
return E_FAIL;
}
}
//+---------------------------------------------------------------------------
//
// Function: HrFolderCommandHandler
//
// Purpose: Command handler switch -- all commands come through this
// point.
//
// Arguments:
// uiCommand [in] The command-id that's been invoked.
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// lpici [in] Command context info
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: jeffspr 11 Feb 1998
//
// Notes:
//
HRESULT HrFolderCommandHandler(
UINT uiCommand,
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPCMINVOKECOMMANDINFO lpici,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
CWaitCursor wc; // Bring up wait cursor now. Remove when we go out of scope.
// refresh all permission so subsequent calls can use cached value
RefreshAllPermission();
switch(uiCommand)
{
case CMIDM_ARRANGE_BY_NAME:
ShellFolderView_ReArrange(hwndOwner, ICOL_NAME);
break;
case CMIDM_ARRANGE_BY_TYPE:
ShellFolderView_ReArrange(hwndOwner, ICOL_TYPE);
break;
case CMIDM_ARRANGE_BY_STATUS:
ShellFolderView_ReArrange(hwndOwner, ICOL_STATUS);
break;
case CMIDM_ARRANGE_BY_OWNER:
ShellFolderView_ReArrange(hwndOwner, ICOL_OWNER);
break;
case CMIDM_ARRANGE_BY_PHONEORHOSTADDRESS:
ShellFolderView_ReArrange(hwndOwner, ICOL_PHONEORHOSTADDRESS);
break;
case CMIDM_ARRANGE_BY_DEVICE_NAME:
ShellFolderView_ReArrange(hwndOwner, ICOL_DEVICE_NAME);
break;
case CMIDM_NEW_CONNECTION:
hr = HrCommandHandlerThread(HrOnCommandNewConnection, apidl, hwndOwner, psf);
break;
case CMIDM_HOMENET_WIZARD:
hr = HrCommandHomeNetWizard();
break;
case CMIDM_NET_DIAGNOSTICS:
hr = HrCommandNetworkDiagnostics();
break;
case CMIDM_NET_TROUBLESHOOT:
hr = HrCommandNetworkTroubleShoot();
break;
case CMIDM_CONNECT:
case CMIDM_ENABLE:
hr = HrCommandHandlerThread(HrOnCommandConnect, apidl, hwndOwner, psf);
break;
case CMIDM_DISCONNECT:
case CMIDM_DISABLE:
hr = HrCommandHandlerThread(HrOnCommandDisconnect, apidl, hwndOwner, psf);
break;
case CMIDM_STATUS:
// the status monitor is already on its own thread
//
hr = HrOnCommandStatus(apidl, hwndOwner, psf);
break;
case CMIDM_FIX:
hr = HrCommandHandlerThread(HrOnCommandFix, apidl, hwndOwner, psf);
break;
case CMIDM_CREATE_SHORTCUT:
hr = HrCommandHandlerThread(HrOnCommandCreateShortcut, apidl, hwndOwner, psf);
break;
case CMIDM_DELETE:
hr = HrCommandHandlerThread(HrOnCommandDelete, apidl, hwndOwner, psf);
break;
case CMIDM_PROPERTIES:
hr = HrCommandHandlerThread(HrOnCommandProperties, apidl, hwndOwner, psf);
break;
case CMIDM_WZCPROPERTIES:
hr = HrCommandHandlerThread(HrOnCommandWZCProperties, apidl, hwndOwner, psf);
break;
case CMIDM_WZCDLG_SHOW:
hr = HrCommandHandlerThread(HrOnCommandWZCDlgShow, apidl, hwndOwner, psf);
break;
case CMIDM_CREATE_COPY:
hr = HrOnCommandCreateCopy(apidl, hwndOwner, psf);
break;
case CMIDM_CONMENU_ADVANCED_CONFIG:
hr = HrCommandHandlerThread(HrOnCommandAdvancedConfig, apidl, hwndOwner, psf);
break;
case CMIDM_SET_DEFAULT:
hr = HrOnCommandSetDefault(apidl, hwndOwner, psf);
break;
case CMIDM_UNSET_DEFAULT:
hr = HrOnCommandUnsetDefault(apidl, hwndOwner, psf);
break;
case CMIDM_CREATE_BRIDGE:
case CMIDM_CONMENU_CREATE_BRIDGE:
if ( TotalValidSelectedConnectionsForBridge(apidl) < 2 )
{
// tell users that he/she needs select 2 or more valid connections in order to acomplish this
NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_OBJECT_TYPE_BRIDGE,
IDS_BRIDGE_EDUCATION,
MB_ICONEXCLAMATION | MB_OK
);
}
else
HrOnCommandBridgeAddConnections(apidl, hwndOwner, psf);
break;
case CMIDM_ADD_TO_BRIDGE:
HrOnCommandBridgeAddConnections(apidl, hwndOwner, psf);
break;
case CMIDM_REMOVE_FROM_BRIDGE:
HrOnCommandBridgeRemoveConnections(apidl, hwndOwner, psf, CMIDM_REMOVE_FROM_BRIDGE);
break;
case CMIDM_CONMENU_NETWORK_ID:
hr = HrOnCommandNetworkId(apidl, hwndOwner, psf);
break;
case CMIDM_CONMENU_OPTIONALCOMPONENTS:
hr = HrOnCommandOptionalComponents(apidl, hwndOwner, psf);
break;
case CMIDM_CONMENU_DIALUP_PREFS:
hr = HrCommandHandlerThread(HrOnCommandDialupPrefs, apidl, hwndOwner, psf);
break;
case CMIDM_CONMENU_OPERATOR_ASSIST:
hr = HrOnCommandOperatorAssist(apidl, hwndOwner, psf);
break;
#if DBG
case CMIDM_DEBUG_TRAY:
hr = HrOnCommandDebugTray(apidl, hwndOwner, psf);
break;
case CMIDM_DEBUG_TRACING:
hr = HrOnCommandDebugTracing(apidl, hwndOwner, psf);
break;
case CMIDM_DEBUG_NOTIFYADD:
hr = HrOnCommandDebugNotifyAdd(apidl, hwndOwner, psf);
break;
case CMIDM_DEBUG_NOTIFYREMOVE:
hr = HrOnCommandDebugNotifyRemove(apidl, hwndOwner, psf);
break;
case CMIDM_DEBUG_NOTIFYTEST:
hr = HrOnCommandDebugNotifyTest(apidl, hwndOwner, psf);
break;
case CMIDM_DEBUG_REFRESH:
hr = HrOnCommandDebugRefresh(apidl, hwndOwner, psf);
break;
case CMIDM_DEBUG_REFRESHNOFLUSH:
hr = HrOnCommandDebugRefreshNoFlush(apidl, hwndOwner, psf);
break;
case CMIDM_DEBUG_REFRESHSELECTED:
hr = HrCommandHandlerThread(HrOnCommandDebugRefreshSelected, apidl, hwndOwner, psf);
break;
case CMIDM_DEBUG_REMOVETRAYICONS:
hr = HrCommandHandlerThread(HrOnCommandDebugRemoveTrayIcons, apidl, hwndOwner, psf);
break;
#endif
default:
#if DBG
char sz[128];
ZeroMemory(sz, 128);
sprintf(sz, "Unknown command (%d) in HrFolderCommandHandler", uiCommand);
TraceHr(ttidError, FAL, hr, FALSE, sz);
#endif
hr = E_INVALIDARG;
}
TraceHr(ttidError, FAL, hr, FALSE, "HrFolderCommandHandler");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandCreateCopy
//
// Purpose: Command handler for the CMIDM_CREATE_COPY command
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
// psf [in] The shell folder interface
//
// Returns:
//
// Author: jeffspr 31 Jan 1998
//
// Notes:
//
HRESULT HrOnCommandCreateCopy(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
INetConnection * pNetCon = NULL;
INetConnection * pNetConDupe = NULL;
CConnectionFolder * pcf = static_cast<CConnectionFolder *>(psf);
NETCFG_TRY
PCONFOLDPIDLFOLDER pidlFolder;
if (pcf)
{
pidlFolder = pcf->PidlGetFolderRoot();
}
PCONFOLDPIDL pidlConnection;
PCONFOLDPIDLVEC::const_iterator iterLoop;
for (iterLoop = apidl.begin(); iterLoop != apidl.end() ; iterLoop++)
{
// Get the INetConnection object from the persist data
//
hr = HrNetConFromPidl(*iterLoop, &pNetCon);
if (SUCCEEDED(hr))
{
CONFOLDENTRY ccfe;
Assert(pNetCon);
hr = iterLoop->ConvertToConFoldEntry(ccfe);
if (SUCCEEDED(hr))
{
if (ccfe.GetCharacteristics() & NCCF_ALLOW_DUPLICATION)
{
PWSTR pszDupeName = NULL;
hr = g_ccl.HrSuggestNameForDuplicate(ccfe.GetName(), &pszDupeName);
if (SUCCEEDED(hr))
{
Assert(pszDupeName);
// Duplicate the connection
//
hr = pNetCon->Duplicate(pszDupeName, &pNetConDupe);
if (SUCCEEDED(hr))
{
Assert(pNetConDupe);
if (pNetConDupe)
{
hr = g_ccl.HrInsertFromNetCon(pNetConDupe,
pidlConnection);
if (SUCCEEDED(hr))
{
GenerateEvent(SHCNE_CREATE, pidlFolder, pidlConnection, NULL);
pidlConnection.Clear();
}
ReleaseObj(pNetConDupe);
pNetConDupe = NULL;
}
}
delete pszDupeName;
}
}
else
{
AssertSz(ccfe.GetCharacteristics() & NCCF_ALLOW_DUPLICATION,
"What menu supported duplicating this connection?");
}
}
ReleaseObj(pNetCon);
pNetCon = NULL;
}
}
NETCFG_CATCH(hr)
TraceHr(ttidError, FAL, hr, FALSE, "HrOnCommandCreateCopy");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandProperties
//
// Purpose: Command handler for the CMIDM_PROPERTIES command
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: jeffspr 4 Nov 1997
//
// Notes:
//
HRESULT HrOnCommandProperties(
IN const PCONFOLDPIDLVEC& apidl,
IN HWND hwndOwner,
LPSHELLFOLDER psf)
{
INT cch;
HRESULT hr = S_OK;
HANDLE hMutex = NULL;
INetConnection * pNetCon = NULL;
WCHAR szConnectionGuid [c_cchGuidWithTerm];
// Just skip out of here if no pidl was supplied
if (apidl.empty())
{
return S_OK;
}
// We can only deal with a single connection. If we have
// multiple, then just use the first one.
//
const PCONFOLDPIDL& pcfp = apidl[0];
if (pcfp.empty())
{
hr = E_INVALIDARG;
goto Error;
}
// If this is an individual incoming connection - disallow this:
if ( (NCCF_INCOMING_ONLY & pcfp->dwCharacteristics) &&
(NCM_NONE != pcfp->ncm) )
{
hr = E_UNEXPECTED;
goto Error;
}
// If this is a LAN connection and the user doesn't have rights
// then disallow properties
//
if ((IsMediaLocalType(pcfp->ncm)) &&
!FHasPermission(NCPERM_LanProperties))
{
hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
goto Error;
}
// If this is a RAS connection and the user doesn't have rights
// then disallow properties
//
if (IsMediaRASType(pcfp->ncm))
{
BOOL fAllowProperties = (TRUE == ((pcfp->dwCharacteristics & NCCF_ALL_USERS) ?
(FHasPermission(NCPERM_RasAllUserProperties)) :
(FHasPermission(NCPERM_RasMyProperties))));
if (!fAllowProperties)
{
hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
goto Error;
}
}
hr = HrNetConFromPidl(apidl[0], &pNetCon);
if (FAILED(hr))
{
goto Error;
}
// Aquire a lock on this connection object
//
cch = StringFromGUID2 (pcfp->guidId, szConnectionGuid,
c_cchGuidWithTerm);
Assert (c_cchGuidWithTerm == cch);
hMutex = CreateMutex(NULL, TRUE, szConnectionGuid);
if ((NULL == hMutex) || (ERROR_ALREADY_EXISTS == GetLastError()))
{
// if the mutex already exists try to find the connection window
//
if (ERROR_ALREADY_EXISTS == GetLastError())
{
Assert(pNetCon);
ActivatePropertyDialog(pNetCon);
Assert(S_OK == hr);
// Don't let the error reporting below display the error.
// We want the user to acknowledge the message box above
// then we'll be nice an bring the property page to the
// foreground.
goto Error;
}
hr = HrFromLastWin32Error();
goto Error;
}
Assert(SUCCEEDED(hr));
// Bring up the connection Properties UI.
//
hr = HrRaiseConnectionPropertiesInternal(
NULL, // ISSUE: Going modal -- hwndOwner ? hwndOwner : GetDesktopWindow(),
0, // First page
pNetCon);
Error:
if (FAILED(hr))
{
UINT ids = 0;
switch(hr)
{
case E_UNEXPECTED:
ids = IDS_CONFOLD_PROPERTIES_ON_RASSERVERINSTEAD;
break;
case HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED):
ids = IDS_CONFOLD_PROPERTIES_NOACCESS;
break;
case HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY):
ids = IDS_CONFOLD_OUTOFMEMORY;
break;
default:
ids = IDS_CONFOLD_UNEXPECTED_ERROR;
break;
}
NcMsgBox(_Module.GetResourceInstance(), NULL, IDS_CONFOLD_WARNING_CAPTION,
ids, MB_ICONEXCLAMATION | MB_OK);
}
if (hMutex)
{
ReleaseMutex(hMutex);
CloseHandle(hMutex);
}
ReleaseObj(pNetCon);
TraceHr(ttidError, FAL, hr, FALSE, "HrOnCommandProperties");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandWZCProperties
//
// Purpose: Command handler for the CMIDM_WZCPROPERTIES command
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: deonb 5 Apr 2001
//
// Notes:
//
HRESULT HrOnCommandWZCProperties(
IN const PCONFOLDPIDLVEC& apidl,
IN HWND hwndOwner,
LPSHELLFOLDER psf)
{
INT cch;
HRESULT hr = S_OK;
HANDLE hMutex = NULL;
INetConnection * pNetCon = NULL;
WCHAR szConnectionGuid [c_cchGuidWithTerm];
// Just skip out of here if no pidl was supplied
if (apidl.empty())
{
return S_OK;
}
// We can only deal with a single connection. If we have
// multiple, then just use the first one.
//
const PCONFOLDPIDL& pcfp = apidl[0];
if (pcfp.empty())
{
hr = E_INVALIDARG;
goto Error;
}
// If this is a LAN connection and the user doesn't have rights
// then disallow properties
//
if ((IsMediaLocalType(pcfp->ncm)) &&
!FHasPermission(NCPERM_LanProperties))
{
hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
goto Error;
}
// If this is a RAS connection and the user doesn't have rights
// then disallow properties
//
if (IsMediaRASType(pcfp->ncm))
{
BOOL fAllowProperties = (TRUE == ((pcfp->dwCharacteristics & NCCF_ALL_USERS) ?
(FHasPermission(NCPERM_RasAllUserProperties)) :
(FHasPermission(NCPERM_RasMyProperties))));
if (!fAllowProperties)
{
hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
goto Error;
}
}
hr = HrNetConFromPidl(apidl[0], &pNetCon);
if (FAILED(hr))
{
goto Error;
}
// Aquire a lock on this connection object
//
cch = StringFromGUID2 (pcfp->guidId, szConnectionGuid,
c_cchGuidWithTerm);
Assert (c_cchGuidWithTerm == cch);
hMutex = CreateMutex(NULL, TRUE, szConnectionGuid);
if ((NULL == hMutex) || (ERROR_ALREADY_EXISTS == GetLastError()))
{
// if the mutex already exists try to find the connection window
//
if (ERROR_ALREADY_EXISTS == GetLastError())
{
Assert(pNetCon);
ActivatePropertyDialog(pNetCon);
Assert(S_OK == hr);
// Don't let the error reporting below display the error.
// We want the user to acknowledge the message box above
// then we'll be nice an bring the property page to the
// foreground.
goto Error;
}
hr = HrFromLastWin32Error();
goto Error;
}
Assert(SUCCEEDED(hr));
// Bring up the connection Properties UI.
//
hr = HrRaiseConnectionPropertiesInternal(
NULL, // ISSUE: Going modal -- hwndOwner ? hwndOwner : GetDesktopWindow(),
1, // Second page
pNetCon);
Error:
if (FAILED(hr))
{
UINT ids = 0;
switch(hr)
{
case HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED):
ids = IDS_CONFOLD_PROPERTIES_NOACCESS;
break;
case HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY):
ids = IDS_CONFOLD_OUTOFMEMORY;
break;
default:
ids = IDS_CONFOLD_UNEXPECTED_ERROR;
break;
}
NcMsgBox(_Module.GetResourceInstance(), NULL, IDS_CONFOLD_WARNING_CAPTION,
ids, MB_ICONEXCLAMATION | MB_OK);
}
if (hMutex)
{
ReleaseMutex(hMutex);
CloseHandle(hMutex);
}
ReleaseObj(pNetCon);
TraceHr(ttidError, FAL, hr, FALSE, "HrOnCommandProperties");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandWZCDlgShow
//
// Purpose: Command handler for the CMIDM_WZCDLG_SHOW command
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: deonb 15 May 2001
//
// Notes:
//
#define WZCDLG_FAILED 0x00010001 // 802.11 automatic configuration failed
HRESULT HrOnCommandWZCDlgShow(
IN const PCONFOLDPIDLVEC& apidl,
IN HWND hwndOwner,
LPSHELLFOLDER psf)
{
INT cch;
HRESULT hr = S_OK;
// Just skip out of here if no pidl was supplied
if (apidl.empty())
{
return S_OK;
}
// We can only deal with a single connection. If we have
// multiple, then just use the first one.
//
const PCONFOLDPIDL& pcfp = apidl[0];
if (!pcfp.empty())
{
WZCDLG_DATA wzcDlgData = {0};
wzcDlgData.dwCode = WZCDLG_FAILED;
wzcDlgData.lParam = 1;
BSTR szCookie = SysAllocStringByteLen(reinterpret_cast<LPSTR>(&wzcDlgData), sizeof(wzcDlgData));
BSTR szName = SysAllocString(pcfp->PszGetNamePointer());
if (szCookie && szName)
{
GUID gdGuid = pcfp->guidId;
hr = WZCOnBalloonClick(&gdGuid, szName, szCookie);
}
else
{
hr = E_OUTOFMEMORY;
}
SysFreeString(szName);
SysFreeString(szCookie);
}
else
{
hr = E_INVALIDARG;
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrRaiseConnectionProperties
//
// Purpose: Public function for bringing 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: scottbri 3 Nov 1998
//
// Notes: Needs to convert the INetConnection * below into suitable
// parameters for a call to HrOnCommandProperties above.
//
HRESULT HrRaiseConnectionProperties(HWND hwnd, INetConnection * pConn)
{
HRESULT hr = S_OK;
PCONFOLDPIDL pidl;
PCONFOLDPIDLFOLDER pidlFolder;
LPSHELLFOLDER psfConnections = NULL;
if (NULL == pConn)
{
hr = E_INVALIDARG;
goto Error;
}
// Create a pidl for the connection
//
hr = HrCreateConFoldPidl(WIZARD_NOT_WIZARD, pConn, pidl);
if (SUCCEEDED(hr))
{
// Get the pidl for the Connections Folder
//
hr = HrGetConnectionsFolderPidl(pidlFolder);
if (SUCCEEDED(hr))
{
// Get the Connections Folder object
//
hr = HrGetConnectionsIShellFolder(pidlFolder, &psfConnections);
if (SUCCEEDED(hr))
{
PCONFOLDPIDLVEC vecPidls;
vecPidls.push_back(pidl);
hr = HrOnCommandProperties(vecPidls, hwnd, psfConnections);
ReleaseObj(psfConnections);
}
}
}
Error:
TraceHr(ttidError, FAL, hr, FALSE, "HrRaiseConnectionProperties");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandConnectInternal
//
// Purpose: The guts of the Connect code. This is called both from
// HrOnCommandConnect and from HrOnCommandNewConnection, since
// that now connects after creating the new connection
//
// Arguments:
// pNetCon [in] INetConnection * of the connection to activate
// hwndOwner [in] Our parent hwnd
// pcfp [in] Our pidl structure
// psf [in] Shell Folder
//
// Returns:
//
// Author: jeffspr 10 Jun 1998
//
// Notes:
//
HRESULT HrOnCommandConnectInternal(
INetConnection * pNetCon,
HWND hwndOwner,
const PCONFOLDPIDL& pcfp,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
CConnectionFolder * pcf = static_cast<CConnectionFolder *>(psf);
NETCFG_TRY
PCONFOLDPIDLFOLDER pidlFolder;
if (pcf)
{
pidlFolder = pcf->PidlGetFolderRoot();
}
BOOL fActivating = FALSE;
// Use a separate var so we can keep track of the result of the connect
// and the result of the get_Status.
//
HRESULT hrConnect = S_OK;
Assert(pNetCon);
Assert(psf);
// Get current activation state
//
CONFOLDENTRY cfEmpty;
(void) HrCheckForActivation(pcfp, cfEmpty, &fActivating);
// Check for rights to connect
//
if (((IsMediaLocalType(pcfp->ncm)) && !FHasPermission(NCPERM_LanConnect)) ||
((IsMediaRASType(pcfp->ncm)) && !FHasPermission(NCPERM_RasConnect)))
{
(void) NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_WARNING_CAPTION,
IDS_CONFOLD_CONNECT_NOACCESS,
MB_OK | MB_ICONEXCLAMATION);
}
// Drop out of this call unless we're currently disconnected.
//
else if (pcfp->ncs == NCS_DISCONNECTED && !fActivating)
{
// Ignore the return code. Failing to set this flag shouldn't keep
// us from attempting to connect.
//
(void) HrSetActivationFlag(pcfp, cfEmpty, TRUE);
// Get the INetConnectionConnectUi interface and make the connection
// Get the hr (for debugging), but we want to update the status
// of the connection even if the connect failed
//
hrConnect = HrConnectOrDisconnectNetConObject(
// It's OK if the hwnd is NULL. We don't want to go modal
// on the desktop.
NULL, // FIXED -- Was going modal with hwndOwner ? hwndOwner : GetDesktopWindow(),
pNetCon,
CD_CONNECT);
// Even on failure, we want to continue, because we might find that
// the device is now listed as unavailable. On cancel (S_FALSE), we
// don't have that concern.
//
if (S_FALSE != hrConnect)
{
// Even on failure, we want to continue, because we might find that
// the device is now listed as unavailable.
if (FAILED(hrConnect))
{
TraceTag(ttidShellFolder, "HrOnCommandConnect: Connect failed, 0x%08x", hrConnect);
}
#if 0 // (JEFFSPR) - 11/20/98 turning this on until the notify COM failures are worked out.
// Now taken care of by the notification engine.
//
// Get the new status from the connection
//
NETCON_PROPERTIES * pProps;
hr = pNetCon->GetProperties(&pProps);
if (SUCCEEDED(hr))
{
// This won't necessarily be connected -- we used to assert here, but it's
// actually possible for the connection to go dead between when we connect
// and when we ask for the status.
//
hr = HrUpdateConnectionStatus(pcfp, pProps->Status, pidlFolder, TRUE, pProps->dwCharacter);
FreeNetconProperties(pProps);
}
#endif
}
else
{
// hrConnect is S_FALSE. Pass that on.
//
hr = hrConnect;
}
// Set us as "not in the process of activating"
//
hr = HrSetActivationFlag(pcfp, cfEmpty, FALSE);
}
else
{
if ((IsMediaRASType(pcfp->ncm)) &&
(pcfp->ncm != NCM_NONE))
{
// For non-LAN connections, attempt to bring the RAS dialer UI
// into focus instead of putting up an error message
HWND hwndDialer;
LPWSTR pszTitle;
NETCON_PROPERTIES * pProps;
hr = pNetCon->GetProperties(&pProps);
if (SUCCEEDED(hr))
{
DwFormatStringWithLocalAlloc(SzLoadIds(IDS_CONFOLD_RAS_DIALER_TITLE_FMT),
&pszTitle, pProps->pszwName);
hwndDialer = FindWindowEx(NULL, NULL, L"#32770", pszTitle);
if (hwndDialer)
{
SetForegroundWindow(hwndDialer);
}
FreeNetconProperties(pProps);
MemFree(pszTitle);
}
}
else if (fActivating)
{
(void) NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_WARNING_CAPTION,
IDS_CONFOLD_CONNECT_IN_PROGRESS,
MB_OK | MB_ICONEXCLAMATION);
}
}
NETCFG_CATCH(hr)
TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrOnCommandConnectInternal");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandFixInternal
//
// Purpose: handle the fix and bring up the progress dialog
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
HRESULT HrOnCommandFixInternal(
const CONFOLDENTRY& ccfe,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
INetConnection * pNetCon = NULL;
CConnectionFolder * pcf = static_cast<CConnectionFolder *>(psf);
Assert(!ccfe.empty());
NETCON_MEDIATYPE ncmType = ccfe.GetNetConMediaType();
//fix is only avalable for LAN and bridge connections
if (NCM_LAN != ncmType && NCM_BRIDGE != ncmType)
{
return S_FALSE;
}
hr = ccfe.HrGetNetCon(IID_INetConnection, reinterpret_cast<VOID**>(&pNetCon));
if (SUCCEEDED(hr))
{
NETCON_PROPERTIES* pProps;
hr = pNetCon->GetProperties(&pProps);
if (SUCCEEDED(hr))
{
tstring strMessage = L"";
CLanConnectionUiDlg dlg;
HWND hwndDlg;
//bring up the dialog to tell the user we're doing the fix
dlg.SetConnection(pNetCon);
hwndDlg = dlg.Create(hwndOwner);
PCWSTR szw = SzLoadIds(IDS_FIX_REPAIRING);
SetDlgItemText(hwndDlg, IDC_TXT_Caption, szw);
//do the fix
hr = HrTryToFix(pProps->guidId, strMessage);
FreeNetconProperties(pProps);
if (NULL != hwndDlg)
{
DestroyWindow(hwndDlg);
}
//tell users the results
NcMsgBox(_Module.GetResourceInstance(),
NULL,
IDS_FIX_CAPTION,
IDS_FIX_MESSAGE,
MB_OK | MB_TOPMOST,
strMessage.c_str());
}
ReleaseObj(pNetCon);
}
TraceHr(ttidShellFolder, FAL, hr, (S_FALSE == hr), "HrOnCommandFixInternal");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandFix
//
// Purpose: Command handler for the CMIDM_FIX command
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
HRESULT HrOnCommandFix(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
CONFOLDENTRY ccfe;
if (!apidl.empty())
{
hr = apidl[0].ConvertToConFoldEntry(ccfe);
if (SUCCEEDED(hr))
{
if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL))
{
TraceTag(ttidError, "Could not set priority for Repair thread");
}
// We don't care if whether the fix succeeds or not
// if it fails, there will be a pop-up saying that
HrOnCommandFixInternal(ccfe, hwndOwner, psf);
}
}
TraceHr(ttidError, FAL, hr, FALSE, "HrOnCommandFix");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandConnect
//
// Purpose: Command handler for the CMIDM_CONNECT or CMIDM_ENABLE command
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: jeffspr 12 Nov 1997
//
// Notes:
//
HRESULT HrOnCommandConnect(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
INetConnection * pNetCon = NULL;
NETCFG_TRY
if (apidl.size() == 1)
{
PCONFOLDPIDL pcfp = apidl[0];
if (!pcfp.empty())
{
// Get the cached pidl. If it's found, then use the copy. If not
// then use whatever info we have (but this might be outdated)
//
PCONFOLDPIDL pcfpCopy;
hr = g_ccl.HrGetCachedPidlCopyFromPidl(apidl[0], pcfpCopy);
if (S_OK == hr)
{
pcfp.Swop(pcfpCopy); // pcfp = pcfpCopy;
}
else
{
TraceHr(ttidShellFolder, FAL, hr, FALSE, "Cached pidl not retrievable in HrOnCommandConnect");
}
// Make sure that this connection is valid for connection (not a wizrd,
// and not already connected. If so, then connect.
//
if ( (WIZARD_NOT_WIZARD == pcfp->wizWizard) && !(fIsConnectedStatus(pcfp->ncs)) )
{
// Ignore this entry if we're getting a connect verb on an incoming connections
// object
//
if (pcfp->ncm != NCM_NONE && (!(pcfp->dwCharacteristics & NCCF_INCOMING_ONLY)))
{
// Get the INetConnection object from the persist data
//
hr = HrNetConFromPidl(apidl[0], &pNetCon);
if (SUCCEEDED(hr))
{
hr = HrOnCommandConnectInternal(pNetCon, hwndOwner, pcfp, psf);
ReleaseObj(pNetCon);
}
}
}
}
// else if (FIsConFoldPidl98(apidl[0]) && FALSE )
// {
// // ISSUE - FIsConFoldPidl98 doesn't give ua a wizWizard anymore! Used to be:
// // FIsConFoldPidl98(apidl[0], &fIsWizard) && !fIsWizard)
//
// // raise an error that the connection is not found
// //
// NcMsgBox(_Module.GetResourceInstance(), NULL,
// IDS_CONFOLD_WARNING_CAPTION,
// IDS_CONFOLD_NO_CONNECTION,
// MB_ICONEXCLAMATION | MB_OK);
// }
}
NETCFG_CATCH(hr)
TraceHr(ttidError, FAL, hr, FALSE, "HrOnCommandConnect");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandDisconnectInternal
//
// Purpose: Internal command handler for the CMIDM_DISCONNECT or CMIDM_DISABLE command.
// This function is callable by the tray, which doesn't have
// the data in pidls, but rather has the actual data that we're
// concerned with. HrOnCommandDisconnect retrieves this data
// and passes on the call to this function
//
// Arguments:
// ccfe [in] Our ConFoldEntry (our connection data)
// hwndOwner [in] Our parent hwnd
//
// Returns:
//
// Author: jeffspr 20 Mar 1998
//
// Notes:
//
HRESULT HrOnCommandDisconnectInternal(
const CONFOLDENTRY& ccfe,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
INetConnection * pNetCon = NULL;
CConnectionFolder * pcf = static_cast<CConnectionFolder *>(psf);
Assert(!ccfe.empty());
// Check for rights to disconnect
//
if (((IsMediaLocalType(ccfe.GetNetConMediaType())) && !FHasPermission(NCPERM_LanConnect)) ||
((IsMediaRASType(ccfe.GetNetConMediaType())) && !FHasPermission(NCPERM_RasConnect)))
{
(void) NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_WARNING_CAPTION,
IDS_CONFOLD_DISCONNECT_NOACCESS,
MB_OK | MB_ICONEXCLAMATION);
}
else
{
PromptForSyncIfNeeded(ccfe, hwndOwner);
{
CWaitCursor wc; // Bring up wait cursor now. Remove when we go out of scope.
// Get the INetConnection object from the persist data
//
hr = ccfe.HrGetNetCon(IID_INetConnection, reinterpret_cast<VOID**>(&pNetCon));
if (SUCCEEDED(hr))
{
Assert(pNetCon);
hr = HrConnectOrDisconnectNetConObject (
hwndOwner, pNetCon, CD_DISCONNECT);
ReleaseObj(pNetCon);
}
}
}
TraceHr(ttidShellFolder, FAL, hr, (S_FALSE == hr), "HrOnCommandDisconnectInternal");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandDisconnect
//
// Purpose: Command handler for the CMIDM_DISCONNECT or CMIDM_DISABLE command
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: jeffspr 12 Nov 1997
//
// Notes: We only act on a single entry in this function
//
HRESULT HrOnCommandDisconnect(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
CONFOLDENTRY ccfe;
if (!apidl.empty())
{
hr = apidl[0].ConvertToConFoldEntry(ccfe);
if (SUCCEEDED(hr))
{
hr = HrOnCommandDisconnectInternal(ccfe, hwndOwner, psf);
// Normalize the return code. We don't care if whether the connection
// was actually disconnected or not (if canceled, it would have \
// returned S_FALSE;
//
if (SUCCEEDED(hr))
{
hr = S_OK;
}
}
}
TraceHr(ttidError, FAL, hr, FALSE, "HrOnCommandDisconnect");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandStatusInternal
//
// Purpose: Internal command handler for the CMIDM_STATUS command.
// This function is callable by the tray, which doesn't have
// the data in pidls, but rather has the actual data that we're
// concerned with. HrOnCommandStatus retrieves this data
// and passes on the call to this function
//
// Arguments:
// ccfe [in] ConFoldEntry for the connection in question
// fCreateEngine [in] Whether a status engine should be created if not exist
//
// Returns:
//
// Author: jeffspr 20 Mar 1998
//
// Notes:
//
HRESULT HrOnCommandStatusInternal(
const CONFOLDENTRY& ccfe,
BOOL fCreateEngine)
{
HRESULT hr = S_OK;
Assert(!ccfe.empty());
// see if we are in safe mode with networking
int iRet = GetSystemMetrics(SM_CLEANBOOT);
if (!iRet)
{
// normal boot
Assert(g_hwndTray);
// The permissions check will be done in the tray message processing.
//
PostMessage(g_hwndTray, MYWM_OPENSTATUS, (WPARAM) ccfe.TearOffItemIdList(), (LPARAM) fCreateEngine);
}
else if (2 == iRet)
{
// safemode with networking, statmon is not tied to tray icon
if (FHasPermission(NCPERM_Statistics))
{
INetStatisticsEngine* pnseNew;
hr = HrGetStatisticsEngineForEntry(ccfe, &pnseNew, TRUE);
if (SUCCEEDED(hr))
{
hr = pnseNew->ShowStatusMonitor();
ReleaseObj(pnseNew);
}
}
}
TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrOnCommandStatusInternal");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandStatus
//
// Purpose: Command handler for the CMIDM_STATUS command
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: jeffspr 12 Nov 1997
//
// Notes:
//
HRESULT HrOnCommandStatus(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
CONFOLDENTRY ccfe;
if (apidl[0].empty())
{
hr = E_INVALIDARG;
}
else
{
AssertSz(apidl.size() == 1, "We don't allow status on multi-selected items");
// Copy the pidl, as the PostMessage isn't sync, and the context menu's
// copy of the pidl could be destroyed before the tray processed the
// message. The tray is responsible for free'ing in the pidl.
//
hr = apidl[0].ConvertToConFoldEntry(ccfe);
if (SUCCEEDED(hr))
{
if (fIsConnectedStatus(ccfe.GetNetConStatus()) ||
ccfe.IsConnected() )
{
hr = HrOnCommandStatusInternal(ccfe, TRUE);
}
}
}
TraceHr(ttidError, FAL, hr, FALSE, "HrOnCommandStatus");
return hr;
}
VOID SetICWComplete();
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandNewConnection
//
// Purpose: Command handler for the CMIDM_NEW_CONNECTION command
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: jeffspr 12 Nov 1997
//
// Notes:
//
HRESULT HrOnCommandNewConnection(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
INetConnection * pNetCon = NULL;
NETCFG_TRY
PCONFOLDPIDL pidlConnection;
// Don't use hwndOwner for anything. We shouldn't become modal!
//
hr = NetSetupAddRasConnection(NULL, &pNetCon);
if (S_OK == hr)
{
CConnectionFolder * pcf = static_cast<CConnectionFolder *>(psf);
PCONFOLDPIDLFOLDER pidlFolder;
if (pcf)
{
pidlFolder = pcf->PidlGetFolderRoot();
}
Assert(pNetCon);
hr = g_ccl.HrInsertFromNetCon(pNetCon, pidlConnection);
if (SUCCEEDED(hr) && (!pidlConnection.empty()) )
{
PCONFOLDPIDL pcfp = pidlConnection;
GenerateEvent(SHCNE_CREATE, pidlFolder, pidlConnection, NULL);
// Don't try to connect an object that's incoming only, and don't connect
// it unless we're listed as disconnected
//
if (!(pcfp->dwCharacteristics & NCCF_INCOMING_ONLY) && (pcfp->ncs == NCS_DISCONNECTED))
{
// If we have Ras connect permissions, then try to dial. Otherwise, don't
// force the user into a failure here.
//
if (FHasPermission(NCPERM_RasConnect))
{
hr = HrOnCommandConnectInternal(pNetCon, hwndOwner, pidlConnection, psf);
}
}
}
pNetCon->Release();
}
else if (SUCCEEDED(hr))
{
// Convert S_FALSE to S_OK
// S_FALSE means no pages were displayed but nothing failed.
// S_FALSE is returned when the wizard is already being displayed
//
hr = S_OK;
}
SetICWComplete();
NETCFG_CATCH(hr)
TraceHr(ttidError, FAL, hr, FALSE, "HrOnCommandNewConnection");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandAdvancedConfig
//
// Purpose: Command handler for the CMIDM_ADVANCED_CONFIG command
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: jeffspr 3 Dec 1997
//
// Notes:
//
HRESULT HrOnCommandAdvancedConfig(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
hr = HrDoAdvCfgDlg(hwndOwner);
TraceError("HrOnCommandAdvancedConfig", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandDelete
//
// Purpose: Command handler for the CMIDM_DELETE command
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
// psf [in] Our folder
//
// Returns:
//
// Author: jeffspr 3 Dec 1997
//
// Notes:
//
HRESULT HrOnCommandDelete(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
INetConnection * pNetCon = NULL;
INT iMBResult = 0;
BOOL fActivating = FALSE;
NETCFG_TRY
PCONFOLDPIDLVEC::const_iterator iterLoop;
HANDLE hMutex = NULL;
for (iterLoop = apidl.begin(); iterLoop != apidl.end(); iterLoop++)
{
CConFoldEntry cfe;
hr = iterLoop->ConvertToConFoldEntry(cfe);
WCHAR szConnectionGuid [c_cchGuidWithTerm];
INT cch = StringFromGUID2 (cfe.GetGuidID(), szConnectionGuid, c_cchGuidWithTerm);
Assert (c_cchGuidWithTerm == cch);
BOOL fDuplicateMutex = FALSE;
hMutex = CreateMutex(NULL, TRUE, szConnectionGuid);
if (hMutex)
{
fDuplicateMutex = (ERROR_ALREADY_EXISTS == GetLastError());
ReleaseMutex(hMutex);
CloseHandle(hMutex);
}
else
{
hr = E_ACCESSDENIED;
break;
}
if (fDuplicateMutex)
{
// if the mutex already exists try to find the connection window
//
NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_ERROR_DELETE_CAPTION,
IDS_CONFOLD_ERROR_DELETE_PROPERTYPAGEOPEN,
MB_ICONEXCLAMATION);
hr = cfe.HrGetNetCon(IID_INetConnection, reinterpret_cast<VOID**>(&pNetCon));
if (FAILED(hr))
{
Assert(FALSE);
break;
}
else
{
ActivatePropertyDialog(pNetCon);
hr = E_ACCESSDENIED;
break;
}
}
}
if (FAILED(hr))
{
goto Exit;
}
// Bring up the prompt for the delete
//
if (apidl.size() > 1)
{
WCHAR wszItemCount[8];
// Convert the item count to a string
//
_itow( apidl.size(), wszItemCount, 10 );
// Bring up the message box
//
iMBResult = NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_DELETE_CONFIRM_MULTI_CAPTION,
IDS_CONFOLD_DELETE_CONFIRM_MULTI,
MB_YESNO | MB_ICONQUESTION,
wszItemCount);
if (IDYES == iMBResult)
{
for (iterLoop = apidl.begin(); iterLoop != apidl.end(); iterLoop++)
{
CConFoldEntry cfe;
hr = iterLoop->ConvertToConFoldEntry(cfe);
if (SUCCEEDED(hr))
{
if ( (NCCF_INCOMING_ONLY & cfe.GetCharacteristics()) &&
(NCM_NONE == cfe.GetNetConMediaType()) )
{
DWORD dwActiveIncoming;
if (SUCCEEDED(g_ccl.HasActiveIncomingConnections(&dwActiveIncoming))
&& dwActiveIncoming)
{
if (1 == dwActiveIncoming )
{
iMBResult = NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_DELETE_CONFIRM_MULTI_CAPTION,
IDS_CONFOLD_DELETE_CONFIRM_RASSERVER,
MB_YESNO | MB_ICONQUESTION);
}
else
{
iMBResult = NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_DELETE_CONFIRM_MULTI_CAPTION,
IDS_CONFOLD_DELETE_CONFIRM_RASSERVER_MULTI,
MB_YESNO | MB_ICONQUESTION,
dwActiveIncoming);
}
}
break;
}
}
}
}
}
else if (apidl.size() == 1)
{
CONFOLDENTRY ccfe;
// Convert the pidl to a confoldentry, and use the name
// to bring up the confirm message box
//
hr = apidl[0].ConvertToConFoldEntry(ccfe);
if (SUCCEEDED(hr))
{
// Don't let them try to delete a wizard
//
if (ccfe.GetWizard())
{
goto Exit;
}
else
{
// Check to see if this connection is in the process of activating.
// If so, then we won't allow the delete.
//
PCONFOLDPIDL pidlEmpty;
hr = HrCheckForActivation(pidlEmpty, ccfe, &fActivating);
if (S_OK == hr)
{
if (!fActivating)
{
if (FALSE == (ccfe.GetNetConMediaType() == NCM_BRIDGE) && // we do allow the bridge to be deleted
((ccfe.GetNetConStatus() == NCS_CONNECTING) ||
fIsConnectedStatus(ccfe.GetNetConStatus()) ||
(ccfe.GetNetConStatus() == NCS_DISCONNECTING)) )
{
// You can't delete an active connection
//
NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_ERROR_DELETE_CAPTION,
IDS_CONFOLD_ERROR_DELETE_ACTIVE,
MB_ICONEXCLAMATION);
goto Exit;
}
else
{
if ( (NCCF_INCOMING_ONLY & ccfe.GetCharacteristics()) &&
(NCM_NONE == ccfe.GetNetConMediaType()) )
{
DWORD dwActiveIncoming;
if (SUCCEEDED(g_ccl.HasActiveIncomingConnections(&dwActiveIncoming))
&& dwActiveIncoming)
{
if (1 == dwActiveIncoming )
{
iMBResult = NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_DELETE_CONFIRM_SINGLE_CAPTION,
IDS_CONFOLD_DELETE_CONFIRM_RASSERVER,
MB_YESNO | MB_ICONQUESTION);
}
else
{
iMBResult = NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_DELETE_CONFIRM_SINGLE_CAPTION,
IDS_CONFOLD_DELETE_CONFIRM_RASSERVER_MULTI,
MB_YESNO | MB_ICONQUESTION,
dwActiveIncoming);
}
}
else
{
iMBResult = NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_DELETE_CONFIRM_SINGLE_CAPTION,
IDS_CONFOLD_DELETE_CONFIRM_SINGLE,
MB_YESNO | MB_ICONQUESTION,
ccfe.GetName());
}
}
else
{
// is it shared?
// if it is warn the user
RASSHARECONN rsc;
hr = ccfe.HrGetNetCon(IID_INetConnection, reinterpret_cast<VOID**>(&pNetCon));
if (SUCCEEDED(hr))
{
hr = HrNetConToSharedConnection(pNetCon, &rsc);
if (SUCCEEDED(hr))
{
BOOL pfShared;
hr = HrRasIsSharedConnection(&rsc, &pfShared);
if ((SUCCEEDED(hr)) && (pfShared == TRUE))
{
// tell the user they are deleting a
// shared connection and get confirmation
iMBResult = NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_DELETE_CONFIRM_SINGLE_CAPTION,
IDS_CONFOLD_DELETE_CONFIRM_SHARED,
MB_YESNO | MB_ICONQUESTION,
ccfe.GetName());
}
else
{
// Ask for delete confirmation
iMBResult = NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_DELETE_CONFIRM_SINGLE_CAPTION,
IDS_CONFOLD_DELETE_CONFIRM_SINGLE,
MB_YESNO | MB_ICONQUESTION,
ccfe.GetName());
}
}
else
{
// Ask for delete confirmation
iMBResult = NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_DELETE_CONFIRM_SINGLE_CAPTION,
IDS_CONFOLD_DELETE_CONFIRM_SINGLE,
MB_YESNO | MB_ICONQUESTION,
ccfe.GetName());
}
}
}
}
}
else
{
// Bring up the MB about "Hey, you can't delete while
// the connection is activating."
//
iMBResult = NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_ERROR_DELETE_CAPTION,
IDS_CONFOLD_ERROR_DELETE_ACTIVE,
MB_ICONEXCLAMATION);
goto Exit;
}
}
else
{
// If the connection wasn't found, then we should just drop out of here
// because we sure can't delete it.
//
if (S_FALSE == hr)
{
goto Exit;
}
}
}
}
else
{
AssertSz(FALSE, "Couldn't get ConFoldEntry from pidl in HrOnCommandDelete");
goto Exit;
}
}
else
{
// No connections were specified. Take a hike.
//
goto Exit;
}
// If the user said "Yes" to the prompt
//
if (iMBResult == IDYES)
{
CConnectionFolder * pcf = static_cast<CConnectionFolder *>(psf);
PCONFOLDPIDLFOLDER pidlFolder;
if (pcf)
{
pidlFolder = pcf->PidlGetFolderRoot();
}
BOOL fShowActivationWarning = FALSE;
BOOL fShowNotDeletableWarning = FALSE;
for (iterLoop = apidl.begin(); iterLoop != apidl.end(); iterLoop++)
{
CONFOLDENTRY ccfe;
hr = iterLoop->ConvertToConFoldEntry(ccfe);
if (SUCCEEDED(hr))
{
// If this is a LAN connection the user doesn't have rights
//
if ((NCM_LAN == ccfe.GetNetConMediaType()) || (ccfe.GetWizard()))
{
fShowNotDeletableWarning = TRUE;
continue;
}
// If this is a RAS connection and the user doesn't have rights
// then skip
//
if (IsMediaRASType(ccfe.GetNetConMediaType()))
{
if ((!FHasPermission(NCPERM_DeleteConnection)) ||
((ccfe.GetCharacteristics() & NCCF_ALL_USERS) &&
!FHasPermission(NCPERM_DeleteAllUserConnection)))
{
fShowNotDeletableWarning = TRUE;
continue;
}
}
PCONFOLDPIDL pidlEmpty;
hr = HrCheckForActivation(pidlEmpty, ccfe, &fActivating);
if (S_OK == hr)
{
// Only allow deletion if this connection is inactive and
// it allows removal.
//
if (fActivating || ((FALSE == (ccfe.GetNetConMediaType() == NCM_BRIDGE))) &&
((ccfe.GetNetConStatus() == NCS_CONNECTING) ||
fIsConnectedStatus(ccfe.GetNetConStatus()) ||
(ccfe.GetNetConStatus() == NCS_DISCONNECTING)) )
{
fShowActivationWarning = TRUE;
}
else if (ccfe.GetCharacteristics() & NCCF_ALLOW_REMOVAL)
{
hr = HrNetConFromPidl(*iterLoop, &pNetCon);
if (SUCCEEDED(hr))
{
if ( NCM_BRIDGE == ccfe.GetNetConMediaType() )
{
//
// Special delete case Removing the Network bridge take so long that we display a status dialog
// and prevent the user from changing anything will we process
//
hr = HrOnCommandBridgeRemoveConnections(
apidl,
hwndOwner,
psf,
0 // Remove the Network bridge
);
}
else
{
hr = pNetCon->Delete();
}
if (SUCCEEDED(hr) && pcf)
{
hr = HrDeleteFromCclAndNotifyShell(pidlFolder, *iterLoop, ccfe);
}
else if(E_ACCESSDENIED == hr && NCM_BRIDGE == ccfe.GetNetConMediaType())
{
// can't delete the bridge while the netcfg lock is held
NcMsgBox(
_Module.GetResourceInstance(),
NULL, IDS_CONFOLD_ERROR_DELETE_CAPTION, IDS_CONFOLD_ERROR_DELETE_BRIDGE_ACCESS, MB_ICONEXCLAMATION);
}
ReleaseObj(pNetCon);
}
}
else
{
// The selected item is not deletable
//
fShowNotDeletableWarning = TRUE;
}
}
}
}
if (fShowNotDeletableWarning)
{
// You can't delete an item that doesn't support it
//
NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_ERROR_DELETE_CAPTION,
(1 == apidl.size()) ?
IDS_CONFOLD_ERROR_DELETE_NOSUPPORT :
IDS_CONFOLD_ERROR_DELETE_NOSUPPORT_MULTI,
MB_ICONEXCLAMATION);
}
else if (fShowActivationWarning)
{
// You can't delete an active connection. Note, if more
// than one are being deleted, then we put up the warning
// that says 'one or more are being ignored'.
//
NcMsgBox(
_Module.GetResourceInstance(),
NULL,
IDS_CONFOLD_ERROR_DELETE_CAPTION,
(1 == apidl.size()) ?
IDS_CONFOLD_ERROR_DELETE_ACTIVE :
IDS_CONFOLD_ERROR_DELETE_ACTIVE_MULTI,
MB_ICONEXCLAMATION);
}
}
Exit:
NETCFG_CATCH(hr)
TraceError("HrOnCommandDelete", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandOptionalComponents
//
// Purpose: Command handler for the CMIDM_CONMENU_OPTIONALCOMPONENTS command.
// Bring up the network optional components UI.
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
// psf [in] Our folder
//
// Returns:
//
// Author: scottbri 29 Oct 1998
//
// Notes:
//
HRESULT HrOnCommandOptionalComponents(IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
return HrLaunchNetworkOptionalComponents();
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandNetworkId
//
// Purpose: Command handler for the CMIDM_CONMENU_NETORK_ID command.
// Bring up the network ID UI
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: jeffspr 26 Feb 1998
//
// Notes:
//
HRESULT HrOnCommandNetworkId(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
TraceFileFunc(ttidShellFolder);
HRESULT hr = S_OK;
WCHAR szPath[MAX_PATH];
hr = SHGetFolderPath(
hwndOwner,
CSIDL_SYSTEM,
NULL,
SHGFP_TYPE_CURRENT,
szPath);
if (SUCCEEDED(hr))
{
HINSTANCE hInst = ::ShellExecute(hwndOwner, NULL, c_szRunDll32, c_szNetworkIdCmdLine, szPath, SW_SHOW );
if (hInst <= reinterpret_cast<HINSTANCE>(32))
{
hr = HRESULT_FROM_WIN32(static_cast<DWORD>(reinterpret_cast<DWORD_PTR>(hInst)));
}
}
TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrOnCommandNetworkId");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandDialupPrefs
//
// Purpose: Command handler for the CMIDM_CONMENU_DIALUP_PREFS command.
// Bring up the dialup prefs dialog
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: jeffspr 26 Feb 1998
//
// Notes:
//
HRESULT HrOnCommandDialupPrefs(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
DWORD dwErr = 0;
dwErr = RasUserPrefsDlg(hwndOwner);
hr = HRESULT_FROM_WIN32 (dwErr);
TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrOnCommandDialupPrefs");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandOperatorAssist
//
// Purpose: Command handler for the CMIDM_CONMENU_OPERATOR_ASSIST command.
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: jeffspr 26 Feb 1998
//
// Notes:
//
HRESULT HrOnCommandOperatorAssist(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
DWORD dwErr = 0;
// Swap the flag
//
g_fOperatorAssistEnabled = !g_fOperatorAssistEnabled;
// Set the state within RasDlg itself
//
dwErr = RasUserEnableManualDial(hwndOwner, FALSE, g_fOperatorAssistEnabled);
hr = HRESULT_FROM_WIN32 (dwErr);
TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrOnCommandDialupPrefs");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandCreateShortcut
//
// Purpose: Command handler for the CMIDM_CREATE_SHORTCUT command.
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: jeffspr 13 Mar 1998
//
// Notes:
//
HRESULT HrOnCommandCreateShortcut(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
hr = HrCreateShortcutWithPath( apidl,
hwndOwner,
psf,
NULL);
TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrOnCommandCreateShortcut");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandSetDefault
//
// Purpose: Command handler for the CMIDM_SET_DEFAULT command
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: deonb 27 Nov 2000
//
// Notes: We only act on a single entry in this function
//
HRESULT HrOnCommandSetDefault(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
CONFOLDENTRY ccfe;
if (!apidl.empty())
{
hr = apidl[0].ConvertToConFoldEntry(ccfe);
if (SUCCEEDED(hr))
{
INetDefaultConnection *pNetDefaultConnection = NULL;
// Get the INetDefaultConnection object from the persist data
//
hr = ccfe.HrGetNetCon(IID_INetDefaultConnection, reinterpret_cast<VOID**>(&pNetDefaultConnection));
if (SUCCEEDED(hr))
{
hr = pNetDefaultConnection->SetDefault(TRUE);
ReleaseObj(pNetDefaultConnection);
hr = S_OK;
}
else
{
if (E_NOINTERFACE == hr)
{
AssertSz(FALSE, "BUG: This connection type does not support INetDefaultConnection. Remove it from the menu");
}
}
}
}
TraceHr(ttidError, FAL, hr, FALSE, "HrOnCommandSetDefault");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandUnsetDefault
//
// Purpose: Command handler for the CMIDM_UNSET_DEFAULT command
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// cidl [in] Size of the array
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: deonb 27 Nov 2000
//
// Notes: We only act on a single entry in this function
//
HRESULT HrOnCommandUnsetDefault(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf)
{
HRESULT hr = S_OK;
CONFOLDENTRY ccfe;
if (!apidl.empty())
{
hr = apidl[0].ConvertToConFoldEntry(ccfe);
if (SUCCEEDED(hr))
{
INetDefaultConnection *pNetDefaultConnection = NULL;
// Get the INetDefaultConnection object from the persist data
//
hr = ccfe.HrGetNetCon(IID_INetDefaultConnection, reinterpret_cast<VOID**>(&pNetDefaultConnection));
if (SUCCEEDED(hr))
{
hr = pNetDefaultConnection->SetDefault(FALSE);
ReleaseObj(pNetDefaultConnection);
hr = S_OK;
}
else
{
if (E_NOINTERFACE == hr)
{
AssertSz(FALSE, "BUG: This connection type does not support INetDefaultConnection. Remove it from the menu");
}
}
}
}
TraceHr(ttidError, FAL, hr, FALSE, "HrOnCommandUnsetDefault");
return hr;
}
HRESULT HrCreateShortcutWithPath(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf,
PCWSTR pszDir)
{
HRESULT hr = S_OK;
LPDATAOBJECT pdtobj = NULL;
LPCITEMIDLIST* apidlInternal = NULL;
ULONG cidlInternal = 0;
PCONFOLDPIDLVEC::const_iterator iterLoop;
if (!apidl.empty())
{
apidlInternal = new LPCITEMIDLIST[apidl.size()];
if (apidlInternal)
{
for (iterLoop = apidl.begin(); iterLoop != apidl.end(); iterLoop++)
{
const PCONFOLDPIDL& pcfp = *iterLoop;
if (!(pcfp->dwCharacteristics & NCCF_INCOMING_ONLY))
{
apidlInternal[cidlInternal++] = iterLoop->GetItemIdList();
}
}
hr = psf->GetUIObjectOf(
hwndOwner,
cidlInternal,
apidlInternal,
IID_IDataObject,
NULL,
(LPVOID *) &pdtobj);
if (SUCCEEDED(hr))
{
SHCreateLinks(hwndOwner, pszDir, pdtobj,
SHCL_USEDESKTOP | SHCL_USETEMPLATE | SHCL_CONFIRM,
NULL);
ReleaseObj(pdtobj);
}
delete apidlInternal;
}
}
TraceError("HrCreateShortcutWithPath", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: RefreshFolderItem
//
// Purpose: Refresh an item within a connections folder. Mostly, this will
// be called after a connect or disconnect operation.
//
// Arguments:
// pidlFolder [in] PIDL for the connections folder
// pidlItemOld[in] PIDL for the item that's changed.
// pidlItemNew[in] PIDL for the item that it's changing to.
// fRestart [in] If this is called during system startup
//
// Returns:
//
// Author: jeffspr 13 Jun 1998
//
// Notes:
//
VOID RefreshFolderItem(const PCONFOLDPIDLFOLDER& pidlFolder, const PCONFOLDPIDL& pidlItemOld, const PCONFOLDPIDL& pidlItemNew, BOOL fRestart)
{
TraceTag(ttidShellFolder, "RefreshFolderItem");
NETCFG_TRY
HRESULT hr = S_OK;
INT iCachedImage = 0;
PCONFOLDPIDLFOLDER pidlFolderCopy;
// If a folder pidl wasn't passed in, try to get one
//
if (pidlFolder.empty())
{
hr = HrGetConnectionsFolderPidl(pidlFolderCopy);
}
else
{
pidlFolderCopy = pidlFolder;
}
// If we now have a pidl, send the GenerateEvent to update the item
//
if (SUCCEEDED(hr))
{
GenerateEvent(SHCNE_UPDATEITEM, pidlFolderCopy, pidlItemNew, NULL);
}
// If we have a old item pidl, try to update its icon (useful for
// shortcuts as well as folder items)
//
if (!pidlItemOld.empty())
{
const PCONFOLDPIDL& pcfp = pidlItemOld;
if (!pcfp.empty())
{
CConFoldEntry cfe;
hr = pcfp.ConvertToConFoldEntry(cfe);
if (SUCCEEDED(hr))
{
g_pNetConfigIcons->HrUpdateSystemImageListForPIDL(cfe);
}
if (fRestart)
{
TraceTag(ttidIcons, "Refreshing Icon Shortcuts for startup");
// RAS connection state will be changed between reboots,
// we need to make sure icons for previously connected
// or disconnected ras connections are also updated
// If it's a ras connection,
BOOL fInbound = !!(pidlItemOld->dwCharacteristics & NCCF_INCOMING_ONLY);
if ((IsMediaRASType(pidlItemOld->ncm)) && !fInbound)
{
PCONFOLDPIDL pcfpTemp = pidlItemOld;
if ((pcfpTemp->ncs == NCS_DISCONNECTED) ||
(pcfpTemp->ncs == NCS_CONNECTING))
{
// get the connected icon
pcfpTemp->ncs = NCS_CONNECTED;
}
else
{
// get the disconnected icon
pcfpTemp->ncs = NCS_DISCONNECTED;
}
cfe.clear();
hr = pcfpTemp.ConvertToConFoldEntry(cfe);
if (SUCCEEDED(hr))
{
g_pNetConfigIcons->HrUpdateSystemImageListForPIDL(cfe);
}
}
}
}
}
NETCFG_CATCH_NOHR
}
//
//
//
HRESULT
HrOnCommandCreateBridge(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf
)
{
HRESULT hResult;
IHNetCfgMgr* pHomeNetConfigManager;
CWaitCursor wc; // display wait cursor
hResult = HrCreateInstance(CLSID_HNetCfgMgr, CLSCTX_INPROC, &pHomeNetConfigManager); // REVIEW combine this with QI?
if(SUCCEEDED(hResult))
{
IHNetBridgeSettings* pNetBridgeSettings;
hResult = pHomeNetConfigManager->QueryInterface(IID_IHNetBridgeSettings, reinterpret_cast<void**>(&pNetBridgeSettings));
if(SUCCEEDED(hResult))
{
IHNetBridge* pNetBridge;
IEnumHNetBridges* pNetBridgeEnum;
hResult = pNetBridgeSettings->EnumBridges(&pNetBridgeEnum);
if(SUCCEEDED(hResult))
{
hResult = pNetBridgeEnum->Next(1, &pNetBridge, NULL);
if(S_FALSE == hResult) // no existing bridges, make a new one
{
hResult = pNetBridgeSettings->CreateBridge(&pNetBridge);
}
if(S_OK == hResult) // can't use SUCCEEDED because someone returns S_FALSE
{
Assert(pNetBridge); // we better have gotten one from somewhere
// Add any selected connections
for ( PCONFOLDPIDLVEC::const_iterator i = apidl.begin(); (i != apidl.end()) && SUCCEEDED(hResult); i++ )
{
const PCONFOLDPIDL& pcfp = *i;
if ( pcfp.empty() )
continue;
if ( NCM_LAN != pcfp->ncm )
continue;
if ( (NCCF_BRIDGED|NCCF_FIREWALLED|NCCF_SHARED) & pcfp->dwCharacteristics )
continue;
//
// Ok we now have a LAN adapter the is valid to bind to the bridge
//
INetConnection* pNetConnection;
hResult = HrNetConFromPidl(*i, &pNetConnection);
if(SUCCEEDED(hResult))
{
IHNetConnection* pHomeNetConnection;
hResult = pHomeNetConfigManager->GetIHNetConnectionForINetConnection(pNetConnection, &pHomeNetConnection);
if(SUCCEEDED(hResult))
{
IHNetBridgedConnection* pBridgedConnection;
hResult = pNetBridge->AddMember(pHomeNetConnection, &pBridgedConnection);
if(SUCCEEDED(hResult))
{
ReleaseObj(pBridgedConnection);
}
ReleaseObj(pHomeNetConnection);
}
ReleaseObj(pNetConnection);
}
// no cleanup needed
}
ReleaseObj(pNetBridge);
}
ReleaseObj(pNetBridgeEnum);
}
ReleaseObj(pNetBridgeSettings);
}
ReleaseObj(pHomeNetConfigManager);
}
SendMessage(hwndOwner, WM_COMMAND, IDCANCEL, 0); // destroy the status dialog
// Show an error dialog on failure
if( FAILED(hResult) )
{
UINT ids;
if( NETCFG_E_NO_WRITE_LOCK == hResult )
{
ids = IDS_CONFOLD_BRIDGE_NOLOCK;
}
else
{
ids = IDS_CONFOLD_BRIDGE_UNEXPECTED;
}
NcMsgBox( _Module.GetResourceInstance(), NULL, IDS_CONFOLD_WARNING_CAPTION, ids, MB_ICONEXCLAMATION | MB_OK);
}
return hResult;
}
//
//
//
INT_PTR CALLBACK
CreateBridgeStatusDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
INT_PTR nResult = FALSE;
switch(uMsg)
{
case WM_INITDIALOG:
{
LPCWSTR pResourceStr = SzLoadIds(IDS_CONFOLD_OBJECT_TYPE_BRIDGE);
SetWindowText(hwndDlg, pResourceStr);
pResourceStr = SzLoadIds(IDS_STATUS_BRIDGE_CREATION);
SetDlgItemText(hwndDlg, IDC_TXT_STATUS, pResourceStr);
CCommandHandlerParams* pCreateBridgeParams = reinterpret_cast<CCommandHandlerParams*>(lParam);
HrCommandHandlerThread(HrOnCommandCreateBridge, *(pCreateBridgeParams->apidl), hwndDlg, pCreateBridgeParams->psf);
// HrOnCommandCreateBridge will send a message to kill this dialog
nResult = TRUE;
}
break;
case WM_COMMAND:
if(IDCANCEL == LOWORD(wParam))
{
EndDialog(hwndDlg, 0);
nResult = TRUE;
}
break;
}
return nResult;
}
//
//
//
HRESULT
HrOnCommandDeleteBridge(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf
)
{
HRESULT hr = S_FALSE;
PCONFOLDPIDLVEC::const_iterator iterator;
for ( iterator = apidl.begin(); iterator != apidl.end(); iterator++ )
{
CONFOLDENTRY ccfe;
hr = iterator->ConvertToConFoldEntry(ccfe);
if ( SUCCEEDED(hr) )
{
if ( NCM_BRIDGE == ccfe.GetNetConMediaType() )
{
//
// Stop at the first select BRIDGE item
// The delete of the bridge is part of a bigger FOR LOOP see HrOnCommandDelete()
//
INetConnection* pNetConnection;
hr = HrNetConFromPidl(*iterator, &pNetConnection);
if ( SUCCEEDED(hr) )
{
hr = pNetConnection->Delete();
ReleaseObj(pNetConnection);
}
break;
}
}
}
SendMessage(hwndOwner, WM_COMMAND, IDCANCEL, hr); // destroy the status dialog
// Show an error dialog on failure
if( FAILED(hr) )
{
UINT ids;
if( NETCFG_E_NO_WRITE_LOCK == hr )
{
ids = IDS_CONFOLD_BRIDGE_NOLOCK;
}
else
{
ids = IDS_CONFOLD_BRIDGE_UNEXPECTED;
}
NcMsgBox( _Module.GetResourceInstance(), NULL, IDS_CONFOLD_WARNING_CAPTION, ids, MB_ICONEXCLAMATION | MB_OK);
}
return S_OK;
}
//
//
//
HRESULT
HrOnCommandDeleteBridgeConnections(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf
)
{
CWaitCursor wc; // display wait cursor
IHNetCfgMgr* pHomeNetConfigManager;
HRESULT hResult = HrCreateInstance(CLSID_HNetCfgMgr, CLSCTX_INPROC, &pHomeNetConfigManager); // REVIEW combine this with QI?
if ( SUCCEEDED(hResult) )
{
//
// Remove any selected connections
//
for ( PCONFOLDPIDLVEC::const_iterator i = apidl.begin(); i != apidl.end() && SUCCEEDED(hResult); i++ )
{
INetConnection* pNetConnection;
hResult = HrNetConFromPidl(*i, &pNetConnection);
if(SUCCEEDED(hResult))
{
IHNetConnection* pHomeNetConnection;
hResult = pHomeNetConfigManager->GetIHNetConnectionForINetConnection(pNetConnection, &pHomeNetConnection);
if(SUCCEEDED(hResult))
{
IHNetBridgedConnection* pBridgedConnection;
hResult = pHomeNetConnection->GetControlInterface(IID_IHNetBridgedConnection, reinterpret_cast<void**>(&pBridgedConnection));
if ( SUCCEEDED(hResult) )
{
hResult = pBridgedConnection->RemoveFromBridge();
ReleaseObj(pBridgedConnection);
}
ReleaseObj(pHomeNetConnection);
}
ReleaseObj(pNetConnection);
}
// no cleanup needed
}
ReleaseObj(pHomeNetConfigManager);
}
SendMessage(hwndOwner, WM_COMMAND, IDCANCEL, hResult); // destroy the status dialog
// Show an error dialog on failure
if( FAILED(hResult) )
{
UINT ids;
if( NETCFG_E_NO_WRITE_LOCK == hResult )
{
ids = IDS_CONFOLD_BRIDGE_NOLOCK;
}
else
{
ids = IDS_CONFOLD_BRIDGE_UNEXPECTED;
}
NcMsgBox( _Module.GetResourceInstance(), NULL, IDS_CONFOLD_WARNING_CAPTION, ids, MB_ICONEXCLAMATION | MB_OK);
}
return S_OK;
}
//
//
//
INT_PTR CALLBACK
DeleteBridgeStatusDialogProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
INT_PTR nResult = FALSE;
switch(uMsg)
{
case WM_INITDIALOG:
{
LPCWSTR pResourceStr = SzLoadIds(IDS_CONFOLD_OBJECT_TYPE_BRIDGE);
SetWindowText(hwndDlg, pResourceStr);
CCommandHandlerParams* pDeleteBridgeParams = reinterpret_cast<CCommandHandlerParams*>(lParam);
if ( pDeleteBridgeParams->nAdditionalParam == CMIDM_REMOVE_FROM_BRIDGE )
{
//
// Only remove the currently selected connections from the Network bridge
//
pResourceStr = SzLoadIds(IDS_STATUS_BRIDGE_REMOVE_MEMBER);
SetDlgItemText(hwndDlg, IDC_TXT_STATUS, pResourceStr);
HrCommandHandlerThread(HrOnCommandDeleteBridgeConnections, *(pDeleteBridgeParams->apidl), hwndDlg, pDeleteBridgeParams->psf);
}
else
{
//
// Full delete of the network bridge
//
pResourceStr = SzLoadIds(IDS_STATUS_BRIDGE_DELETING);
SetDlgItemText(hwndDlg, IDC_TXT_STATUS, pResourceStr);
HrCommandHandlerThread(HrOnCommandDeleteBridge, *(pDeleteBridgeParams->apidl), hwndDlg, pDeleteBridgeParams->psf);
}
// After the delete a HrOnCommandDeleteBridge will send a SendMessage(hwndOwner, WM_COMMAND, IDCANCEL, 0); // destroy the status dialog
nResult = TRUE;
}
break;
case WM_COMMAND:
if(IDCANCEL == LOWORD(wParam))
{
EndDialog(hwndDlg, lParam);
nResult = TRUE;
}
break;
}
return nResult;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandBridgeAddConnections
//
// Purpose: Command handler for the CMIDM_CREATE_BRIDGE, CMDIDM_CONMENU_CREATE_BRIDGE, CMIDM_ADD_TO_BRIDGE.
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// psf [in] SHELLFOLDER
// hwndOwner [in] Owner hwnd
//
// Returns:
//
// Author: jpdup 6 March 2000
//
// Notes:
//
HRESULT
HrOnCommandBridgeAddConnections(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf
)
{
CCommandHandlerParams CreateBridgeParams;
CreateBridgeParams.apidl = &apidl;
CreateBridgeParams.hwndOwner = hwndOwner;
CreateBridgeParams.psf = psf;
HRESULT hr = DialogBoxParam(
_Module.GetResourceInstance(),
MAKEINTRESOURCE(IDD_STATUS),
hwndOwner,
CreateBridgeStatusDialogProc,
reinterpret_cast<LPARAM>(&CreateBridgeParams)
);
TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrOnCommandBridgeAddConnections");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOnCommandBridgeRemoveConnections
//
// Purpose: Command handler for the CMIDM_REMOVE_FROM_BRIDGE and the DELETE command when done on the NetworkBridge object
//
// Arguments:
// apidl [in] PIDL array (item 0 is our item to work on)
// hwndOwner [in] Owner hwnd
// psf [in] SHELLFOLDER
// bDeleteTheNetworkBridge [in] true is the NetworkBridge needs to be totaly remove, false if only the currently select item found in apild needs to be remove
//
// Returns:
//
// Author: jpdup 6 March 2000
//
// Notes:
//
HRESULT
HrOnCommandBridgeRemoveConnections(
IN const PCONFOLDPIDLVEC& apidl,
HWND hwndOwner,
LPSHELLFOLDER psf,
UINT_PTR nDeleteTheNetworkBridgeMode
)
{
CCommandHandlerParams DeleteBridgeParams;
DeleteBridgeParams.apidl = &apidl;
DeleteBridgeParams.hwndOwner = hwndOwner;
DeleteBridgeParams.psf = psf;
DeleteBridgeParams.nAdditionalParam = nDeleteTheNetworkBridgeMode;
HRESULT hr = DialogBoxParam(
_Module.GetResourceInstance(),
MAKEINTRESOURCE(IDD_STATUS),
hwndOwner,
DeleteBridgeStatusDialogProc,
reinterpret_cast<LPARAM>(&DeleteBridgeParams)
);
TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrOnCommandBridgeRemoveConnections");
return hr;
}