|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionThis article provides a code snippet in order to programmatically send one or more files to the mail recipient, mimicking the Introducing the SendTo mail shortcutYou may skip this section if you are not interested in the r.e. technique. The The trick is to find out that the Ok, basically I need to prepare a bag with dropped filenames, make sure they can be retrieved by implementing the One of the interesting points is to start implementing the If you are interested in mimicking other IDataObject implementationThe following code implements the
Because on Windows file drag-and-drop operations rely on the #include <windows.h> #include <ole2.h> // IDataObject #include <shlobj.h> // DROPFILES #include <tchar.h> // TCHAR class CDataObject : public IDataObject, IEnumFORMATETC { // Members protected: BOOL m_bReset; LPTSTR m_szFiles; int m_nLen; // Constructor public: CDataObject(LPTSTR szFiles) { Reset(); if (!szFiles) { m_szFiles = NULL; return; } // replace \n chars with \0 chars m_nLen = _tcslen(szFiles)+1; m_szFiles = new TCHAR[m_nLen]; memcpy(m_szFiles, szFiles, m_nLen * sizeof(TCHAR)); LPTSTR szTmp = m_szFiles; while ( szTmp=_tcschr(szTmp,'\n') ) *szTmp++ = '\0'; } virtual ~CDataObject() { delete [] m_szFiles; } public: HRESULT __stdcall QueryInterface(REFIID iid, void** ppvObject) { *ppvObject = (IDataObject*) this; return S_OK; } ULONG __stdcall AddRef() { return 1; } ULONG __stdcall Release() { return 0; } // IDataObject implementation // HRESULT __stdcall GetData(FORMATETC* pFormatetc, STGMEDIUM* pmedium) { if (pFormatetc->cfFormat != CF_HDROP || !pmedium) return S_FALSE; if (!m_szFiles) return S_FALSE; // make sure to set the files before pmedium->tymed = TYMED_HGLOBAL; // set DROPFILES structure HGLOBAL hglbCopy = ::GlobalAlloc(GMEM_MOVEABLE, sizeof(DROPFILES) + (m_nLen + 2) * sizeof(TCHAR)); LPDROPFILES pDropFiles = (LPDROPFILES) ::GlobalLock(hglbCopy); pDropFiles->pFiles = sizeof(DROPFILES); pDropFiles->pt.x = pDropFiles->pt.y = 0; pDropFiles->fNC = TRUE; pDropFiles->fWide = FALSE; // ANSI charset LPTSTR lptstrCopy = (LPTSTR) pDropFiles; lptstrCopy += pDropFiles->pFiles; memcpy(lptstrCopy, m_szFiles, m_nLen * sizeof(TCHAR)); lptstrCopy[m_nLen] = '\0'; // null character lptstrCopy[m_nLen+1] = '\0'; // null character ::GlobalUnlock(hglbCopy); pmedium->hGlobal = hglbCopy; pmedium->pUnkForRelease = NULL; return S_OK; } HRESULT __stdcall GetDataHere(FORMATETC* pFormatetc, STGMEDIUM* pmedium) { return S_OK; } HRESULT __stdcall QueryGetData(FORMATETC* pFormatetc) { return S_OK; } HRESULT __stdcall GetCanonicalFormatEtc(FORMATETC* pFormatetcIn, FORMATETC* pFormatetcOut) { return S_OK; } HRESULT __stdcall SetData(FORMATETC* pFormatetc, STGMEDIUM* pmedium, BOOL fRelease) { return S_OK; } HRESULT __stdcall EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC** ppenumFormatetc) { if (dwDirection==DATADIR_GET) { *ppenumFormatetc = this; return S_OK; } else return S_FALSE; } HRESULT __stdcall DAdvise(FORMATETC* pFormatetc, DWORD advf, IAdviseSink* pAdvSink, DWORD* pdwConnection) { return S_OK; } HRESULT __stdcall DUnadvise(DWORD dwConnection) { return S_OK; } HRESULT __stdcall EnumDAdvise(IEnumSTATDATA** ppenumAdvise) { return S_OK; } // IEnumFORMATETC implementation // HRESULT __stdcall Next( /*[in]*/ ULONG celt, /*[out]*/ FORMATETC __RPC_FAR* rgelt, /*[out]*/ ULONG __RPC_FAR* pceltFetched) { if (!m_bReset) return S_FALSE; m_bReset = FALSE; FORMATETC fmt; fmt.cfFormat = CF_HDROP; fmt.dwAspect = DVASPECT_CONTENT; fmt.lindex = -1; fmt.ptd = NULL; fmt.tymed = TYMED_HGLOBAL; *rgelt = fmt; // copy struct if (pceltFetched) *pceltFetched = 1; return S_OK; } HRESULT __stdcall Skip(/*[in]*/ ULONG celt) { return S_FALSE; } HRESULT __stdcall Reset() { m_bReset = TRUE; return S_OK; } HRESULT __stdcall Clone( /* [out] */ IEnumFORMATETC** ppenum) { return S_OK; } }; Using itAnd here is how to use it to send c:\346.jpg and c:\tmp\myfile.zip: ::CoInitialize(NULL); CDataObject cdobj("c:\\346.jpg\nC:\\tmp\\myfile.zip"); IDataObject *pDataObject = &cdobj; IDropTarget *pDropTarget = NULL; // create an instance, and mimic drag-and-drop hr = ::CoCreateInstance( CLSID_SendMail, NULL, CLSCTX_ALL, IID_IDropTarget, (void **)&pDropTarget); if (SUCCEEDED(hr)) { POINTL pt = {0,0}; DWORD dwEffect = 0; pDropTarget->DragEnter(pDataObject, MK_LBUTTON, pt, &dwEffect); pDropTarget->Drop(pDataObject, MK_LBUTTON, pt, &dwEffect); ::Sleep(6*1000); pDropTarget->Release(); } ::CoUninitialize(); To compile this code, you only need WIN32. Why SendTo is better than the mailto trickYou could tell me that shell-executing a mailto URL is just as fine, and much simpler code in practice. Yes and no. Yes, it does so, and it can't be simpler since that's only one line of code (just remember to escape ASCII chars in the body with hex replacements of the form No, it does not provide support for file attachment(s), which is why the History
|
||||||||||||||||||||||