NX二次开发-遍历UG Part复合文档

适用版本:NX 11及以前版本 (从NX12.0开始不适用)

一、概述

UG Part (*.prt)是一个复合文档,Windows系统里有很多常用的文件都是复合文档,比如Office的xls、doc等等。简单地说,复合文档就是在一个文件里可以内嵌入其他各种文档,不仅可以包含文本,还可以包括图形、电子表格数据、声音、视频图像以及其它信息。在UG Part (*.prt)文件里除了包括模型数据之外,还包括用于预览显示的图像和部件的属性等。

二、复合文档原理

复合文档的原理就像一个文件系统(文件系统:如 FAT 与 NTFS )。复合文档将数据分成许多流( Streams ),这些流又存储在不同的仓库( Storages )里。将复合文档想象成你的 D 盘, D 盘用的是 NTFS ( NT File System )格式,流就相当于 D 盘里的文件,仓库就相当于 D 盘里的文件夹。流和仓库的命名规则与文件系统相似,同一个仓库下的流及仓库不能重名,不同仓库下可以有同名的流。每个复合文档都有一个根仓库( root storage )。

三、功能说明

       在C#中,System.IO.Packaging命名空间包含了用于封装OLE结构化存储访问的公开(pubic)的StorageInfo类和StreamInfo类,不幸的是,创建或打开文件所需的StorageRoot类是一个内部(internal)类,但是我们可以使用反射来访问StorageRoot类上的方法。下面的代码可以获取到UG Part(*.prt)文件的属性:

//需要引用 WindowsBase.dll

using System.IO.Packaging;
using System.Runtime.InteropServices;

namespace Bizca
{
    public class PartAttributeCollection:System.Collections.Generic.IEnumerable
    {
        private readonly System.Collections.Generic.List _thePartAttributes;
        public PartAttributeCollection(string partFile)
        {
            _thePartAttributes = new System.Collections.Generic.List();

            if (!System.IO.File.Exists(partFile)) return;
            if (StgIsStorageFile(partFile) != 0) return;
            var storageRoot = GetStorageRoot(partFile);
            var stream = storageRoot?.GetSubStorageInfo("part")?.GetStreamInfo("attrs")?.GetStream();
            if (stream != null)
            {
                System.Xml.XmlDocument document = new System.Xml.XmlDocument();
                document.Load(stream);
                var nodeList = document.SelectNodes("/UgAttributes/Attribute");
                if (nodeList != null)
                    for (int i = 0; i < nodeList.Count; i++)
                        _thePartAttributes.Add(new PartAttribute(nodeList[i]));
            }
            CloseStorageRoot(storageRoot);
        }

        public PartAttribute this[string title]
        {
            get
            {
                foreach (var partAttribute in _thePartAttributes)
                {
                    if (string.Compare(partAttribute.Title, title, System.StringComparison.OrdinalIgnoreCase) == 0)
                        return partAttribute;
                }
                return null;
            }
        }

        public System.Collections.Generic.IEnumerator GetEnumerator()
        {
            foreach (var partAttribute in _thePartAttributes)
            {
                yield return partAttribute;
            }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        /// 
        /// 关闭复合文档
        /// 
        /// The storage root.
        private static void CloseStorageRoot(StorageInfo storageRoot)
        {
            InvokeStorageRootMethod(storageRoot, "Close");
        }

        /// 
        /// 判断是否为复合文档
        /// 
        /// Name of the file.
        /// System.Int32.
        [DllImport("ole32.dll", CharSet = CharSet.Unicode)]
        private static extern int StgIsStorageFile(string fileName);

        /// 
        /// 取复合文档的根
        /// 
        /// 文件全路径
        /// StorageInfo.
        /// 
        private static StorageInfo GetStorageRoot(string fileName)
        {
            System.IO.Packaging.StorageInfo storageRoot = (StorageInfo)InvokeStorageRootMethod(null, "Open", fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
            if (storageRoot == null)
            {
                throw new System.InvalidOperationException($"Unable to open \"{fileName}\" as a structured storage file.");
                //Utilities.ThrowInvalidStateFmt("Unable to open \"{0}\" as a structured storage file.", fileName);
            }
            return storageRoot;
        }
        private static object InvokeStorageRootMethod(StorageInfo storageRoot, string methodName, params object[] methodArgs)
        {
            System.Type storageRootType = typeof(System.IO.Packaging.StorageInfo).Assembly.GetType("System.IO.Packaging.StorageRoot", true, false);
            object result = storageRootType.InvokeMember(methodName, System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.InvokeMethod, null, storageRoot, methodArgs);
            return result;
        }
    }

    public class PartAttribute
    {
        public PartAttribute(System.Xml.XmlNode node)
        {
            this.Owner = node.Attributes?["owner"]?.Value;
            this.Title = node.Attributes?["title"]?.Value;
            this.Value = node.Attributes?["value"]?.Value;
            this.Version = node.Attributes?["version"]?.Value;
            this.PdmBased = node.Attributes?["pdmBased"]?.Value;
            this.Type = node.Attributes?["xsi:type"]?.Value;
            this.Utf8Title = node.Attributes?["utf8title"]?.Value;
            this.Utf8Value = node.Attributes?["utf8value"]?.Value;
        }

        public string Owner { get; }

        public string Title { get; }

        public string Value { get; }

        public string Version { get; }

        public string PdmBased { get; }

        /// 
        /// BoolAttributeType IntegerAttributeType RealAttributeType TimeAttributeType StringAttributeType
        /// 
        public string Type { get; }

        public string Utf8Title { get; }

        public string Utf8Value { get; }

    }

}

三、总结

      这种方式可以在不打开NX快速获取和编辑UG Part(*.prt)文件的各种信息。

你可能感兴趣的:(NX,二次开发,开发语言,c#,.net)