This article provides a code snippet in order to programmatically send one or more files to the mail recipient, mimicking the SendTo mail recipient shell extension. I have heard many people searching for this feature, and actually I thought that, as there doesn't seem to be such source code posted on the net, I could just as well post it.
|
// SendMail.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#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 (see constructor)
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,
/* [length_is][size_is][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 __RPC_FAR *__RPC_FAR *ppenum)
{
return S_OK;
}
};
// helper
//
// purpose:tells us whether the file exists
BOOL FileExists(LPTSTR szFilename)
{
BOOL bFound = FALSE;
WIN32_FIND_DATA findFile;
HANDLE hContext;
hContext=::FindFirstFile(szFilename, &findFile);
if ( hContext != INVALID_HANDLE_VALUE )
{
::FindClose(hContext);
bFound = TRUE;
}
return bFound;
}
int main(int argc, char* argv[])
{
long nTotalLength = 0, i;
// read cmdline, and make sure that files actually exist before they are sent
for (i=1; i<argc; i++)
nTotalLength += FileExists(argv[i]) ? (_tcslen(argv[i]) + 1) : 0;
if ( nTotalLength==0 )
return 0; // good bye!
LPTSTR szCmdLine = new TCHAR[nTotalLength+1];
if (!szCmdLine)
return 0;
*szCmdLine = 0;
for (i=1; i<argc; i++)
{
_tcscat(szCmdLine, argv[i]);
_tcscat(szCmdLine, "\n");
}
if ( szCmdLine )
{
// sendmail helper (requires either OE or Outlook)
static const IID CLSID_SendMail = { 0x9E56BE60, 0xC50F, 0x11CF,
{ 0x9A, 0x2C, 0x00, 0xA0, 0xC9, 0x0A, 0x90, 0xCE }
};
CDataObject cdobj(szCmdLine);
IDataObject *pDataObject = &cdobj;
::CoInitialize(NULL);
IDropTarget *pDropTarget = NULL;
HRESULT hr;
// sendmail object
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();
}
delete [] szCmdLine;
return 0;
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.