windows-nt/Source/XPSP1/NT/shell/shell32/syreclen.cpp
2020-09-26 16:20:57 +08:00

191 lines
5.8 KiB
C++

#include "shellprv.h"
#pragma hdrstop
#include <regstr.h>
#include <olectl.h>
#include <tlhelp32.h>
class CSystemRestoreCleaner : public IFileSystemRestoreDialog
{
private:
LONG _cRef;
public:
CSystemRestoreCleaner(void);
~CSystemRestoreCleaner(void);
STDMETHODIMP ShowProperties(HWND hwnd);
// IUnknown
STDMETHODIMP QueryInterface (REFIID, void **);
STDMETHODIMP_(ULONG) AddRef (void);
STDMETHODIMP_(ULONG) Release (void);
// IFileSystemRestoreDialog interface members
STDMETHODIMP CanShowFileSystemRestoreDialog(void);
STDMETHODIMP ShowFileSystemRestoreDialog(HWND hwnd); //hwnd points to the parent window.
};
CSystemRestoreCleaner::CSystemRestoreCleaner(void)
{
_cRef = 1;
}
CSystemRestoreCleaner::~CSystemRestoreCleaner(void)
{
}
STDMETHODIMP CSystemRestoreCleaner::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] = {
QITABENT(CSystemRestoreCleaner, IFileSystemRestoreDialog),
QITABENT(CSystemRestoreCleaner, IUnknown),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) CSystemRestoreCleaner::AddRef (void)
{
return InterlockedIncrement(&_cRef);
}
STDMETHODIMP_(ULONG) CSystemRestoreCleaner::Release (void)
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
STDMETHODIMP CSystemRestoreCleaner::CanShowFileSystemRestoreDialog(void)
{
typedef BOOL (* PFNISSRENABLED)(void);
HRESULT hr = E_FAIL;
HMODULE hMod = LoadLibrary(TEXT("sfc.dll"));
if (hMod)
{
PFNISSRENABLED pfnIsSREnabled = (PFNISSRENABLED)GetProcAddress(hMod, "IsSREnabled");
if (pfnIsSREnabled)
{
if (pfnIsSREnabled())
hr = S_OK;
else
hr = S_FALSE;
}
FreeLibrary(hMod);
}
return hr;
}
STDMETHODIMP CSystemRestoreCleaner::ShowFileSystemRestoreDialog(HWND hwnd)
{
HRESULT hr = E_FAIL;
if ((hwnd != NULL) && (CanShowFileSystemRestoreDialog() == S_OK))
{
hr = ShowProperties(hwnd);
}
return hr;
}
typedef struct
{
int icon;
TCHAR cpl[ CCHPATHMAX ];
TCHAR applet[ MAX_PATH ];
TCHAR *params;
} CPLEXECINFO;
typedef struct
{
ATOM aCPL; // CPL name atom (so we can match requests)
ATOM aApplet; // applet name atom (so we can match requests, may be zero)
HWND hwndStub; // window for this dude (so we can switch to it)
UINT flags; // see PCPLIF_ flags below
} CPLAPPLETID;
STDAPI_(void) CPL_ParseCommandLine(CPLEXECINFO *info, LPTSTR pszCmdLine, BOOL extract_icon);
STDAPI_(BOOL) SHRunDLLThread(HWND hwnd, LPCTSTR pszCmdLine, int nCmdShow);
STDAPI_(BOOL) CPL_Identify( CPLAPPLETID *identity, CPLEXECINFO *info, HWND stub );
STDAPI_(void) CPL_UnIdentify( CPLAPPLETID *identity );
STDAPI_(HWND) FindCPLWindowByStubWindowClassName(LPTSTR pszWndClassName, CPLAPPLETID *target);
STDMETHODIMP CSystemRestoreCleaner::ShowProperties(HWND hwnd)
{
HRESULT hr = E_FAIL;
CPLEXECINFO info;
CPL_ParseCommandLine( &info, TEXT("sysdm.cpl"), FALSE );
if (PathFindOnPath( info.cpl, NULL ))
{
CPLAPPLETID identity;
if (CPL_Identify( &identity, &info, NULL ))
{
//explorer launches sysdm.cpl control panel on a new process Rundll32 with window name as RunDLL.
HWND hwndTarget = FindCPLWindowByStubWindowClassName(TEXT("RunDLL"), &identity);
if (hwndTarget == NULL)
{
if (SHRunDLLThread(hwnd, TEXT("shell32.dll,Control_RunDLL sysdm.cpl"), SW_SHOWNORMAL))
{
//HACK - We need to wait till the new thread SetProp's the atom to the newly created
//window. Other wise the FindCPLWindowByStubWindowClassName will not find the window.
//Ideally we need to synchronize with the new created thread when it is done SetProp's the
//atom for this Control panel - Look in
int nRetryCount = 0;
while ((NULL == hwndTarget) && nRetryCount < 10)
{
hwndTarget = FindCPLWindowByStubWindowClassName((LPTSTR) c_szStubWindowClass, &identity);
Sleep(50);
++nRetryCount;
}
}
}
//Even if we don't get the Control's panels hwnd, we would have atleast launched the Property sheet
//for the control panel.
if (hwndTarget && IsWindow(hwndTarget))
{
//If we get the window handle, we switch to the correct tab for the Performance Page and
//emulate File System button click.
// try to find a CPL window on top of it
HWND hDialogWnd = GetLastActivePopup(hwndTarget);
if (hDialogWnd && IsWindow(hDialogWnd))
{
SetForegroundWindow(hDialogWnd);
PropSheet_SetCurSel(hDialogWnd, NULL, 3);
//HACK - Need to simulate a button click on the CPL Dialog. Since it is a 16bit code, we
//can't call the do this hack. 2603 is the ID For the FileSystem button in sysdm.cpl.
PostMessage(hDialogWnd, WM_COMMAND, BN_CLICKED<<16 | 2603, 0 );
hr = S_OK;
}
}
CPL_UnIdentify(&identity);
}
}
return hr;
}
STDAPI CSystemRestoreCleaner_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
{
HRESULT hr;
CSystemRestoreCleaner* pdt = new CSystemRestoreCleaner();
if (pdt)
{
hr = pdt->QueryInterface(riid, ppv);
pdt->Release();
}
else
{
*ppv = NULL;
hr = E_OUTOFMEMORY;
}
return hr;
}