Windows2000/private/shell/ext/sendmail/sendmail.c
2020-09-30 17:12:32 +02:00

1396 lines
43 KiB
C

#include "sendmail.h" // pch file
#include "resource.h"
#include "shlguidp.h"
#include "debug.h"
// these bits are set by the user (holding down the keys) durring drag drop,
// but more importantly, they are set in the SimulateDragDrop() call that the
// browser implements to get the "Send Page..." vs "Send Link..." feature
#define IS_FORCE_LINK(grfKeyState) ((grfKeyState == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) || \
(grfKeyState == (MK_LBUTTON | MK_ALT)))
#define IS_FORCE_COPY(grfKeyState) (grfKeyState == (MK_LBUTTON | MK_CONTROL))
STDAPI DesktopShortcutDropHandler(IDataObject* pdtobj, DWORD grfKeyState, DWORD dwEffect);
UINT g_cfShellURL = 0;
UINT g_cfFileContents = 0;
UINT g_cfFileDescA = 0;
UINT g_cfFileDescW = 0;
UINT g_cfHIDA = 0;
BOOL RunningOnNT()
{
static int s_bOnNT = -1; // -1 means uninited, 0 means no, 1 means yes
if (s_bOnNT == -1) {
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(osvi);
GetVersionEx(&osvi);
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
s_bOnNT = 1;
else
s_bOnNT = 0;
}
return (BOOL)s_bOnNT;
}
// thunks // {
// from browseui/runonnt.c
#define g_fRunningOnNT RunningOnNT()
int _AorW_PathCleanupSpec(/*IN OPTIONAL*/ LPCTSTR pszDir, /*IN OUT*/ LPTSTR pszSpec)
{
//THUNKMSG(TEXT("PathCleanupSpec"));
if (g_fRunningOnNT) {
WCHAR wzDir[MAX_PATH];
WCHAR wzSpec[MAX_PATH];
LPWSTR pwszDir = wzDir;
int iRet;
if (pszDir)
SHTCharToUnicode(pszDir, wzDir, ARRAYSIZE(wzDir));
else
pwszDir = NULL;
SHTCharToUnicode(pszSpec, wzSpec, ARRAYSIZE(wzSpec));
iRet = PathCleanupSpec((LPTSTR)pwszDir, (LPTSTR)wzSpec);
SHUnicodeToTChar(wzSpec, pszSpec, MAX_PATH);
return iRet;
} else {
CHAR szDir[MAX_PATH];
CHAR szSpec[MAX_PATH];
LPSTR pszDir2 = szDir;
int iRet;
if (pszDir)
SHTCharToAnsi(pszDir, szDir, ARRAYSIZE(szDir));
else
pszDir2 = NULL;
SHTCharToAnsi(pszSpec, szSpec, ARRAYSIZE(szSpec));
iRet = PathCleanupSpec((LPTSTR)pszDir2, (LPTSTR)szSpec);
SHAnsiToTChar(szSpec, pszSpec, MAX_PATH);
return iRet;
}
}
#define PathCleanupSpec(s1, s2) _AorW_PathCleanupSpec(s1, s2)
// from shell32/copyfgd.cpp // {
// thunk A/W funciton to access A/W FILEGROUPDESCRIPTOR
// this relies on the fact that the first part of the A/W structures are
// identical. only the string buffer part is different. so all accesses to the
// cFileName field need to go through this function.
FILEDESCRIPTOR* GetFileDescriptor(FILEGROUPDESCRIPTOR* pfgd, BOOL fUnicode, int nIndex, LPTSTR pszName)
{
if (fUnicode) {
// Yes, so grab the data because it matches.
FILEGROUPDESCRIPTORW* pfgdW = (FILEGROUPDESCRIPTORW*)pfgd; // cast to what this really is
if (pszName)
SHUnicodeToTChar(pfgdW->fgd[nIndex].cFileName, pszName, MAX_PATH);
return (FILEDESCRIPTOR*)&pfgdW->fgd[nIndex]; // cast assume the non string parts are the same!
} else {
FILEGROUPDESCRIPTORA* pfgdA = (FILEGROUPDESCRIPTORA*)pfgd; // cast to what this really is
if (pszName)
SHAnsiToTChar(pfgdA->fgd[nIndex].cFileName, pszName, MAX_PATH);
return (FILEDESCRIPTOR*)&pfgdA->fgd[nIndex]; // cast assume the non string parts are the same!
}
}
// }
// }
// our own impl since URLMON IStream::CopyTo is busted, danpoz will be fixing this
HRESULT IStream_CopyTo(IStream* pstmFrom,
IStream* pstmTo,
ULARGE_INTEGER cb,
ULARGE_INTEGER* pcbRead,
ULARGE_INTEGER* pcbWritten)
{
BYTE buf[512];
ULONG cbRead;
HRESULT hres = NOERROR;
if (pcbRead) {
pcbRead->LowPart = 0;
pcbRead->HighPart = 0;
}
if (pcbWritten) {
pcbWritten->LowPart = 0;
pcbWritten->HighPart = 0;
}
ASSERT(cb.HighPart == 0);
while (cb.LowPart) {
hres = pstmFrom->lpVtbl->Read(pstmFrom, buf, min(cb.LowPart, SIZEOF(buf)), &cbRead);
if (pcbRead)
pcbRead->LowPart += cbRead;
if (FAILED(hres) || (cbRead == 0))
break;
cb.LowPart -= cbRead;
hres = pstmTo->lpVtbl->Write(pstmTo, buf, cbRead, &cbRead);
if (pcbWritten)
pcbWritten->LowPart += cbRead;
if (FAILED(hres) || (cbRead == 0))
break;
}
return hres;
}
STDMETHODIMP DropHandler_QueryInterface(IDropTarget* pdropt, REFIID riid, void** ppv)
{
CDropHandler* this = IToClass(CDropHandler, dt, pdropt);
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDropTarget)) {
*ppv = &this->dt;
} else if (IsEqualIID(riid, &IID_IPersistFile)) {
*ppv = &this->pf;
} else if (IsEqualIID(riid, &IID_IShellExtInit)) {
*ppv = &this->sxi;
} else {
*ppv = NULL;
return E_NOINTERFACE;
}
this->cRef++;
// pdropt->lpVtbl->AddRef(pdropt);
return S_OK;
}
STDMETHODIMP_(ULONG) DropHandler_AddRef(IDropTarget* pdropt)
{
CDropHandler* this = IToClass(CDropHandler, dt, pdropt);
this->cRef++;
return this->cRef;
}
STDMETHODIMP_(ULONG) DropHandler_Release(IDropTarget* pdropt)
{
CDropHandler* this = IToClass(CDropHandler, dt, pdropt);
this->cRef--;
if (this->cRef > 0)
return this->cRef;
LocalFree((HLOCAL)this);
DllRelease();
return 0;
}
STDMETHODIMP DropHandler_DragEnter(IDropTarget* pdropt,
IDataObject* pdtobj,
DWORD grfKeyState,
POINTL pt,
DWORD* pdwEffect)
{
CDropHandler* this = IToClass(CDropHandler, dt, pdropt);
TraceMsg(DM_TRACE, "DropHandler_DragEnter");
this->grfKeyStateLast = grfKeyState;
this->dwEffectLast = *pdwEffect;
return S_OK;
}
STDMETHODIMP DropHandler_DragOver(IDropTarget* pdropt, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
{
CDropHandler* this = IToClass(CDropHandler, dt, pdropt);
*pdwEffect &= ~DROPEFFECT_MOVE;
if (IS_FORCE_COPY(grfKeyState))
*pdwEffect &= DROPEFFECT_COPY;
else if (IS_FORCE_LINK(grfKeyState))
*pdwEffect &= DROPEFFECT_LINK;
this->grfKeyStateLast = grfKeyState;
this->dwEffectLast = *pdwEffect;
return S_OK;
}
STDMETHODIMP DropHandler_DragLeave(IDropTarget* pdropt)
{
CDropHandler* this = IToClass(CDropHandler, dt, pdropt);
return S_OK;
}
STDMETHODIMP DropHandler_Drop(IDropTarget* pdropt, IDataObject* pdtobj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
{
CDropHandler* this = IToClass(CDropHandler, dt, pdropt);
HRESULT hres = this->pfnDrop(pdtobj, this->grfKeyStateLast, this->dwEffectLast);
*pdwEffect = DROPEFFECT_COPY; // don't let source delete data
return hres;
}
const IDropTargetVtbl c_DropHandler_DTVtbl =
{
DropHandler_QueryInterface, DropHandler_AddRef, DropHandler_Release,
DropHandler_DragEnter,
DropHandler_DragOver,
DropHandler_DragLeave,
DropHandler_Drop,
};
STDMETHODIMP DropHandler_PF_QueryInterface(IPersistFile* ppf, REFIID riid, void** ppv)
{
CDropHandler* this = IToClass(CDropHandler, pf, ppf);
return DropHandler_QueryInterface(&this->dt, riid, ppv);
}
STDMETHODIMP_(ULONG) DropHandler_PF_AddRef(IPersistFile* ppf)
{
CDropHandler* this = IToClass(CDropHandler, pf, ppf);
return ++this->cRef;
}
STDMETHODIMP_(ULONG) DropHandler_PF_Release(IPersistFile* ppf)
{
CDropHandler* this = IToClass(CDropHandler, pf, ppf);
return DropHandler_Release(&this->dt);
}
STDMETHODIMP DropHandler_GetClassID(IPersistFile* ppf, CLSID* pClassID)
{
*pClassID = CLSID_MailRecipient;
return S_OK;
}
STDMETHODIMP DropHandler_IsDirty(IPersistFile* psf)
{
return S_FALSE;
}
STDMETHODIMP DropHandler_Load(IPersistFile* psf, LPCOLESTR pwszFile, DWORD grfMode)
{
TraceMsg(DM_TRACE, "DropHandler_Load");
return S_OK;
}
STDMETHODIMP DropHandler_Save(IPersistFile* psf, LPCOLESTR pwszFile, BOOL fRemember)
{
return S_OK;
}
STDMETHODIMP DropHandler_SaveCompleted(IPersistFile* psf, LPCOLESTR pwszFile)
{
return S_OK;
}
STDMETHODIMP DropHandler_GetCurFile(IPersistFile* psf, LPOLESTR* ppszFileName)
{
*ppszFileName = NULL;
return S_OK;
}
const IPersistFileVtbl c_DropHandler_PFVtbl = {
DropHandler_PF_QueryInterface, DropHandler_PF_AddRef, DropHandler_PF_Release,
DropHandler_GetClassID,
DropHandler_IsDirty,
DropHandler_Load,
DropHandler_Save,
DropHandler_SaveCompleted,
DropHandler_GetCurFile
};
STDMETHODIMP DropHandler_SXI_QueryInterface(IShellExtInit* psxi, REFIID riid, void** ppv)
{
CDropHandler* this = IToClass(CDropHandler, sxi, psxi);
return DropHandler_QueryInterface(&this->dt, riid, ppv);
}
STDMETHODIMP_(ULONG) DropHandler_SXI_AddRef(IShellExtInit* psxi)
{
CDropHandler* this = IToClass(CDropHandler, sxi, psxi);
return ++this->cRef;
}
STDMETHODIMP_(ULONG) DropHandler_SXI_Release(IShellExtInit* psxi)
{
CDropHandler* this = IToClass(CDropHandler, sxi, psxi);
return DropHandler_Release(&this->dt);
}
STDMETHODIMP DropHandler_SXI_Initialize(IShellExtInit* psxi, LPCITEMIDLIST pidl, IDataObject* pdtobj, HKEY hkeyProgID)
{
CDropHandler* this = IToClass(CDropHandler, sxi, psxi);
TraceMsg(DM_TRACE, "DropHandler_SXI_Initialize");
return S_OK;
}
IShellExtInitVtbl c_DropHandler_SXIVtbl = {
DropHandler_SXI_QueryInterface, DropHandler_SXI_AddRef, DropHandler_SXI_Release,
DropHandler_SXI_Initialize
};
STDAPI DropHandler_CreateInstance(LPDROPPROC pfnDrop, IUnknown* punkOuter, REFIID riid, void** ppv)
{
HRESULT hres;
CDropHandler* this;
*ppv = NULL; // assume error
TraceMsg(DM_TRACE, "DropHandler_CreateInstance");
if (punkOuter)
return CLASS_E_NOAGGREGATION;
this = (CDropHandler*)LocalAlloc(LPTR, sizeof(CDropHandler));
if (this) {
this->dt.lpVtbl = &c_DropHandler_DTVtbl;
this->sxi.lpVtbl = &c_DropHandler_SXIVtbl;
this->pf.lpVtbl = &c_DropHandler_PFVtbl;
this->pfnDrop = pfnDrop;
this->cRef = 1;
DllAddRef();
hres = DropHandler_QueryInterface(&this->dt, riid, ppv);
DropHandler_Release(&this->dt);
} else
hres = E_OUTOFMEMORY;
return hres;
}
// deal with IShellLinkA/W uglyness...
HRESULT ShellLinkSetPath(IUnknown* punk, LPCTSTR pszPath)
{
HRESULT hres;
#ifdef UNICODE
IShellLinkW* pslW;
hres = punk->lpVtbl->QueryInterface(punk, &IID_IShellLinkW, (void**)&pslW);
if (SUCCEEDED(hres)) {
hres = pslW->lpVtbl->SetPath(pslW, pszPath);
pslW->lpVtbl->Release(pslW);
} else
#endif
{
IShellLinkA* pslA;
hres = punk->lpVtbl->QueryInterface(punk, &IID_IShellLinkA, (void**)&pslA);
if (SUCCEEDED(hres)) {
CHAR szPath[MAX_PATH];
SHUnicodeToAnsi(pszPath, szPath, ARRAYSIZE(szPath));
hres = pslA->lpVtbl->SetPath(pslA, szPath);
pslA->lpVtbl->Release(pslA);
}
}
return hres;
}
// deal with IShellLinkA/W uglyness...
HRESULT ShellLinkGetPath(IUnknown* punk, LPTSTR pszPath, UINT cch)
{
HRESULT hres;
#ifdef UNICODE
IShellLinkW* pslW;
hres = punk->lpVtbl->QueryInterface(punk, &IID_IShellLinkW, (void**)&pslW);
if (SUCCEEDED(hres)) {
hres = pslW->lpVtbl->GetPath(pslW, pszPath, cch, NULL, SLGP_UNCPRIORITY);
pslW->lpVtbl->Release(pslW);
} else
#endif
{
IShellLinkA* pslA;
hres = punk->lpVtbl->QueryInterface(punk, &IID_IShellLinkA, (void**)&pslA);
if (SUCCEEDED(hres)) {
CHAR szPath[MAX_PATH];
hres = pslA->lpVtbl->GetPath(pslA, szPath, ARRAYSIZE(szPath), NULL, SLGP_UNCPRIORITY);
if (SUCCEEDED(hres))
SHAnsiToUnicode(szPath, pszPath, cch);
pslA->lpVtbl->Release(pslA);
}
}
return hres;
}
HRESULT _CreateShortcutToPath(LPCTSTR pszPath, LPCTSTR pszTarget)
{
IUnknown* punk;
HRESULT hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, &punk);
if (SUCCEEDED(hres)) {
IPersistFile* ppf;
ShellLinkSetPath(punk, pszTarget);
hres = punk->lpVtbl->QueryInterface(punk, &IID_IPersistFile, &ppf);
if (SUCCEEDED(hres)) {
WCHAR wszPath[MAX_PATH];
SHTCharToUnicode(pszPath, wszPath, ARRAYSIZE(wszPath));
hres = ppf->lpVtbl->Save(ppf, wszPath, TRUE);
ppf->lpVtbl->Release(ppf);
}
punk->lpVtbl->Release(punk);
}
return hres;
}
BOOL _IsShortcut(LPCTSTR pszFile)
{
SHFILEINFO sfi;
return SHGetFileInfo(pszFile, 0, &sfi, sizeof(sfi), SHGFI_ATTRIBUTES) && (sfi.dwAttributes & SFGAO_LINK);
}
// create a temporary shortcut to a file
// BUGBUG: Colision is not handled here
BOOL _CreateTempFileShortcut(LPCTSTR pszTarget, LPTSTR pszShortcut)
{
TCHAR szShortcutPath[MAX_PATH + 1];
BOOL bSuccess = FALSE;
if (GetTempPath(ARRAYSIZE(szShortcutPath), szShortcutPath)) {
PathAppend(szShortcutPath, PathFindFileName(pszTarget));
if (_IsShortcut(pszTarget)) {
TCHAR szTarget[MAX_PATH + 1];
SHFILEOPSTRUCT shop = {0};
shop.wFunc = FO_COPY;
shop.pFrom = szTarget;
shop.pTo = szShortcutPath;
shop.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
StrCpyN(szTarget, pszTarget, ARRAYSIZE(szTarget));
szTarget[lstrlen(szTarget) + 1] = TEXT('\0');
szShortcutPath[lstrlen(szShortcutPath) + 1] = TEXT('\0');
bSuccess = (0 == SHFileOperation(&shop));
} else {
PathRenameExtension(szShortcutPath, TEXT(".lnk"));
bSuccess = SUCCEEDED(_CreateShortcutToPath(szShortcutPath, pszTarget));
}
if (bSuccess)
lstrcpyn(pszShortcut, szShortcutPath, MAX_PATH);
}
return bSuccess;
}
BOOL AllocatePMP(MRPARAM* pmp, DWORD cchTitle, DWORD cchFiles)
{
pmp->pszTitle = GlobalAlloc(GPTR, cchTitle * SIZEOF(TCHAR));
if (!pmp->pszTitle)
return FALSE;
pmp->pszFiles = GlobalAlloc(GPTR, cchFiles * SIZEOF(TCHAR));
if (!pmp->pszFiles)
return FALSE;
Assert(pmp->pszTitle[cchTitle - 1] == 0);
Assert(pmp->pszFiles[cchFiles - 1] == 0);
return TRUE;
}
void DeleteMultipleFiles(LPCTSTR pszFiles)
{
SHFILEOPSTRUCT shop = {0};
shop.wFunc = FO_DELETE;
shop.pFrom = pszFiles; // This is already double null terminated.
shop.fFlags = FOF_SILENT | FOF_NOCONFIRMATION;
SHFileOperation(&shop);
}
BOOL CleanupPMP(MRPARAM* pmp)
{
if (pmp->dwFlags & MRPARAM_DELETEFILE)
DeleteMultipleFiles(pmp->pszFiles);
if (pmp->pszFiles) {
GlobalFree((LPVOID)pmp->pszFiles);
pmp->pszFiles = NULL;
}
if (pmp->pszTitle) {
GlobalFree((LPVOID)pmp->pszTitle);
pmp->pszTitle = NULL;
}
GlobalFree(pmp);
return TRUE;
}
HRESULT _GetFileNameFromData(IDataObject* pdtobj, FORMATETC* pfmtetc, LPTSTR pszDescription)
{
STGMEDIUM medium;
HRESULT hres = pdtobj->lpVtbl->GetData(pdtobj, pfmtetc, &medium);
if (SUCCEEDED(hres)) {
// NOTE: this is a TCHAR format, we depend on how we are compiled, we really
// should test both the A and W formats
FILEGROUPDESCRIPTOR* pfgd = (FILEGROUPDESCRIPTOR*)GlobalLock(medium.hGlobal);
if (pfgd) {
TCHAR szFdName[MAX_PATH]; // pfd->cFileName
FILEDESCRIPTOR* pfd;
// &pfgd->fgd[0], w/ thunk
ASSERT(pfmtetc->cfFormat == g_cfFileDescW || pfmtetc->cfFormat == g_cfFileDescA);
// for now, all callers are ANSI (other untested)
//ASSERT(pfmtetc->cfFormat == g_cfFileDescA);
pfd = GetFileDescriptor(pfgd, pfmtetc->cfFormat == g_cfFileDescW, 0, szFdName);
lstrcpy(pszDescription, szFdName); // pfd->cFileName
GlobalUnlock(medium.hGlobal);
hres = S_OK;
}
ReleaseStgMedium(&medium);
}
return hres;
}
// construct a nice title "<File Name> (<File Type>)"
void _GetFileAndTypeDescFromPath(LPCTSTR pszPath, LPTSTR pszDesc)
{
SHFILEINFO sfi;
if (!SHGetFileInfo(pszPath, 0, &sfi, sizeof(sfi), SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME | SHGFI_DISPLAYNAME)) {
lstrcpyn(sfi.szDisplayName, PathFindFileName(pszPath), ARRAYSIZE(sfi.szDisplayName));
sfi.szTypeName[0] = 0;
}
lstrcpyn(pszDesc, sfi.szDisplayName, MAX_PATH);
}
/*
* pcszURL -> "ftp://ftp.microsoft.com"
* pcszPath -> "c:\windows\desktop\internet\Microsoft FTP.url"
*/
HRESULT CreateNewURLShortcut(LPCTSTR pcszURL, LPCTSTR pcszURLFile)
{
IUniformResourceLocator* purl;
HRESULT hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER, &IID_IUniformResourceLocator, (void**)&purl);
if (SUCCEEDED(hr)) {
hr = purl->lpVtbl->SetURL(purl, pcszURL, 0);
if (SUCCEEDED(hr)) {
IPersistFile* ppf;
hr = purl->lpVtbl->QueryInterface(purl, &IID_IPersistFile, (void**)&ppf);
if (SUCCEEDED(hr)) {
WCHAR wszFile[INTERNET_MAX_URL_LENGTH];
SHTCharToUnicode(pcszURLFile, wszFile, ARRAYSIZE(wszFile));
hr = ppf->lpVtbl->Save(ppf, wszFile, TRUE);
ppf->lpVtbl->Release(ppf);
}
}
purl->lpVtbl->Release(purl);
}
return hr;
}
HRESULT _CreateURLFileToSend(IDataObject* pdtobj, MRPARAM* pmp)
{
HRESULT hr = CreateNewURLShortcut(pmp->pszTitle, pmp->pszFiles);
if (SUCCEEDED(hr)) {
_GetFileAndTypeDescFromPath(pmp->pszFiles, pmp->pszTitle);
pmp->dwFlags |= MRPARAM_DELETEFILE;
}
return hr;
}
// First undefine everything that we are intercepting as to not forward back to us...
#undef SHGetSpecialFolderPath
// Explicit prototype because only the A/W prototypes exist in the headers
STDAPI_(BOOL) SHGetSpecialFolderPath(HWND hwnd, LPTSTR lpszPath, int nFolder, BOOL fCreate);
BOOL _SHGetSpecialFolderPath(HWND hwnd, LPTSTR pszPath, int nFolder, BOOL fCreate)
{
BOOL fRet;
if (RunningOnNT()) {
#ifdef UNICODE
fRet = SHGetSpecialFolderPath(hwnd, pszPath, nFolder, fCreate);
#else
WCHAR wszPath[MAX_PATH];
fRet = SHGetSpecialFolderPath(hwnd, (LPTSTR)wszPath, nFolder, fCreate);
if (fRet)
SHUnicodeToTChar(wszPath, pszPath, MAX_PATH);
#endif
} else {
#ifdef UNICODE
CHAR szPath[MAX_PATH];
fRet = SHGetSpecialFolderPath(hwnd, (LPTSTR)szPath, nFolder, fCreate);
if (fRet)
SHAnsiToTChar(szPath, pszPath, MAX_PATH);
#else
fRet = SHGetSpecialFolderPath(hwnd, pszPath, nFolder, fCreate);
#endif
}
return fRet;
}
BOOL PathYetAnotherMakeUniqueNameT(LPTSTR pszUniqueName,
LPCTSTR pszPath,
LPCTSTR pszShort,
LPCTSTR pszFileSpec)
{
if (RunningOnNT()) {
WCHAR wszUniqueName[MAX_PATH];
WCHAR wszPath[MAX_PATH];
WCHAR wszShort[32];
WCHAR wszFileSpec[MAX_PATH];
BOOL fRet;
SHTCharToUnicode(pszPath, wszPath, ARRAYSIZE(wszPath));
pszPath = (LPCTSTR)wszPath; // overload the pointer to pass through...
if (pszShort) {
SHTCharToUnicode(pszShort, wszShort, ARRAYSIZE(wszShort));
pszShort = (LPCTSTR)wszShort; // overload the pointer to pass through...
}
if (pszFileSpec) {
SHTCharToUnicode(pszFileSpec, wszFileSpec, ARRAYSIZE(wszFileSpec));
pszFileSpec = (LPCTSTR)wszFileSpec; // overload the pointer to pass through...
}
fRet = PathYetAnotherMakeUniqueName((LPTSTR)wszUniqueName, pszPath, pszShort, pszFileSpec);
if (fRet)
SHUnicodeToTChar(wszUniqueName, pszUniqueName, MAX_PATH);
return fRet;
} else {
// win9x thunk code from runonnt.c
CHAR szUniqueName[MAX_PATH];
CHAR szPath[MAX_PATH];
CHAR szShort[32];
CHAR szFileSpec[MAX_PATH];
BOOL fRet;
SHTCharToAnsi(pszPath, szPath, ARRAYSIZE(szPath));
pszPath = (LPCTSTR)szPath; // overload the pointer to pass through...
if (pszShort) {
SHTCharToAnsi(pszShort, szShort, ARRAYSIZE(szShort));
pszShort = (LPCTSTR)szShort; // overload the pointer to pass through...
}
if (pszFileSpec) {
SHTCharToAnsi(pszFileSpec, szFileSpec, ARRAYSIZE(szFileSpec));
pszFileSpec = (LPCTSTR)szFileSpec; // overload the pointer to pass through...
}
fRet = PathYetAnotherMakeUniqueName((LPTSTR)szUniqueName, pszPath, pszShort, pszFileSpec);
if (fRet)
SHAnsiToTChar(szUniqueName, pszUniqueName, MAX_PATH);
return fRet;
}
}
HRESULT _GetHDROPFromData(IDataObject* pdtobj, FORMATETC* pfmtetc, STGMEDIUM* pmedium, DWORD grfKeyState, MRPARAM* pmp)
{
HRESULT hres = E_FAIL;
TCHAR szPath[MAX_PATH], szDesc[MAX_PATH];
pmp->nFiles = DragQueryFile(pmedium->hGlobal, -1, NULL, 0);
if (pmp->nFiles && AllocatePMP(pmp, MAX_PATH * pmp->nFiles, MAX_PATH * pmp->nFiles)) {
int i;
BOOL bAllTempLinks = TRUE;
LPTSTR pszFile, pszTitle;
for (i = 0, pszFile = pmp->pszFiles, pszTitle = pmp->pszTitle; DragQueryFile(pmedium->hGlobal, i, szPath, ARRAYSIZE(szPath)); i++) {
if (IS_FORCE_LINK(grfKeyState) || PathIsDirectory(szPath)) {
// Want to send a link even for the real file, we will create links to the real files
// and send it.
_CreateTempFileShortcut(szPath, pszFile);
} else {
bAllTempLinks = FALSE;
lstrcpy(pszFile, szPath);
}
_GetFileAndTypeDescFromPath(pszFile, szDesc);
// This is used to separate the names
if (pszTitle != pmp->pszTitle)
*pszTitle++ = TEXT(';');
lstrcpy(pszTitle, szDesc);
pszTitle += lstrlen(pszTitle); // ";" seperated string
pszFile[lstrlen(pszFile) + 1] = TEXT('\0'); // Double Null terminate
pszFile += lstrlen(pszFile) + 1; // dbl null string
}
if (bAllTempLinks)
pmp->dwFlags |= MRPARAM_DELETEFILE;
hres = S_OK;
}
return hres;
}
// "Uniform Resource Locator" format
HRESULT _GetURLFromData(IDataObject* pdtobj, FORMATETC* pfmtetc, STGMEDIUM* pmedium, DWORD grfKeyState, MRPARAM* pmp)
{
HRESULT hres = E_FAIL;
// This DataObj is from the internet
// NOTE: We only allow to send one file here.
pmp->nFiles = 1;
if (AllocatePMP(pmp, INTERNET_MAX_URL_LENGTH, MAX_PATH)) {
// n.b. STR not TSTR! since URLs only support ansi
//lstrcpyn(pmp->pszTitle, (LPSTR)GlobalLock(pmedium->hGlobal), INTERNET_MAX_URL_LENGTH);
SHAnsiToTChar((LPSTR)GlobalLock(pmedium->hGlobal), pmp->pszTitle, INTERNET_MAX_URL_LENGTH);
GlobalUnlock(pmedium->hGlobal);
if (pmp->pszTitle[0]) {
// Note some of these functions depend on which OS we
// are running on to know if we should pass ansi or unicode strings
// to it
// Windows 95
if (GetTempPath(MAX_PATH, pmp->pszFiles)) {
TCHAR szFileName[MAX_PATH];
// it's an URL, which is always ANSI, but the filename can still be wide (?)
FORMATETC fmteW = {(CLIPFORMAT)g_cfFileDescW, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
FORMATETC fmteA = {(CLIPFORMAT)g_cfFileDescA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
// #ifdef UNICODE
if (FAILED(_GetFileNameFromData(pdtobj, &fmteW, szFileName)))
// #endif
if (FAILED(_GetFileNameFromData(pdtobj, &fmteA, szFileName)))
LoadString(g_hinst, IDS_SENDMAIL_URL_FILENAME, szFileName, ARRAYSIZE(szFileName));
PathCleanupSpec(pmp->pszFiles, szFileName);
hres = _CreateURLFileToSend(pdtobj, pmp);
}
}
}
return hres;
}
// transfer FILECONTENTS/FILEGROUPDESCRIPTOR data to a temp file then send that in mail
HRESULT _GetFileContentsFromData(IDataObject* pdtobj, FORMATETC* pfmtetc, STGMEDIUM* pmedium, DWORD grfKeyState, MRPARAM* pmp)
{
HRESULT hres = E_FAIL;
// NOTE: We only allow to send one file here.
pmp->nFiles = 1;
if (AllocatePMP(pmp, INTERNET_MAX_URL_LENGTH, MAX_PATH)) {
FILEGROUPDESCRIPTOR* pfgd = (FILEGROUPDESCRIPTOR*)GlobalLock(pmedium->hGlobal);
if (pfgd) {
TCHAR szFdName[MAX_PATH]; // pfd->cFileName
FILEDESCRIPTOR* pfd;
// &pfgd->fgd[0], w/ thunk
ASSERT(pfmtetc->cfFormat == g_cfFileDescW || pfmtetc->cfFormat == g_cfFileDescA);
pfd = GetFileDescriptor(pfgd, pfmtetc->cfFormat == g_cfFileDescW, 0, szFdName);
if (GetTempPath(MAX_PATH, pmp->pszFiles)) {
STGMEDIUM medium;
FORMATETC fmte = {(CLIPFORMAT)g_cfFileContents, NULL, pfmtetc->dwAspect, 0, TYMED_ISTREAM | TYMED_HGLOBAL};
hres = pdtobj->lpVtbl->GetData(pdtobj, &fmte, &medium);
if (SUCCEEDED(hres)) {
IStream* pstmFile;
PathAppend(pmp->pszFiles, szFdName); // pfd->cFileName
PathCleanupSpec(pmp->pszFiles, PathFindFileName(pmp->pszFiles));
PathYetAnotherMakeUniqueNameT(pmp->pszFiles, pmp->pszFiles, NULL, NULL);
hres = SHCreateStreamOnFile(pmp->pszFiles, STGM_WRITE | STGM_CREATE, &pstmFile);
if (SUCCEEDED(hres)) {
const ULARGE_INTEGER li = {-1, 0}; // the whole thing
switch (medium.tymed) {
case TYMED_ISTREAM:
hres = IStream_CopyTo(medium.pstm, pstmFile, li, NULL, NULL);
break;
case TYMED_HGLOBAL:
hres = pstmFile->lpVtbl->Write(pstmFile,
GlobalLock(medium.hGlobal),
pfd->dwFlags & FD_FILESIZE ? pfd->nFileSizeLow : (DWORD)GlobalSize(medium.hGlobal),
NULL);
GlobalUnlock(medium.hGlobal);
break;
default:
hres = E_FAIL;
}
pstmFile->lpVtbl->Release(pstmFile);
if (FAILED(hres))
DeleteFile(pmp->pszFiles);
}
ReleaseStgMedium(&medium);
}
}
GlobalUnlock(pmedium->hGlobal);
}
}
if (SUCCEEDED(hres)) {
_GetFileAndTypeDescFromPath(pmp->pszFiles, pmp->pszTitle);
pmp->dwFlags |= MRPARAM_DELETEFILE;
if (pfmtetc->dwAspect == DVASPECT_COPY) {
IQueryCodePage* pqcp;
pmp->dwFlags |= MRPARAM_DOC; // we are sending the document
// get the code page if there is one
if (SUCCEEDED(pdtobj->lpVtbl->QueryInterface(pdtobj, &IID_IQueryCodePage, (void**)&pqcp))) {
if (SUCCEEDED(pqcp->lpVtbl->GetCodePage(pqcp, &pmp->uiCodePage)))
pmp->dwFlags |= MRPARAM_USECODEPAGE;
pqcp->lpVtbl->Release(pqcp);
}
}
} else if (pfmtetc->dwAspect == DVASPECT_COPY) {
TCHAR szFailureMsg[MAX_PATH], szFailureMsgTitle[40];
int iRet;
LoadString(g_hinst, IDS_SENDMAIL_FAILUREMSG, szFailureMsg, ARRAYSIZE(szFailureMsg));
LoadString(g_hinst, IDS_SENDMAIL_FAILUREMSGTITLE, szFailureMsgTitle, ARRAYSIZE(szFailureMsgTitle));
iRet = MessageBox(NULL, szFailureMsg, szFailureMsgTitle, MB_YESNO);
if (iRet == IDNO)
hres = S_FALSE; // convert to success to we don't try DVASPECT_LINK
}
return hres;
}
typedef struct {
HRESULT(*pfnCreateFromData)(IDataObject*, FORMATETC*, STGMEDIUM*, DWORD, MRPARAM*);
FORMATETC fmte;
} DATA_HANDLER;
HRESULT _CreateSendToFilesFromDataObj(IDataObject* pdtobj, DWORD grfKeyState, MRPARAM* pmp)
{
HRESULT hres;
DWORD dwAspectPrefered;
IEnumFORMATETC* penum;
if (g_cfShellURL == 0) {
// URL is always ANSI
g_cfShellURL = RegisterClipboardFormat(CFSTR_SHELLURL);
g_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS);
g_cfFileDescA = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
// #ifdef UNICODE
g_cfFileDescW = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
// #endif
}
if (IS_FORCE_COPY(grfKeyState))
dwAspectPrefered = DVASPECT_COPY;
else if (IS_FORCE_LINK(grfKeyState))
dwAspectPrefered = DVASPECT_LINK;
else
dwAspectPrefered = DVASPECT_CONTENT;
hres = pdtobj->lpVtbl->EnumFormatEtc(pdtobj, DATADIR_GET, &penum);
if (SUCCEEDED(hres)) {
DATA_HANDLER rg_data_handlers[] = {
// #ifdef UNICODE
_GetFileContentsFromData, {(CLIPFORMAT)g_cfFileDescW, NULL, dwAspectPrefered, -1, TYMED_HGLOBAL},
_GetFileContentsFromData, {(CLIPFORMAT)g_cfFileDescW, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL},
// #endif
_GetFileContentsFromData, {(CLIPFORMAT)g_cfFileDescA, NULL, dwAspectPrefered, -1, TYMED_HGLOBAL},
_GetFileContentsFromData, {(CLIPFORMAT)g_cfFileDescA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL},
_GetHDROPFromData, {(CLIPFORMAT)CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL},
_GetURLFromData, {(CLIPFORMAT)g_cfShellURL, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL},
};
FORMATETC fmte;
while (penum->lpVtbl->Next(penum, 1, &fmte, NULL) == S_OK) {
int i;
for (i = 0; i < ARRAYSIZE(rg_data_handlers); i++) {
if (rg_data_handlers[i].fmte.cfFormat == fmte.cfFormat &&
rg_data_handlers[i].fmte.dwAspect == fmte.dwAspect) {
STGMEDIUM medium;
if (SUCCEEDED(pdtobj->lpVtbl->GetData(pdtobj, &rg_data_handlers[i].fmte, &medium))) {
hres = rg_data_handlers[i].pfnCreateFromData(pdtobj, &fmte, &medium, grfKeyState, pmp);
ReleaseStgMedium(&medium);
if (SUCCEEDED(hres))
goto Done;
}
}
}
}
Done:
penum->lpVtbl->Release(penum);
}
return hres;
}
// send as mail support
// {9E56BE60-C50F-11CF-9A2C-00A0C90A90CE}
const GUID CLSID_MailRecipient = {0x9E56BE60L, 0xC50F, 0x11CF, 0x9A, 0x2C, 0x00, 0xA0, 0xC9, 0x0A, 0x90, 0xCE};
const GUID CLSID_DesktopShortcut = {0x9E56BE61L, 0xC50F, 0x11CF, 0x9A, 0x2C, 0x00, 0xA0, 0xC9, 0x0A, 0x90, 0xCE};
#include <mapi.h>
#define SIZEOF(x) sizeof(x) // has been checked for UNICODE correctness
// like OLE GetClassFile(), but it only works on ProgID\CLSID type registration
// not real doc files or pattern matched files
HRESULT _CLSIDFromExtension(LPCTSTR pszExt, CLSID* pclsid)
{
TCHAR szProgID[80];
ULONG cb = SIZEOF(szProgID);
if (RegQueryValue(HKEY_CLASSES_ROOT, pszExt, szProgID, &cb) == ERROR_SUCCESS) {
TCHAR szCLSID[80];
lstrcat(szProgID, TEXT("\\CLSID"));
cb = SIZEOF(szCLSID);
if (RegQueryValue(HKEY_CLASSES_ROOT, szProgID, szCLSID, &cb) == ERROR_SUCCESS) {
WCHAR wszCLSID[80];
SHTCharToUnicode(szCLSID, wszCLSID, ARRAYSIZE(wszCLSID));
return CLSIDFromString(wszCLSID, pclsid);
}
}
return E_FAIL;
}
BOOL _GetShortcutTarget(LPCTSTR pszPath, LPTSTR pszTarget, UINT cch)
// get the target of a shortcut.
// this uses IShellLink which Internet Shortcuts (.URL) and Shell Shortcuts (.LNK) support so
// it should work generally
{
IUnknown* punk;
HRESULT hres;
CLSID clsid;
*pszTarget = 0; // assume none
if (!_IsShortcut(pszPath))
return FALSE;
if (FAILED(_CLSIDFromExtension(PathFindExtension(pszPath), &clsid)))
clsid = CLSID_ShellLink; // assume it's a shell link
hres = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, &punk);
if (SUCCEEDED(hres)) {
IPersistFile* ppf;
if (SUCCEEDED(punk->lpVtbl->QueryInterface(punk, &IID_IPersistFile, &ppf))) {
WCHAR wszPath[MAX_PATH];
SHTCharToUnicode(pszPath, wszPath, ARRAYSIZE(wszPath));
ppf->lpVtbl->Load(ppf, wszPath, 0);
ppf->lpVtbl->Release(ppf);
}
hres = ShellLinkGetPath(punk, pszTarget, cch);
punk->lpVtbl->Release(punk);
}
return FALSE;
}
#define MAIL_HANDLER TEXT("Software\\Clients\\Mail")
#define MAIL_ATHENA_V1 TEXT("Internet Mail and News")
#define MAIL_ATHENA_V2 TEXT("Outlook Express")
BOOL GetDefaultMailHandler(LPTSTR pszMAPIDLL, DWORD cbMAPIDLL, BOOL* pbWantsCodePageInfo)
{
TCHAR szDefaultProg[80];
DWORD cb = SIZEOF(szDefaultProg);
*pbWantsCodePageInfo = FALSE;
*pszMAPIDLL = 0;
if (ERROR_SUCCESS == SHRegGetUSValue(MAIL_HANDLER, TEXT(""), NULL, szDefaultProg, &cb, FALSE, NULL, 0)) {
HKEY hkey;
TCHAR szProgKey[128];
lstrcpy(szProgKey, MAIL_HANDLER TEXT("\\"));
lstrcat(szProgKey, szDefaultProg);
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szProgKey, 0, KEY_QUERY_VALUE, &hkey)) {
// ugly, hard code this for OE
*pbWantsCodePageInfo = (lstrcmpi(szDefaultProg, MAIL_ATHENA_V2) == 0);
cb = cbMAPIDLL;
if (ERROR_SUCCESS != SHQueryValueEx(hkey, TEXT("DLLPath"), 0, NULL, (LPBYTE)pszMAPIDLL, &cb)) {
if (lstrcmpi(szDefaultProg, MAIL_ATHENA_V1) == 0) {
lstrcpyn(pszMAPIDLL, TEXT("mailnews.dll"), cbMAPIDLL);
}
}
RegCloseKey(hkey);
}
}
return *pszMAPIDLL;
}
HMODULE LoadMailProvider(BOOL* pbWantsCodePageInfo)
{
TCHAR szMAPIDLL[MAX_PATH];
if (!GetDefaultMailHandler(szMAPIDLL, sizeof(szMAPIDLL), pbWantsCodePageInfo)) {
// read win.ini (bogus hu!) for mapi dll provider
if (GetProfileString(TEXT("Mail"), TEXT("CMCDLLName32"), TEXT(""), szMAPIDLL, ARRAYSIZE(szMAPIDLL)) <= 0)
lstrcpy(szMAPIDLL, TEXT("mapi32.dll"));
}
return LoadLibrary(szMAPIDLL);
}
typedef struct {
TCHAR szTempShortcut[MAX_PATH];
MapiMessage mm;
MapiFileDesc mfd[0];
} MAPI_FILES;
int lstrzlen(int nStrs, LPCTSTR pszStrs)
{
LPCTSTR psz;
int i;
for (i = 0, psz = pszStrs; ((i < nStrs) && (*psz)); psz += lstrlen(psz) + 1, i++)
;
return (int)(psz - pszStrs + 1);
}
BOOL SHPathToAnsi(LPCTSTR pszSrc, LPSTR pszDest, int cbDest)
// SHPathToAnsi creates an ANSI version of a pathname. If there is going to be a
// loss when converting from Unicode, the short pathname is obtained and stored in the destination.
// pszSrc : Source buffer containing filename (of existing file) to be converted
// pszDest : Destination buffer to receive converted ANSI string.
// cbDest : Size of the destination buffer, in bytes.
// returns:
// TRUE, the filename was converted without change
// FALSE, we had to convert to short name
{
#ifdef UNICODE
BOOL bUsedDefaultChar;
WideCharToMultiByte(CP_ACP, 0, pszSrc, -1, pszDest, cbDest, NULL, &bUsedDefaultChar);
if (bUsedDefaultChar) {
TCHAR szTemp[MAX_PATH];
if (GetShortPathName(pszSrc, szTemp, ARRAYSIZE(szTemp)))
SHTCharToAnsi(szTemp, pszDest, cbDest);
}
return !bUsedDefaultChar;
#else
SHTCharToAnsi(pszSrc, pszDest, cbDest);
return TRUE;
#endif
}
MAPI_FILES* _AllocMapiFiles(int nFiles, LPCTSTR pszFiles)
{
MAPI_FILES* pmf;
int n;
n = SIZEOF(*pmf) + (nFiles * SIZEOF(pmf->mfd[0]));
// buffer space *2 for DBCS
pmf = GlobalAlloc(GPTR, n + (lstrzlen(nFiles, pszFiles) * 2));
if (pmf) {
pmf->mm.nFileCount = nFiles;
if (nFiles) {
int i;
LPCTSTR psz;
LPSTR pszA = (CHAR*)pmf + n; // thunk buffer
pmf->mm.lpFiles = pmf->mfd;
for (i = 0, psz = pszFiles; ((i < nFiles) && (*psz));
pszA += lstrlen(psz) + 1, psz += lstrlen(psz) + 1, i++) {
// if the first item is a folder, we will create a shortcut to
// that instead of trying to mail the folder (that MAPI does not support)
SHPathToAnsi(psz, pszA, (lstrlen(psz) * 2) + 1); // buffer space *2 for DBCS
pmf->mfd[i].lpszPathName = pszA;
pmf->mfd[i].lpszFileName = PathFindFileNameA(pszA);
pmf->mfd[i].nPosition = (UINT)-1;
}
}
}
return pmf;
}
void _FreeMapiFiles(MAPI_FILES* pmf)
{
if (pmf->szTempShortcut[0])
DeleteFile(pmf->szTempShortcut);
GlobalFree(pmf);
}
// pv is pointer to double null terminated file list
const TCHAR c_szPad[] = TEXT(" \r\n ");
STDAPI_(DWORD) MailRecipientThreadProc(void* pv)
{
MRPARAM* pmp = (MRPARAM*)pv;
MAPI_FILES* pmf;
CoInitialize(NULL); // we are going to do some COM stuff
pmf = _AllocMapiFiles(pmp->nFiles, pmp->pszFiles);
if (pmf) {
TCHAR szText[2148]; // hold a URL/FilePath + some formatting text
CHAR szTextA[2148]; // ...
CHAR szTitleA[80]; // because the title is supposed to be non-const (and ansi)
HMODULE hmodMail;
BOOL bWantsCodePageInfo = FALSE;
if (pmf->mm.nFileCount) {
lstrcpy(szText, c_szPad); // init the buffer with some stuff
if (_IsShortcut(pmp->pszFiles))
_GetShortcutTarget(pmp->pszFiles, szText + ARRAYSIZE(c_szPad) - 1, ARRAYSIZE(szText) - ARRAYSIZE(c_szPad));
else
lstrcpyn(szText + ARRAYSIZE(c_szPad) - 1, pmp->pszTitle, ARRAYSIZE(szText) - ARRAYSIZE(c_szPad));
// Don't fill in lpszNoteText if we know we are sending
// documents because OE will puke on it
SHTCharToAnsi(szText, szTextA, ARRAYSIZE(szTextA));
if (!(pmp->dwFlags & MRPARAM_DOC)) {
pmf->mm.lpszNoteText = szTextA;
} else
Assert(pmf->mm.lpszNoteText == NULL);
if (pmp->pszTitle) {
//lstrcpyn(szTitle, pmp->pszTitle, ARRAYSIZE(szTitle));
SHTCharToAnsi(pmp->pszTitle, szTitleA, ARRAYSIZE(szTitleA));
pmf->mm.lpszSubject = szTitleA;
} else
pmf->mm.lpszSubject = szTextA + ARRAYSIZE(c_szPad) - 1;
}
hmodMail = LoadMailProvider(&bWantsCodePageInfo);
if (bWantsCodePageInfo && (pmp->dwFlags & MRPARAM_USECODEPAGE)) {
// When this flag is set, we know that we have just one file to send and we have a code page
// Athena will then look at ulReserved for the code page
// BUGBUG: Will the other MAPI handlers puke on this? -- dli
ASSERT(pmf->mm.nFileCount == 1);
pmf->mfd[0].ulReserved = ((MRPARAM*)pmp)->uiCodePage;
}
if (hmodMail) {
LPMAPISENDMAIL pfnSendMail = (LPMAPISENDMAIL)GetProcAddress(hmodMail, "MAPISendMail");
if (pfnSendMail)
pfnSendMail(0, 0, &pmf->mm, MAPI_LOGON_UI | MAPI_DIALOG, 0);
FreeLibrary(hmodMail);
}
_FreeMapiFiles(pmf);
}
CleanupPMP(pmp);
DllRelease();
CoUninitialize();
return 0;
}
STDAPI MailRecipientDropHandler(IDataObject* pdtobj, DWORD grfKeyState, DWORD dwEffect)
{
MRPARAM* pmp = GlobalAlloc(GPTR, SIZEOF(*pmp));
if (pmp) {
if (!pdtobj || SUCCEEDED(_CreateSendToFilesFromDataObj(pdtobj, grfKeyState, pmp))) {
DllAddRef();
if (SHCreateThread(MailRecipientThreadProc, pmp, CTF_PROCESS_REF, NULL)) {
return S_OK;
}
}
CleanupPMP(pmp);
DllRelease();
}
return E_OUTOFMEMORY;
}
STDAPI MailRecipient_CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv)
{
return DropHandler_CreateInstance(MailRecipientDropHandler, punkOuter, riid, ppv);
}
void GetIconString(LPTSTR pszBuf, LPCTSTR pszModule, int id)
{
wnsprintf(pszBuf, MAX_PATH, TEXT("%s,-%d"), pszModule, id);
}
// get the pathname to a sendto folder item
HRESULT GetDropTargetPath(LPTSTR pszPath, int id, LPCTSTR pszExt)
{
LPITEMIDLIST pidl;
if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_SENDTO, &pidl))) {
TCHAR szFileName[128], szBase[64];
SHGetPathFromIDList(pidl, pszPath);
SHFree(pidl);
LoadString(g_hinst, id, szBase, ARRAYSIZE(szBase));
wnsprintf(szFileName, ARRAYSIZE(szFileName), TEXT("\\%s.%s"), szBase, pszExt);
lstrcat(pszPath, szFileName);
return S_OK;
}
return E_FAIL;
}
#define SENDMAIL_EXTENSION TEXT("MAPIMail")
#define EXCHANGE_EXTENSION TEXT("lnk")
void CommonRegister(HKEY hkCLSID, LPCTSTR pszCLSID, LPCTSTR pszExtension, int idFileName)
{
TCHAR szFile[MAX_PATH];
HKEY hk;
TCHAR szKey[80];
// BUGBUG 981007 review BYTE/TEXT
RegSetValueEx(hkCLSID, NEVERSHOWEXT, 0, REG_SZ, (BYTE*)TEXT(""), SIZEOF(TCHAR));
if (RegCreateKey(hkCLSID, SHELLEXT_DROPHANDLER, &hk) == ERROR_SUCCESS) {
RegSetValueEx(hk, NULL, 0, REG_SZ, (LPBYTE)pszCLSID, (lstrlen(pszCLSID) + 1) * SIZEOF(TCHAR));
RegCloseKey(hk);
}
wnsprintf(szKey, ARRAYSIZE(szKey), TEXT(".%s"), pszExtension);
if (RegCreateKey(HKEY_CLASSES_ROOT, szKey, &hk) == ERROR_SUCCESS) {
TCHAR szProgID[80];
wnsprintf(szProgID, ARRAYSIZE(szProgID), TEXT("CLSID\\%s"), pszCLSID);
RegSetValueEx(hk, NULL, 0, REG_SZ, (LPBYTE)szProgID, (lstrlen(szProgID) + 1) * SIZEOF(TCHAR));
RegCloseKey(hk);
}
if (SUCCEEDED(GetDropTargetPath(szFile, idFileName, pszExtension))) {
HANDLE hfile = CreateFile(szFile, 0, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hfile != INVALID_HANDLE_VALUE)
CloseHandle(hfile);
}
}
STDAPI MailRecipient_RegUnReg(BOOL bReg, HKEY hkCLSID, LPCTSTR pszCLSID, LPCTSTR pszModule)
{
TCHAR szFile[MAX_PATH];
if (bReg) {
HKEY hk;
CommonRegister(hkCLSID, pszCLSID, SENDMAIL_EXTENSION, IDS_MAIL_FILENAME);
if (RegCreateKey(hkCLSID, DEFAULTICON, &hk) == ERROR_SUCCESS) {
TCHAR szIcon[MAX_PATH + 10];
GetIconString(szIcon, pszModule, IDI_MAIL);
RegSetValueEx(hk, NULL, 0, REG_SZ, (LPBYTE)szIcon, (lstrlen(szIcon) + 1) * SIZEOF(TCHAR));
RegCloseKey(hk);
}
// hide the exchange shortcut
if (SUCCEEDED(GetDropTargetPath(szFile, IDS_MAIL_FILENAME, EXCHANGE_EXTENSION)))
SetFileAttributes(szFile, FILE_ATTRIBUTE_HIDDEN);
} else {
if (SUCCEEDED(GetDropTargetPath(szFile, IDS_MAIL_FILENAME, SENDMAIL_EXTENSION)))
DeleteFile(szFile);
// unhide the exchange shortcut
if (SUCCEEDED(GetDropTargetPath(szFile, IDS_MAIL_FILENAME, EXCHANGE_EXTENSION)))
SetFileAttributes(szFile, FILE_ATTRIBUTE_NORMAL);
}
return S_OK;
}