前一段时间我写了篇文章"关于以前写的VBA在新版本64位Inventor中无法使用的问题",然后就对Structure Storage API似乎有一发不可收拾的兴趣。 这一次我打算使用Structure Storage API来做个有效、方便的工具来删除Inventor文件中的VBA。Inventor文件是基于Structure Storage的,或者说IStorage/IStream。这类文件有些人翻译成复合文件。这一类型的文件都支持structure storage API,因此我们就可以用structure storage API来修改文件(内部包含的属性、信息)。IStorage是一种COM接口,能用C++调用,如果你对如何用C++调用IStorage接口来删除VBA程序感兴趣,我建议你看看Brian的博客: http://modthemachine.typepad.com/my_weblog/2009/01/removing-vba-document-projects-from-inventor-files.html 我今天要讲的是C#调用IStorage接口。为了调用IStorage接口,我们要先给这个COM接口做一个.NET封装(wrapper),下面我会贴出C#的封装源代码,以及我的程序中主要的实现代码供大家参考: IStorage 的C#封装: [DllImport("ole32.dll")] static extern int StgIsStorageFile([MarshalAs(UnmanagedType.LPWStr)] string pwcsName);
[DllImport("ole32.dll")] static extern int StgCreateDocfile([MarshalAs(UnmanagedType.LPWStr)] string pwcsName, STGM grfMode, uint reserved, out IStorage ppstgOpen);
[DllImport("ole32.dll")] static extern int StgOpenStorage( [MarshalAs(UnmanagedType.LPWStr)] string pwcsName , IStorage pstgPriority , STGM grfMode , IntPtr snbExclude , uint reserved , out IStorage ppstgOpen);
private ArrayList fileList = new ArrayList();
public SSProcessor(ArrayList _fileList) { SetFileList(_fileList); }
private void SetFileList(ArrayList _fileList) { fileList = _fileList; }
public void CullFiles() { int count = 0;
foreach (FileSystemInfo file in fileList) { try { StgIsStorageFile(file.FullName); count++; } catch { fileList.RemoveAt(count); //add code to log non-storagefile items } } }
public enum STGM : uint { STGM_READ = 0x00000000, STGM_WRITE = 0x00000001, STGM_READWRITE = 0x00000002, STGM_SHARE_DENY_NONE = 0x00000040, STGM_SHARE_DENY_READ = 0x00000030, STGM_SHARE_DENY_WRITE = 0x00000020, STGM_SHARE_EXCLUSIVE = 0x00000010, STGM_PRIORITY = 0x00040000, STGM_CREATE = 0x00001000, STGM_CONVERT = 0x00020000, STGM_FAILIFTHERE = 0x00000000, STGM_DIRECT = 0x00000000, STGM_TRANSACTED = 0x00010000, STGM_NOSCRATCH = 0x00100000, STGM_NOSNAPSHOT = 0x00200000, STGM_SIMPLE = 0x08000000, STGM_DIRECT_SWMR = 0x00400000, STGM_DELETEONRELEASE = 0x04000000, }
public enum STGC : uint { STGC_DEFAULT = 0, STGC_OVERWRITE = 1, STGC_ONLYIFCURRENT = 2, STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4, STGC_CONSOLIDATE = 8 }
public enum STATFLAG : uint { STATFLAG_DEFAULT = 0, STATFLAG_NONAME = 1 }
[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] out 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 )] public interface IStorage { void CreateStream( /* [string][in] */ string pwcsName, /* [in] */ STGM grfMode, /* [in] */ uint reserved1, /* [in] */ uint reserved2, /* [out] */ out IStream ppstm);
void OpenStream( /* [string][in] */ string pwcsName, /* [unique][in] */ IntPtr reserved1, /* [in] */ STGM grfMode, /* [in] */ uint reserved2, /* [out] */ out IStream ppstm);
void CreateStorage( /* [string][in] */ string pwcsName, /* [in] */ STGM grfMode, /* [in] */ uint reserved1, /* [in] */ uint reserved2, /* [out] */ out IStorage ppstg);
void OpenStorage( /* [string][unique][in] */ string pwcsName, /* [unique][in] */ IStorage pstgPriority, /* [in] */ STGM grfMode, /* [unique][in] */ IntPtr snbExclude, /* [in] */ uint reserved, /* [out] */ out IStorage ppstg);
void CopyTo( /* [in] */ uint ciidExclude, ///* [size_is][unique][in] */ Guid rgiidExclude, //Guid[] rgiidExclude, IntPtr rgiidExclude, ///* [unique][in] */ IntPtr snbExclude, //string[] snbExclude, //IntPtr[] snbExclude, IntPtr snbExclude, /* [unique][in] */ IStorage pstgDest);
void MoveElementTo( /* [string][in] */ string pwcsName, /* [unique][in] */ IStorage pstgDest, /* [string][in] */ string pwcsNewName, /* [in] */ uint grfFlags);
void Commit( /* [in] */ STGC grfCommitFlags);
void Revert();
void EnumElements( /* [in] */ uint reserved1, /* [size_is][unique][in] */ IntPtr reserved2, /* [in] */ uint reserved3, /* [out] */ out IEnumSTATSTG ppenum);
void DestroyElement( /* [string][in] */ string pwcsName);
void RenameElement( /* [string][in] */ string pwcsOldName, /* [string][in] */ string pwcsNewName);
void SetElementTimes( /* [string][unique][in] */ string pwcsName, /* [unique][in] */ ComTypes.FILETIME pctime, /* [unique][in] */ ComTypes.FILETIME patime, /* [unique][in] */ ComTypes.FILETIME pmtime);
void SetClass( /* [in] */ Guid clsid);
void SetStateBits( /* [in] */ uint grfStateBits, /* [in] */ uint grfMask);
void Stat( /* [out] */ out ComTypes.STATSTG pstatstg, /* [in] */ STATFLAG grfStatFlag); } 调用IStorage来删除VBA代码的函数(节点RSeStorage/RSeEmbeddings/apc) : public void ProcessFiles() { foreach (FileSystemInfo file in fileList) { // Open the file as a storage. IStorage stg; IStorage stg_new;
int result = StgOpenStorage(file.FullName, null, STGM.STGM_DIRECT | STGM.STGM_READWRITE | STGM.STGM_SHARE_EXCLUSIVE, IntPtr.Zero, 0, out stg);
// Find the storage with the path "RSeStorage/RSeEmbeddings/apc" stg.OpenStorage("RSeStorage", null, STGM.STGM_DIRECT | STGM.STGM_READWRITE | STGM.STGM_SHARE_EXCLUSIVE, IntPtr.Zero, 0, out stg_new);
if (stg_new == null) { System.Windows.Forms.MessageBox.Show("can't find RSeStorage node"); return; } stg_new.OpenStorage("RSeEmbeddings", null, STGM.STGM_DIRECT | STGM.STGM_READWRITE | STGM.STGM_SHARE_EXCLUSIVE, IntPtr.Zero, 0, out stg); if (stg == null) { System.Windows.Forms.MessageBox.Show("can't find RSeEmbeddings node"); return; } ComTypes.STATSTG s1 = new ComTypes.STATSTG(); IEnumSTATSTG SSenum; stg.EnumElements(0, IntPtr.Zero, 0, out SSenum);
uint NumReturned = 0; do { SSenum.Next(1, out s1, out NumReturned); if (NumReturned > 0) { if (s1.pwcsName == "apc") { // Delete the storage stg.DestroyElement("apc"); stg.Commit(STGC.STGC_DEFAULT); break; } } } while (NumReturned > 0); } System.Windows.Forms.MessageBox.Show("VBA project has been deleted!"); } 调用上面的函数的代码: ArrayList fileList; // Open the storage and read from storage if (fileList.Count > 0) { SSProcessor ssProc = new SSProcessor(fileList); ssProc.ProcessFiles(); } 实现选择文件功能: try { FolderBrowserDialog folderDlg = new FolderBrowserDialog(); folderDlg.Description = "选择文件夹";
DialogResult res = folderDlg.ShowDialog(this); if (res == DialogResult.OK) { fileList.Clear(); this.listBox1.Items.Clear(); //Get the Directory Info using Directory Name DirectoryInfo dirInfor = new DirectoryInfo(folderDlg.SelectedPath); FileInfo[] partFiles = dirInfor.GetFiles("*.ipt"); foreach (FileInfo fInfo in partFiles) { this.listBox1.Items.Add(fInfo.FullName); fileList.Add(fInfo); } FileInfo[] assFiles = dirInfor.GetFiles("*.iam"); foreach (FileInfo fInfo in assFiles) { this.listBox1.Items.Add(fInfo.FullName); fileList.Add(fInfo); } FileInfo[] drFiles = dirInfor.GetFiles("*.idw"); foreach (FileInfo fInfo in drFiles) { this.listBox1.Items.Add(fInfo.FullName); fileList.Add(fInfo); } } } catch (Exception ex) { MessageBox.Show(ex.Message); } 简单的执行界面图:
你也可以到我的资源中心(http://barbarahan.download.csdn.net/)去下载完整的源码deleteVBA_C#_source和执行程序deleteVBA_C#_exe。(我刚才上传了exe资源,但是CSDN没有显示,也许等你看的时候就出来了。)
文章来源:http://blog.csdn.net/barbarahan
|