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.
1123 lines
31 KiB
1123 lines
31 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 2000
|
|
//
|
|
// File: cpaction.cpp
|
|
//
|
|
// This module implements the various 'action' objects used by the
|
|
// Control Panel's 'category' view. Each 'link' in the UI has an
|
|
// associated 'action'. The action objects are defined in cpnamespc.cpp.
|
|
// All 'action' objects are designed so that object construction is
|
|
// very cheap and that minimal processing is performed until the action
|
|
// is invoked.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
#include "shellprv.h"
|
|
|
|
#include <idhidden.h>
|
|
|
|
#include "cpviewp.h"
|
|
#include "cpaction.h"
|
|
#include "cpguids.h"
|
|
#include "cpuiele.h"
|
|
#include "cputil.h"
|
|
|
|
|
|
//// from shell\sdspatch\sdfolder.cpp
|
|
VARIANT_BOOL GetBarricadeStatus(LPCTSTR pszValueName);
|
|
|
|
|
|
//
|
|
// Disable warning. ShellExecute uses SEH.
|
|
// "nonstandard extension used: 'Execute' uses SEH and 'se' has destructor".
|
|
//
|
|
#pragma warning( push )
|
|
#pragma warning( disable:4509 )
|
|
|
|
|
|
using namespace CPL;
|
|
|
|
|
|
//
|
|
// Helper to append a bare file name to the system directory.
|
|
//
|
|
HRESULT
|
|
AppendToSysDir(
|
|
LPCWSTR pszToAppend, // Append this
|
|
LPWSTR pszPath, // [out] Contains concatenated result
|
|
size_t cchPath
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
WCHAR szTemp[MAX_PATH];
|
|
if (0 != GetSystemDirectory(szTemp, ARRAYSIZE(szTemp)))
|
|
{
|
|
if (PathAppend(szTemp, pszToAppend))
|
|
{
|
|
hr = StringCchCopy(pszPath, cchPath, szTemp);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = ResultFromLastError();
|
|
}
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CRestrictApplet::IsRestricted(
|
|
ICplNamespace *pns
|
|
) const
|
|
{
|
|
UNREFERENCED_PARAMETER(pns);
|
|
|
|
DBG_ENTER(FTF_CPANEL, "RestrictApplet");
|
|
|
|
HRESULT hr = S_FALSE;
|
|
if (!IsAppletEnabled(m_pszFile, m_pszApplet))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
DBG_EXIT_HRES(FTF_CPANEL, "RestrictApplet", hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CAction implementation
|
|
//--------------------------------------------------------------------------
|
|
|
|
CAction::CAction(
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : m_pRestrict(pRestrict)
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Returns:
|
|
// S_FALSE - Not restricted.
|
|
// S_OK - Restricted.
|
|
// Failure - Cannot determine.
|
|
//
|
|
HRESULT
|
|
CAction::IsRestricted(
|
|
ICplNamespace *pns
|
|
) const
|
|
{
|
|
HRESULT hr = S_FALSE; // Assume not restricted.
|
|
|
|
if (NULL != m_pRestrict)
|
|
{
|
|
hr = m_pRestrict->IsRestricted(pns);
|
|
}
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COpenUserMgrApplet implementation
|
|
//--------------------------------------------------------------------------
|
|
|
|
COpenUserMgrApplet::COpenUserMgrApplet(
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
): CAction(pRestrict)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
COpenUserMgrApplet::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
DBG_ENTER(FTF_CPANEL, "COpenUserMgrApplet::Execute");
|
|
|
|
HRESULT hr = E_FAIL;
|
|
if (IsOsServer())
|
|
{
|
|
CShellExecuteSysDir action(L"lusrmgr.msc");
|
|
hr = action.Execute(hwndParent, punkSite);
|
|
}
|
|
else
|
|
{
|
|
COpenCplAppletSysDir action(L"nusrmgr.cpl");
|
|
hr = action.Execute(hwndParent, punkSite);
|
|
}
|
|
|
|
DBG_EXIT_HRES(FTF_CPANEL, "COpenUserMgrApplet::Execute", hr);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COpenCplApplet implementation
|
|
//--------------------------------------------------------------------------
|
|
|
|
COpenCplApplet::COpenCplApplet(
|
|
LPCWSTR pszApplet,
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : CAction(pRestrict),
|
|
m_pszApplet(pszApplet)
|
|
{
|
|
ASSERT(NULL != pszApplet);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
COpenCplApplet::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
DBG_ENTER(FTF_CPANEL, "COpenCplApplet::Execute");
|
|
|
|
ASSERT(NULL != m_pszApplet);
|
|
ASSERT(NULL == hwndParent || IsWindow(hwndParent));
|
|
|
|
UNREFERENCED_PARAMETER(punkSite);
|
|
|
|
//
|
|
// Build a path consisting of the system directory, the
|
|
// "%SystemDir%\shell32,Control_RunDLL" string and the
|
|
// applet name. i.e.:
|
|
//
|
|
// "c:\windows\system32\shell32,Control_RundLL desk.cpl"
|
|
//
|
|
WCHAR szArgs[MAX_PATH * 2];
|
|
HRESULT hr = AppendToSysDir(L"shell32.dll,Control_RunDLL ", szArgs, ARRAYSIZE(szArgs));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = StringCchCat(szArgs, ARRAYSIZE(szArgs), m_pszApplet);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Build a path to rundll32.exe.
|
|
// i.e.:
|
|
// "c:\windows\system32\rundll32.exe"
|
|
//
|
|
WCHAR szRunDll32[MAX_PATH];
|
|
hr = AppendToSysDir(L"rundll32.exe", szRunDll32, ARRAYSIZE(szRunDll32));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TraceMsg(TF_CPANEL, "Executing: \"%s %s\"", szRunDll32, szArgs);
|
|
|
|
SHELLEXECUTEINFOW sei = {
|
|
sizeof(sei), // cbSize;
|
|
0, // fMask
|
|
hwndParent, // hwnd
|
|
NULL, // lpVerb
|
|
szRunDll32, // lpFile
|
|
szArgs, // lpParameters
|
|
NULL, // lpDirectory
|
|
SW_SHOWNORMAL, // nShow
|
|
0, // hInstApp
|
|
NULL, // lpIDList
|
|
NULL, // lpClass
|
|
NULL, // hkeyClass
|
|
0, // dwHotKey
|
|
NULL, // hIcon
|
|
NULL // hProcess
|
|
};
|
|
if (!ShellExecuteExW(&sei))
|
|
{
|
|
hr = ResultFromLastError();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DBG_EXIT_HRES(FTF_CPANEL, "COpenCplApplet::Execute", hr);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COpenCplAppletSysDir implementation
|
|
//
|
|
// Minor extension of COpenCplApplet that assumes the applet is in
|
|
// %SystemRoot%\System32 directory.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
COpenCplAppletSysDir::COpenCplAppletSysDir(
|
|
LPCWSTR pszApplet,
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : COpenCplApplet(pszApplet, pRestrict)
|
|
{
|
|
ASSERT(NULL != pszApplet);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
COpenCplAppletSysDir::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
DBG_ENTER(FTF_CPANEL, "COpenCplAppletSysDir::Execute");
|
|
|
|
ASSERT(NULL != m_pszApplet);
|
|
ASSERT(NULL == hwndParent || IsWindow(hwndParent));
|
|
|
|
UNREFERENCED_PARAMETER(punkSite);
|
|
|
|
//
|
|
// Build a path consisting of the system directory and the
|
|
// applet name. i.e.:
|
|
//
|
|
// "c:\windows\system32\desk.cpl"
|
|
//
|
|
WCHAR szAppletPath[MAX_PATH];
|
|
HRESULT hr = AppendToSysDir(m_pszApplet, szAppletPath, ARRAYSIZE(szAppletPath));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
COpenCplApplet oca(szAppletPath);
|
|
hr = oca.Execute(hwndParent, punkSite);
|
|
}
|
|
|
|
DBG_EXIT_HRES(FTF_CPANEL, "COpenCplAppletSysDir::Execute", hr);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COpenDeskCpl implementation
|
|
//--------------------------------------------------------------------------
|
|
|
|
COpenDeskCpl::COpenDeskCpl(
|
|
eDESKCPLTAB eCplTab,
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : CAction(pRestrict),
|
|
m_eCplTab(eCplTab)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
COpenDeskCpl::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
DBG_ENTER(FTF_CPANEL, "COpenDeskCpl::Execute");
|
|
TraceMsg(TF_CPANEL, "Desk CPL tab ID = %d", m_eCplTab);
|
|
|
|
ASSERT(NULL == hwndParent || IsWindow(hwndParent));
|
|
|
|
UNREFERENCED_PARAMETER(punkSite);
|
|
|
|
HRESULT hr = E_FAIL;
|
|
WCHAR szTab[MAX_PATH];
|
|
|
|
const int iTab = CPL::DeskCPL_GetTabIndex(m_eCplTab, szTab, ARRAYSIZE(szTab));
|
|
if (CPLTAB_ABSENT != iTab)
|
|
{
|
|
WCHAR szArgs[MAX_PATH];
|
|
|
|
hr = StringCchPrintfW(szArgs, ARRAYSIZE(szArgs), L"desk.cpl ,@%ls", szTab);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
COpenCplAppletSysDir oca(szArgs);
|
|
hr = oca.Execute(hwndParent, punkSite);
|
|
}
|
|
}
|
|
|
|
DBG_EXIT_HRES(FTF_CPANEL, "COpenDeskCpl::Execute", hr);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CNavigateURL implementation
|
|
//--------------------------------------------------------------------------
|
|
|
|
CNavigateURL::CNavigateURL(
|
|
LPCWSTR pszURL,
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : CAction(pRestrict),
|
|
m_pszURL(pszURL)
|
|
{
|
|
ASSERT(NULL != pszURL);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CNavigateURL::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
DBG_ENTER(FTF_CPANEL, "CNavigateURL::Execute");
|
|
|
|
ASSERT(NULL != m_pszURL);
|
|
ASSERT(NULL == hwndParent || IsWindow(hwndParent));
|
|
|
|
UNREFERENCED_PARAMETER(hwndParent);
|
|
|
|
TraceMsg(TF_CPANEL, "URL = \"%s\"", m_pszURL);
|
|
|
|
IWebBrowser2 *pwb;
|
|
HRESULT hr = IUnknown_QueryService(punkSite, SID_SWebBrowserApp, IID_IWebBrowser2, (void **)&pwb);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPTSTR pszExpanded;
|
|
hr = CPL::ExpandEnvironmentVars(m_pszURL, &pszExpanded);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
VARIANT varURL;
|
|
hr = InitVariantFromStr(&varURL, pszExpanded);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
VARIANT varEmpty;
|
|
VariantInit(&varEmpty);
|
|
|
|
VARIANT varFlags;
|
|
varFlags.vt = VT_UINT;
|
|
varFlags.uintVal = 0;
|
|
|
|
hr = pwb->Navigate2(&varURL, &varFlags, &varEmpty, &varEmpty, &varEmpty);
|
|
VariantClear(&varURL);
|
|
}
|
|
LocalFree(pszExpanded);
|
|
}
|
|
pwb->Release();
|
|
}
|
|
DBG_EXIT_HRES(FTF_CPANEL, "CNavigateURL::Execute", hr);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COpenTroubleshooter implementation
|
|
//--------------------------------------------------------------------------
|
|
|
|
COpenTroubleshooter::COpenTroubleshooter(
|
|
LPCWSTR pszTs,
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : CAction(pRestrict),
|
|
m_pszTs(pszTs)
|
|
{
|
|
ASSERT(NULL != pszTs);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
COpenTroubleshooter::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
DBG_ENTER(FTF_CPANEL, "COpenTroubleshooter::Execute");
|
|
|
|
ASSERT(NULL != m_pszTs);
|
|
ASSERT(NULL == hwndParent || IsWindow(hwndParent));
|
|
|
|
UNREFERENCED_PARAMETER(punkSite);
|
|
|
|
WCHAR szPath[MAX_PATH];
|
|
HRESULT hr = StringCchPrintfW(szPath, ARRAYSIZE(szPath), L"hcp://help/tshoot/%s", m_pszTs);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CNavigateURL actionURL(szPath);
|
|
|
|
hr = actionURL.Execute(hwndParent, punkSite);
|
|
}
|
|
|
|
DBG_EXIT_HRES(FTF_CPANEL, "COpenTroubleshooter::Execute", hr);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CShellExecute implementation
|
|
//--------------------------------------------------------------------------
|
|
|
|
CShellExecute::CShellExecute(
|
|
LPCWSTR pszExe,
|
|
LPCWSTR pszArgs, // optional. default = NULL.
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : CAction(pRestrict),
|
|
m_pszExe(pszExe),
|
|
m_pszArgs(pszArgs)
|
|
{
|
|
ASSERT(NULL != pszExe);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CShellExecute::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
DBG_ENTER(FTF_CPANEL, "CShellExecute::Execute");
|
|
|
|
ASSERT(NULL != m_pszExe);
|
|
ASSERT(NULL == hwndParent || IsWindow(hwndParent));
|
|
|
|
UNREFERENCED_PARAMETER(punkSite);
|
|
|
|
TraceMsg(TF_CPANEL, "ShellExecute: \"%s %s\"", m_pszExe, m_pszArgs ? m_pszArgs : L"<no args>");
|
|
|
|
SHELLEXECUTEINFOW sei = {
|
|
sizeof(sei), // cbSize;
|
|
SEE_MASK_DOENVSUBST, // fMask
|
|
hwndParent, // hwnd
|
|
L"open", // lpVerb
|
|
m_pszExe, // lpFile
|
|
m_pszArgs, // lpParameters
|
|
NULL, // lpDirectory
|
|
SW_SHOWNORMAL, // nShow
|
|
0, // hInstApp
|
|
NULL, // lpIDList
|
|
NULL, // lpClass
|
|
NULL, // hkeyClass
|
|
0, // dwHotKey
|
|
NULL, // hIcon
|
|
NULL // hProcess
|
|
};
|
|
|
|
HRESULT hr = S_OK;
|
|
if (!ShellExecuteExW(&sei))
|
|
{
|
|
hr = ResultFromLastError();
|
|
}
|
|
|
|
DBG_EXIT_HRES(FTF_CPANEL, "CShellExecute::Execute", hr);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CShellExecuteSysDir implementation
|
|
// Simply wraps CShellExecute assuming that the EXE exists in the
|
|
// SYSTEM32 directory.
|
|
//--------------------------------------------------------------------------
|
|
|
|
CShellExecuteSysDir::CShellExecuteSysDir(
|
|
LPCWSTR pszExe,
|
|
LPCWSTR pszArgs, // optional. default = NULL.
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : CShellExecute(pszExe, pszArgs, pRestrict)
|
|
{
|
|
ASSERT(NULL != pszExe);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CShellExecuteSysDir::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
DBG_ENTER(FTF_CPANEL, "CShellExecuteSysDir::Execute");
|
|
|
|
ASSERT(NULL != m_pszExe);
|
|
ASSERT(NULL == hwndParent || IsWindow(hwndParent));
|
|
|
|
UNREFERENCED_PARAMETER(punkSite);
|
|
|
|
TraceMsg(TF_CPANEL, "ShellExecuteSysDir: \"%s %s\"", m_pszExe, m_pszArgs ? m_pszArgs : L"<no args>");
|
|
|
|
//
|
|
// Build a path consisting of the system directory and the
|
|
// EXE name. i.e.:
|
|
//
|
|
// "c:\windows\system32\myapp.exe"
|
|
//
|
|
WCHAR szExePath[MAX_PATH];
|
|
HRESULT hr = AppendToSysDir(m_pszExe, szExePath, ARRAYSIZE(szExePath));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CShellExecute se(szExePath, m_pszArgs);
|
|
hr = se.Execute(hwndParent, punkSite);
|
|
}
|
|
|
|
DBG_EXIT_HRES(FTF_CPANEL, "CShellExecuteSysDir::Execute", hr);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CRundll32 implementation
|
|
// This is a simple wrapper around CShellExecute that saves an instance
|
|
// definition from having to type L"%SystemRoot%\\system32\\rundll32.exe".
|
|
//--------------------------------------------------------------------------
|
|
|
|
CRunDll32::CRunDll32(
|
|
LPCWSTR pszArgs,
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : CAction(pRestrict),
|
|
m_pszArgs(pszArgs)
|
|
{
|
|
ASSERT(NULL != pszArgs);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CRunDll32::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
DBG_ENTER(FTF_CPANEL, "CRunDll32::Execute");
|
|
|
|
ASSERT(NULL != m_pszArgs);
|
|
ASSERT(NULL == hwndParent || IsWindow(hwndParent));
|
|
|
|
TraceMsg(TF_CPANEL, "CRunDll32: \"%s\"", m_pszArgs);
|
|
|
|
WCHAR szPath[MAX_PATH];
|
|
HRESULT hr = AppendToSysDir(L"rundll32.exe", szPath, ARRAYSIZE(szPath));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CShellExecute se(szPath, m_pszArgs);
|
|
hr = se.Execute(hwndParent, punkSite);
|
|
}
|
|
|
|
DBG_EXIT_HRES(FTF_CPANEL, "CRunDll32::Execute", hr);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CExecDiskUtil implementation
|
|
//--------------------------------------------------------------------------
|
|
|
|
CExecDiskUtil::CExecDiskUtil(
|
|
eDISKUTILS eUtil,
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : CAction(pRestrict),
|
|
m_eUtil(eUtil)
|
|
{
|
|
ASSERT(eDISKUTIL_NUMUTILS > m_eUtil);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CExecDiskUtil::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
DBG_ENTER(FTF_CPANEL, "CExecDiskUtil::Execute");
|
|
TCHAR szValue[MAX_PATH];
|
|
DWORD dwType;
|
|
DWORD cbValue = sizeof(szValue);
|
|
|
|
//
|
|
// These strings must remain in sync with the eDISKUTILS enumeration.
|
|
//
|
|
static LPCTSTR rgpszRegNames[] = {
|
|
TEXT("MyComputer\\backuppath"), // eDISKUTIL_BACKUP
|
|
TEXT("MyComputer\\defragpath"), // eDISKUTIL_DEFRAG
|
|
TEXT("MyComputer\\cleanuppath"), // eDISKUTIL_CLEANUP
|
|
};
|
|
|
|
HRESULT hr = SKGetValue(SHELLKEY_HKLM_EXPLORER,
|
|
rgpszRegNames[int(m_eUtil)],
|
|
NULL,
|
|
&dwType,
|
|
szValue,
|
|
&cbValue);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPTSTR pszExpanded = NULL;
|
|
//
|
|
// Expand environment strings.
|
|
// According to the code in shell32\drvx.cpp, some apps
|
|
// use embedded env vars even if the value type is REG_SZ.
|
|
//
|
|
hr = CPL::ExpandEnvironmentVars(szValue, &pszExpanded);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// The drive utility command strings were designed to be
|
|
// invoked from the drives property page. They therefore
|
|
// accept a drive letter. Since control panel launches
|
|
// the utilities for no particular drive, we need to remove
|
|
// the "%c:" format specifier.
|
|
//
|
|
hr = _RemoveDriveLetterFmtSpec(pszExpanded);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TCHAR szArgs[MAX_PATH] = {0};
|
|
PathRemoveBlanks(pszExpanded);
|
|
hr = PathSeperateArgs(pszExpanded, szArgs, ARRAYSIZE(szArgs), NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Note that it's valid to use a NULL restriction here.
|
|
// If there's a restriction on the CExecDiskUtil object
|
|
// we won't get this far (i.e. Execute isn't called).
|
|
//
|
|
CShellExecute exec(pszExpanded, szArgs);
|
|
hr = exec.Execute(hwndParent, punkSite);
|
|
}
|
|
}
|
|
LocalFree(pszExpanded);
|
|
}
|
|
}
|
|
DBG_EXIT_HRES(FTF_CPANEL, "CExecDiskUtil::Execute", hr);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
//
|
|
// The command line strings for the backup, defrag and disk cleanup utilities
|
|
// can contain a format specifier for the drive letter. That's because
|
|
// they're designed to be opened from a particular volume's "Tools" property
|
|
// page. Control Panel launches these from outside the context of any particular
|
|
// volume. Therefore, the drive letter is not available and the the format
|
|
// specifier is unused. This function removes that format specifier if it exists.
|
|
//
|
|
// i.e.: "c:\windows\system32\ntbackup.exe" -> "c:\windows\system32\ntbackpu.exe"
|
|
// "c:\windows\system32\cleanmgr.exe /D %c:" -> "c:\windows\system32\cleanmgr.exe"
|
|
// "c:\windows\system32\defrg.msc %c:" -> "c:\windows\system32\defrg.msc"
|
|
//
|
|
HRESULT
|
|
CExecDiskUtil::_RemoveDriveLetterFmtSpec( // [static]
|
|
LPTSTR pszCmdLine
|
|
)
|
|
{
|
|
LPCTSTR pszRead = pszCmdLine;
|
|
LPTSTR pszWrite = pszCmdLine;
|
|
|
|
while(*pszRead)
|
|
{
|
|
if (TEXT('%') == *pszRead && TEXT('c') == *(pszRead + 1))
|
|
{
|
|
//
|
|
// Skip over the "%c" or "%c:" fmt specifier.
|
|
//
|
|
pszRead += 2;
|
|
if (TEXT(':') == *pszRead)
|
|
{
|
|
pszRead++;
|
|
}
|
|
}
|
|
if (*pszRead)
|
|
{
|
|
*pszWrite++ = *pszRead++;
|
|
}
|
|
}
|
|
*pszWrite = *pszRead; // pick up null terminator.
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COpenCplCategory implementation
|
|
//--------------------------------------------------------------------------
|
|
|
|
COpenCplCategory::COpenCplCategory(
|
|
eCPCAT eCategory,
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : CAction(pRestrict),
|
|
m_eCategory(eCategory)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
COpenCplCategory::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
DBG_ENTER(FTF_CPANEL, "COpenCplCategory::Execute");
|
|
TraceMsg(TF_CPANEL, "Category ID = %d", m_eCategory);
|
|
|
|
ASSERT(NULL != punkSite);
|
|
|
|
UNREFERENCED_PARAMETER(hwndParent);
|
|
|
|
IShellBrowser *psb;
|
|
HRESULT hr = CPL::ShellBrowserFromSite(punkSite, &psb);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPITEMIDLIST pidlFolder;
|
|
hr = SHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidlFolder);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WCHAR szCategory[10];
|
|
hr = StringCchPrintfW(szCategory, ARRAYSIZE(szCategory), L"%d", m_eCategory);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPITEMIDLIST pidlTemp = ILAppendHiddenStringW(pidlFolder, IDLHID_NAVIGATEMARKER, szCategory);
|
|
if (NULL == pidlTemp)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
pidlFolder = pidlTemp;
|
|
pidlTemp = NULL;
|
|
|
|
hr = CPL::BrowseIDListInPlace(pidlFolder, psb);
|
|
}
|
|
ILFree(pidlFolder);
|
|
}
|
|
}
|
|
psb->Release();
|
|
}
|
|
DBG_EXIT_HRES(FTF_CPANEL, "COpenCplCategory::Execute", hr);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COpenCplCategory2 implementation
|
|
//--------------------------------------------------------------------------
|
|
|
|
COpenCplCategory2::COpenCplCategory2(
|
|
eCPCAT eCategory,
|
|
const IAction *pDefAction,
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : CAction(pRestrict),
|
|
m_eCategory(eCategory),
|
|
m_pDefAction(pDefAction)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
COpenCplCategory2::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
DBG_ENTER(FTF_CPANEL, "COpenCplCategory2::Execute");
|
|
TraceMsg(TF_CPANEL, "Category ID = %d", m_eCategory);
|
|
|
|
ASSERT(NULL != punkSite);
|
|
|
|
bool bOpenCategory = false;
|
|
HRESULT hr = _ExecuteActionOnSingleCplApplet(hwndParent, punkSite, &bOpenCategory);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (bOpenCategory)
|
|
{
|
|
//
|
|
// Category has more than one CPL.
|
|
// Open the category page.
|
|
//
|
|
COpenCplCategory action(m_eCategory);
|
|
hr = action.Execute(hwndParent, punkSite);
|
|
}
|
|
}
|
|
DBG_EXIT_HRES(FTF_CPANEL, "COpenCplCategory2::Execute", hr);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
COpenCplCategory2::_ExecuteActionOnSingleCplApplet(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite,
|
|
bool *pbOpenCategory // optional. Can be NULL
|
|
) const
|
|
{
|
|
DBG_ENTER(FTF_CPANEL, "COpenCplCategory2::_ExecuteActionOnSingleCplApplet");
|
|
|
|
bool bOpenCategory = true;
|
|
ICplView *pview;
|
|
HRESULT hr = CPL::ControlPanelViewFromSite(punkSite, &pview);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IServiceProvider *psp;
|
|
hr = pview->QueryInterface(IID_IServiceProvider, (void **)&psp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ICplNamespace *pns;
|
|
hr = psp->QueryService(SID_SControlPanelView, IID_ICplNamespace, (void **)&pns);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ICplCategory *pCategory;
|
|
hr = pns->GetCategory(m_eCategory, &pCategory);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IEnumUICommand *penum;
|
|
hr = pCategory->EnumCplApplets(&penum);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// See if the category has more than one CPL applet
|
|
// assigned to it.
|
|
//
|
|
ULONG cApplets = 0;
|
|
IUICommand *rgpuic[2] = {0};
|
|
if (SUCCEEDED(hr = penum->Next(ARRAYSIZE(rgpuic), rgpuic, &cApplets)))
|
|
{
|
|
for (int i = 0; i < ARRAYSIZE(rgpuic); i++)
|
|
{
|
|
ATOMICRELEASE(rgpuic[i]);
|
|
}
|
|
if (2 > cApplets)
|
|
{
|
|
//
|
|
// There's zero or one CPLs registered for this category.
|
|
// Simply execute the default action. If there's one
|
|
// we assume it's the "default" applet (i.e. ARP or
|
|
// User Accounts).
|
|
//
|
|
hr = m_pDefAction->IsRestricted(pns);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (S_FALSE == hr)
|
|
{
|
|
bOpenCategory = false;
|
|
hr = m_pDefAction->Execute(hwndParent, punkSite);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Default action is restricted.
|
|
// Open the category page. Note that the
|
|
// category page may be displayed as a 'barrier'
|
|
// if no tasks or CPL applets are available.
|
|
//
|
|
ASSERT(bOpenCategory);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
penum->Release();
|
|
}
|
|
pCategory->Release();
|
|
}
|
|
pns->Release();
|
|
}
|
|
psp->Release();
|
|
}
|
|
pview->Release();
|
|
}
|
|
if (NULL != pbOpenCategory)
|
|
{
|
|
*pbOpenCategory = bOpenCategory;
|
|
}
|
|
|
|
DBG_EXIT_HRES(FTF_CPANEL, "COpenCplCategory2::_ExecuteActionOnSingleCplApplet", hr);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COpenCplView implementation
|
|
//--------------------------------------------------------------------------
|
|
|
|
COpenCplView::COpenCplView(
|
|
eCPVIEWTYPE eViewType,
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : CAction(pRestrict),
|
|
m_eViewType(eViewType)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
COpenCplView::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
UNREFERENCED_PARAMETER(hwndParent);
|
|
|
|
ASSERT(NULL != punkSite);
|
|
|
|
HRESULT hr = _SetFolderBarricadeStatus();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IShellBrowser *psb;
|
|
hr = CPL::ShellBrowserFromSite(punkSite, &psb);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPITEMIDLIST pidlFolder;
|
|
hr = SHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidlFolder);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CPL::BrowseIDListInPlace(pidlFolder, psb);
|
|
ILFree(pidlFolder);
|
|
}
|
|
psb->Release();
|
|
}
|
|
}
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
COpenCplView::_SetFolderBarricadeStatus(
|
|
void
|
|
) const
|
|
{
|
|
VARIANT_BOOL vtb = VARIANT_FALSE;
|
|
if (eCPVIEWTYPE_CATEGORY == m_eViewType)
|
|
{
|
|
vtb = VARIANT_TRUE;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(eCPVIEWTYPE_CLASSIC == m_eViewType);
|
|
}
|
|
|
|
HRESULT hr = CPL::SetControlPanelBarricadeStatus(vtb);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CAddPrinter implementation
|
|
//--------------------------------------------------------------------------
|
|
|
|
CAddPrinter::CAddPrinter(
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : CAction(pRestrict)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CAddPrinter::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
DBG_ENTER(FTF_CPANEL, "CAddPrinter::Execute");
|
|
|
|
ASSERT(NULL == hwndParent || IsWindow(hwndParent));
|
|
|
|
UNREFERENCED_PARAMETER(punkSite);
|
|
|
|
HRESULT hr = E_FAIL;
|
|
if (SHInvokePrinterCommandW(hwndParent,
|
|
PRINTACTION_OPEN,
|
|
L"WinUtils_NewObject",
|
|
NULL,
|
|
FALSE))
|
|
{
|
|
//
|
|
// Navigate to the printers folder after invoking the add-printer wizard.
|
|
// This gives the user visual feedback when a printer is added. We navigate
|
|
// even if the user cancels the wizard because we cannot determine if the
|
|
// wizard was cancelled. We've determined this is acceptable.
|
|
//
|
|
CNavigateURL prnfldr(L"shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}");
|
|
hr = prnfldr.Execute(hwndParent, punkSite);
|
|
}
|
|
|
|
DBG_EXIT_HRES(FTF_CPANEL, "CAddPrinter::Execute", hr);
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CTrayCommand implementation
|
|
//--------------------------------------------------------------------------
|
|
|
|
CTrayCommand::CTrayCommand(
|
|
UINT idm,
|
|
const CPL::IRestrict *pRestrict // optional. default = NULL
|
|
) : CAction(pRestrict),
|
|
m_idm(idm)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CTrayCommand::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
UNREFERENCED_PARAMETER(hwndParent);
|
|
UNREFERENCED_PARAMETER(punkSite);
|
|
|
|
// APPHACK! 221008 DesktopX creates their own window with class
|
|
// name "Shell_TrayWnd", so if we're not careful we will end
|
|
// posting the messages to the wrong window. They create their
|
|
// window with the title "CTrayServer"; ours has a null title.
|
|
// Use the null title to find the correct window.
|
|
|
|
HWND hwndTray = FindWindowA(WNDCLASS_TRAYNOTIFY, "");
|
|
if (hwndTray)
|
|
{
|
|
PostMessage(hwndTray, WM_COMMAND, m_idm, 0);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CActionNYI implementation
|
|
//--------------------------------------------------------------------------
|
|
|
|
CActionNYI::CActionNYI(
|
|
LPCWSTR pszText
|
|
) : m_pszText(pszText)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CActionNYI::Execute(
|
|
HWND hwndParent,
|
|
IUnknown *punkSite
|
|
) const
|
|
{
|
|
ASSERT(NULL == hwndParent || IsWindow(hwndParent));
|
|
|
|
UNREFERENCED_PARAMETER(punkSite);
|
|
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
if (NULL != m_pszText)
|
|
{
|
|
MessageBoxW(hwndParent, m_pszText, L"Action Not Yet Implemented", MB_OK);
|
|
hr = S_OK;
|
|
}
|
|
return THR(hr);
|
|
}
|
|
|
|
|
|
|
|
#pragma warning( pop )
|