diff --git a/PInvoke/Opc/MsOpc.cs b/PInvoke/Opc/MsOpc.cs
index 250f5f53..144cdc72 100644
--- a/PInvoke/Opc/MsOpc.cs
+++ b/PInvoke/Opc/MsOpc.cs
@@ -1,6 +1,10 @@
using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
+using Vanara.Extensions.Reflection;
using Vanara.InteropServices;
using static Vanara.PInvoke.Crypt32;
using static Vanara.PInvoke.UrlMon;
@@ -59,10 +63,10 @@ namespace Vanara.PInvoke
public enum OPC_COMPRESSION_OPTIONS
{
/// Compression is turned off.
- OPC_COMPRESSION_NONE,
+ OPC_COMPRESSION_NONE = -1,
/// Compression is optimized for a balance between size and performance.
- OPC_COMPRESSION_NORMAL,
+ OPC_COMPRESSION_NORMAL = 0,
/// Compression is optimized for size.
OPC_COMPRESSION_MAXIMUM,
@@ -261,7 +265,7 @@ namespace Vanara.PInvoke
/// The signature is not valid.Signature markup or signed package components might have been altered. Alternatively, the
/// signature might not exist in the current package.
///
- OPC_SIGNATURE_INVALID,
+ OPC_SIGNATURE_INVALID = -1,
}
/// Describes the read/write status of a stream.
@@ -272,7 +276,7 @@ namespace Vanara.PInvoke
public enum OPC_STREAM_IO_MODE
{
/// Creates a read-only stream for loading an existing package.
- OPC_STREAM_IO_READ,
+ OPC_STREAM_IO_READ = 1,
/// Creates a write-only stream for saving a new package.
OPC_STREAM_IO_WRITE,
@@ -1670,7 +1674,7 @@ namespace Vanara.PInvoke
// LPCWSTR filename, OPC_STREAM_IO_MODE ioMode, LPSECURITY_ATTRIBUTES securityAttributes, DWORD dwFlagsAndAttributes, IStream
// **stream );
[PreserveSig]
- HRESULT CreateStreamOnFile([MarshalAs(UnmanagedType.LPWStr)] string filename, OPC_STREAM_IO_MODE ioMode, SECURITY_ATTRIBUTES securityAttributes, FileFlagsAndAttributes dwFlagsAndAttributes, out IStream stream);
+ HRESULT CreateStreamOnFile([MarshalAs(UnmanagedType.LPWStr)] string filename, OPC_STREAM_IO_MODE ioMode, [Optional] SECURITY_ATTRIBUTES securityAttributes, FileFlagsAndAttributes dwFlagsAndAttributes, out IStream stream);
/// Creates a package object that represents an empty package.
/// A pointer to the IOpcPackage interface of the package object that represents an empty package.
@@ -6798,5 +6802,67 @@ namespace Vanara.PInvoke
[PInvokeData("msopc.h", MSDNShortId = "0a265a0a-c109-4afc-a0ad-d3ee31757aa1")]
[ComImport, ClassInterface(ClassInterfaceType.None), Guid("6B2D6BA0-9F3E-4f27-920B-313CC426A39E")]
public class OpcFactory { }
+
+ /// Creates an instance from one of the IOpcXXXEnumerator interface instances.
+ ///
+ /// The type of the enumerator interface. This interface must support the MoveNext, GetCurrent and Clone methods.
+ ///
+ /// The type of the elemement interface returned as the parameter in TElem.GetCurrent.
+ ///
+ public class OpcEnumerator : IEnumerator
+ {
+ private MethodInfo getCurrent;
+ private MethodInfo moveNext;
+ private TEnum opcEnum;
+
+ /// Initializes a new instance of the class.
+ /// The opc enumerator.
+ /// opcEnumerator
+ /// The type specified for TEnum is not a valid Opc Enumerator instance.
+ public OpcEnumerator(TEnum opcEnumerator)
+ {
+ opcEnum = opcEnumerator ?? throw new ArgumentNullException(nameof(opcEnumerator));
+ moveNext = typeof(TEnum).GetMethod("MoveNext");
+ getCurrent = typeof(TEnum).GetMethod("GetCurrent");
+ if (moveNext is null || getCurrent is null) throw new ArgumentException("The type specified for TEnum is not a valid Opc Enumerator instance.");
+ }
+
+ /// Gets the element in the collection at the current position of the enumerator.
+ public TElem Current
+ {
+ get
+ {
+ var p = new object[] { default(TElem) };
+ ((HRESULT)getCurrent.Invoke(opcEnum, p)).ThrowIfFailed();
+ return (TElem)p[0];
+ }
+ }
+
+ /// Gets the element in the collection at the current position of the enumerator.
+ object IEnumerator.Current => Current;
+
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ public void Dispose() => Marshal.ReleaseComObject(opcEnum);
+
+ /// Advances the enumerator to the next element of the collection.
+ ///
+ /// if the enumerator was successfully advanced to the next element; if the
+ /// enumerator has passed the end of the collection.
+ ///
+ public bool MoveNext()
+ {
+ var p = new object[] { false };
+ ((HRESULT)moveNext.Invoke(opcEnum, p)).ThrowIfFailed();
+ return (bool)p[0];
+ }
+
+ /// Sets the enumerator to its initial position, which is before the first element in the collection.
+ public void Reset()
+ {
+ var clone = opcEnum.InvokeMethod("Clone");
+ Marshal.ReleaseComObject(opcEnum);
+ opcEnum = clone;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/UnitTests/PInvoke/Opc/OpcTests.cs b/UnitTests/PInvoke/Opc/OpcTests.cs
index 0489f7d5..ccf14186 100644
--- a/UnitTests/PInvoke/Opc/OpcTests.cs
+++ b/UnitTests/PInvoke/Opc/OpcTests.cs
@@ -1,10 +1,11 @@
using NUnit.Framework;
using System;
-using System.Linq;
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading;
using Vanara.Extensions;
+using Vanara.Extensions.Reflection;
using Vanara.InteropServices;
using static Vanara.PInvoke.Opc;
@@ -13,5 +14,55 @@ namespace Vanara.PInvoke.Tests
[TestFixture]
public class OpcTests
{
+ public IOpcFactory factory;
+
+ [OneTimeSetUp]
+ public void _Setup() => factory = new IOpcFactory();
+
+ [OneTimeTearDown]
+ public void _TearDown() => Marshal.ReleaseComObject(factory);
+
+ [Test]
+ public void LoadTest()
+ {
+ Assert.That(factory.CreateStreamOnFile(TestCaseSources.WordDoc, OPC_STREAM_IO_MODE.OPC_STREAM_IO_READ, null, 0, out var sourceFileStream), ResultIs.Successful);
+ using var psourceFileString = ComReleaserFactory.Create(sourceFileStream);
+
+ Assert.That(factory.ReadPackageFromStream(sourceFileStream, OPC_READ_FLAGS.OPC_CACHE_ON_ACCESS, out var outPackage), ResultIs.Successful);
+ using var poutPackage = ComReleaserFactory.Create(outPackage);
+
+ IOpcPartSet pset = null;
+ Assert.That(() => pset = outPackage.GetPartSet(), Throws.Nothing);
+ using var ppset = ComReleaserFactory.Create(pset);
+
+ IOpcPartEnumerator penum = null;
+ Assert.That(() => penum = pset.GetEnumerator(), Throws.Nothing);
+ using var ppenum = new OpcEnumerator(penum);
+
+ while (ppenum.MoveNext())
+ TestContext.WriteLine($"{ppenum.Current.GetContentType()}, {ppenum.Current.GetCompressionOptions()}");
+ TestContext.WriteLine();
+
+ IOpcRelationshipSet rset = null;
+ Assert.That(() => rset = outPackage.GetRelationshipSet(), Throws.Nothing);
+ using var prset = ComReleaserFactory.Create(rset);
+
+ IOpcRelationshipEnumerator renum = null;
+ Assert.That(() => renum = rset.GetEnumerator(), Throws.Nothing);
+ using var prenum = new OpcEnumerator(renum);
+
+ while (prenum.MoveNext())
+ TestContext.WriteLine($"{prenum.Current.GetId()}, {prenum.Current.GetRelationshipType()}, {prenum.Current.GetTargetMode()}");
+ TestContext.WriteLine();
+ }
+
+ [Test]
+ public void RootTest()
+ {
+ IOpcUri rootUri = null;
+ Assert.That(() => rootUri = factory.CreatePackageRootUri(), Throws.Nothing);
+ Assert.That(rootUri, Is.Not.Null);
+ Marshal.ReleaseComObject(rootUri);
+ }
}
}
\ No newline at end of file