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

302 lines
7.4 KiB
C++

#include "diskcopy.h"
#include "shlwapip.h"
#include "ids.h"
#define INITGUID
#include <initguid.h>
// {59099400-57FF-11CE-BD94-0020AF85B590}
DEFINE_GUID(CLSID_DriveMenuExt, 0x59099400L, 0x57FF, 0x11CE, 0xBD, 0x94, 0x00, 0x20, 0xAF, 0x85, 0xB5, 0x90);
void DoRunDllThing(int _iDrive);
BOOL DriveIdIsFloppy(int _iDrive);
HINSTANCE g_hinst = NULL;
LONG g_cRefThisDll = 0; // Reference count of this DLL.
//----------------------------------------------------------------------------
class CDriveMenuExt : public IContextMenu, IShellExtInit
{
public:
CDriveMenuExt();
// IUnknown
STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
// IContextMenu
STDMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags);
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpici);
STDMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax);
// IShellExtInit
STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT lpdobj, HKEY hkeyProgID);
private:
~CDriveMenuExt();
INT _DriveFromDataObject(IDataObject *pdtobj);
LONG _cRef;
INT _iDrive;
};
CDriveMenuExt::CDriveMenuExt(): _cRef(1)
{
}
CDriveMenuExt::~CDriveMenuExt()
{
}
STDMETHODIMP_(ULONG) CDriveMenuExt::AddRef()
{
return InterlockedIncrement(&_cRef);
}
STDMETHODIMP_(ULONG) CDriveMenuExt::Release()
{
if (InterlockedDecrement(&_cRef))
{
return _cRef;
}
else
{
delete this;
return 0;
}
}
STDMETHODIMP CDriveMenuExt::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] = {
QITABENT(CDriveMenuExt, IContextMenu),
QITABENT(CDriveMenuExt, IShellExtInit),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
INT CDriveMenuExt::_DriveFromDataObject(IDataObject *pdtobj)
{
INT _iDrive = -1;
STGMEDIUM medium;
FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
if (pdtobj && SUCCEEDED(pdtobj->GetData(&fmte, &medium)))
{
if (DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, NULL, 0) == 1)
{
TCHAR szFile[MAX_PATH];
DragQueryFile((HDROP)medium.hGlobal, 0, szFile, ARRAYSIZE(szFile));
Assert(lstrlen(szFile) == 3); // we are on the "Drives" class
_iDrive = DRIVEID(szFile);
}
ReleaseStgMedium(&medium);
}
return _iDrive;
}
STDMETHODIMP CDriveMenuExt::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID)
{
_iDrive = _DriveFromDataObject(pdtobj);
if ((_iDrive >= 0) &&
!DriveIdIsFloppy(_iDrive))
{
_iDrive = -1;
}
return S_OK;
}
STDMETHODIMP CDriveMenuExt::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
if (_iDrive >= 0)
{
TCHAR szMenu[64];
LoadString(g_hinst, IDS_DISKCOPYMENU, szMenu, ARRAYSIZE(szMenu));
// this will end up right above "Format Disk..."
InsertMenu(hmenu, indexMenu++, MF_SEPARATOR | MF_BYPOSITION, idCmdFirst, szMenu);
InsertMenu(hmenu, indexMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + 1, szMenu);
}
return (HRESULT)2; // room for 2 menu cmds, only use one now...
}
STDMETHODIMP CDriveMenuExt::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
{
if (HIWORD(pici->lpVerb) == 0)
{
Assert(LOWORD(pici->lpVerb) == 0);
DoRunDllThing(_iDrive);
return S_OK;
}
return E_INVALIDARG;
}
STDMETHODIMP CDriveMenuExt::GetCommandString(UINT_PTR idCmd, UINT uType,
UINT *pwReserved, LPSTR pszName, UINT cchMax)
{
switch(uType)
{
case GCS_HELPTEXTA:
return(LoadStringA(g_hinst, IDS_HELPSTRING, pszName, cchMax) ? NOERROR : E_OUTOFMEMORY);
case GCS_VERBA:
return(LoadStringA(g_hinst, IDS_VERBSTRING, pszName, cchMax) ? NOERROR : E_OUTOFMEMORY);
case GCS_HELPTEXTW:
return(LoadStringW(g_hinst, IDS_HELPSTRING, (LPWSTR)pszName, cchMax) ? NOERROR : E_OUTOFMEMORY);
case GCS_VERBW:
return(LoadStringW(g_hinst, IDS_VERBSTRING, (LPWSTR)pszName, cchMax) ? NOERROR : E_OUTOFMEMORY);
case GCS_VALIDATEA:
case GCS_VALIDATEW:
default:
return S_OK;
}
}
STDAPI CDriveMenuExt_CreateInstance(IUnknown* punkOuter, REFIID riid, void **ppv)
{
if (punkOuter)
return CLASS_E_NOAGGREGATION;
CDriveMenuExt *pdme = new CDriveMenuExt;
if (!pdme)
return E_OUTOFMEMORY;
HRESULT hr = pdme->QueryInterface(riid, ppv);
pdme->Release();
return hr;
}
// static class factory (no allocs!)
class ClassFactory : public IClassFactory
{
public:
ClassFactory() : _cRef(1) {}
~ClassFactory() {}
// IUnknown
STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
// IClassFactory
STDMETHODIMP CreateInstance (IUnknown *punkOuter, REFIID riid, void **ppv);
STDMETHODIMP LockServer(BOOL fLock);
private:
LONG _cRef;
};
STDMETHODIMP_(ULONG) ClassFactory::AddRef()
{
return InterlockedIncrement(&_cRef);
}
STDMETHODIMP_(ULONG) ClassFactory::Release()
{
if (InterlockedDecrement(&_cRef))
{
return _cRef;
}
else
{
delete this;
return 0;
}
}
STDMETHODIMP ClassFactory::QueryInterface(REFIID riid, void **ppv)
{
if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
{
*ppv = static_cast<IClassFactory*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
STDMETHODIMP ClassFactory::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
{
return CDriveMenuExt_CreateInstance(punkOuter, riid, ppv);
}
STDMETHODIMP ClassFactory::LockServer(BOOL fLock)
{
if (fLock)
InterlockedIncrement(&g_cRefThisDll);
else
InterlockedDecrement(&g_cRefThisDll);
return S_OK;
}
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
{
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
*ppv = NULL;
if (IsEqualGUID(rclsid, CLSID_DriveMenuExt))
{
ClassFactory* ccf = new ClassFactory;
if (ccf)
{
hr = ccf->QueryInterface(riid, ppv);
ccf->Release();
}
}
return hr;
}
STDAPI DllCanUnloadNow(void)
{
return g_cRefThisDll == 0 ? S_OK : S_FALSE;
}
TCHAR const c_szParamTemplate[] = TEXT("%s,DiskCopyRunDll %d");
void DoRunDllThing(int _iDrive)
{
TCHAR szModule[MAX_PATH];
TCHAR szParam[MAX_PATH + ARRAYSIZE(c_szParamTemplate) + 5];
GetModuleFileName(g_hinst, szModule, ARRAYSIZE(szModule));
wsprintf(szParam, c_szParamTemplate, szModule, _iDrive);
ShellExecute(NULL, NULL, TEXT("rundll32.exe"), szParam, NULL, SW_SHOWNORMAL);
}
// allow command lines to do diskcopy, use the syntax:
// rundll32.dll diskcopy.dll,DiskCopyRunDll
void WINAPI DiskCopyRunDll(HWND hwndStub, HINSTANCE hAppInstance, LPSTR pszCmdLine, int nCmdShow)
{
int _iDrive = StrToIntA(pszCmdLine);
SHCopyDisk(NULL, _iDrive, _iDrive, 0);
}
void WINAPI DiskCopyRunDllW(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR pwszCmdLine, int nCmdShow)
{
int _iDrive = StrToIntW(pwszCmdLine);
SHCopyDisk(NULL, _iDrive, _iDrive, 0);
}