前面我们了解了可以通过iProperties或Attribute为文档附加数据。由于Inventor 文件也是一种Windows文件,因此Windows提供的附加数据方法也适用。那就是 IStorage & IStream. 在全球博客上,我已经撰写了专门的文章介绍。不过是用C++写的。
How to use private storage and stream in C++
后来我琢磨着如何用.NET写。前几个月,正好论坛上有人问起,我就花时间去研究。最后,创建是没问题,可读取却总是失败,见论坛讨论:
http://forums.autodesk.com/t5/Autodesk-Inventor-Customization/Store-object-inside-document/td-p/3610956
百思不得其解。由于忙于DevDays,就暂时放下了。这几天重新翻出来,有请我们开发部的同事Mona帮忙看看。她发现问题出在创建IStorage后,没有释放。于是第二次访问(例如读取)就发生失败了。而C++代码比较幸运,用的是智能指针,自动释放了。这真是太有帮助的发现了!基于此,对代码稍作修改,就运行正常了!再次特别感谢Mona,还有两个网上文章:
http://www.pinvoke.net/default.aspx/Enums/STGM.html
http://bytes.com/topic/c-sharp/answers/760093-accessing-com-c-istream-parameter
以下是代码样例,测试可打开一个现有文档,执行test,先是创建数据,添加到文档,接着读取出来。
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]
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,
}
// 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)
return false;
// 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)
return false ;
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);
return true;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return false;
}
}
// read the storge and stream
bool ReadPrivateStorageAndStream(Document pDoc,
string StorageName,
string StreamName,
out string 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)
return false;
// 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)
return false;
byte[] byteVsize = new byte[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 =
new byte[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);
return true;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return false;
}
}
// main function to test
private void 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);
}
}