Source code of Windows XP (NT5)
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.

301 lines
7.4 KiB

  1. #include "diskcopy.h"
  2. #include "shlwapip.h"
  3. #include "ids.h"
  4. #define INITGUID
  5. #include <initguid.h>
  6. // {59099400-57FF-11CE-BD94-0020AF85B590}
  7. DEFINE_GUID(CLSID_DriveMenuExt, 0x59099400L, 0x57FF, 0x11CE, 0xBD, 0x94, 0x00, 0x20, 0xAF, 0x85, 0xB5, 0x90);
  8. void DoRunDllThing(int _iDrive);
  9. BOOL DriveIdIsFloppy(int _iDrive);
  10. HINSTANCE g_hinst = NULL;
  11. LONG g_cRefThisDll = 0; // Reference count of this DLL.
  12. //----------------------------------------------------------------------------
  13. class CDriveMenuExt : public IContextMenu, IShellExtInit
  14. {
  15. public:
  16. CDriveMenuExt();
  17. // IUnknown
  18. STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
  19. ULONG STDMETHODCALLTYPE AddRef();
  20. ULONG STDMETHODCALLTYPE Release();
  21. // IContextMenu
  22. STDMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags);
  23. STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpici);
  24. STDMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax);
  25. // IShellExtInit
  26. STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT lpdobj, HKEY hkeyProgID);
  27. private:
  28. ~CDriveMenuExt();
  29. INT _DriveFromDataObject(IDataObject *pdtobj);
  30. LONG _cRef;
  31. INT _iDrive;
  32. };
  33. CDriveMenuExt::CDriveMenuExt(): _cRef(1)
  34. {
  35. }
  36. CDriveMenuExt::~CDriveMenuExt()
  37. {
  38. }
  39. STDMETHODIMP_(ULONG) CDriveMenuExt::AddRef()
  40. {
  41. return InterlockedIncrement(&_cRef);
  42. }
  43. STDMETHODIMP_(ULONG) CDriveMenuExt::Release()
  44. {
  45. if (InterlockedDecrement(&_cRef))
  46. {
  47. return _cRef;
  48. }
  49. else
  50. {
  51. delete this;
  52. return 0;
  53. }
  54. }
  55. STDMETHODIMP CDriveMenuExt::QueryInterface(REFIID riid, void **ppv)
  56. {
  57. static const QITAB qit[] = {
  58. QITABENT(CDriveMenuExt, IContextMenu),
  59. QITABENT(CDriveMenuExt, IShellExtInit),
  60. { 0 },
  61. };
  62. return QISearch(this, qit, riid, ppv);
  63. }
  64. INT CDriveMenuExt::_DriveFromDataObject(IDataObject *pdtobj)
  65. {
  66. INT _iDrive = -1;
  67. STGMEDIUM medium;
  68. FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  69. if (pdtobj && SUCCEEDED(pdtobj->GetData(&fmte, &medium)))
  70. {
  71. if (DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, NULL, 0) == 1)
  72. {
  73. TCHAR szFile[MAX_PATH];
  74. DragQueryFile((HDROP)medium.hGlobal, 0, szFile, ARRAYSIZE(szFile));
  75. Assert(lstrlen(szFile) == 3); // we are on the "Drives" class
  76. _iDrive = DRIVEID(szFile);
  77. }
  78. ReleaseStgMedium(&medium);
  79. }
  80. return _iDrive;
  81. }
  82. STDMETHODIMP CDriveMenuExt::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID)
  83. {
  84. _iDrive = _DriveFromDataObject(pdtobj);
  85. if ((_iDrive >= 0) &&
  86. !DriveIdIsFloppy(_iDrive))
  87. {
  88. _iDrive = -1;
  89. }
  90. return S_OK;
  91. }
  92. STDMETHODIMP CDriveMenuExt::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
  93. {
  94. if (_iDrive >= 0)
  95. {
  96. TCHAR szMenu[64];
  97. LoadString(g_hinst, IDS_DISKCOPYMENU, szMenu, ARRAYSIZE(szMenu));
  98. // this will end up right above "Format Disk..."
  99. InsertMenu(hmenu, indexMenu++, MF_SEPARATOR | MF_BYPOSITION, idCmdFirst, szMenu);
  100. InsertMenu(hmenu, indexMenu++, MF_STRING | MF_BYPOSITION, idCmdFirst + 1, szMenu);
  101. }
  102. return (HRESULT)2; // room for 2 menu cmds, only use one now...
  103. }
  104. STDMETHODIMP CDriveMenuExt::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
  105. {
  106. if (HIWORD(pici->lpVerb) == 0)
  107. {
  108. Assert(LOWORD(pici->lpVerb) == 0);
  109. DoRunDllThing(_iDrive);
  110. return S_OK;
  111. }
  112. return E_INVALIDARG;
  113. }
  114. STDMETHODIMP CDriveMenuExt::GetCommandString(UINT_PTR idCmd, UINT uType,
  115. UINT *pwReserved, LPSTR pszName, UINT cchMax)
  116. {
  117. switch(uType)
  118. {
  119. case GCS_HELPTEXTA:
  120. return(LoadStringA(g_hinst, IDS_HELPSTRING, pszName, cchMax) ? NOERROR : E_OUTOFMEMORY);
  121. case GCS_VERBA:
  122. return(LoadStringA(g_hinst, IDS_VERBSTRING, pszName, cchMax) ? NOERROR : E_OUTOFMEMORY);
  123. case GCS_HELPTEXTW:
  124. return(LoadStringW(g_hinst, IDS_HELPSTRING, (LPWSTR)pszName, cchMax) ? NOERROR : E_OUTOFMEMORY);
  125. case GCS_VERBW:
  126. return(LoadStringW(g_hinst, IDS_VERBSTRING, (LPWSTR)pszName, cchMax) ? NOERROR : E_OUTOFMEMORY);
  127. case GCS_VALIDATEA:
  128. case GCS_VALIDATEW:
  129. default:
  130. return S_OK;
  131. }
  132. }
  133. STDAPI CDriveMenuExt_CreateInstance(IUnknown* punkOuter, REFIID riid, void **ppv)
  134. {
  135. if (punkOuter)
  136. return CLASS_E_NOAGGREGATION;
  137. CDriveMenuExt *pdme = new CDriveMenuExt;
  138. if (!pdme)
  139. return E_OUTOFMEMORY;
  140. HRESULT hr = pdme->QueryInterface(riid, ppv);
  141. pdme->Release();
  142. return hr;
  143. }
  144. // static class factory (no allocs!)
  145. class ClassFactory : public IClassFactory
  146. {
  147. public:
  148. ClassFactory() : _cRef(1) {}
  149. ~ClassFactory() {}
  150. // IUnknown
  151. STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
  152. ULONG STDMETHODCALLTYPE AddRef();
  153. ULONG STDMETHODCALLTYPE Release();
  154. // IClassFactory
  155. STDMETHODIMP CreateInstance (IUnknown *punkOuter, REFIID riid, void **ppv);
  156. STDMETHODIMP LockServer(BOOL fLock);
  157. private:
  158. LONG _cRef;
  159. };
  160. STDMETHODIMP_(ULONG) ClassFactory::AddRef()
  161. {
  162. return InterlockedIncrement(&_cRef);
  163. }
  164. STDMETHODIMP_(ULONG) ClassFactory::Release()
  165. {
  166. if (InterlockedDecrement(&_cRef))
  167. {
  168. return _cRef;
  169. }
  170. else
  171. {
  172. delete this;
  173. return 0;
  174. }
  175. }
  176. STDMETHODIMP ClassFactory::QueryInterface(REFIID riid, void **ppv)
  177. {
  178. if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
  179. {
  180. *ppv = static_cast<IClassFactory*>(this);
  181. }
  182. else
  183. {
  184. *ppv = NULL;
  185. return E_NOINTERFACE;
  186. }
  187. reinterpret_cast<IUnknown*>(*ppv)->AddRef();
  188. return S_OK;
  189. }
  190. STDMETHODIMP ClassFactory::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  191. {
  192. return CDriveMenuExt_CreateInstance(punkOuter, riid, ppv);
  193. }
  194. STDMETHODIMP ClassFactory::LockServer(BOOL fLock)
  195. {
  196. if (fLock)
  197. InterlockedIncrement(&g_cRefThisDll);
  198. else
  199. InterlockedDecrement(&g_cRefThisDll);
  200. return S_OK;
  201. }
  202. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
  203. {
  204. HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
  205. *ppv = NULL;
  206. if (IsEqualGUID(rclsid, CLSID_DriveMenuExt))
  207. {
  208. ClassFactory* ccf = new ClassFactory;
  209. if (ccf)
  210. {
  211. hr = ccf->QueryInterface(riid, ppv);
  212. ccf->Release();
  213. }
  214. }
  215. return hr;
  216. }
  217. STDAPI DllCanUnloadNow(void)
  218. {
  219. return g_cRefThisDll == 0 ? S_OK : S_FALSE;
  220. }
  221. TCHAR const c_szParamTemplate[] = TEXT("%s,DiskCopyRunDll %d");
  222. void DoRunDllThing(int _iDrive)
  223. {
  224. TCHAR szModule[MAX_PATH];
  225. TCHAR szParam[MAX_PATH + ARRAYSIZE(c_szParamTemplate) + 5];
  226. GetModuleFileName(g_hinst, szModule, ARRAYSIZE(szModule));
  227. wsprintf(szParam, c_szParamTemplate, szModule, _iDrive);
  228. ShellExecute(NULL, NULL, TEXT("rundll32.exe"), szParam, NULL, SW_SHOWNORMAL);
  229. }
  230. // allow command lines to do diskcopy, use the syntax:
  231. // rundll32.dll diskcopy.dll,DiskCopyRunDll
  232. void WINAPI DiskCopyRunDll(HWND hwndStub, HINSTANCE hAppInstance, LPSTR pszCmdLine, int nCmdShow)
  233. {
  234. int _iDrive = StrToIntA(pszCmdLine);
  235. SHCopyDisk(NULL, _iDrive, _iDrive, 0);
  236. }
  237. void WINAPI DiskCopyRunDllW(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR pwszCmdLine, int nCmdShow)
  238. {
  239. int _iDrive = StrToIntW(pwszCmdLine);
  240. SHCopyDisk(NULL, _iDrive, _iDrive, 0);
  241. }