mirror of https://github.com/lianthony/NT4.0
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.
376 lines
12 KiB
376 lines
12 KiB
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
static const TCHAR c_szQVStub[] = TEXT("\\viewers\\quikview.exe");
|
|
static const TCHAR c_szQVParam[] = TEXT("-v -f:\"");
|
|
static const TCHAR c_szFileViewers[] = TEXT("QuickView\\");
|
|
static const TCHAR c_szFileViewersAll[] = TEXT("*\\QuickView");
|
|
|
|
//==========================================================================
|
|
// System Default Pages/Menu Extension
|
|
//==========================================================================
|
|
|
|
//
|
|
// CShellViewerExt class
|
|
//
|
|
typedef struct // shcmd
|
|
{
|
|
CCommonUnknown cunk;
|
|
CCommonShellExtInit cshx;
|
|
CKnownContextMenu kcxm;
|
|
} CShellViewerExt, *PSHELLVIEWEREXT;
|
|
|
|
//
|
|
// Member function prototypes
|
|
//
|
|
STDMETHODIMP CShellViewerExt_QueryInterface(LPUNKNOWN punk, REFIID riid, LPVOID FAR* ppvObj);
|
|
STDMETHODIMP_(ULONG) CShellViewerExt_AddRef(LPUNKNOWN punk);
|
|
STDMETHODIMP_(ULONG) CShellViewerExt_Release(LPUNKNOWN punk);
|
|
STDMETHODIMP CShellViewerExt_QueryContextMenu(LPCONTEXTMENU pcxm,
|
|
HMENU hmenu,
|
|
UINT indexMenu,
|
|
UINT idCmdFirst,
|
|
UINT idCmdLast,
|
|
UINT uFlags);
|
|
STDMETHODIMP CShellViewerExt_InvokeCommand(LPCONTEXTMENU pcxm,
|
|
LPCMINVOKECOMMANDINFO pici);
|
|
STDMETHODIMP CShellViewerExt_GetCommandString(
|
|
LPCONTEXTMENU pcxm,
|
|
UINT idCmd,
|
|
UINT wReserved,
|
|
UINT * pwReserved,
|
|
LPSTR pszName,
|
|
UINT cchMax);
|
|
|
|
//
|
|
// CShellViewerExt vtables
|
|
//
|
|
#pragma warning(error: 4090 4028 4047)
|
|
#pragma data_seg(".text", "CODE")
|
|
|
|
STATIC IUnknownVtbl c_CShellViewerExtVtbl =
|
|
{
|
|
CShellViewerExt_QueryInterface,
|
|
CShellViewerExt_AddRef,
|
|
CShellViewerExt_Release,
|
|
};
|
|
|
|
STATIC IContextMenuVtbl c_CShellViewerExtCXMVtbl =
|
|
{
|
|
Common_QueryInterface,
|
|
Common_AddRef,
|
|
Common_Release,
|
|
CShellViewerExt_QueryContextMenu,
|
|
CShellViewerExt_InvokeCommand,
|
|
CShellViewerExt_GetCommandString
|
|
};
|
|
|
|
#pragma data_seg()
|
|
#pragma warning(default: 4090 4028 4047)
|
|
|
|
|
|
HRESULT CALLBACK CShellViewerExt_CreateInstance(LPUNKNOWN punkOuter,
|
|
REFIID riid, LPVOID * ppv)
|
|
{
|
|
HRESULT hres = ResultFromScode(E_OUTOFMEMORY);
|
|
PSHELLVIEWEREXT pshcmd;
|
|
|
|
//
|
|
// We are not supposed to pass non-zero value here.
|
|
//
|
|
Assert(punkOuter==NULL);
|
|
|
|
pshcmd = (PSHELLVIEWEREXT)(void*)LocalAlloc(LPTR, SIZEOF(CShellViewerExt));
|
|
if (pshcmd)
|
|
{
|
|
// Initialize CommonUnknown
|
|
pshcmd->cunk.unk.lpVtbl = &c_CShellViewerExtVtbl;
|
|
pshcmd->cunk.cRef = 1;
|
|
|
|
// Initialize CCommonShellExtInit
|
|
CCommonShellExtInit_Init(&pshcmd->cshx, &pshcmd->cunk);
|
|
|
|
// Initialize CKnownContextMenu
|
|
pshcmd->kcxm.unk.lpVtbl = &c_CShellViewerExtCXMVtbl;
|
|
pshcmd->kcxm.nOffset = (int)&pshcmd->kcxm - (int)&pshcmd->cunk;
|
|
|
|
hres = CShellViewerExt_QueryInterface(&pshcmd->cunk.unk, riid, ppv);
|
|
CShellViewerExt_Release(&pshcmd->cunk.unk);
|
|
}
|
|
|
|
return(hres);
|
|
}
|
|
|
|
//
|
|
// CShellViewerExt::QueryInterface
|
|
//
|
|
STDMETHODIMP CShellViewerExt_QueryInterface(LPUNKNOWN punk, REFIID riid, LPVOID FAR* ppvObj)
|
|
{
|
|
PSHELLVIEWEREXT this = IToClassN(CShellViewerExt, cunk.unk, punk);
|
|
|
|
if (IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*((LPUNKNOWN *)ppvObj) = &this->cunk.unk;
|
|
this->cunk.cRef++;
|
|
return NOERROR;
|
|
}
|
|
|
|
if (IsEqualIID(riid, &IID_IShellExtInit)
|
|
|| IsEqualIID(riid, &CLSID_CCommonShellExtInit))
|
|
{
|
|
*((LPSHELLEXTINIT *)ppvObj) = &this->cshx.kshx.unk;
|
|
this->cunk.cRef++;
|
|
return NOERROR;
|
|
}
|
|
|
|
if (IsEqualIID(riid, &IID_IContextMenu))
|
|
{
|
|
*((LPCONTEXTMENU *)ppvObj) = &this->kcxm.unk;
|
|
this->cunk.cRef++;
|
|
return NOERROR;
|
|
}
|
|
|
|
*ppvObj = NULL;
|
|
return(ResultFromScode(E_NOINTERFACE));
|
|
}
|
|
|
|
//
|
|
// CShellViewerExt::AddRef
|
|
//
|
|
STDMETHODIMP_(ULONG) CShellViewerExt_AddRef(LPUNKNOWN punk)
|
|
{
|
|
PSHELLVIEWEREXT this = IToClassN(CShellViewerExt, cunk.unk, punk);
|
|
|
|
this->cunk.cRef++;
|
|
return this->cunk.cRef;
|
|
}
|
|
|
|
//
|
|
// CShellViewerExt::Release
|
|
//
|
|
STDMETHODIMP_(ULONG) CShellViewerExt_Release(LPUNKNOWN punk)
|
|
{
|
|
PSHELLVIEWEREXT this = IToClassN(CShellViewerExt, cunk.unk, punk);
|
|
|
|
this->cunk.cRef--;
|
|
if (this->cunk.cRef > 0)
|
|
{
|
|
return this->cunk.cRef;
|
|
}
|
|
|
|
CCommonShellExtInit_Delete(&this->cshx);
|
|
|
|
LocalFree((HLOCAL)this);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
BOOL SV_Viewable(WIN32_FIND_DATA *pfd, LPCTSTR szPath)
|
|
{
|
|
BOOL fViewable = FALSE;
|
|
if ((pfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)==0)
|
|
{
|
|
TCHAR *szExt = PathFindExtension(szPath);
|
|
|
|
if (*szExt)
|
|
{
|
|
HKEY hkeyExt;
|
|
TCHAR szViewer[MAX_PATH];
|
|
TCHAR szSubViewer[MAX_PATH];
|
|
LONG lRet;
|
|
|
|
lstrcpy(szViewer, c_szFileViewers);
|
|
lstrcat(szViewer, szExt);
|
|
|
|
if (RegOpenKey(HKEY_CLASSES_ROOT, szViewer, &hkeyExt)==ERROR_SUCCESS)
|
|
{
|
|
if ((lRet = RegEnumKey(hkeyExt, 0, szSubViewer, ARRAYSIZE(szSubViewer))) == ERROR_SUCCESS)
|
|
fViewable=TRUE;
|
|
|
|
RegCloseKey(hkeyExt);
|
|
|
|
if (lRet == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
// Does not have any subkeys, nuke it now!
|
|
RegDeleteKey(HKEY_CLASSES_ROOT, szViewer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TCHAR szValue[MAX_PATH];
|
|
LONG cbValue = SIZEOF(szValue);
|
|
|
|
// See if the * class has the FileViews key... If it does
|
|
// it should return true for all file extensions...
|
|
// First we need to get the type name for this item
|
|
if (SHRegQueryValue(HKEY_CLASSES_ROOT, c_szFileViewersAll,
|
|
szValue, &cbValue) == ERROR_SUCCESS)
|
|
{
|
|
fViewable=TRUE;
|
|
}
|
|
|
|
// Last we need to get the type name for this item
|
|
else if (SHRegQueryValue(HKEY_CLASSES_ROOT, szExt, szValue, &cbValue)
|
|
== ERROR_SUCCESS)
|
|
{
|
|
lstrcpy(szViewer, szValue);
|
|
PathAppend(szViewer, c_szFileViewers);
|
|
PathRemoveBackslash(szViewer);
|
|
|
|
if (SHRegQueryValue(HKEY_CLASSES_ROOT, szViewer, szValue,
|
|
&cbValue) == ERROR_SUCCESS)
|
|
{
|
|
// Make sure the * class exists...
|
|
TCHAR szCheckStars[MAX_PATH];
|
|
lstrcpy(szCheckStars, c_szFileViewers);
|
|
lstrcat(szCheckStars, TEXT("*"));
|
|
|
|
if (RegOpenKey(HKEY_CLASSES_ROOT, szCheckStars, &hkeyExt)==ERROR_SUCCESS)
|
|
{
|
|
if ((lRet = RegEnumKey(hkeyExt, 0, szSubViewer, ARRAYSIZE(szSubViewer))) == ERROR_SUCCESS)
|
|
fViewable=TRUE;
|
|
|
|
RegCloseKey(hkeyExt);
|
|
|
|
if (lRet == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
// Does not have any subkeys, nuke it now!
|
|
RegDeleteKey(HKEY_CLASSES_ROOT, szViewer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return fViewable;
|
|
}
|
|
|
|
STDMETHODIMP CShellViewerExt_QueryContextMenu(LPCONTEXTMENU pcxm,
|
|
HMENU hmenu,
|
|
UINT indexMenu,
|
|
UINT idCmdFirst,
|
|
UINT idCmdLast,
|
|
UINT uFlags)
|
|
{
|
|
PSHELLVIEWEREXT this = IToClassN(CShellViewerExt, kcxm.unk, pcxm);
|
|
HRESULT hres;
|
|
STGMEDIUM medium;
|
|
DataObj_GetHIDA(this->cshx.pdtobj, &medium);
|
|
if (medium.hGlobal)
|
|
{
|
|
FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
// Check if the data object contains file system object(s)
|
|
hres = this->cshx.pdtobj->lpVtbl->QueryGetData(this->cshx.pdtobj, &fmte);
|
|
if (hres == NOERROR && HIDA_GetCount(medium.hGlobal))
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
WIN32_FIND_DATA fd;
|
|
// Then, check if the first one is a file.
|
|
CFSFolder_FillFindData(medium.hGlobal, 0, szPath, &fd);
|
|
if (SV_Viewable(&fd, szPath))
|
|
{
|
|
TCHAR szMenuString[CCH_MENUMAX];
|
|
LoadString(HINST_THISDLL, IDS_MENUQUICKVIEW, szMenuString, ARRAYSIZE(szMenuString));
|
|
InsertMenu(hmenu, indexMenu, MF_BYPOSITION | MF_STRING, idCmdFirst, szMenuString);
|
|
}
|
|
hres = ResultFromShort(1);
|
|
}
|
|
HIDA_ReleaseStgMedium(NULL, &medium);
|
|
}
|
|
else
|
|
hres = ResultFromShort(0);
|
|
|
|
return hres;
|
|
}
|
|
|
|
STDMETHODIMP CShellViewerExt_InvokeCommand(LPCONTEXTMENU pcxm,
|
|
LPCMINVOKECOMMANDINFO pici)
|
|
{
|
|
PSHELLVIEWEREXT this = IToClassN(CShellViewerExt, kcxm.unk, pcxm);
|
|
STGMEDIUM medium;
|
|
|
|
if (pici->lpVerb != 0)
|
|
return ResultFromScode(E_FAIL);
|
|
|
|
|
|
DataObj_GetHIDA(this->cshx.pdtobj, &medium);
|
|
if (medium.hGlobal)
|
|
{
|
|
UINT i;
|
|
for (i = 0; i < HIDA_GetCount(medium.hGlobal); i++)
|
|
{
|
|
WIN32_FIND_DATA fd;
|
|
TCHAR szPath[MAX_PATH+ARRAYSIZE(c_szQVParam)+2];
|
|
// Move qvstub.exe into the viewers directory under the
|
|
// system folder
|
|
|
|
TCHAR szQVStubPath[MAX_PATH];
|
|
GetSystemDirectory(szQVStubPath, ARRAYSIZE(szQVStubPath));
|
|
lstrcat(szQVStubPath, c_szQVStub);
|
|
|
|
lstrcpy(szPath, c_szQVParam);
|
|
CFSFolder_FillFindData(medium.hGlobal, i, szPath+lstrlen(szPath), &fd);
|
|
if (SV_Viewable(&fd, szPath))
|
|
{
|
|
|
|
// REVIEW: Any reason this ignores fMask & hIcon & dwHotKey ??
|
|
|
|
SHELLEXECUTEINFO shexi =
|
|
{
|
|
SIZEOF(SHELLEXECUTEINFO),
|
|
SEE_MASK_FLAG_NO_UI, // fMask
|
|
pici->hwnd,
|
|
NULL, // lpVerb
|
|
szQVStubPath, // lpFile
|
|
szPath, // lpParameters
|
|
NULL, // lpDirectory
|
|
SW_NORMAL,
|
|
NULL // [out]hinst
|
|
};
|
|
|
|
//
|
|
// This is real gross, append a trailing " onto the name
|
|
lstrcat(szPath, TEXT("\""));
|
|
|
|
if (!ShellExecuteEx(&shexi))
|
|
{
|
|
// we don't let ShellExecuteEx put up err ui because
|
|
// we want the title to say IDS_QUICKVIEWERROR, but don't
|
|
// forget to pay attention to the flags passed to us
|
|
shexi.fMask = pici->fMask & SEE_VALID_CMIC_FLAGS;
|
|
_ShellExecuteError(&shexi, MAKEINTRESOURCE(IDS_QUICKVIEWERROR), 0);
|
|
}
|
|
}
|
|
}
|
|
HIDA_ReleaseStgMedium(NULL, &medium);
|
|
}
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CShellViewerExt_GetCommandString(
|
|
LPCONTEXTMENU pcxm,
|
|
UINT idCmd,
|
|
UINT uFlags,
|
|
UINT * pwReserved,
|
|
LPSTR pszName,
|
|
UINT cchMax)
|
|
{
|
|
if (uFlags & GCS_HELPTEXTA)
|
|
{
|
|
UINT cch;
|
|
|
|
if ((uFlags & GCS_HELPTEXTW) == GCS_HELPTEXTW)
|
|
cch = LoadStringW(HINST_THISDLL, IDS_HELPQUICKVIEW,
|
|
(LPWSTR)pszName, cchMax);
|
|
else
|
|
cch = LoadStringA(HINST_THISDLL, IDS_HELPQUICKVIEW,
|
|
pszName, cchMax);
|
|
return NOERROR;
|
|
}
|
|
else
|
|
return ResultFromScode(E_FAIL);
|
|
}
|