From 60f75abcd1fe49052c118a2597ac59a82c372b64 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Tue, 16 Mar 2021 10:49:09 -0700 Subject: Migrate PInvoke out of Core to Core.Native --- .../PatchAPI/PatchInterop.cs | 989 --------------------- 1 file changed, 989 deletions(-) delete mode 100644 src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs (limited to 'src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs') diff --git a/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs b/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs deleted file mode 100644 index 3874d8e7..00000000 --- a/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs +++ /dev/null @@ -1,989 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.PatchAPI -{ - using System; - using System.Collections.Generic; - using System.Diagnostics.CodeAnalysis; - using System.Globalization; - using System.Runtime.InteropServices; - using WixToolset.Data.Symbols; - - /// - /// Interop class for the mspatchc.dll. - /// - internal static class PatchInterop - { - // From WinError.h in the Platform SDK - internal const ushort FACILITY_WIN32 = 7; - - /// - /// Parse a number from text in either hex or decimal. - /// - /// Source value. Treated as hex if it starts 0x (or 0X), decimal otherwise. - /// Numeric value that source represents. - static internal UInt32 ParseHexOrDecimal(string source) - { - string value = source.Trim(); - if (String.Equals(value.Substring(0, 2), "0x", StringComparison.OrdinalIgnoreCase)) - { - return UInt32.Parse(value.Substring(2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture.NumberFormat); - } - else - { - return UInt32.Parse(value, CultureInfo.InvariantCulture.NumberFormat); - } - } - - /// - /// Create a binary delta file. - /// - /// Name of the delta file to create. - /// Name of updated file. - /// Optional paths to updated file's symbols. - /// Optional offsets to the delta retain sections in the updated file. - /// Optional array of target files. - /// Optional array of target files' symbol paths (must match basisFiles array). - /// Optional array of target files' delta ignore section lengths (must match basisFiles array)(each entry must match basisIgnoreOffsets entries). - /// Optional array of target files' delta ignore section offsets (must match basisFiles array)(each entry must match basisIgnoreLengths entries). - /// Optional array of target files' delta protect section lengths (must match basisFiles array)(each entry must match basisRetainOffsets and targetRetainOffsets entries). - /// Optional array of target files' delta protect section offsets (must match basisFiles array)(each entry must match basisRetainLengths and targetRetainOffsets entries). - /// ApiPatchingSymbolFlags value. - /// OptimizePatchSizeForLargeFiles value. - /// Flag to indicate retain ranges were ignored due to mismatch. - /// true if delta file was created, false if whole file should be used instead. - static public bool CreateDelta( - string deltaFile, - string targetFile, - string targetSymbolPath, - string targetRetainOffsets, - string[] basisFiles, - string[] basisSymbolPaths, - string[] basisIgnoreLengths, - string[] basisIgnoreOffsets, - string[] basisRetainLengths, - string[] basisRetainOffsets, - PatchSymbolFlags apiPatchingSymbolFlags, - bool optimizePatchSizeForLargeFiles, - out bool retainRangesIgnored - ) - { - retainRangesIgnored = false; - if (0 != (apiPatchingSymbolFlags & ~(PatchSymbolFlags.PatchSymbolNoImagehlp | PatchSymbolFlags.PatchSymbolNoFailures | PatchSymbolFlags.PatchSymbolUndecoratedToo))) - { - throw new ArgumentOutOfRangeException("apiPatchingSymbolFlags"); - } - - if (null == deltaFile || 0 == deltaFile.Length) - { - throw new ArgumentNullException("deltaFile"); - } - - if (null == targetFile || 0 == targetFile.Length) - { - throw new ArgumentNullException("targetFile"); - } - - if (null == basisFiles || 0 == basisFiles.Length) - { - return false; - } - uint countOldFiles = (uint)basisFiles.Length; - - if (null != basisSymbolPaths) - { - if (0 != basisSymbolPaths.Length) - { - if ((uint)basisSymbolPaths.Length != countOldFiles) - { - throw new ArgumentOutOfRangeException("basisSymbolPaths"); - } - } - } - // a null basisSymbolPaths is allowed. - - if (null != basisIgnoreLengths) - { - if (0 != basisIgnoreLengths.Length) - { - if ((uint)basisIgnoreLengths.Length != countOldFiles) - { - throw new ArgumentOutOfRangeException("basisIgnoreLengths"); - } - } - } - else - { - basisIgnoreLengths = new string[countOldFiles]; - } - - if (null != basisIgnoreOffsets) - { - if (0 != basisIgnoreOffsets.Length) - { - if ((uint)basisIgnoreOffsets.Length != countOldFiles) - { - throw new ArgumentOutOfRangeException("basisIgnoreOffsets"); - } - } - } - else - { - basisIgnoreOffsets = new string[countOldFiles]; - } - - if (null != basisRetainLengths) - { - if (0 != basisRetainLengths.Length) - { - if ((uint)basisRetainLengths.Length != countOldFiles) - { - throw new ArgumentOutOfRangeException("basisRetainLengths"); - } - } - } - else - { - basisRetainLengths = new string[countOldFiles]; - } - - if (null != basisRetainOffsets) - { - if (0 != basisRetainOffsets.Length) - { - if ((uint)basisRetainOffsets.Length != countOldFiles) - { - throw new ArgumentOutOfRangeException("basisRetainOffsets"); - } - } - } - else - { - basisRetainOffsets = new string[countOldFiles]; - } - - PatchOptionData pod = new PatchOptionData(); - pod.symbolOptionFlags = apiPatchingSymbolFlags; - pod.newFileSymbolPath = targetSymbolPath; - pod.oldFileSymbolPathArray = basisSymbolPaths; - pod.extendedOptionFlags = 0; - PatchOldFileInfoW[] oldFileInfoArray = new PatchOldFileInfoW[countOldFiles]; - string[] newRetainOffsetArray = ((null == targetRetainOffsets) ? new string[0] : targetRetainOffsets.Split(',')); - for (uint i = 0; i < countOldFiles; ++i) - { - PatchOldFileInfoW ofi = new PatchOldFileInfoW(); - ofi.oldFileName = basisFiles[i]; - string[] ignoreLengthArray = ((null == basisIgnoreLengths[i]) ? new string[0] : basisIgnoreLengths[i].Split(',')); - string[] ignoreOffsetArray = ((null == basisIgnoreOffsets[i]) ? new string[0] : basisIgnoreOffsets[i].Split(',')); - string[] retainLengthArray = ((null == basisRetainLengths[i]) ? new string[0] : basisRetainLengths[i].Split(',')); - string[] retainOffsetArray = ((null == basisRetainOffsets[i]) ? new string[0] : basisRetainOffsets[i].Split(',')); - // Validate inputs - if (ignoreLengthArray.Length != ignoreOffsetArray.Length) - { - throw new ArgumentOutOfRangeException("basisIgnoreLengths"); - } - - if (retainLengthArray.Length != retainOffsetArray.Length) - { - throw new ArgumentOutOfRangeException("basisRetainLengths"); - } - - if (newRetainOffsetArray.Length != retainOffsetArray.Length) - { - // remove all retain range information - retainRangesIgnored = true; - for (uint j = 0; j < countOldFiles; ++j) - { - basisRetainLengths[j] = null; - basisRetainOffsets[j] = null; - } - retainLengthArray = new string[0]; - retainOffsetArray = new string[0]; - newRetainOffsetArray = new string[0]; - for (uint j = 0; j < oldFileInfoArray.Length; ++j) - { - oldFileInfoArray[j].retainRange = null; - } - } - - // Populate IgnoreRange structure - PatchIgnoreRange[] ignoreArray = null; - if (0 != ignoreLengthArray.Length) - { - ignoreArray = new PatchIgnoreRange[ignoreLengthArray.Length]; - for (int j = 0; j < ignoreLengthArray.Length; ++j) - { - PatchIgnoreRange ignoreRange = new PatchIgnoreRange(); - ignoreRange.offsetInOldFile = ParseHexOrDecimal(ignoreOffsetArray[j]); - ignoreRange.lengthInBytes = ParseHexOrDecimal(ignoreLengthArray[j]); - ignoreArray[j] = ignoreRange; - } - ofi.ignoreRange = ignoreArray; - } - - PatchRetainRange[] retainArray = null; - if (0 != newRetainOffsetArray.Length) - { - retainArray = new PatchRetainRange[retainLengthArray.Length]; - for (int j = 0; j < newRetainOffsetArray.Length; ++j) - { - PatchRetainRange retainRange = new PatchRetainRange(); - retainRange.offsetInOldFile = ParseHexOrDecimal(retainOffsetArray[j]); - retainRange.lengthInBytes = ParseHexOrDecimal(retainLengthArray[j]); - retainRange.offsetInNewFile = ParseHexOrDecimal(newRetainOffsetArray[j]); - retainArray[j] = retainRange; - } - ofi.retainRange = retainArray; - } - oldFileInfoArray[i] = ofi; - } - - if (CreatePatchFileExW( - countOldFiles, - oldFileInfoArray, - targetFile, - deltaFile, - PatchOptionFlags(optimizePatchSizeForLargeFiles), - pod, - null, - IntPtr.Zero)) - { - return true; - } - - // determine if this is an error or a need to use whole file. - int err = Marshal.GetLastWin32Error(); - switch (err) - { - case unchecked((int)ERROR_PATCH_BIGGER_THAN_COMPRESSED): - break; - - // too late to exclude this file -- should have been caught before - case unchecked((int)ERROR_PATCH_SAME_FILE): - default: - throw new System.ComponentModel.Win32Exception(err); - } - return false; - } - - /// - /// Extract the delta header. - /// - /// Name of delta file. - /// Name of file to create with the delta's header. - static public void ExtractDeltaHeader(string delta, string deltaHeader) - { - if (!ExtractPatchHeaderToFileW(delta, deltaHeader)) - { - throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); - } - } - - /// - /// Returns the PatchOptionFlags to use. - /// - /// True if optimizing for large files. - /// PATCH_OPTION_FLAG values - static private UInt32 PatchOptionFlags(bool optimizeForLargeFiles) - { - UInt32 flags = PATCH_OPTION_FAIL_IF_SAME_FILE | PATCH_OPTION_FAIL_IF_BIGGER | PATCH_OPTION_USE_LZX_BEST; - if (optimizeForLargeFiles) - { - flags |= PATCH_OPTION_USE_LZX_LARGE; - } - return flags; - } - - //--------------------------------------------------------------------- - // From PatchApi.h - //--------------------------------------------------------------------- - - // - // The following contants can be combined and used as the OptionFlags - // parameter in the patch creation apis. - - internal const uint PATCH_OPTION_USE_BEST = 0x00000000; // auto choose best (slower) - - internal const uint PATCH_OPTION_USE_LZX_BEST = 0x00000003; // auto choose best of LXZ A/B (but not large) - internal const uint PATCH_OPTION_USE_LZX_A = 0x00000001; // normal - internal const uint PATCH_OPTION_USE_LXZ_B = 0x00000002; // better on some x86 binaries - internal const uint PATCH_OPTION_USE_LZX_LARGE = 0x00000004; // better support for large files (requires 5.1 or higher applyer) - - internal const uint PATCH_OPTION_NO_BINDFIX = 0x00010000; // PE bound imports - internal const uint PATCH_OPTION_NO_LOCKFIX = 0x00020000; // PE smashed locks - internal const uint PATCH_OPTION_NO_REBASE = 0x00040000; // PE rebased image - internal const uint PATCH_OPTION_FAIL_IF_SAME_FILE = 0x00080000; // don't create if same - internal const uint PATCH_OPTION_FAIL_IF_BIGGER = 0x00100000; // fail if patch is larger than simply compressing new file (slower) - internal const uint PATCH_OPTION_NO_CHECKSUM = 0x00200000; // PE checksum zero - internal const uint PATCH_OPTION_NO_RESTIMEFIX = 0x00400000; // PE resource timestamps - internal const uint PATCH_OPTION_NO_TIMESTAMP = 0x00800000; // don't store new file timestamp in patch - internal const uint PATCH_OPTION_SIGNATURE_MD5 = 0x01000000; // use MD5 instead of CRC (reserved for future support) - internal const uint PATCH_OPTION_INTERLEAVE_FILES = 0x40000000; // better support for large files (requires 5.2 or higher applyer) - internal const uint PATCH_OPTION_RESERVED1 = 0x80000000; // (used internally) - - internal const uint PATCH_OPTION_VALID_FLAGS = 0xC0FF0007; - - // - // The following flags are used with PATCH_OPTION_DATA ExtendedOptionFlags: - // - - internal const uint PATCH_TRANSFORM_PE_RESOURCE_2 = 0x00000100; // better handling of PE resources (requires 5.2 or higher applyer) - internal const uint PATCH_TRANSFORM_PE_IRELOC_2 = 0x00000200; // better handling of PE stripped relocs (requires 5.2 or higher applyer) - - // - // In addition to the standard Win32 error codes, the following error codes may - // be returned via GetLastError() when one of the patch APIs fails. - - internal const uint ERROR_PATCH_ENCODE_FAILURE = 0xC00E3101; // create - internal const uint ERROR_PATCH_INVALID_OPTIONS = 0xC00E3102; // create - internal const uint ERROR_PATCH_SAME_FILE = 0xC00E3103; // create - internal const uint ERROR_PATCH_RETAIN_RANGES_DIFFER = 0xC00E3104; // create - internal const uint ERROR_PATCH_BIGGER_THAN_COMPRESSED = 0xC00E3105; // create - internal const uint ERROR_PATCH_IMAGEHLP_FALURE = 0xC00E3106; // create - - /// - /// Delegate type that the PatchAPI calls for progress notification. - /// - /// . - /// . - /// . - /// True for success - public delegate bool PatchProgressCallback( - IntPtr context, - uint currentPosition, - uint maxPosition - ); - - /// - /// Delegate type that the PatchAPI calls for patch symbol load information. - /// - /// . - /// . - /// . - /// . - /// . - /// . - /// . - /// . - /// ??? - public delegate bool PatchSymloadCallback( - uint whichFile, // 0 for new file, 1 for first old file, etc - [MarshalAs(UnmanagedType.LPStr)] string symbolFileName, - uint symType, // see SYM_TYPE in imagehlp.h - uint symbolFileCheckSum, - uint symbolFileTimeDate, - uint imageFileCheckSum, - uint imageFileTimeDate, - IntPtr context - ); - - /// - /// Wraps PATCH_IGNORE_RANGE - /// - [StructLayout(LayoutKind.Sequential)] - internal class PatchIgnoreRange - { - public uint offsetInOldFile; - public uint lengthInBytes; - } - - /// - /// Wraps PATCH_RETAIN_RANGE - /// - [StructLayout(LayoutKind.Sequential)] - internal class PatchRetainRange - { - public uint offsetInOldFile; - public uint lengthInBytes; - public uint offsetInNewFile; - } - - /// - /// Wraps PATCH_OLD_FILE_INFO (except for the OldFile~ portion) - /// - internal class PatchOldFileInfo - { - public PatchIgnoreRange[] ignoreRange; - public PatchRetainRange[] retainRange; - } - - /// - /// Wraps PATCH_OLD_FILE_INFO_W - /// - internal class PatchOldFileInfoW : PatchOldFileInfo - { - public string oldFileName; - } - - /// - /// Wraps each PATCH_INTERLEAVE_MAP Range - /// - [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses"), StructLayout(LayoutKind.Sequential)] - internal class PatchInterleaveMapRange - { - public uint oldOffset; - public uint oldLength; - public uint newLength; - } - - /// - /// Wraps PATCH_INTERLEAVE_MAP - /// - internal class PatchInterleaveMap - { - public PatchInterleaveMapRange[] ranges = null; - } - - - /// - /// Wraps PATCH_OPTION_DATA - /// - [BestFitMapping(false, ThrowOnUnmappableChar = true)] - internal class PatchOptionData - { - public PatchSymbolFlags symbolOptionFlags; // PATCH_SYMBOL_xxx flags - [MarshalAs(UnmanagedType.LPStr)] public string newFileSymbolPath; // always ANSI, never Unicode - [MarshalAs(UnmanagedType.LPStr)] public string[] oldFileSymbolPathArray; // array[ OldFileCount ] - public uint extendedOptionFlags; - public PatchSymloadCallback symLoadCallback = null; - public IntPtr symLoadContext = IntPtr.Zero; - public PatchInterleaveMap[] interleaveMapArray = null; // array[ OldFileCount ] (requires 5.2 or higher applyer) - public uint maxLzxWindowSize = 0; // limit memory requirements (requires 5.2 or higher applyer) - } - - // - // Note that PATCH_OPTION_DATA contains LPCSTR paths, and no LPCWSTR (Unicode) - // path argument is available, even when used with one of the Unicode APIs - // such as CreatePatchFileW. This is because the unlerlying system services - // for symbol file handling (IMAGEHLP.DLL) only support ANSI file/path names. - // - - // - // A note about PATCH_RETAIN_RANGE specifiers with multiple old files: - // - // Each old version file must have the same RetainRangeCount, and the same - // retain range LengthInBytes and OffsetInNewFile values in the same order. - // Only the OffsetInOldFile values can differ between old foles for retain - // ranges. - // - - // - // The following prototypes are (some of the) interfaces for creating patches from files. - // - - /// - /// Creates a new delta. - /// - /// Size of oldFileInfoArray. - /// Target file information. - /// Name of updated file. - /// Name of delta to create. - /// PATCH_OPTION_xxx. - /// Optional PATCH_OPTION_DATA structure. - /// Delegate for progress callbacks. - /// Context for progress callback delegate. - /// true if successfull, sets Marshal.GetLastWin32Error() if not. - [DllImport("mspatchc.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool CreatePatchFileExW( - uint oldFileCount, // maximum 255 - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(PatchAPIMarshaler), MarshalCookie="PATCH_OLD_FILE_INFO_W")] - PatchOldFileInfoW[] oldFileInfoArray, - string newFileName, // input file (required) - string patchFileName, // output file (required) - uint optionFlags, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(PatchAPIMarshaler), MarshalCookie="PATCH_OPTION_DATA")] - PatchOptionData optionData, - [MarshalAs (UnmanagedType.FunctionPtr)] - PatchProgressCallback progressCallback, - IntPtr context - ); - - /// - /// Extracts delta header from delta. - /// - /// Name of delta file. - /// Name of file to create with delta header. - /// true if successfull, sets Marshal.GetLastWin32Error() if not. - [DllImport("mspatchc.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool ExtractPatchHeaderToFileW( - string patchFileName, // input file - string patchHeaderFileName // output file - ); - - // TODO: Add rest of APIs to enable custom binders to perform more exhaustive checks - - /// - /// Marshals arguments for the CreatePatch~ APIs - /// - [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] - internal class PatchAPIMarshaler : ICustomMarshaler - { - internal static ICustomMarshaler GetInstance(string cookie) - { - return new PatchAPIMarshaler(cookie); - } - - private enum MarshalType - { - PATCH_OPTION_DATA, - PATCH_OLD_FILE_INFO_W - }; - private PatchAPIMarshaler.MarshalType marshalType; - - private PatchAPIMarshaler(string cookie) - { - this.marshalType = (PatchAPIMarshaler.MarshalType)Enum.Parse(typeof(PatchAPIMarshaler.MarshalType), cookie); - } - - // - // Summary: - // Returns the size of the native data to be marshaled. - // - // Returns: - // The size in bytes of the native data. - public int GetNativeDataSize() - { - return Marshal.SizeOf(typeof(IntPtr)); - } - - // - // Summary: - // Performs necessary cleanup of the managed data when it is no longer needed. - // - // Parameters: - // ManagedObj: - // The managed object to be destroyed. - public void CleanUpManagedData(object ManagedObj) - { - } - - // - // Summary: - // Performs necessary cleanup of the unmanaged data when it is no longer needed. - // - // Parameters: - // pNativeData: - // A pointer to the unmanaged data to be destroyed. - public void CleanUpNativeData(IntPtr pNativeData) - { - if (IntPtr.Zero == pNativeData) - { - return; - } - - switch (this.marshalType) - { - case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA: - this.CleanUpPOD(pNativeData); - break; - default: - this.CleanUpPOFI_A(pNativeData); - break; - } - } - - // - // Summary: - // Converts the managed data to unmanaged data. - // - // Parameters: - // ManagedObj: - // The managed object to be converted. - // - // Returns: - // Returns the COM view of the managed object. - public IntPtr MarshalManagedToNative(object ManagedObj) - { - if (null == ManagedObj) - { - return IntPtr.Zero; - } - - switch (this.marshalType) - { - case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA: - return this.MarshalPOD(ManagedObj as PatchOptionData); - case PatchAPIMarshaler.MarshalType.PATCH_OLD_FILE_INFO_W: - return this.MarshalPOFIW_A(ManagedObj as PatchOldFileInfoW[]); - default: - throw new InvalidOperationException(); - } - } - - - // - // Summary: - // Converts the unmanaged data to managed data. - // - // Parameters: - // pNativeData: - // A pointer to the unmanaged data to be wrapped. - // - // Returns: - // Returns the managed view of the COM data. - public object MarshalNativeToManaged(IntPtr pNativeData) - { - return null; - } - - // Implementation ************************************************* - - // PATCH_OPTION_DATA offsets - private static readonly int symbolOptionFlagsOffset = Marshal.SizeOf(typeof(Int32)); - private static readonly int newFileSymbolPathOffset = 2 * Marshal.SizeOf(typeof(Int32)); - private static readonly int oldFileSymbolPathArrayOffset = 2 * Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr)); - private static readonly int extendedOptionFlagsOffset = 2 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr)); - private static readonly int symLoadCallbackOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr)); - private static readonly int symLoadContextOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 3 * Marshal.SizeOf(typeof(IntPtr)); - private static readonly int interleaveMapArrayOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 4 * Marshal.SizeOf(typeof(IntPtr)); - private static readonly int maxLzxWindowSizeOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 5 * Marshal.SizeOf(typeof(IntPtr)); - private static readonly int patchOptionDataSize = 4 * Marshal.SizeOf(typeof(Int32)) + 5 * Marshal.SizeOf(typeof(IntPtr)); - - // PATCH_OLD_FILE_INFO offsets - private static readonly int oldFileOffset = Marshal.SizeOf(typeof(Int32)); - private static readonly int ignoreRangeCountOffset = Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr)); - private static readonly int ignoreRangeArrayOffset = 2 * Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr)); - private static readonly int retainRangeCountOffset = 2 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr)); - private static readonly int retainRangeArrayOffset = 3 * Marshal.SizeOf(typeof(Int32)) + 2 * Marshal.SizeOf(typeof(IntPtr)); - private static readonly int patchOldFileInfoSize = 3 * Marshal.SizeOf(typeof(Int32)) + 3 * Marshal.SizeOf(typeof(IntPtr)); - - // Methods and data used to preserve data needed for cleanup - - // This dictionary holds the quantity of items internal to each native structure that will need to be freed (the OldFileCount) - private static readonly Dictionary OldFileCounts = new Dictionary(); - private static readonly object OldFileCountsLock = new object(); - - private IntPtr CreateMainStruct(int oldFileCount) - { - int nativeSize; - switch (this.marshalType) - { - case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA: - nativeSize = patchOptionDataSize; - break; - case PatchAPIMarshaler.MarshalType.PATCH_OLD_FILE_INFO_W: - nativeSize = oldFileCount * patchOldFileInfoSize; - break; - default: - throw new InvalidOperationException(); - } - - IntPtr native = Marshal.AllocCoTaskMem(nativeSize); - - lock (PatchAPIMarshaler.OldFileCountsLock) - { - PatchAPIMarshaler.OldFileCounts.Add(native, oldFileCount); - } - - return native; - } - - private static void ReleaseMainStruct(IntPtr native) - { - lock (PatchAPIMarshaler.OldFileCountsLock) - { - PatchAPIMarshaler.OldFileCounts.Remove(native); - } - Marshal.FreeCoTaskMem(native); - } - - private static int GetOldFileCount(IntPtr native) - { - lock (PatchAPIMarshaler.OldFileCountsLock) - { - return PatchAPIMarshaler.OldFileCounts[native]; - } - } - - // Helper methods - - private static IntPtr OptionalAnsiString(string managed) - { - return (null == managed) ? IntPtr.Zero : Marshal.StringToCoTaskMemAnsi(managed); - } - - private static IntPtr OptionalUnicodeString(string managed) - { - return (null == managed) ? IntPtr.Zero : Marshal.StringToCoTaskMemUni(managed); - } - - // string array must be of the same length as the number of old files - private static IntPtr CreateArrayOfStringA(string[] managed) - { - if (null == managed) - { - return IntPtr.Zero; - } - - int size = managed.Length * Marshal.SizeOf(typeof(IntPtr)); - IntPtr native = Marshal.AllocCoTaskMem(size); - - for (int i = 0; i < managed.Length; ++i) - { - Marshal.WriteIntPtr(native, i * Marshal.SizeOf(typeof(IntPtr)), OptionalAnsiString(managed[i])); - } - - return native; - } - - // string array must be of the same length as the number of old files - private static IntPtr CreateArrayOfStringW(string[] managed) - { - if (null == managed) - { - return IntPtr.Zero; - } - - int size = managed.Length * Marshal.SizeOf(typeof(IntPtr)); - IntPtr native = Marshal.AllocCoTaskMem(size); - - for (int i = 0; i < managed.Length; ++i) - { - Marshal.WriteIntPtr(native, i * Marshal.SizeOf(typeof(IntPtr)), OptionalUnicodeString(managed[i])); - } - - return native; - } - - private static IntPtr CreateInterleaveMapRange(PatchInterleaveMap managed) - { - if (null == managed) - { - return IntPtr.Zero; - } - - if (null == managed.ranges) - { - return IntPtr.Zero; - } - - if (0 == managed.ranges.Length) - { - return IntPtr.Zero; - } - - IntPtr native = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(UInt32)) - + managed.ranges.Length * (Marshal.SizeOf(typeof(PatchInterleaveMap)))); - WriteUInt32(native, (uint)managed.ranges.Length); - - for (int i = 0; i < managed.ranges.Length; ++i) - { - Marshal.StructureToPtr(managed.ranges[i], (IntPtr)((Int64)native + i * Marshal.SizeOf(typeof(PatchInterleaveMap))), false); - } - return native; - } - - private static IntPtr CreateInterleaveMap(PatchInterleaveMap[] managed) - { - if (null == managed) - { - return IntPtr.Zero; - } - - IntPtr native = Marshal.AllocCoTaskMem(managed.Length * Marshal.SizeOf(typeof(IntPtr))); - - for (int i = 0; i < managed.Length; ++i) - { - Marshal.WriteIntPtr(native, i * Marshal.SizeOf(typeof(IntPtr)), CreateInterleaveMapRange(managed[i])); - } - - return native; - } - - private static void WriteUInt32(IntPtr native, uint data) - { - Marshal.WriteInt32(native, unchecked((int)data)); - } - - private static void WriteUInt32(IntPtr native, int offset, uint data) - { - Marshal.WriteInt32(native, offset, unchecked((int)data)); - } - - // Marshal operations - - private IntPtr MarshalPOD(PatchOptionData managed) - { - if (null == managed) - { - throw new ArgumentNullException("managed"); - } - - IntPtr native = this.CreateMainStruct(managed.oldFileSymbolPathArray.Length); - Marshal.WriteInt32(native, patchOptionDataSize); // SizeOfThisStruct - WriteUInt32(native, symbolOptionFlagsOffset, (uint)managed.symbolOptionFlags); - Marshal.WriteIntPtr(native, newFileSymbolPathOffset, PatchAPIMarshaler.OptionalAnsiString(managed.newFileSymbolPath)); - Marshal.WriteIntPtr(native, oldFileSymbolPathArrayOffset, PatchAPIMarshaler.CreateArrayOfStringA(managed.oldFileSymbolPathArray)); - WriteUInt32(native, extendedOptionFlagsOffset, managed.extendedOptionFlags); - - // GetFunctionPointerForDelegate() throws an ArgumentNullException if the delegate is null. - if (null == managed.symLoadCallback) - { - Marshal.WriteIntPtr(native, symLoadCallbackOffset, IntPtr.Zero); - } - else - { - Marshal.WriteIntPtr(native, symLoadCallbackOffset, Marshal.GetFunctionPointerForDelegate(managed.symLoadCallback)); - } - - Marshal.WriteIntPtr(native, symLoadContextOffset, managed.symLoadContext); - Marshal.WriteIntPtr(native, interleaveMapArrayOffset, PatchAPIMarshaler.CreateInterleaveMap(managed.interleaveMapArray)); - WriteUInt32(native, maxLzxWindowSizeOffset, managed.maxLzxWindowSize); - return native; - } - - private IntPtr MarshalPOFIW_A(PatchOldFileInfoW[] managed) - { - if (null == managed) - { - throw new ArgumentNullException("managed"); - } - - if (0 == managed.Length) - { - return IntPtr.Zero; - } - - IntPtr native = this.CreateMainStruct(managed.Length); - - for (int i = 0; i < managed.Length; ++i) - { - PatchAPIMarshaler.MarshalPOFIW(managed[i], (IntPtr)((Int64)native + i * patchOldFileInfoSize)); - } - - return native; - } - - private static void MarshalPOFIW(PatchOldFileInfoW managed, IntPtr native) - { - PatchAPIMarshaler.MarshalPOFI(managed, native); - Marshal.WriteIntPtr(native, oldFileOffset, PatchAPIMarshaler.OptionalUnicodeString(managed.oldFileName)); // OldFileName - } - - private static void MarshalPOFI(PatchOldFileInfo managed, IntPtr native) - { - Marshal.WriteInt32(native, patchOldFileInfoSize); // SizeOfThisStruct - WriteUInt32(native, ignoreRangeCountOffset, - (null == managed.ignoreRange) ? 0 : (uint)managed.ignoreRange.Length); // IgnoreRangeCount // maximum 255 - Marshal.WriteIntPtr(native, ignoreRangeArrayOffset, MarshalPIRArray(managed.ignoreRange)); // IgnoreRangeArray - WriteUInt32(native, retainRangeCountOffset, - (null == managed.retainRange) ? 0 : (uint)managed.retainRange.Length); // RetainRangeCount // maximum 255 - Marshal.WriteIntPtr(native, retainRangeArrayOffset, MarshalPRRArray(managed.retainRange)); // RetainRangeArray - } - - private static IntPtr MarshalPIRArray(PatchIgnoreRange[] array) - { - if (null == array) - { - return IntPtr.Zero; - } - - if (0 == array.Length) - { - return IntPtr.Zero; - } - - IntPtr native = Marshal.AllocCoTaskMem(array.Length * Marshal.SizeOf(typeof(PatchIgnoreRange))); - - for (int i = 0; i < array.Length; ++i) - { - Marshal.StructureToPtr(array[i], (IntPtr)((Int64)native + (i * Marshal.SizeOf(typeof(PatchIgnoreRange)))), false); - } - - return native; - } - - private static IntPtr MarshalPRRArray(PatchRetainRange[] array) - { - if (null == array) - { - return IntPtr.Zero; - } - - if (0 == array.Length) - { - return IntPtr.Zero; - } - - IntPtr native = Marshal.AllocCoTaskMem(array.Length * Marshal.SizeOf(typeof(PatchRetainRange))); - - for (int i = 0; i < array.Length; ++i) - { - Marshal.StructureToPtr(array[i], (IntPtr)((Int64)native + (i * Marshal.SizeOf(typeof(PatchRetainRange)))), false); - } - - return native; - } - - // CleanUp operations - - private void CleanUpPOD(IntPtr native) - { - Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, newFileSymbolPathOffset)); - - if (IntPtr.Zero != Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset)) - { - for (int i = 0; i < GetOldFileCount(native); ++i) - { - Marshal.FreeCoTaskMem( - Marshal.ReadIntPtr( - Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset), - i * Marshal.SizeOf(typeof(IntPtr)))); - } - - Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset)); - } - - if (IntPtr.Zero != Marshal.ReadIntPtr(native, interleaveMapArrayOffset)) - { - for (int i = 0; i < GetOldFileCount(native); ++i) - { - Marshal.FreeCoTaskMem( - Marshal.ReadIntPtr( - Marshal.ReadIntPtr(native, interleaveMapArrayOffset), - i * Marshal.SizeOf(typeof(IntPtr)))); - } - - Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, interleaveMapArrayOffset)); - } - - PatchAPIMarshaler.ReleaseMainStruct(native); - } - - private void CleanUpPOFI_A(IntPtr native) - { - for (int i = 0; i < GetOldFileCount(native); ++i) - { - PatchAPIMarshaler.CleanUpPOFI((IntPtr)((Int64)native + i * patchOldFileInfoSize)); - } - - PatchAPIMarshaler.ReleaseMainStruct(native); - } - - private static void CleanUpPOFI(IntPtr native) - { - if (IntPtr.Zero != Marshal.ReadIntPtr(native, oldFileOffset)) - { - Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, oldFileOffset)); - } - - PatchAPIMarshaler.CleanUpPOFIH(native); - } - - private static void CleanUpPOFIH(IntPtr native) - { - if (IntPtr.Zero != Marshal.ReadIntPtr(native, ignoreRangeArrayOffset)) - { - Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, ignoreRangeArrayOffset)); - } - - if (IntPtr.Zero != Marshal.ReadIntPtr(native, retainRangeArrayOffset)) - { - Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, retainRangeArrayOffset)); - } - } - } - } -} -- cgit v1.2.3-55-g6feb