Hi Steven,
I had to deal with *.msg files as well a while back. Turns out they are
actually so-called compound files (a single file containing several
streams/subdirectories).
First you need the StgOpenStorage(Ex) function from the ole32.dll to
open these files, then
you can use the IStream/IStorage Interfaces to work with the contents
(IStream is already implemented in the .NET Framework, IStorage
unfortunately isn't).
I can't release the classes I created to work with these messages, but
I can provide you with my IStorage-Interface and StgOpenStorage
definitions, hopefully these will enable you to open the *.msg files
and take a look at their contents.
Its actually pretty straightforward from there, certain properties are
always stored in certain subdirectories/streams, so you need to figure
out the names of the streams you need and read their contents.
For further assistance with the IStream/IStorage interfaces you can
take a look at the msdn, they are pretty well documented.
Sincerely,
Kevin Wienhold
Definitions:
[ComImport,ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown )]
[Guid("0000000b-0000-0000-C000-000000000046")]
public interface IStorage
{
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint CreateStream(
[In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
[In] int grfMode,
[In] int reserved1,
[In] int reserved2,
[Out] out UCOMIStream ppstm);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint OpenStream(
[In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
[In] IntPtr reserved1,
[In] int grfMode,
[In] int reserved2,
[Out] out UCOMIStream ppstm);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint CreateStorage(
[In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
[In] int grfMode,
[In] int reserved1,
[In] int reserved2,
[Out] out IStorage ppstg);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint OpenStorage(
[In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
[In, MarshalAs(UnmanagedType.Interface)] IStorage pstgPriority,
[In] int grfMode,
[In] string[] snbExclude,
[In] int reserved,
[Out] out IStorage ppstg);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint CopyTo(
[In] int ciidExclude,
[In] Guid[] rgiidExclude,
[In] string[] snbExclude,
[In, MarshalAs(UnmanagedType.Interface)] IStorage pstgDest);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint MoveElementTo(
[In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
[In, MarshalAs(UnmanagedType.Interface)] IStorage pstgDest,
[In, MarshalAs(UnmanagedType.LPWStr)] string pwcsNewName,
[In] int grfFlags);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint Commit(
[In] int grfCommitFlags);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint Revert();
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint EnumElements(
[In] int reserved1,
[In] IntPtr reserved2,
[In] int reserved3,
[Out] out IEnumSTATSTG ppenum);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint DestroyElement(
[In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint RenameElement(
[In, MarshalAs(UnmanagedType.LPWStr)] string pwcsOldName,
[In, MarshalAs(UnmanagedType.LPWStr)] string pwcsNewName);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint SetElementTimes(
[In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
[In] ref FILETIME pctime,
[In] ref FILETIME patime,
[In] ref FILETIME pmtime);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint SetClass(
[In] ref Guid clsid);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint SetStateBits(
[In] uint grfStateBits,
[In] uint grfMask);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
uint Stat(
[Out] out STATSTG pstatstg,
[In] uint grfStatFlag);
}
[DllImport("Ole32.dll")]
private static extern int StgOpenStorage
(
[MarshalAs(UnmanagedType.LPWStr)] string wcsName,
IStorage pstgPriority,
int grfMode, // access method
IntPtr snbExclude, // must be NULL
int reserved, // reserved
out IStorage storage // returned storage
);
Steven Nagy schrieb:
Hi all,
I need to be able to take messages that have been saved from Outlook
(*.msg) and read them into a C# application (think of it as workflow
management). But these msg files are pretty funky.
All my research only turned up stuff about Automating Exchange and MAPI
which I know nothing about. I would prefer in this instance to think of
it more as a "black box" scenario where I can have a nice managed
library where I can load a msg file and have nicely exposed properties
about the message. We would then save the important information
(sender, subject, body, importance) to a database table and discard the
actual message file.
I can pay for such a component if it exists, but can develop one with
the right guidance as well.
Can you please provide advice to help me solve my problem?
Many thanks,
Steven Nagy