class ObjDropTarget : public IDropTarget
{
private:
.....
public:
......
// IUnknown Members
HRESULT __stdcall QueryInterface(REFIID iid, void **ppvObject)
{....} et.c....
HRESULT __stdcall Drop(IDataObject *pDataObj,
DWORD grfKeyState,
POINTL pt,
DWORD *pdwEffect)
{
.......................
unsigned short cp_format_descriptor =
RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
unsigned short cp_format_contents =
RegisterClipboardFormat(CFSTR_FILECONTENTS);
//Set up format structure for the descriptor and contents
FORMATETC descriptor_format =
{cp_format_descriptor, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
FORMATETC contents_format =
{cp_format_contents, NULL, DVASPECT_CONTENT, -1, TYMED_ISTREAM};
FORMATETC filename_format =
{CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
// Check for descriptor format type
hResult = pDataObj->QueryGetData(&descriptor_format);
if (hResult == S_OK)
{
// Check for contents format type
hResult = pDataObj->QueryGetData(&contents_format);
if (hResult == S_OK)
{
hResult = pDataObj->GetData(&descriptor_format, &stMedium);
if (hResult != S_OK)
{ ...... }
file_group_descriptor = (FILEGROUPDESCRIPTOR *)
GlobalLock(stMedium.hGlobal);
// For each file, get the name and copy the stream to a file
for (unsigned int file_index = 0; file_index <
file_group_descriptor->cItems; file_index++)
{
file_descriptor = file_group_descriptor->fgd[file_index];
contents_format.lindex = file_index;
hResult = pDataObj->GetData(&contents_format, &stMedium);
if (hResult == S_OK) // Dump stream to a file
{
sprintf(szFileBuff, "C:\\ACTemp\\%s",
file_descriptor.cFileName);
hResult = StreamToFile(stMedium.pstm, szFileBuff);
strFilePath = szFileBuff;
.........................
}
else
{
THIS IS THE AREA
filename_format.lindex = file_index;
hResult = pDataObj->GetData(&filename_format, &stMedium);
if (hResult == S_OK)
{
hDrop = (HANDLE)stMedium.hGlobal;
WHEN THIS IS EXECUTED, THE OUTLOOK ERROR APPEARS
uiCount = DragQueryFile(hDrop, -1, szFileBuff,
sizeof(szFileBuff));
...................
}
}
}
GlobalUnlock(stMedium.hGlobal);
GlobalFree(stMedium.hGlobal);
}
}
The problem is when I drop an Outlook message onto my window, I get this
message from Outlook; (The operation failed due to network or other
communication problems. Check your connections and try again.)
I am assuming that I some how need to tell outlook wher to place the message
file. So far, I have looked in all kinds of books and googled myself to
death looking for hints on this one thing. If anyone know the trick, I
would really appreciate it.
Thanks,
Mike
> My problem is, I need to allow for the message itself to be
> dropped into my application which is not working. My class
> looks like below with a bunch of code left out; Most of the
> problem area is at the location marked THIS IS THE AREA.
Outlook provides CFSTR_FILEDESCRIPTOR and CFSTR_FILECONTENTS formats for
dragged messages. The FILEDESCRIPTOR is passed as an HGLOBAL, and the
FILECONTENTS are passed as IStorage interfaces. With the IStorage
interfaces for each message, you can drill into the contents using the
IStorage::OpenStorage() and IStorage::OpenStream() methods. The Sender,
Recipients, Subject, and message body (and even different formats of the
body) are stored in separate streams of the message. You have to extract
them indiviudally.
The following works for me. You can build on it as needed.
#include <vcl.h>
#pragma hdrstop
#include "OutlookDropForm.h"
#include <shlobj.h>
//--------------------------------------------------------------------------
-
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//--------------------------------------------------------------------------
-
UINT CF_FILEDESCRIPTOR = 0;
UINT CF_FILECONTENTS = 0;
//--------------------------------------------------------------------------
-
void DisplayStream(IStream *pStream)
{
char buffer[1024];
ULONG read;
while( pStream->Read(buffer, 1024, &read) == S_OK )
{
if( read == 0 )
break;
try
{
Form1->Memo1->SelStart = Form1->Memo1->GetTextLen();
Form1->Memo1->SelText = AnsiString(buffer, read);
}
catch(const Exception &)
{
return;
}
}
}
void DisplayStorage(IStorage *pStorage)
{
IEnumSTATSTG *pEnum = NULL;
HRESULT hRes = pStorage->EnumElements(0, NULL, 0, &pEnum);
if( FAILED(hRes) )
return;
pEnum->Reset();
STATSTG stat;
while( pEnum->Next(1, &stat, NULL) == S_OK )
{
if( stat.pwcsName )
{
try
{
Form1->Memo1->Lines->Add(stat.pwcsName);
switch( stat.type )
{
case STGTY_STORAGE:
{
IStorage *pSubStorage = NULL;
hRes = pStorage->OpenStorage(stat.pwcsName, NULL,
STGM_SHARE_EXCLUSIVE, NULL, 0, &pSubStorage);
if( SUCCEEDED(hRes) )
{
DisplayStorage(pSubStorage);
pSubStorage->Release();
}
break;
}
case STGTY_STREAM:
{
IStream *pStream = NULL;
hRes = pStorage->OpenStream(stat.pwcsName, NULL,
STGM_SHARE_EXCLUSIVE, 0, &pStream);
if( SUCCEEDED(hRes) )
{
DisplayStream(pStream);
pStream->Release();
}
break;
}
}
Form1->Memo1->Lines->Add("----------");
}
catch(const Exception &)
{
}
CoTaskMemFree(stat.pwcsName);
}
}
pEnum->Release();
}
class TDropTarget : public IDropTarget
{
private:
ULONG RefCnt;
public:
TDropTarget() : RefCnt(1) {}
HRESULT __stdcall QueryInterface(REFIID riid, LPVOID* ppv)
{
if( !ppv )
return E_POINTER;
*ppv = NULL;
if( riid == IID_IUnknown )
*ppv = (IUnknown*) this;
else if( riid == IID_IUnknown )
*ppv = (IDropTarget*) this;
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
ULONG __stdcall AddRef()
{
return ++RefCnt;
}
ULONG __stdcall Release()
{
if( --RefCnt == 0 )
{
delete this;
return 0;
}
return RefCnt;
}
HRESULT __stdcall DragEnter(IDataObject *pDataObject, DWORD grfKeyState,
POINTL pt, DWORD *pdwEffect)
{
if( !pDataObject || !pdwEffect )
return E_INVALIDARG;
if( *pdwEffect & DROPEFFECT_COPY )
{
FORMATETC fmt = {0};
fmt.cfFormat = CF_FILEDESCRIPTOR;
fmt.dwAspect = DVASPECT_CONTENT;
fmt.lindex = -1;
fmt.tymed = TYMED_HGLOBAL;
if( SUCCEEDED(pDataObject->QueryGetData(&fmt)) )
{
fmt.cfFormat = CF_FILECONTENTS;
fmt.dwAspect = DVASPECT_CONTENT;
fmt.lindex = -1;
fmt.tymed = TYMED_ISTORAGE;
if( SUCCEEDED(pDataObject->QueryGetData(&fmt)) )
{
*pdwEffect = DROPEFFECT_COPY;
return S_OK;
}
}
}
*pdwEffect = DROPEFFECT_NONE;
return S_OK;
}
HRESULT __stdcall DragOver(DWORD grfKeyState, POINTL pt, DWORD
*pdwEffect)
{
*pdwEffect = DROPEFFECT_COPY;
return S_OK;
}
HRESULT __stdcall DragLeave()
{
return S_OK;
}
HRESULT __stdcall Drop(IDataObject *pDataObject, DWORD grfKeyState,
POINTL pt, DWORD *pdwEffect)
{
if( !pDataObject || !pdwEffect )
return E_INVALIDARG;
Form1->Memo1->Clear();
if( *pdwEffect & DROPEFFECT_COPY )
{
FORMATETC fmt = {0};
fmt.cfFormat = CF_FILEDESCRIPTOR;
fmt.dwAspect = DVASPECT_CONTENT;
fmt.lindex = -1;
fmt.tymed = TYMED_HGLOBAL;
STGMEDIUM stg = {0};
UINT uiCount = 0;
HRESULT hRes = pDataObject->GetData(&fmt, &stg);
if( SUCCEEDED(hRes) )
{
LPFILEGROUPDESCRIPTOR pDesc = (LPFILEGROUPDESCRIPTOR)
GlobalLock(stg.hGlobal);
if( pDesc )
{
uiCount = pDesc->cItems;
GlobalUnlock(stg.hGlobal);
}
ReleaseStgMedium(&stg);
}
if( uiCount )
{
fmt.cfFormat = CF_FILECONTENTS;
fmt.dwAspect = DVASPECT_CONTENT;
fmt.tymed = TYMED_ISTORAGE;
char buffer[256];
ULONG read;
for(UINT ui = 0; ui < uiCount; ++ui)
{
fmt.lindex = ui;
hRes = pDataObject->GetData(&fmt, &stg);
if( SUCCEEDED(hRes) )
{
DisplayStorage(stg.pstg);
ReleaseStgMedium(&stg);
}
}
}
*pdwEffect = DROPEFFECT_COPY;
return S_OK;
}
*pdwEffect = DROPEFFECT_NONE;
return S_OK;
}
};
//--------------------------------------------------------------------------
-
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
OleInitialize(NULL);
CF_FILEDESCRIPTOR = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
CF_FILECONTENTS = RegisterClipboardFormat(CFSTR_FILECONTENTS);
TDropTarget *Target = new TDropTarget;
RegisterDragDrop(Panel1->Handle, Target);
Target->Release();
}
//--------------------------------------------------------------------------
-
__fastcall TForm1::~TForm1()
{
RevokeDragDrop(Panel1->Handle);
OleUninitialize();
}
//--------------------------------------------------------------------------
-
Gambit
Thanks,
Mike
> where did you find the information about how
> Outlook handles this type of opertion?
Nowhere. I had to figure out myself. I used IDataObject::EnumFormatEtc()
to figure out which clipboard formats the IDataObject provided, and then
started drilling into their respective raw data to see what was actually
available. The IStorage was the key to solving it. I first tried using
HGLOBAL and IStream, but they did not work for retreiving the message data.
I tried IStorage, since I knew from past experience that Outlook uses
Compound Files (and thus IStorage) for storing email mesages on the hard
drive, and it worked. So I then started looking at the individual IStream
interfaces inside of the IStorage and viola, all the data you are looking
for was in there.
Gambit
Mike