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.
336 lines
8.7 KiB
336 lines
8.7 KiB
|
|
#include "diskcopy.h"
|
|
#include <shlwapip.h>
|
|
#include "ids.h"
|
|
#include <strsafe.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()
|
|
{
|
|
Assert( 0 != _cRef );
|
|
ULONG cRef = InterlockedDecrement(&_cRef);
|
|
if ( 0 == cRef )
|
|
{
|
|
delete this;
|
|
}
|
|
return cRef;
|
|
}
|
|
|
|
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) &&
|
|
(_iDrive < 26) &&
|
|
!DriveIdIsFloppy(_iDrive))
|
|
{
|
|
_iDrive = -1; // Copy Disk only works on floppies
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CDriveMenuExt::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
|
|
{
|
|
int cEntries = 0;
|
|
if (_iDrive >= 0 &&
|
|
_iDrive < 26)
|
|
{
|
|
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);
|
|
cEntries = 2;
|
|
}
|
|
return ResultFromShort(cEntries);
|
|
}
|
|
|
|
STDMETHODIMP CDriveMenuExt::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
|
{
|
|
HRESULT hr;
|
|
if (HIWORD(pici->lpVerb) == 0)
|
|
{
|
|
DoRunDllThing(_iDrive);
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CDriveMenuExt::GetCommandString(UINT_PTR idCmd, UINT uType,
|
|
UINT *pwReserved, LPSTR pszName, UINT cchMax)
|
|
{
|
|
switch(uType)
|
|
{
|
|
case GCS_HELPTEXTA:
|
|
LoadStringA(g_hinst, IDS_HELPSTRING, pszName, cchMax);
|
|
break;
|
|
case GCS_VERBA:
|
|
LoadStringA(g_hinst, IDS_VERBSTRING, pszName, cchMax);
|
|
break;
|
|
case GCS_HELPTEXTW:
|
|
return(LoadStringW(g_hinst, IDS_HELPSTRING, (LPWSTR)pszName, cchMax));
|
|
break;
|
|
case GCS_VERBW:
|
|
LoadStringW(g_hinst, IDS_VERBSTRING, (LPWSTR)pszName, cchMax);
|
|
break;
|
|
case GCS_VALIDATEA:
|
|
case GCS_VALIDATEW:
|
|
default:
|
|
break;
|
|
}
|
|
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()
|
|
{
|
|
Assert( 0 != _cRef );
|
|
ULONG cRef = InterlockedDecrement(&_cRef);
|
|
if ( 0 == cRef )
|
|
{
|
|
delete this;
|
|
}
|
|
return cRef;
|
|
}
|
|
|
|
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
|
|
{
|
|
Assert( 0 != g_cRefThisDll );
|
|
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)
|
|
{
|
|
if (_iDrive >= 0 && _iDrive < 26)
|
|
{
|
|
TCHAR szModule[MAX_PATH];
|
|
int cchModule = GetModuleFileName(g_hinst, szModule, ARRAYSIZE(szModule));
|
|
|
|
if (cchModule > 0 &&
|
|
cchModule < ARRAYSIZE(szModule))
|
|
{
|
|
TCHAR szParam[MAX_PATH + ARRAYSIZE(c_szParamTemplate)];
|
|
if (SUCCEEDED(StringCchPrintf(szParam, ARRAYSIZE(szParam),
|
|
c_szParamTemplate, szModule, _iDrive)))
|
|
{
|
|
SHELLEXECUTEINFO shexinfo = {0};
|
|
shexinfo.cbSize = sizeof (shexinfo);
|
|
shexinfo.fMask = SEE_MASK_DOENVSUBST;
|
|
shexinfo.nShow = SW_SHOWNORMAL;
|
|
shexinfo.lpFile = L"%windir%\\system32\\rundll32.exe";
|
|
shexinfo.lpParameters = szParam;
|
|
|
|
ShellExecuteEx(&shexinfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
if (StrToIntExA(pszCmdLine, STIF_DEFAULT, &iDrive) &&
|
|
iDrive >= 0 &&
|
|
iDrive < 26)
|
|
{
|
|
SHCopyDisk(NULL, iDrive, iDrive, 0);
|
|
}
|
|
}
|
|
|
|
void WINAPI DiskCopyRunDllW(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR pwszCmdLine, int nCmdShow)
|
|
{
|
|
int iDrive;
|
|
if (StrToIntExW(pwszCmdLine, STIF_DEFAULT, &iDrive) &&
|
|
iDrive >= 0 &&
|
|
iDrive < 26)
|
|
{
|
|
SHCopyDisk(NULL, iDrive, iDrive, 0);
|
|
}
|
|
}
|