|
|
#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); }
|