442 lines
14 KiB
C++
442 lines
14 KiB
C++
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
/* File: extinit.cpp
|
||
|
|
||
|
Description: Implements IShellExtInit for disk quota shell extensions.
|
||
|
|
||
|
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Date Description Programmer
|
||
|
-------- --------------------------------------------------- ----------
|
||
|
08/15/96 Initial creation. BrianAu
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
#include "pch.h" // PCH
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include "extinit.h"
|
||
|
#include "prshtext.h"
|
||
|
#include "volprop.h"
|
||
|
#include "guidsp.h"
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
/* Function: ShellExtInit::QueryInterface
|
||
|
|
||
|
Description: Returns an interface pointer to the object's IUnknown or
|
||
|
IShellExtInit interface. Only IID_IUnknown and
|
||
|
IID_IShellExtInit are recognized.
|
||
|
|
||
|
Arguments:
|
||
|
riid - Reference to requested interface ID.
|
||
|
|
||
|
ppvOut - Address of interface pointer variable to accept interface ptr.
|
||
|
|
||
|
Returns:
|
||
|
NO_ERROR - Success.
|
||
|
E_NOINTERFACE - Requested interface not supported.
|
||
|
E_INVALIDARG - ppvOut argument was NULL.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Date Description Programmer
|
||
|
-------- --------------------------------------------------- ----------
|
||
|
08/15/96 Initial creation. BrianAu
|
||
|
06/25/98 Disabled MMC snapin code. BrianAu
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
STDMETHODIMP
|
||
|
ShellExtInit::QueryInterface(
|
||
|
REFIID riid,
|
||
|
LPVOID *ppvOut
|
||
|
)
|
||
|
{
|
||
|
HRESULT hResult = E_NOINTERFACE;
|
||
|
|
||
|
if (NULL == ppvOut)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*ppvOut = NULL;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
if (IID_IUnknown == riid ||
|
||
|
IID_IShellExtInit == riid)
|
||
|
{
|
||
|
*ppvOut = this;
|
||
|
((LPUNKNOWN)*ppvOut)->AddRef();
|
||
|
hResult = NOERROR;
|
||
|
}
|
||
|
else if (IID_IShellPropSheetExt == riid)
|
||
|
{
|
||
|
//
|
||
|
// This can throw OutOfMemory.
|
||
|
//
|
||
|
hResult = Create_IShellPropSheetExt(riid, ppvOut);
|
||
|
}
|
||
|
#ifdef POLICY_MMC_SNAPIN
|
||
|
else if (IID_ISnapInPropSheetExt == riid)
|
||
|
{
|
||
|
hResult = Create_ISnapInPropSheetExt(riid, ppvOut);
|
||
|
}
|
||
|
#endif // POLICY_MMC_SNAPIN
|
||
|
}
|
||
|
catch(CAllocException& e)
|
||
|
{
|
||
|
hResult = E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
return hResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
/* Function: ShellExtInit::AddRef
|
||
|
|
||
|
Description: Increments object reference count.
|
||
|
|
||
|
Arguments: None.
|
||
|
|
||
|
Returns: New reference count value.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Date Description Programmer
|
||
|
-------- --------------------------------------------------- ----------
|
||
|
08/15/96 Initial creation. BrianAu
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
STDMETHODIMP_(ULONG)
|
||
|
ShellExtInit::AddRef(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
ULONG ulReturn = m_cRef + 1;
|
||
|
|
||
|
DBGPRINT((DM_COM, DL_HIGH, TEXT("ShellExtInit::AddRef, 0x%08X %d -> %d\n"),
|
||
|
this, ulReturn - 1, ulReturn));
|
||
|
|
||
|
InterlockedIncrement(&m_cRef);
|
||
|
|
||
|
return ulReturn;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
/* Function: ShellExtInit::Release
|
||
|
|
||
|
Description: Decrements object reference count. If count drops to 0,
|
||
|
object is deleted.
|
||
|
|
||
|
Arguments: None.
|
||
|
|
||
|
Returns: New reference count value.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Date Description Programmer
|
||
|
-------- --------------------------------------------------- ----------
|
||
|
08/15/96 Initial creation. BrianAu
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
STDMETHODIMP_(ULONG)
|
||
|
ShellExtInit::Release(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
ULONG ulReturn = m_cRef - 1;
|
||
|
|
||
|
DBGPRINT((DM_COM, DL_HIGH, TEXT("ShellExtInit::Release, 0x%08X %d -> %d\n"),
|
||
|
this, ulReturn + 1, ulReturn));
|
||
|
|
||
|
if (InterlockedDecrement(&m_cRef) == 0)
|
||
|
{
|
||
|
delete this;
|
||
|
ulReturn = 0;
|
||
|
}
|
||
|
return ulReturn;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
/* Function: ShellExtInit::Initialize
|
||
|
|
||
|
Description: Called by the shell to initialize the shell extension.
|
||
|
|
||
|
Arguments:
|
||
|
pidlFolder - Pointer to IDL of selected folder. This NULL for
|
||
|
property sheet and context menu extensions.
|
||
|
|
||
|
lpDataObj - Pointer to data object containing list of selected objects.
|
||
|
|
||
|
hkeyProgID - Registry key for the file object or folder type.
|
||
|
|
||
|
Returns:
|
||
|
S_OK - Success.
|
||
|
E_FAIL - Can't initialize extension.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Date Description Programmer
|
||
|
-------- --------------------------------------------------- ----------
|
||
|
08/15/96 Initial creation. BrianAu
|
||
|
06/28/98 Added mounted-volume support. BrianAu
|
||
|
Includes introduction of CVolumeID object.
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
STDMETHODIMP
|
||
|
ShellExtInit::Initialize(
|
||
|
LPCITEMIDLIST pidlFolder,
|
||
|
LPDATAOBJECT lpDataObj,
|
||
|
HKEY hkeyProgID)
|
||
|
{
|
||
|
HRESULT hResult = E_FAIL;
|
||
|
if (NULL != lpDataObj)
|
||
|
{
|
||
|
//
|
||
|
// First assume it's a normal volume ID (i.e. "C:\").
|
||
|
// The DataObject will provide CF_HDROP if it is.
|
||
|
//
|
||
|
FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||
|
STGMEDIUM medium;
|
||
|
bool bMountedVol = false;
|
||
|
|
||
|
hResult = lpDataObj->GetData(&fe, &medium);
|
||
|
if (FAILED(hResult))
|
||
|
{
|
||
|
//
|
||
|
// Isn't a normal volume name. Maybe it's a mounted volume.
|
||
|
// Mounted volume names come in on a different clipboard format
|
||
|
// so we can treat them differently from normal volume
|
||
|
// names like "C:\". A mounted volume name will be the path
|
||
|
// to the folder hosting the mounted volume.
|
||
|
// For mounted volumes, the DataObject provides CF "MountedVolume".
|
||
|
//
|
||
|
fe.cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_MOUNTEDVOLUME);
|
||
|
hResult = lpDataObj->GetData(&fe, &medium);
|
||
|
bMountedVol = SUCCEEDED(hResult);
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hResult))
|
||
|
{
|
||
|
if (1 == DragQueryFile((HDROP)medium.hGlobal, (DWORD)-1, NULL, 0))
|
||
|
{
|
||
|
//
|
||
|
// Retrieve volume ID string passed in from the shell.
|
||
|
//
|
||
|
CString strForParsing; // Used for calling Win32 functions.
|
||
|
CString strForDisplay; // Used for UI display.
|
||
|
CString strFSPath; // Used when an FS path is required.
|
||
|
DragQueryFile((HDROP)medium.hGlobal,
|
||
|
0,
|
||
|
strForParsing.GetBuffer(MAX_PATH),
|
||
|
MAX_PATH);
|
||
|
strForParsing.ReleaseBuffer();
|
||
|
|
||
|
if (!bMountedVol)
|
||
|
{
|
||
|
//
|
||
|
// If it's a normal volume name like "C:\", just
|
||
|
// use that as the display name and FS Path also.
|
||
|
//
|
||
|
strFSPath = strForDisplay = strForParsing;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// It's a mounted volume so we need to come up with something
|
||
|
// better than "\\?\Volume{ <guid> }\" to display.
|
||
|
//
|
||
|
// The UI spec says the name shall be like this:
|
||
|
//
|
||
|
// <label> (<mounted path>)
|
||
|
//
|
||
|
TCHAR szMountPtGUID[MAX_PATH] = { TEXT('\0') };
|
||
|
GetVolumeNameForVolumeMountPoint(strForParsing,
|
||
|
szMountPtGUID,
|
||
|
ARRAYSIZE(szMountPtGUID));
|
||
|
|
||
|
TCHAR szLabel[MAX_VOL_LABEL] = { TEXT('\0') };
|
||
|
GetVolumeInformation(szMountPtGUID,
|
||
|
szLabel,
|
||
|
ARRAYSIZE(szLabel),
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
0);
|
||
|
//
|
||
|
// Format display name as:
|
||
|
//
|
||
|
// "VOL_LABEL (C:\MountDir)" or
|
||
|
// "(C:\MountDir)" if no volume label is available.
|
||
|
//
|
||
|
// First remove any trailing backslash from the original parsing
|
||
|
// string. It was needed for the call to get the volume mount
|
||
|
// point but we don't want to display it in the UI.
|
||
|
//
|
||
|
if (!strForParsing.IsEmpty())
|
||
|
{
|
||
|
int iLastBS = strForParsing.Last(TEXT('\\'));
|
||
|
if (iLastBS == strForParsing.Length() - 1)
|
||
|
strForParsing = strForParsing.SubString(0, iLastBS);
|
||
|
}
|
||
|
strForDisplay.Format(g_hInstDll,
|
||
|
IDS_FMT_MOUNTEDVOL_DISPLAYNAME,
|
||
|
szLabel,
|
||
|
strForParsing.Cstr());
|
||
|
//
|
||
|
// Remember the "C:\MountDir" form as the "FSPath".
|
||
|
//
|
||
|
strFSPath = strForParsing;
|
||
|
//
|
||
|
// From here on out, the mounted volume GUID string
|
||
|
// is used for parsing.
|
||
|
//
|
||
|
strForParsing = szMountPtGUID;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Store the parsing and display name strings in our CVolumeID
|
||
|
// object for convenient packaging. This way we can pass around
|
||
|
// one object and the various parts of the UI can use either the
|
||
|
// parsable or displayable name as they see fit. Since the
|
||
|
// CString objects are reference-counted, all the copying doesn't
|
||
|
// result in duplication of the actual string contents.
|
||
|
//
|
||
|
m_idVolume.SetNames(strForParsing, strForDisplay, strFSPath);
|
||
|
|
||
|
hResult = S_OK;
|
||
|
}
|
||
|
ReleaseStgMedium(&medium);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
/* Function: ShellExtInit::Create_IShellPropSheetExt
|
||
|
|
||
|
Description: Creates a shell property sheet extension object and returns
|
||
|
a pointer to it's IShellPropSheetExt interface.
|
||
|
|
||
|
Arguments:
|
||
|
riid - Reference to interface IID.
|
||
|
|
||
|
ppvOut - Address of interface pointer variable to receive interface
|
||
|
pointer.
|
||
|
|
||
|
Returns:
|
||
|
NO_ERROR - Success.
|
||
|
E_FAIL - Extension initialized with something other
|
||
|
than the name of a volume or directory.
|
||
|
- OR -
|
||
|
The volume or directory doesn't support quotas.
|
||
|
|
||
|
Exceptions: OutOfMemory.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Date Description Programmer
|
||
|
-------- --------------------------------------------------- ----------
|
||
|
08/16/96 Initial creation. BrianAu
|
||
|
10/07/97 Removed "access denied" and "invalid FS Ver" msgs BrianAu
|
||
|
from prop sheet page. Only display page if
|
||
|
volume supports quotas and quota control object
|
||
|
can be initialized.
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
HRESULT
|
||
|
ShellExtInit::Create_IShellPropSheetExt(
|
||
|
REFIID riid,
|
||
|
LPVOID *ppvOut
|
||
|
)
|
||
|
{
|
||
|
HRESULT hResult = E_FAIL;
|
||
|
DWORD dwFileSysFlags = 0;
|
||
|
TCHAR szFileSysName[MAX_PATH];
|
||
|
|
||
|
if (GetVolumeInformation(m_idVolume.ForParsing(), // Volume id str [in]
|
||
|
NULL, 0, // Don't want volume name
|
||
|
NULL, // Don't want serial no.
|
||
|
NULL, // Don't want max comp length.
|
||
|
&dwFileSysFlags, // File system flags.
|
||
|
szFileSysName,
|
||
|
ARRAYSIZE(szFileSysName)))
|
||
|
{
|
||
|
//
|
||
|
// Only continue if the volume supports quotas.
|
||
|
//
|
||
|
if (0 != (dwFileSysFlags & FILE_VOLUME_QUOTAS))
|
||
|
{
|
||
|
DiskQuotaPropSheetExt *pSheetExt = NULL;
|
||
|
try
|
||
|
{
|
||
|
pSheetExt = new VolumePropPage;
|
||
|
|
||
|
//
|
||
|
// This can throw OutOfMemory.
|
||
|
//
|
||
|
hResult = pSheetExt->Initialize(m_idVolume,
|
||
|
IDD_PROPPAGE_VOLQUOTA,
|
||
|
VolumePropPage::DlgProc);
|
||
|
if (SUCCEEDED(hResult))
|
||
|
{
|
||
|
hResult = pSheetExt->QueryInterface(riid, ppvOut);
|
||
|
}
|
||
|
}
|
||
|
catch(CAllocException& e)
|
||
|
{
|
||
|
hResult = E_OUTOFMEMORY;
|
||
|
}
|
||
|
if (FAILED(hResult))
|
||
|
{
|
||
|
delete pSheetExt;
|
||
|
*ppvOut = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hResult;
|
||
|
}
|
||
|
|
||
|
#ifdef POLICY_MMC_SNAPIN
|
||
|
|
||
|
HRESULT
|
||
|
ShellExtInit::Create_ISnapInPropSheetExt(
|
||
|
REFIID riid,
|
||
|
LPVOID *ppvOut
|
||
|
)
|
||
|
{
|
||
|
HRESULT hResult = E_FAIL;
|
||
|
DiskQuotaPropSheetExt *pSheetExt = NULL;
|
||
|
try
|
||
|
{
|
||
|
pSheetExt = new SnapInVolPropPage;
|
||
|
|
||
|
hResult = pSheetExt->Initialize(NULL,
|
||
|
IDD_PROPPAGE_POLICY,
|
||
|
VolumePropPage::DlgProc);
|
||
|
if (SUCCEEDED(hResult))
|
||
|
{
|
||
|
hResult = pSheetExt->QueryInterface(riid, ppvOut);
|
||
|
}
|
||
|
}
|
||
|
catch(CAllocException& e)
|
||
|
{
|
||
|
hResult = E_OUTOFMEMORY;
|
||
|
}
|
||
|
if (FAILED(hResult))
|
||
|
{
|
||
|
delete pSheetExt;
|
||
|
*ppvOut = NULL;
|
||
|
}
|
||
|
return hResult;
|
||
|
}
|
||
|
|
||
|
#endif // POLICY_MMC_SNAPIN
|