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:
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