fix PROPVARIANT at 64-bit, Clearing string Vectors + UT (#413)

* fix PROPVARIANT @64-bit

* fix PROPVARIANT.Clear() - string arrays

* enh. IPropSetStorageTest - R/W multiple properties

* whitespace

---------

Co-authored-by: Pavel Luft <pavel.luft@cadteam.cz>
pull/416/head
cuft 2023-07-06 03:48:03 +02:00 committed by GitHub
parent a2fee2ce86
commit f66686c287
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 20 deletions

View File

@ -108,7 +108,7 @@ namespace Vanara.PInvoke
/// The middle three members are reserved for future use.
/// </para>
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = 16, Pack = 8)]
[StructLayout(LayoutKind.Explicit)]
public sealed class PROPVARIANT : ICloneable, IComparable, IComparable<PROPVARIANT>, IDisposable, IEquatable<PROPVARIANT>
{
/// <summary>Value type tag.</summary>
@ -548,12 +548,12 @@ namespace Vanara.PInvoke
{
case VARTYPE.VT_VECTOR | VARTYPE.VT_BSTR:
foreach (var ptr in _blob.pBlobData.ToIEnum<IntPtr>((int)_blob.cbSize))
Marshal.FreeBSTR(Marshal.ReadIntPtr(ptr));
Marshal.FreeBSTR(ptr);
Marshal.FreeCoTaskMem(_blob.pBlobData);
break;
case VARTYPE.VT_VECTOR | VARTYPE.VT_LPSTR:
//foreach (var ptr in _blob.pBlobData.ToIEnum<IntPtr>((int)_blob.cbSize))
// Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(ptr));
foreach (var ptr in _blob.pBlobData.ToIEnum<IntPtr>((int)_blob.cbSize))
Marshal.FreeCoTaskMem(ptr);
Marshal.FreeCoTaskMem(_blob.pBlobData);
break;
case VARTYPE.VT_VECTOR | VARTYPE.VT_I1:
@ -588,7 +588,7 @@ namespace Vanara.PInvoke
break;
}
vt = 0;
_ulong = 0;
_blob = new();
}
/// <summary>Copies the contents of one PROPVARIANT structure to another.</summary>
@ -1158,7 +1158,7 @@ namespace Vanara.PInvoke
/// </para>
/// <note>This structure is mostly used for arrays where the fixed structure size is critical for interop.</note>
/// </summary>
[StructLayout(LayoutKind.Sequential, Size = 16, Pack = 8)]
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct PROPVARIANT_IMMUTABLE
{
/// <summary>Value type tag.</summary>
@ -1173,18 +1173,18 @@ namespace Vanara.PInvoke
/// <summary>Reserved for future use.</summary>
private ushort wReserved3;
/// <summary>The value when a numeric value less than 8 bytes.</summary>
private ulong _ulong;
/// <summary>The BLOB when VT_BLOB</summary>
private BLOB _blob;
/// <summary>Performs an implicit conversion from <see cref="PROPVARIANT"/> to <see cref="PROPVARIANT_IMMUTABLE"/>.</summary>
/// <param name="pv">The PROPVARIANT instance.</param>
/// <returns>The resulting <see cref="PROPVARIANT_IMMUTABLE"/> instance from the conversion.</returns>
public static implicit operator PROPVARIANT_IMMUTABLE(PROPVARIANT pv) => new() { vt = pv.vt, wReserved1 = pv.wReserved1, wReserved2 = pv.wReserved2, wReserved3 = pv.wReserved3, _ulong = pv._ulong };
public static implicit operator PROPVARIANT_IMMUTABLE(PROPVARIANT pv) => new() { vt = pv.vt, wReserved1 = pv.wReserved1, wReserved2 = pv.wReserved2, wReserved3 = pv.wReserved3, _blob = pv._blob };
/// <summary>Performs an implicit conversion from <see cref="PROPVARIANT_IMMUTABLE"/> to <see cref="PROPVARIANT"/>.</summary>
/// <param name="pv">The PROPVARIANT_IMMUTABLE instance.</param>
/// <returns>The resulting <see cref="PROPVARIANT"/> instance from the conversion.</returns>
public static explicit operator PROPVARIANT(in PROPVARIANT_IMMUTABLE pv) => new() { vt = pv.vt, wReserved1 = pv.wReserved1, wReserved2 = pv.wReserved2, wReserved3 = pv.wReserved3, _ulong = pv._ulong };
public static explicit operator PROPVARIANT(in PROPVARIANT_IMMUTABLE pv) => new() { vt = pv.vt, wReserved1 = pv.wReserved1, wReserved2 = pv.wReserved2, wReserved3 = pv.wReserved3, _blob = pv._blob };
}
}
}

View File

@ -1,5 +1,6 @@
using NUnit.Framework;
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using Vanara.InteropServices;
@ -67,32 +68,45 @@ namespace Vanara.PInvoke.Tests
[Test]
public void IPropSetStorageTest()
{
var propKey = PROPERTYKEY.System.Title;
var propSetKey = PROPERTYKEY.System.Title.Key;
// creates a new storage object using NTFS implementation
StgOpenStorageEx(TestCaseSources.LogFile, STGM.STGM_DIRECT | STGM.STGM_READWRITE | STGM.STGM_SHARE_EXCLUSIVE,
STGFMT.STGFMT_ANY, default, default, default, typeof(IPropertySetStorage).GUID, out var iptr).ThrowIfFailed();
using var istg = ComReleaserFactory.Create((IPropertySetStorage)iptr);
var prc = new PROPSPEC(propKey.Id);
var prcs = new[] { PROPERTYKEY.System.Title.Id, PROPERTYKEY.System.Author.Id, PROPERTYKEY.System.Comment.Id }.Select(propid => new PROPSPEC(propid)).ToArray();
var vals = prcs.Select((prc, idx) => "VALUE" + idx).ToArray();
// creates propertystorage
istg.Item.Create(propKey.Key, default, PROPSETFLAG.PROPSETFLAG_DEFAULT, STGM.STGM_CREATE | STGM.STGM_READWRITE | STGM.STGM_SHARE_EXCLUSIVE, out var ipse).ThrowIfFailed();
istg.Item.Create(propSetKey, default, PROPSETFLAG.PROPSETFLAG_DEFAULT, STGM.STGM_CREATE | STGM.STGM_READWRITE | STGM.STGM_SHARE_EXCLUSIVE, out var ipse).ThrowIfFailed();
using (var pipse = ComReleaserFactory.Create(ipse))
{
// write property
using var prv = new PROPVARIANT("VALUE", VarEnum.VT_LPWSTR);
ipse.WriteMultiple(new[] { prc }, new[] { prv }, PID_FIRST_USABLE).ThrowIfFailed();
// write properties
var prvs = vals.Select(val => new PROPVARIANT(val, VarEnum.VT_LPWSTR)).ToArray();
try
{
ipse.WriteMultiple(prcs, prvs, PID_FIRST_USABLE).ThrowIfFailed();
}
finally
{
foreach (var prv in prvs)
prv.Dispose();
}
}
//hr = ipse.Commit((uint)STGC.STGC_DEFAULT);
// read property
istg.Item.Open(propKey.Key, STGM.STGM_READ | STGM.STGM_SHARE_EXCLUSIVE, out ipse).ThrowIfFailed();
istg.Item.Open(propSetKey, STGM.STGM_READ | STGM.STGM_SHARE_EXCLUSIVE, out ipse).ThrowIfFailed();
using (var pipse = ComReleaserFactory.Create(ipse))
{
ipse.ReadMultiple(new[] { prc }, out var prvRead).ThrowIfFailed();
Assert.That(prvRead.Length, Is.EqualTo(1));
Assert.That(prvRead[0].Value, Is.EqualTo("VALUE"));
var prvs = new PROPVARIANT[0];
ipse.ReadMultiple(prcs, out var prvRead).ThrowIfFailed();
CollectionAssert.AreEqual(prvRead.Select(prv => prv.Value), vals);
foreach (var prv in prvs)
prv.Dispose();
}
}