Save extra data in Inventor file – 3

By Xiaodong Liang

Note: the solution in this article uses the the wrapped functions of Inventor API with IStorage and IStream which require to make the document dirty. If you do not need Inventor API, please refer to the other article. 

Inventor files are also a kind of Windows files. Windows API allows you attach data to the file, which is called IStorage & IStream. The other post tells in detail, including the C++ demo code.

How to use private storage and stream in C++

So, I was ready to post the equivalent .NET codes. Actually, I had such discussion on the forum a few months ago:

http://forums.autodesk.com/t5/Autodesk-Inventor-Customization/Store-object-inside-document/td-p/3610956

in which, I have written out some codes. It works well with creating, unfortunately however it failed with reading. I was stuck and the reason was not clear to me.

These days,  my colleague Mona in the engineer team kindly offered a hand on this issue. She finally found the private storage failed to get again is because of it being locked. The IStorage pointer is not released when creating the private storage for the first time. Then for the second time to get it, it’s considered as locked. The way to solve it is to release the pointer before it is called next time, by “Marshal.ReleaseComObject(pStg);” It is the developer’s responsibility to release it. C++ code is lucky since the demo uses smart pointer which can release it for you.

Thanks Mona so much for the solution!  Now, the code works :) And thanks again for these two articles which helped me a lot.

 http://www.pinvoke.net/default.aspx/Enums/STGM.html
http://bytes.com/topic/c-sharp/answers/760093-accessing-com-c-istream-parameter

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Reflection;
using Inventor;
using System.Diagnostics;
using MVOI = Microsoft.VisualStudio.OLE.Interop;
//enum flags for STGM
        [Flags]
        publicenumSTGM : 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,
        }
 
        // create private storage and stream
        bool  CreatePrivateStorageAndStream(Document pDoc,
            string StorageName,
            string StreamName,
            string data)
        {
            try
            {
                // create/get storage. "true" means if create                //if it does not exists.
                MVOI.IStorage pStg = 
                    (MVOI.IStorage)pDoc.GetPrivateStorage                                         (StorageName, true);
                if (pStg == null)
                    returnfalse;
 
                // create stream in the storage
                MVOI.IStream pStream = null;
                pStg.CreateStream(StreamName, (uint)                    (STGM.DIRECT | STGM.CREATE |                    STGM.READWRITE | STGM.SHARE_EXCLUSIVE),
                    0, 0, out pStream);
 
                if (pStream == null)
                    returnfalse ;
 
                byte[] byteVsize = 
                    System.BitConverter.GetBytes                                     (data.Length);               
                byte[] byteVData = 
                    Encoding.Default.GetBytes(data);
                uint dummy;
 
    // convert string to byte and store it to the stream 
                pStream.Write(byteVsize, 
                    (uint)(sizeof(int)),
                    out dummy);
                pStream.Write(byteVData,
                    (uint)(byteVData.Length),
                    out dummy);               
 
                // Save the data           
                pStream.Commit((uint)                          (MVOI.STGC.STGC_OVERWRITE |
                          MVOI.STGC.STGC_DEFAULT));
 
          //Don't forget to commit changes also in storage
                pStg.Commit((uint)(MVOI.STGC.STGC_DEFAULT |                            MVOI.STGC.STGC_OVERWRITE));
 
                // force document to be dirty thus 
                // the change can be saved when document                //is saved.
                pDoc.Dirty = true;                
                pDoc.Save();
 
                //Don't forget to release the object!!
                Marshal.ReleaseComObject(pStg);
 
                returntrue;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                returnfalse;
            }
        }
 
        // read the storge and stream
        bool ReadPrivateStorageAndStream(Document pDoc,
            string StorageName,
            string StreamName,
              outstring  outDataStr)
        {
            outDataStr = "";
            try
            {               
                //get the storge. "false" means do not create                //if it does not exist
                MVOI.IStorage pStg = 
                    (MVOI.IStorage)pDoc.GetPrivateStorage                          (StorageName, false);
                if (pStg == null)
                    returnfalse;
 
                // open stream to read
                MVOI.IStream pStream = null;
                pStg.OpenStream(StreamName,IntPtr.Zero, 
                    (uint)(STGM.DIRECT| STGM.READWRITE |                              STGM.SHARE_EXCLUSIVE),
                    0,  out pStream);
 
                if (pStream == null)
                    returnfalse;
 
                byte[] byteVsize = newbyte[16];
                uint intSize = sizeof(int);
 
                // read the stream
                uint dummy;
                pStream.Read(byteVsize, 
                    (uint)intSize, out dummy);
                int lSize = System.BitConverter.ToInt16                                      (byteVsize,0);
 
                byte[] outDataByte = 
                    newbyte[8192];
                pStream.Read(outDataByte, 
                    (uint)lSize, out dummy);
 
                // convert byte to string
                outDataStr =
                    Encoding.Default.GetString(outDataByte,                                                0, lSize);
 
                //Don't forget to release the object!!
                Marshal.ReleaseComObject(pStg);
                returntrue;  
            }
            catch (Exception ex)
            {
            MessageBox.Show(ex.ToString());                
                returnfalse;
            }
 
        }
 
        // main function to test
        privatevoid test()
        {
            //get Inventor application
            string progId = "Inventor.Application";
            Inventor.Application m_inventorApp =
               (Inventor.Application)Marshal.GetActiveObject                                                (progId );
 
            //get the current document.              
            Document pDoc = m_inventorApp.ActiveDocument;
 
            //create the storage and stream
            bool Result  = CreatePrivateStorageAndStream                                 (pDoc,
                                "MyPrvStorage1",
                                "MyStream1",
                                "Some private stored data");
 
            if (Result)
            {
                pDoc = m_inventorApp.ActiveDocument;
                string outPutStr = null;
                //read the storage and stream
                bool readResult = ReadPrivateStorageAndStream                                 (pDoc,
                                "MyPrvStorage1",
                                "MyStream1", out outPutStr);
 
                MessageBox.Show(outPutStr);
            }
        }

Last, I’d like to point out a tool Structured Storage Viewer which even enables you to read/write data without Inventor. It also proves that you can read/write this data programmatically without using any Inventor API because Inventor file is also a kind of Windows file:
 http://download.cnet.com/Structured-Storage-Viewer/3000-2248_4-75649632.html


Comments

One response to “Save extra data in Inventor file – 3”

  1. The Download Cnet file dont work

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading