Thursday, March 11, 2010

SWT: Drop an Outlook Email

I wanted to drop an outlook email to my RCP application and as always I asked google to help me. You don't find much on this, an older post was

That got me startet. The damn it didn't work, I asked on the forum again and the answer made confusion even greater:

gladly my wife gladly does some more windows thingy's with c# and with her help and a c# example i found out that i have to make an os call to get the type of the transfer that may change with every boot.

public static int registerType() {
// Look name up in the registry
// If name is not in registry, add it and return assigned value.
// If name already exists in registry, return its assigned value
TCHAR chFormatName = new TCHAR(0, "FileContents", true);
return OS.RegisterClipboardFormat(chFormatName);
Then at least the stuff from the first post started to do something, i could get an IStorage and enumerate over the STATSTG's

public Object nativeToJava(TransferData transferData) {

IDataObject idata = new IDataObject(transferData.pIDataObject);
FORMATETC formatetc = new FORMATETC();

STGMEDIUM stgmedium = new STGMEDIUM();
formatetc.cfFormat = type;
formatetc.lindex = 0;
formatetc.ptd = 0;
formatetc.tymed = 4 | 8 | 1;
formatetc.dwAspect = COM.DVASPECT_CONTENT;
transferData.result = getData(idata, formatetc, stgmedium);
if (transferData.result != COM.S_OK) {
System.out.println("Fehler" + transferData.result);
return null;

if ((stgmedium.tymed & 8) == 8) {
// IStorage
IStorage storage = new IStorage(stgmedium.unionField);
long[] x = new long[1];
long ret = storage.EnumElements(0, 0, 0, x);

IEnumSTATSTG enumSTATSTG = new IEnumSTATSTG(x[0]);
STATSTG[] data = new STATSTG[0];
// Loop over enumerator
long rgelt = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, STATSTG.sizeof);
int[] pceltFetched = new int[1];
while (enumSTATSTG.Next(1, rgelt, pceltFetched) == COM.S_OK && pceltFetched[0] == 1) {
STATSTG statstg = new STATSTG();
COM.MoveMemory(statstg, rgelt, STATSTG.sizeof);
STATSTG[] newData = new STATSTG[data.length + 1];
System.arraycopy(data, 0, newData, 0, data.length);
newData[data.length] = statstg;
data = newData;


// do something with STATSTG[]

but i still did not know what the heck to do with these objects. I started to search again and finally found an example in the eclipse OleClient:

private byte[] readStream(IStorage storage, String stream) {
boolean success = false;

long[] address = new long[1];
// Look for a CONTENTS stream
if (storage.OpenStream(stream, 0, COM.STGM_DIRECT | COM.STGM_READ | COM.STGM_SHARE_EXCLUSIVE, 0, address) == COM.S_OK) {
IStream tempContents = new IStream(address[0]);

try {
ByteArrayOutputStream w = new ByteArrayOutputStream();

int increment = 1024 * 4;
long pv = COM.CoTaskMemAlloc(increment);
int[] pcbWritten = new int[1];
while (tempContents.Read(pv, increment, pcbWritten) == COM.S_OK && pcbWritten[0] > 0) {
byte[] buffer = new byte[pcbWritten[0]];
OS.MoveMemory(buffer, pv, pcbWritten[0]);
success = true;

return w.toByteArray();
} catch (IOException err) {
} finally {


return null;

now with that I can read Streams from the IStorage. What streams there are is in the STATSTG's

// do something with STATSTG[]
Map result = new HashMap();
for (STATSTG s : data) {
String stream = getString(s.pwcsName);
result.put(stream, readStream(storage, stream));

return result;
There we are. The IStorage contains the data in the .msg Format that I return in some strange way via the Map. I don't know how to get the .msg in one piece, but at least with some informations from

I can now extract the contents of the message and push it to jackrabbit ;) The code in these examples is for x86_64, you may need some ints for the adresses on 32bit windows.


Joerg said...


It's realy a hard work that you have done. Thanks.

Can I provider the code for the method getString in the line:
String stream = getString(s.pwcsName);

Another thing is, I have now the map with data, but I which format are the data und how can I extract the e-Mail from the map?

I'm looking to hear from you. Thanks.

Kind regards

Thomas Kratz said...

getstring does the following
public static String getString(long addr) {
String str = null;
TCHAR buffer = new TCHAR(0, 256);
OS.MoveMemory(buffer, addr, 256);
str = buffer.toString(0, buffer.strlen());
return str;

the map is somehow in the format described in the last link. you have to look for the right strems you are interestest in. i found that on my outlook 2007 i get extra bytes for each character that i simply removed, i don't understand why, just happy that it works. drop me a mail at eiswind at gmail dot com

Jörg said...

Hi Thomas

Thanks for getString.

The code works. The data in the map are a little wirred...

Until know I was unable to figure out who attachments are represented in the map. Do you have any idea?


Thomas Kratz said...

Sorry Jörg, I didn't give a try on the attachments, but they should be in the map too in some way.

Alexis said...

There are many tools on my computer. Yesterday I had unpleasant difficult problem,which I didn't know how to restore it. But for luck I entered the Internet and observed there an extraordinary software - microsoft exchange moving outlook ost file. I used the utility and it determined my issue for a minute and free of charge as I kept in mind. The software restored my crashed emails completely easy.

Using Mapstruct with Protobuf3