tags:

views:

212

answers:

1

Greets,

I found a similar question at Opening OLE Compound Documents read-only with StgOpenStorage but that solution didn't work for me.

I try to open an outlook .msg file with StgOpenStorage(). My problem is, that StgOpenStorage always locks my file.

So, how can I avoid/remove the lock StgOpenStorage() adds to my file?

(see last method of code OpenStorage())

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

namespace IStorageLock
{
    [ComImport]
    [Guid("0000000d-0000-0000-C000-000000000046")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IEnumSTATSTG
    {
     // The user needs to allocate an STATSTG array whose size is celt.
     [PreserveSig]
     uint Next(uint celt,
               [MarshalAs(UnmanagedType.LPArray), Out]
               System.Runtime.InteropServices.ComTypes.STATSTG[] rgelt,
               out uint pceltFetched);

     void Skip(uint celt);
     void Reset();

     [return: MarshalAs(UnmanagedType.Interface)]
     IEnumSTATSTG Clone();
    }

    [ComImport]
    [Guid("0000000b-0000-0000-C000-000000000046")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    interface IStorage
    {
     void CreateStream(string pwcsName, uint grfMode, uint reserved1,
                       uint reserved2, out IStream ppstm);

     void OpenStream(string pwcsName, IntPtr reserved1, uint grfMode,
                     uint reserved2, out IStream ppstm);

     void CreateStorage(string pwcsName, uint grfMode, uint reserved1,
                        uint reserved2, out IStorage ppstg);

     void OpenStorage(string pwcsName, IStorage pstgPriority, uint grfMode,
                      IntPtr snbExclude, uint reserved, out IStorage ppstg);

     void CopyTo(uint ciidExclude, Guid rgiidExclude, IntPtr snbExclude,
                 IStorage pstgDest);

     void MoveElementTo(string pwcsName, IStorage pstgDest,
                        string pwcsNewName, uint grfFlags);

     void Commit(uint grfCommitFlags);

     void Revert();

     void EnumElements(uint reserved1, IntPtr reserved2, uint reserved3,
                       out IEnumSTATSTG ppenum);

     void DestroyElement(string pwcsName);

     void RenameElement(string pwcsOldName, string pwcsNewName);

     void SetElementTimes(string pwcsName,
                      System.Runtime.InteropServices.ComTypes.FILETIME pctime,
                          System.Runtime.InteropServices.ComTypes.FILETIME patime,
                          System.Runtime.InteropServices.ComTypes.FILETIME pmtime);

     void SetClass(Guid clsid);

     void SetStateBits(uint grfStateBits, uint grfMask);

     void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg,
               uint grfStatFlag);
    }

    class Lock
    {
     [Flags]
     public enum STGM : int {
      DIRECT           = 0x00000000,
      TRANSACTED       = 0x00010000,
      SIMPLE           = 0x08000000,
      READ             = 0x00000000,
      WRITE            = 0x00000001,
      READWRITE        = 0x00000002,
      SHARE_DENY_NONE  = 0x00000040,
      SHARE_DENY_READ  = 0x00000030,
      SHARE_DENY_WRITE = 0x00000020,
      SHARE_EXCLUSIVE  = 0x00000010,
      PRIORITY         = 0x00040000,
      DELETEONRELEASE  = 0x04000000,
      NOSCRATCH        = 0x00100000,
      CREATE           = 0x00001000,
      CONVERT          = 0x00020000,
      FAILIFTHERE      = 0x00000000,
      NOSNAPSHOT       = 0x00200000,
      DIRECT_SWMR      = 0x00400000,
     }

     [DllImport("ole32.dll")]
     private static extern int StgIsStorageFile([MarshalAs(UnmanagedType.LPWStr)]
                                                string pwcsName);

     [DllImport("ole32.dll")]
     static extern int StgOpenStorage([MarshalAs(UnmanagedType.LPWStr)]
                                      string       pwcsName,
                                      IStorage     pstgPriority,
                                      STGM         grfMode,
                                      IntPtr       snbExclude,
                                      uint         reserved,
                                      out IStorage ppstgOpen);

     public IStorage OpenStorage(string fileName)
     {
      if (StgIsStorageFile(fileName) != 0) {
       return null;
      }

      IStorage storage = null;

      //
      // StgOpenStorage() locks file 'fileName'
      //
      // Set flags like:
      // [http://stackoverflow.com/questions/1086814/opening-ole-compound-documents-read-only-with-stgopenstorage]
      //
      int stgOpenStorage = StgOpenStorage(fileName, null,
                                          STGM.READ            |
                                          STGM.SHARE_DENY_NONE |
                                          STGM.TRANSACTED,
                                          IntPtr.Zero, 0,
                                          out storage);

      //
      // Try to rename file (for testing purposes only)
      //
      try {
       File.Move(fileName, fileName + @".renamed");
      } catch (Exception ex) {  // exception: file alreay in use by another process
       throw;
      }

      if (stgOpenStorage != 0) {
       return null;
      } else {
       return storage;
      }
     }
    }
}

Hope you can help me.

Regards,

inno

A: 

Have you tried reading the file into memory and using StgOpenStorageOnILockBytes instead?

Mattias S
Any further hints? How to get file into memory so I can use it with StgOpenStorageOnILockBytes?
Inno
- Allocate a native memory block and get a HGLOBAL hanlde to it. It has to be moveable so you can't use Marshal.AllocHGlobal, got to use GlobalAlloc.- Read the file into it whatever way you want. You can read from a rgular .NET FileStream and write the conntent with Marshal.Copy. Make sure you release the FileStream to remove all "locks" on the file.- Call CreateILockBytesOnHGlobal to get the ILockBytes object.
Mattias S