Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

IDropTarget with Outlook

397 views
Skip to first unread message

Mike Baker

unread,
Jun 27, 2006, 4:40:49 PM6/27/06
to
Hello all. I think this is the correct forum for this question. I am using
CBuilder 6.0 and have created an IDropTarget interface to accept files from
explorer into my application. This is working fine. I have also added in
the code to accept attachments from Outlook which is also working fine. 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.

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


Remy Lebeau (TeamB)

unread,
Jun 28, 2006, 12:14:48 AM6/28/06
to

"Mike Baker" <mba...@accentsol.com> wrote in message
news:44a197cf$1...@newsgroups.borland.com...

> 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


Mike Baker

unread,
Jul 6, 2006, 10:21:07 AM7/6/06
to
Remy Lebeau , thanks very much for all of this info. This is getting me on
the correct track. My question now is, where did you find the information
about how Outlook handles this type of opertion? I have been looking all
over the place without much luck.

Thanks,
Mike


Remy Lebeau (TeamB)

unread,
Jul 6, 2006, 1:30:37 PM7/6/06
to

"Mike Baker" <mba...@accentsol.com> wrote in message
news:44ad1c53$1...@newsgroups.borland.com...

> 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 Baker

unread,
Jul 7, 2006, 3:26:36 PM7/7/06
to
Again, thanks for the information. This has turned out to be one heck of a
project. Once I get this completed, the next step is IDropSource.

Mike


0 new messages