|
ms
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Outlook Message Format LibraryI 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 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: Show quoteHide quote > 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 Thanks Kevin. This is definately a good place for me to start.
Great well rounded response! KWienhold wrote: Show quoteHide quote > 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
Other interesting topics
Fast Case Insensitive String Comparisons
How to properly check for NULL! Search a file and find all occurences Launch Application as Different User in C# Windows Applicatoin Visual Studio Plugin? Appropriate pattern Need Simple Example of Class Event Raising and Handling in Form KeyedCollection in use for GUI editor? Chicken in Egg problem... InvalidOperations excetion running wsh with Process class Envox CT ADE Development / RealSpeak Telecom |
|||||||||||||||||||||||