diff options
Diffstat (limited to 'src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs')
-rw-r--r-- | src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs | 989 |
1 files changed, 989 insertions, 0 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs b/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs new file mode 100644 index 00000000..fcd749d2 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/PatchAPI/PatchInterop.cs | |||
@@ -0,0 +1,989 @@ | |||
1 | // 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. | ||
2 | |||
3 | namespace WixToolset.PatchAPI | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Diagnostics.CodeAnalysis; | ||
8 | using System.Globalization; | ||
9 | using System.Runtime.InteropServices; | ||
10 | using WixToolset.Core; | ||
11 | |||
12 | /// <summary> | ||
13 | /// Interop class for the mspatchc.dll. | ||
14 | /// </summary> | ||
15 | internal static class PatchInterop | ||
16 | { | ||
17 | // From WinError.h in the Platform SDK | ||
18 | internal const ushort FACILITY_WIN32 = 7; | ||
19 | |||
20 | /// <summary> | ||
21 | /// Parse a number from text in either hex or decimal. | ||
22 | /// </summary> | ||
23 | /// <param name="source">Source value. Treated as hex if it starts 0x (or 0X), decimal otherwise.</param> | ||
24 | /// <returns>Numeric value that source represents.</returns> | ||
25 | static internal UInt32 ParseHexOrDecimal(string source) | ||
26 | { | ||
27 | string value = source.Trim(); | ||
28 | if (String.Equals(value.Substring(0,2), "0x", StringComparison.OrdinalIgnoreCase)) | ||
29 | { | ||
30 | return UInt32.Parse(value.Substring(2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture.NumberFormat); | ||
31 | } | ||
32 | else | ||
33 | { | ||
34 | return UInt32.Parse(value, CultureInfo.InvariantCulture.NumberFormat); | ||
35 | } | ||
36 | } | ||
37 | |||
38 | /// <summary> | ||
39 | /// Create a binary delta file. | ||
40 | /// </summary> | ||
41 | /// <param name="deltaFile">Name of the delta file to create.</param> | ||
42 | /// <param name="targetFile">Name of updated file.</param> | ||
43 | /// <param name="targetSymbolPath">Optional paths to updated file's symbols.</param> | ||
44 | /// <param name="targetRetainOffsets">Optional offsets to the delta retain sections in the updated file.</param> | ||
45 | /// <param name="basisFiles">Optional array of target files.</param> | ||
46 | /// <param name="basisSymbolPaths">Optional array of target files' symbol paths (must match basisFiles array).</param> | ||
47 | /// <param name="basisIgnoreLengths">Optional array of target files' delta ignore section lengths (must match basisFiles array)(each entry must match basisIgnoreOffsets entries).</param> | ||
48 | /// <param name="basisIgnoreOffsets">Optional array of target files' delta ignore section offsets (must match basisFiles array)(each entry must match basisIgnoreLengths entries).</param> | ||
49 | /// <param name="basisRetainLengths">Optional array of target files' delta protect section lengths (must match basisFiles array)(each entry must match basisRetainOffsets and targetRetainOffsets entries).</param> | ||
50 | /// <param name="basisRetainOffsets">Optional array of target files' delta protect section offsets (must match basisFiles array)(each entry must match basisRetainLengths and targetRetainOffsets entries).</param> | ||
51 | /// <param name="apiPatchingSymbolFlags">ApiPatchingSymbolFlags value.</param> | ||
52 | /// <param name="optimizePatchSizeForLargeFiles">OptimizePatchSizeForLargeFiles value.</param> | ||
53 | /// <param name="retainRangesIgnored">Flag to indicate retain ranges were ignored due to mismatch.</param> | ||
54 | /// <returns>true if delta file was created, false if whole file should be used instead.</returns> | ||
55 | static public bool CreateDelta( | ||
56 | string deltaFile, | ||
57 | string targetFile, | ||
58 | string targetSymbolPath, | ||
59 | string targetRetainOffsets, | ||
60 | string[] basisFiles, | ||
61 | string[] basisSymbolPaths, | ||
62 | string[] basisIgnoreLengths, | ||
63 | string[] basisIgnoreOffsets, | ||
64 | string[] basisRetainLengths, | ||
65 | string[] basisRetainOffsets, | ||
66 | PatchSymbolFlagsType apiPatchingSymbolFlags, | ||
67 | bool optimizePatchSizeForLargeFiles, | ||
68 | out bool retainRangesIgnored | ||
69 | ) | ||
70 | { | ||
71 | retainRangesIgnored = false; | ||
72 | if (0 != (apiPatchingSymbolFlags & ~(PatchSymbolFlagsType.PATCH_SYMBOL_NO_IMAGEHLP | PatchSymbolFlagsType.PATCH_SYMBOL_NO_FAILURES | PatchSymbolFlagsType.PATCH_SYMBOL_UNDECORATED_TOO))) | ||
73 | { | ||
74 | throw new ArgumentOutOfRangeException("apiPatchingSymbolFlags"); | ||
75 | } | ||
76 | |||
77 | if (null == deltaFile || 0 == deltaFile.Length) | ||
78 | { | ||
79 | throw new ArgumentNullException("deltaFile"); | ||
80 | } | ||
81 | |||
82 | if (null == targetFile || 0 == targetFile.Length) | ||
83 | { | ||
84 | throw new ArgumentNullException("targetFile"); | ||
85 | } | ||
86 | |||
87 | if (null == basisFiles || 0 == basisFiles.Length) | ||
88 | { | ||
89 | return false; | ||
90 | } | ||
91 | uint countOldFiles = (uint) basisFiles.Length; | ||
92 | |||
93 | if (null != basisSymbolPaths) | ||
94 | { | ||
95 | if (0 != basisSymbolPaths.Length) | ||
96 | { | ||
97 | if ((uint) basisSymbolPaths.Length != countOldFiles) | ||
98 | { | ||
99 | throw new ArgumentOutOfRangeException("basisSymbolPaths"); | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | // a null basisSymbolPaths is allowed. | ||
104 | |||
105 | if (null != basisIgnoreLengths) | ||
106 | { | ||
107 | if (0 != basisIgnoreLengths.Length) | ||
108 | { | ||
109 | if ((uint) basisIgnoreLengths.Length != countOldFiles) | ||
110 | { | ||
111 | throw new ArgumentOutOfRangeException("basisIgnoreLengths"); | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | else | ||
116 | { | ||
117 | basisIgnoreLengths = new string[countOldFiles]; | ||
118 | } | ||
119 | |||
120 | if (null != basisIgnoreOffsets) | ||
121 | { | ||
122 | if (0 != basisIgnoreOffsets.Length) | ||
123 | { | ||
124 | if ((uint) basisIgnoreOffsets.Length != countOldFiles) | ||
125 | { | ||
126 | throw new ArgumentOutOfRangeException("basisIgnoreOffsets"); | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | else | ||
131 | { | ||
132 | basisIgnoreOffsets = new string[countOldFiles]; | ||
133 | } | ||
134 | |||
135 | if (null != basisRetainLengths) | ||
136 | { | ||
137 | if (0 != basisRetainLengths.Length) | ||
138 | { | ||
139 | if ((uint) basisRetainLengths.Length != countOldFiles) | ||
140 | { | ||
141 | throw new ArgumentOutOfRangeException("basisRetainLengths"); | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | else | ||
146 | { | ||
147 | basisRetainLengths = new string[countOldFiles]; | ||
148 | } | ||
149 | |||
150 | if (null != basisRetainOffsets) | ||
151 | { | ||
152 | if (0 != basisRetainOffsets.Length) | ||
153 | { | ||
154 | if ((uint) basisRetainOffsets.Length != countOldFiles) | ||
155 | { | ||
156 | throw new ArgumentOutOfRangeException("basisRetainOffsets"); | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | else | ||
161 | { | ||
162 | basisRetainOffsets = new string[countOldFiles]; | ||
163 | } | ||
164 | |||
165 | PatchOptionData pod = new PatchOptionData(); | ||
166 | pod.symbolOptionFlags = apiPatchingSymbolFlags; | ||
167 | pod.newFileSymbolPath = targetSymbolPath; | ||
168 | pod.oldFileSymbolPathArray = basisSymbolPaths; | ||
169 | pod.extendedOptionFlags = 0; | ||
170 | PatchOldFileInfoW[] oldFileInfoArray = new PatchOldFileInfoW[countOldFiles]; | ||
171 | string[] newRetainOffsetArray = ((null == targetRetainOffsets) ? new string[0] : targetRetainOffsets.Split(',')); | ||
172 | for (uint i = 0; i < countOldFiles; ++i) | ||
173 | { | ||
174 | PatchOldFileInfoW ofi = new PatchOldFileInfoW(); | ||
175 | ofi.oldFileName = basisFiles[i]; | ||
176 | string[] ignoreLengthArray = ((null == basisIgnoreLengths[i]) ? new string[0] : basisIgnoreLengths[i].Split(',')); | ||
177 | string[] ignoreOffsetArray = ((null == basisIgnoreOffsets[i]) ? new string[0] : basisIgnoreOffsets[i].Split(',')); | ||
178 | string[] retainLengthArray = ((null == basisRetainLengths[i]) ? new string[0] : basisRetainLengths[i].Split(',')); | ||
179 | string[] retainOffsetArray = ((null == basisRetainOffsets[i]) ? new string[0] : basisRetainOffsets[i].Split(',')); | ||
180 | // Validate inputs | ||
181 | if (ignoreLengthArray.Length != ignoreOffsetArray.Length) | ||
182 | { | ||
183 | throw new ArgumentOutOfRangeException("basisIgnoreLengths"); | ||
184 | } | ||
185 | |||
186 | if (retainLengthArray.Length != retainOffsetArray.Length) | ||
187 | { | ||
188 | throw new ArgumentOutOfRangeException("basisRetainLengths"); | ||
189 | } | ||
190 | |||
191 | if (newRetainOffsetArray.Length != retainOffsetArray.Length) | ||
192 | { | ||
193 | // remove all retain range information | ||
194 | retainRangesIgnored = true; | ||
195 | for (uint j = 0; j < countOldFiles; ++j) | ||
196 | { | ||
197 | basisRetainLengths[j] = null; | ||
198 | basisRetainOffsets[j] = null; | ||
199 | } | ||
200 | retainLengthArray = new string[0]; | ||
201 | retainOffsetArray = new string[0]; | ||
202 | newRetainOffsetArray = new string[0]; | ||
203 | for (uint j = 0; j < oldFileInfoArray.Length; ++j) | ||
204 | { | ||
205 | oldFileInfoArray[j].retainRange = null; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | // Populate IgnoreRange structure | ||
210 | PatchIgnoreRange[] ignoreArray = null; | ||
211 | if (0 != ignoreLengthArray.Length) | ||
212 | { | ||
213 | ignoreArray = new PatchIgnoreRange[ignoreLengthArray.Length]; | ||
214 | for (int j = 0; j < ignoreLengthArray.Length; ++j) | ||
215 | { | ||
216 | PatchIgnoreRange ignoreRange = new PatchIgnoreRange(); | ||
217 | ignoreRange.offsetInOldFile = ParseHexOrDecimal(ignoreOffsetArray[j]); | ||
218 | ignoreRange.lengthInBytes = ParseHexOrDecimal(ignoreLengthArray[j]); | ||
219 | ignoreArray[j] = ignoreRange; | ||
220 | } | ||
221 | ofi.ignoreRange = ignoreArray; | ||
222 | } | ||
223 | |||
224 | PatchRetainRange[] retainArray = null; | ||
225 | if (0 != newRetainOffsetArray.Length) | ||
226 | { | ||
227 | retainArray = new PatchRetainRange[retainLengthArray.Length]; | ||
228 | for (int j = 0; j < newRetainOffsetArray.Length; ++j) | ||
229 | { | ||
230 | PatchRetainRange retainRange = new PatchRetainRange(); | ||
231 | retainRange.offsetInOldFile = ParseHexOrDecimal(retainOffsetArray[j]); | ||
232 | retainRange.lengthInBytes = ParseHexOrDecimal(retainLengthArray[j]); | ||
233 | retainRange.offsetInNewFile = ParseHexOrDecimal(newRetainOffsetArray[j]); | ||
234 | retainArray[j] = retainRange; | ||
235 | } | ||
236 | ofi.retainRange = retainArray; | ||
237 | } | ||
238 | oldFileInfoArray[i] = ofi; | ||
239 | } | ||
240 | |||
241 | if (CreatePatchFileExW( | ||
242 | countOldFiles, | ||
243 | oldFileInfoArray, | ||
244 | targetFile, | ||
245 | deltaFile, | ||
246 | PatchOptionFlags(optimizePatchSizeForLargeFiles), | ||
247 | pod, | ||
248 | null, | ||
249 | IntPtr.Zero)) | ||
250 | { | ||
251 | return true; | ||
252 | } | ||
253 | |||
254 | // determine if this is an error or a need to use whole file. | ||
255 | int err = Marshal.GetLastWin32Error(); | ||
256 | switch(err) | ||
257 | { | ||
258 | case unchecked((int) ERROR_PATCH_BIGGER_THAN_COMPRESSED): | ||
259 | break; | ||
260 | |||
261 | // too late to exclude this file -- should have been caught before | ||
262 | case unchecked((int) ERROR_PATCH_SAME_FILE): | ||
263 | default: | ||
264 | throw new System.ComponentModel.Win32Exception(err); | ||
265 | } | ||
266 | return false; | ||
267 | } | ||
268 | |||
269 | /// <summary> | ||
270 | /// Extract the delta header. | ||
271 | /// </summary> | ||
272 | /// <param name="delta">Name of delta file.</param> | ||
273 | /// <param name="deltaHeader">Name of file to create with the delta's header.</param> | ||
274 | static public void ExtractDeltaHeader(string delta, string deltaHeader) | ||
275 | { | ||
276 | if (!ExtractPatchHeaderToFileW(delta, deltaHeader)) | ||
277 | { | ||
278 | throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | /// <summary> | ||
283 | /// Returns the PatchOptionFlags to use. | ||
284 | /// </summary> | ||
285 | /// <param name="optimizeForLargeFiles">True if optimizing for large files.</param> | ||
286 | /// <returns>PATCH_OPTION_FLAG values</returns> | ||
287 | static private UInt32 PatchOptionFlags(bool optimizeForLargeFiles) | ||
288 | { | ||
289 | UInt32 flags = PATCH_OPTION_FAIL_IF_SAME_FILE | PATCH_OPTION_FAIL_IF_BIGGER | PATCH_OPTION_USE_LZX_BEST; | ||
290 | if (optimizeForLargeFiles) | ||
291 | { | ||
292 | flags |= PATCH_OPTION_USE_LZX_LARGE; | ||
293 | } | ||
294 | return flags; | ||
295 | } | ||
296 | |||
297 | //--------------------------------------------------------------------- | ||
298 | // From PatchApi.h | ||
299 | //--------------------------------------------------------------------- | ||
300 | |||
301 | // | ||
302 | // The following contants can be combined and used as the OptionFlags | ||
303 | // parameter in the patch creation apis. | ||
304 | |||
305 | internal const uint PATCH_OPTION_USE_BEST = 0x00000000; // auto choose best (slower) | ||
306 | |||
307 | internal const uint PATCH_OPTION_USE_LZX_BEST = 0x00000003; // auto choose best of LXZ A/B (but not large) | ||
308 | internal const uint PATCH_OPTION_USE_LZX_A = 0x00000001; // normal | ||
309 | internal const uint PATCH_OPTION_USE_LXZ_B = 0x00000002; // better on some x86 binaries | ||
310 | internal const uint PATCH_OPTION_USE_LZX_LARGE = 0x00000004; // better support for large files (requires 5.1 or higher applyer) | ||
311 | |||
312 | internal const uint PATCH_OPTION_NO_BINDFIX = 0x00010000; // PE bound imports | ||
313 | internal const uint PATCH_OPTION_NO_LOCKFIX = 0x00020000; // PE smashed locks | ||
314 | internal const uint PATCH_OPTION_NO_REBASE = 0x00040000; // PE rebased image | ||
315 | internal const uint PATCH_OPTION_FAIL_IF_SAME_FILE = 0x00080000; // don't create if same | ||
316 | internal const uint PATCH_OPTION_FAIL_IF_BIGGER = 0x00100000; // fail if patch is larger than simply compressing new file (slower) | ||
317 | internal const uint PATCH_OPTION_NO_CHECKSUM = 0x00200000; // PE checksum zero | ||
318 | internal const uint PATCH_OPTION_NO_RESTIMEFIX = 0x00400000; // PE resource timestamps | ||
319 | internal const uint PATCH_OPTION_NO_TIMESTAMP = 0x00800000; // don't store new file timestamp in patch | ||
320 | internal const uint PATCH_OPTION_SIGNATURE_MD5 = 0x01000000; // use MD5 instead of CRC (reserved for future support) | ||
321 | internal const uint PATCH_OPTION_INTERLEAVE_FILES = 0x40000000; // better support for large files (requires 5.2 or higher applyer) | ||
322 | internal const uint PATCH_OPTION_RESERVED1 = 0x80000000; // (used internally) | ||
323 | |||
324 | internal const uint PATCH_OPTION_VALID_FLAGS = 0xC0FF0007; | ||
325 | |||
326 | // | ||
327 | // The following flags are used with PATCH_OPTION_DATA ExtendedOptionFlags: | ||
328 | // | ||
329 | |||
330 | internal const uint PATCH_TRANSFORM_PE_RESOURCE_2 = 0x00000100; // better handling of PE resources (requires 5.2 or higher applyer) | ||
331 | internal const uint PATCH_TRANSFORM_PE_IRELOC_2 = 0x00000200; // better handling of PE stripped relocs (requires 5.2 or higher applyer) | ||
332 | |||
333 | // | ||
334 | // In addition to the standard Win32 error codes, the following error codes may | ||
335 | // be returned via GetLastError() when one of the patch APIs fails. | ||
336 | |||
337 | internal const uint ERROR_PATCH_ENCODE_FAILURE = 0xC00E3101; // create | ||
338 | internal const uint ERROR_PATCH_INVALID_OPTIONS = 0xC00E3102; // create | ||
339 | internal const uint ERROR_PATCH_SAME_FILE = 0xC00E3103; // create | ||
340 | internal const uint ERROR_PATCH_RETAIN_RANGES_DIFFER = 0xC00E3104; // create | ||
341 | internal const uint ERROR_PATCH_BIGGER_THAN_COMPRESSED = 0xC00E3105; // create | ||
342 | internal const uint ERROR_PATCH_IMAGEHLP_FALURE = 0xC00E3106; // create | ||
343 | |||
344 | /// <summary> | ||
345 | /// Delegate type that the PatchAPI calls for progress notification. | ||
346 | /// </summary> | ||
347 | /// <param name="context">.</param> | ||
348 | /// <param name="currentPosition">.</param> | ||
349 | /// <param name="maxPosition">.</param> | ||
350 | /// <returns>True for success</returns> | ||
351 | public delegate bool PatchProgressCallback( | ||
352 | IntPtr context, | ||
353 | uint currentPosition, | ||
354 | uint maxPosition | ||
355 | ); | ||
356 | |||
357 | /// <summary> | ||
358 | /// Delegate type that the PatchAPI calls for patch symbol load information. | ||
359 | /// </summary> | ||
360 | /// <param name="whichFile">.</param> | ||
361 | /// <param name="symbolFileName">.</param> | ||
362 | /// <param name="symType">.</param> | ||
363 | /// <param name="symbolFileCheckSum">.</param> | ||
364 | /// <param name="symbolFileTimeDate">.</param> | ||
365 | /// <param name="imageFileCheckSum">.</param> | ||
366 | /// <param name="imageFileTimeDate">.</param> | ||
367 | /// <param name="context">.</param> | ||
368 | /// <returns>???</returns> | ||
369 | public delegate bool PatchSymloadCallback( | ||
370 | uint whichFile, // 0 for new file, 1 for first old file, etc | ||
371 | [MarshalAs(UnmanagedType.LPStr)] string symbolFileName, | ||
372 | uint symType, // see SYM_TYPE in imagehlp.h | ||
373 | uint symbolFileCheckSum, | ||
374 | uint symbolFileTimeDate, | ||
375 | uint imageFileCheckSum, | ||
376 | uint imageFileTimeDate, | ||
377 | IntPtr context | ||
378 | ); | ||
379 | |||
380 | /// <summary> | ||
381 | /// Wraps PATCH_IGNORE_RANGE | ||
382 | /// </summary> | ||
383 | [StructLayout(LayoutKind.Sequential)] | ||
384 | internal class PatchIgnoreRange | ||
385 | { | ||
386 | public uint offsetInOldFile; | ||
387 | public uint lengthInBytes; | ||
388 | } | ||
389 | |||
390 | /// <summary> | ||
391 | /// Wraps PATCH_RETAIN_RANGE | ||
392 | /// </summary> | ||
393 | [StructLayout(LayoutKind.Sequential)] | ||
394 | internal class PatchRetainRange | ||
395 | { | ||
396 | public uint offsetInOldFile; | ||
397 | public uint lengthInBytes; | ||
398 | public uint offsetInNewFile; | ||
399 | } | ||
400 | |||
401 | /// <summary> | ||
402 | /// Wraps PATCH_OLD_FILE_INFO (except for the OldFile~ portion) | ||
403 | /// </summary> | ||
404 | internal class PatchOldFileInfo | ||
405 | { | ||
406 | public PatchIgnoreRange[] ignoreRange; | ||
407 | public PatchRetainRange[] retainRange; | ||
408 | } | ||
409 | |||
410 | /// <summary> | ||
411 | /// Wraps PATCH_OLD_FILE_INFO_W | ||
412 | /// </summary> | ||
413 | internal class PatchOldFileInfoW : PatchOldFileInfo | ||
414 | { | ||
415 | public string oldFileName; | ||
416 | } | ||
417 | |||
418 | /// <summary> | ||
419 | /// Wraps each PATCH_INTERLEAVE_MAP Range | ||
420 | /// </summary> | ||
421 | [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses"), StructLayout(LayoutKind.Sequential)] | ||
422 | internal class PatchInterleaveMapRange | ||
423 | { | ||
424 | public uint oldOffset; | ||
425 | public uint oldLength; | ||
426 | public uint newLength; | ||
427 | } | ||
428 | |||
429 | /// <summary> | ||
430 | /// Wraps PATCH_INTERLEAVE_MAP | ||
431 | /// </summary> | ||
432 | internal class PatchInterleaveMap | ||
433 | { | ||
434 | public PatchInterleaveMapRange[] ranges = null; | ||
435 | } | ||
436 | |||
437 | |||
438 | /// <summary> | ||
439 | /// Wraps PATCH_OPTION_DATA | ||
440 | /// </summary> | ||
441 | [BestFitMapping(false, ThrowOnUnmappableChar = true)] | ||
442 | internal class PatchOptionData | ||
443 | { | ||
444 | public PatchSymbolFlagsType symbolOptionFlags; // PATCH_SYMBOL_xxx flags | ||
445 | [MarshalAs(UnmanagedType.LPStr)] public string newFileSymbolPath; // always ANSI, never Unicode | ||
446 | [MarshalAs(UnmanagedType.LPStr)] public string[] oldFileSymbolPathArray; // array[ OldFileCount ] | ||
447 | public uint extendedOptionFlags; | ||
448 | public PatchSymloadCallback symLoadCallback = null; | ||
449 | public IntPtr symLoadContext = IntPtr.Zero; | ||
450 | public PatchInterleaveMap[] interleaveMapArray = null; // array[ OldFileCount ] (requires 5.2 or higher applyer) | ||
451 | public uint maxLzxWindowSize = 0; // limit memory requirements (requires 5.2 or higher applyer) | ||
452 | } | ||
453 | |||
454 | // | ||
455 | // Note that PATCH_OPTION_DATA contains LPCSTR paths, and no LPCWSTR (Unicode) | ||
456 | // path argument is available, even when used with one of the Unicode APIs | ||
457 | // such as CreatePatchFileW. This is because the unlerlying system services | ||
458 | // for symbol file handling (IMAGEHLP.DLL) only support ANSI file/path names. | ||
459 | // | ||
460 | |||
461 | // | ||
462 | // A note about PATCH_RETAIN_RANGE specifiers with multiple old files: | ||
463 | // | ||
464 | // Each old version file must have the same RetainRangeCount, and the same | ||
465 | // retain range LengthInBytes and OffsetInNewFile values in the same order. | ||
466 | // Only the OffsetInOldFile values can differ between old foles for retain | ||
467 | // ranges. | ||
468 | // | ||
469 | |||
470 | // | ||
471 | // The following prototypes are (some of the) interfaces for creating patches from files. | ||
472 | // | ||
473 | |||
474 | /// <summary> | ||
475 | /// Creates a new delta. | ||
476 | /// </summary> | ||
477 | /// <param name="oldFileCount">Size of oldFileInfoArray.</param> | ||
478 | /// <param name="oldFileInfoArray">Target file information.</param> | ||
479 | /// <param name="newFileName">Name of updated file.</param> | ||
480 | /// <param name="patchFileName">Name of delta to create.</param> | ||
481 | /// <param name="optionFlags">PATCH_OPTION_xxx.</param> | ||
482 | /// <param name="optionData">Optional PATCH_OPTION_DATA structure.</param> | ||
483 | /// <param name="progressCallback">Delegate for progress callbacks.</param> | ||
484 | /// <param name="context">Context for progress callback delegate.</param> | ||
485 | /// <returns>true if successfull, sets Marshal.GetLastWin32Error() if not.</returns> | ||
486 | [DllImport("mspatchc.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] | ||
487 | [return: MarshalAs(UnmanagedType.Bool)] | ||
488 | internal static extern bool CreatePatchFileExW( | ||
489 | uint oldFileCount, // maximum 255 | ||
490 | [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(PatchAPIMarshaler), MarshalCookie="PATCH_OLD_FILE_INFO_W")] | ||
491 | PatchOldFileInfoW[] oldFileInfoArray, | ||
492 | string newFileName, // input file (required) | ||
493 | string patchFileName, // output file (required) | ||
494 | uint optionFlags, | ||
495 | [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(PatchAPIMarshaler), MarshalCookie="PATCH_OPTION_DATA")] | ||
496 | PatchOptionData optionData, | ||
497 | [MarshalAs (UnmanagedType.FunctionPtr)] | ||
498 | PatchProgressCallback progressCallback, | ||
499 | IntPtr context | ||
500 | ); | ||
501 | |||
502 | /// <summary> | ||
503 | /// Extracts delta header from delta. | ||
504 | /// </summary> | ||
505 | /// <param name="patchFileName">Name of delta file.</param> | ||
506 | /// <param name="patchHeaderFileName">Name of file to create with delta header.</param> | ||
507 | /// <returns>true if successfull, sets Marshal.GetLastWin32Error() if not.</returns> | ||
508 | [DllImport("mspatchc.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] | ||
509 | [return: MarshalAs(UnmanagedType.Bool)] | ||
510 | internal static extern bool ExtractPatchHeaderToFileW( | ||
511 | string patchFileName, // input file | ||
512 | string patchHeaderFileName // output file | ||
513 | ); | ||
514 | |||
515 | // TODO: Add rest of APIs to enable custom binders to perform more exhaustive checks | ||
516 | |||
517 | /// <summary> | ||
518 | /// Marshals arguments for the CreatePatch~ APIs | ||
519 | /// </summary> | ||
520 | [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] | ||
521 | internal class PatchAPIMarshaler : ICustomMarshaler | ||
522 | { | ||
523 | internal static ICustomMarshaler GetInstance(string cookie) | ||
524 | { | ||
525 | return new PatchAPIMarshaler(cookie); | ||
526 | } | ||
527 | |||
528 | private enum MarshalType | ||
529 | { | ||
530 | PATCH_OPTION_DATA, | ||
531 | PATCH_OLD_FILE_INFO_W | ||
532 | }; | ||
533 | private PatchAPIMarshaler.MarshalType marshalType; | ||
534 | |||
535 | private PatchAPIMarshaler(string cookie) | ||
536 | { | ||
537 | this.marshalType = (PatchAPIMarshaler.MarshalType) Enum.Parse(typeof(PatchAPIMarshaler.MarshalType), cookie); | ||
538 | } | ||
539 | |||
540 | // | ||
541 | // Summary: | ||
542 | // Returns the size of the native data to be marshaled. | ||
543 | // | ||
544 | // Returns: | ||
545 | // The size in bytes of the native data. | ||
546 | public int GetNativeDataSize() | ||
547 | { | ||
548 | return Marshal.SizeOf(typeof(IntPtr)); | ||
549 | } | ||
550 | |||
551 | // | ||
552 | // Summary: | ||
553 | // Performs necessary cleanup of the managed data when it is no longer needed. | ||
554 | // | ||
555 | // Parameters: | ||
556 | // ManagedObj: | ||
557 | // The managed object to be destroyed. | ||
558 | public void CleanUpManagedData(object ManagedObj) | ||
559 | { | ||
560 | } | ||
561 | |||
562 | // | ||
563 | // Summary: | ||
564 | // Performs necessary cleanup of the unmanaged data when it is no longer needed. | ||
565 | // | ||
566 | // Parameters: | ||
567 | // pNativeData: | ||
568 | // A pointer to the unmanaged data to be destroyed. | ||
569 | public void CleanUpNativeData(IntPtr pNativeData) | ||
570 | { | ||
571 | if (IntPtr.Zero == pNativeData) | ||
572 | { | ||
573 | return; | ||
574 | } | ||
575 | |||
576 | switch (this.marshalType) | ||
577 | { | ||
578 | case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA: | ||
579 | this.CleanUpPOD(pNativeData); | ||
580 | break; | ||
581 | default: | ||
582 | this.CleanUpPOFI_A(pNativeData); | ||
583 | break; | ||
584 | } | ||
585 | } | ||
586 | |||
587 | // | ||
588 | // Summary: | ||
589 | // Converts the managed data to unmanaged data. | ||
590 | // | ||
591 | // Parameters: | ||
592 | // ManagedObj: | ||
593 | // The managed object to be converted. | ||
594 | // | ||
595 | // Returns: | ||
596 | // Returns the COM view of the managed object. | ||
597 | public IntPtr MarshalManagedToNative(object ManagedObj) | ||
598 | { | ||
599 | if (null == ManagedObj) | ||
600 | { | ||
601 | return IntPtr.Zero; | ||
602 | } | ||
603 | |||
604 | switch(this.marshalType) | ||
605 | { | ||
606 | case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA: | ||
607 | return this.MarshalPOD(ManagedObj as PatchOptionData); | ||
608 | case PatchAPIMarshaler.MarshalType.PATCH_OLD_FILE_INFO_W: | ||
609 | return this.MarshalPOFIW_A(ManagedObj as PatchOldFileInfoW[]); | ||
610 | default: | ||
611 | throw new InvalidOperationException(); | ||
612 | } | ||
613 | } | ||
614 | |||
615 | |||
616 | // | ||
617 | // Summary: | ||
618 | // Converts the unmanaged data to managed data. | ||
619 | // | ||
620 | // Parameters: | ||
621 | // pNativeData: | ||
622 | // A pointer to the unmanaged data to be wrapped. | ||
623 | // | ||
624 | // Returns: | ||
625 | // Returns the managed view of the COM data. | ||
626 | public object MarshalNativeToManaged(IntPtr pNativeData) | ||
627 | { | ||
628 | return null; | ||
629 | } | ||
630 | |||
631 | // Implementation ************************************************* | ||
632 | |||
633 | // PATCH_OPTION_DATA offsets | ||
634 | private static readonly int symbolOptionFlagsOffset = Marshal.SizeOf(typeof(Int32)); | ||
635 | private static readonly int newFileSymbolPathOffset = 2*Marshal.SizeOf(typeof(Int32)); | ||
636 | private static readonly int oldFileSymbolPathArrayOffset = 2*Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr)); | ||
637 | private static readonly int extendedOptionFlagsOffset = 2*Marshal.SizeOf(typeof(Int32)) + 2*Marshal.SizeOf(typeof(IntPtr)); | ||
638 | private static readonly int symLoadCallbackOffset = 3*Marshal.SizeOf(typeof(Int32)) + 2*Marshal.SizeOf(typeof(IntPtr)); | ||
639 | private static readonly int symLoadContextOffset = 3*Marshal.SizeOf(typeof(Int32)) + 3*Marshal.SizeOf(typeof(IntPtr)); | ||
640 | private static readonly int interleaveMapArrayOffset = 3*Marshal.SizeOf(typeof(Int32)) + 4*Marshal.SizeOf(typeof(IntPtr)); | ||
641 | private static readonly int maxLzxWindowSizeOffset = 3*Marshal.SizeOf(typeof(Int32)) + 5*Marshal.SizeOf(typeof(IntPtr)); | ||
642 | private static readonly int patchOptionDataSize = 4*Marshal.SizeOf(typeof(Int32)) + 5*Marshal.SizeOf(typeof(IntPtr)); | ||
643 | |||
644 | // PATCH_OLD_FILE_INFO offsets | ||
645 | private static readonly int oldFileOffset = Marshal.SizeOf(typeof(Int32)); | ||
646 | private static readonly int ignoreRangeCountOffset = Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr)); | ||
647 | private static readonly int ignoreRangeArrayOffset = 2*Marshal.SizeOf(typeof(Int32)) + Marshal.SizeOf(typeof(IntPtr)); | ||
648 | private static readonly int retainRangeCountOffset = 2*Marshal.SizeOf(typeof(Int32)) + 2*Marshal.SizeOf(typeof(IntPtr)); | ||
649 | private static readonly int retainRangeArrayOffset = 3*Marshal.SizeOf(typeof(Int32)) + 2*Marshal.SizeOf(typeof(IntPtr)); | ||
650 | private static readonly int patchOldFileInfoSize = 3*Marshal.SizeOf(typeof(Int32)) + 3*Marshal.SizeOf(typeof(IntPtr)); | ||
651 | |||
652 | // Methods and data used to preserve data needed for cleanup | ||
653 | |||
654 | // This dictionary holds the quantity of items internal to each native structure that will need to be freed (the OldFileCount) | ||
655 | private static readonly Dictionary<IntPtr, int> OldFileCounts = new Dictionary<IntPtr, int>(); | ||
656 | private static readonly object OldFileCountsLock = new object(); | ||
657 | |||
658 | private IntPtr CreateMainStruct(int oldFileCount) | ||
659 | { | ||
660 | int nativeSize; | ||
661 | switch(this.marshalType) | ||
662 | { | ||
663 | case PatchAPIMarshaler.MarshalType.PATCH_OPTION_DATA: | ||
664 | nativeSize = patchOptionDataSize; | ||
665 | break; | ||
666 | case PatchAPIMarshaler.MarshalType.PATCH_OLD_FILE_INFO_W: | ||
667 | nativeSize = oldFileCount*patchOldFileInfoSize; | ||
668 | break; | ||
669 | default: | ||
670 | throw new InvalidOperationException(); | ||
671 | } | ||
672 | |||
673 | IntPtr native = Marshal.AllocCoTaskMem(nativeSize); | ||
674 | |||
675 | lock (PatchAPIMarshaler.OldFileCountsLock) | ||
676 | { | ||
677 | PatchAPIMarshaler.OldFileCounts.Add(native, oldFileCount); | ||
678 | } | ||
679 | |||
680 | return native; | ||
681 | } | ||
682 | |||
683 | private static void ReleaseMainStruct(IntPtr native) | ||
684 | { | ||
685 | lock (PatchAPIMarshaler.OldFileCountsLock) | ||
686 | { | ||
687 | PatchAPIMarshaler.OldFileCounts.Remove(native); | ||
688 | } | ||
689 | Marshal.FreeCoTaskMem(native); | ||
690 | } | ||
691 | |||
692 | private static int GetOldFileCount(IntPtr native) | ||
693 | { | ||
694 | lock (PatchAPIMarshaler.OldFileCountsLock) | ||
695 | { | ||
696 | return PatchAPIMarshaler.OldFileCounts[native]; | ||
697 | } | ||
698 | } | ||
699 | |||
700 | // Helper methods | ||
701 | |||
702 | private static IntPtr OptionalAnsiString(string managed) | ||
703 | { | ||
704 | return (null == managed) ? IntPtr.Zero : Marshal.StringToCoTaskMemAnsi(managed); | ||
705 | } | ||
706 | |||
707 | private static IntPtr OptionalUnicodeString(string managed) | ||
708 | { | ||
709 | return (null == managed) ? IntPtr.Zero : Marshal.StringToCoTaskMemUni(managed); | ||
710 | } | ||
711 | |||
712 | // string array must be of the same length as the number of old files | ||
713 | private static IntPtr CreateArrayOfStringA(string[] managed) | ||
714 | { | ||
715 | if (null == managed) | ||
716 | { | ||
717 | return IntPtr.Zero; | ||
718 | } | ||
719 | |||
720 | int size = managed.Length * Marshal.SizeOf(typeof(IntPtr)); | ||
721 | IntPtr native = Marshal.AllocCoTaskMem(size); | ||
722 | |||
723 | for (int i = 0; i < managed.Length; ++i) | ||
724 | { | ||
725 | Marshal.WriteIntPtr(native, i*Marshal.SizeOf(typeof(IntPtr)), OptionalAnsiString(managed[i])); | ||
726 | } | ||
727 | |||
728 | return native; | ||
729 | } | ||
730 | |||
731 | // string array must be of the same length as the number of old files | ||
732 | private static IntPtr CreateArrayOfStringW(string[] managed) | ||
733 | { | ||
734 | if (null == managed) | ||
735 | { | ||
736 | return IntPtr.Zero; | ||
737 | } | ||
738 | |||
739 | int size = managed.Length * Marshal.SizeOf(typeof(IntPtr)); | ||
740 | IntPtr native = Marshal.AllocCoTaskMem(size); | ||
741 | |||
742 | for (int i = 0; i < managed.Length; ++i) | ||
743 | { | ||
744 | Marshal.WriteIntPtr(native, i*Marshal.SizeOf(typeof(IntPtr)), OptionalUnicodeString(managed[i])); | ||
745 | } | ||
746 | |||
747 | return native; | ||
748 | } | ||
749 | |||
750 | private static IntPtr CreateInterleaveMapRange(PatchInterleaveMap managed) | ||
751 | { | ||
752 | if (null == managed) | ||
753 | { | ||
754 | return IntPtr.Zero; | ||
755 | } | ||
756 | |||
757 | if (null == managed.ranges) | ||
758 | { | ||
759 | return IntPtr.Zero; | ||
760 | } | ||
761 | |||
762 | if (0 == managed.ranges.Length) | ||
763 | { | ||
764 | return IntPtr.Zero; | ||
765 | } | ||
766 | |||
767 | IntPtr native = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(UInt32)) | ||
768 | + managed.ranges.Length*(Marshal.SizeOf(typeof(PatchInterleaveMap)))); | ||
769 | WriteUInt32(native, (uint) managed.ranges.Length); | ||
770 | |||
771 | for (int i = 0; i < managed.ranges.Length; ++i) | ||
772 | { | ||
773 | Marshal.StructureToPtr(managed.ranges[i], (IntPtr)((Int64)native + i*Marshal.SizeOf(typeof(PatchInterleaveMap))), false); | ||
774 | } | ||
775 | return native; | ||
776 | } | ||
777 | |||
778 | private static IntPtr CreateInterleaveMap(PatchInterleaveMap[] managed) | ||
779 | { | ||
780 | if (null == managed) | ||
781 | { | ||
782 | return IntPtr.Zero; | ||
783 | } | ||
784 | |||
785 | IntPtr native = Marshal.AllocCoTaskMem(managed.Length * Marshal.SizeOf(typeof(IntPtr))); | ||
786 | |||
787 | for (int i = 0; i < managed.Length; ++i) | ||
788 | { | ||
789 | Marshal.WriteIntPtr(native, i*Marshal.SizeOf(typeof(IntPtr)), CreateInterleaveMapRange(managed[i])); | ||
790 | } | ||
791 | |||
792 | return native; | ||
793 | } | ||
794 | |||
795 | private static void WriteUInt32(IntPtr native, uint data) | ||
796 | { | ||
797 | Marshal.WriteInt32(native, unchecked((int) data)); | ||
798 | } | ||
799 | |||
800 | private static void WriteUInt32(IntPtr native, int offset, uint data) | ||
801 | { | ||
802 | Marshal.WriteInt32(native, offset, unchecked((int) data)); | ||
803 | } | ||
804 | |||
805 | // Marshal operations | ||
806 | |||
807 | private IntPtr MarshalPOD(PatchOptionData managed) | ||
808 | { | ||
809 | if (null == managed) | ||
810 | { | ||
811 | throw new ArgumentNullException("managed"); | ||
812 | } | ||
813 | |||
814 | IntPtr native = this.CreateMainStruct(managed.oldFileSymbolPathArray.Length); | ||
815 | Marshal.WriteInt32(native, patchOptionDataSize); // SizeOfThisStruct | ||
816 | WriteUInt32(native, symbolOptionFlagsOffset, (uint) managed.symbolOptionFlags); | ||
817 | Marshal.WriteIntPtr(native, newFileSymbolPathOffset, PatchAPIMarshaler.OptionalAnsiString(managed.newFileSymbolPath)); | ||
818 | Marshal.WriteIntPtr(native, oldFileSymbolPathArrayOffset, PatchAPIMarshaler.CreateArrayOfStringA(managed.oldFileSymbolPathArray)); | ||
819 | WriteUInt32(native, extendedOptionFlagsOffset, managed.extendedOptionFlags); | ||
820 | |||
821 | // GetFunctionPointerForDelegate() throws an ArgumentNullException if the delegate is null. | ||
822 | if (null == managed.symLoadCallback) | ||
823 | { | ||
824 | Marshal.WriteIntPtr(native, symLoadCallbackOffset, IntPtr.Zero); | ||
825 | } | ||
826 | else | ||
827 | { | ||
828 | Marshal.WriteIntPtr(native, symLoadCallbackOffset, Marshal.GetFunctionPointerForDelegate(managed.symLoadCallback)); | ||
829 | } | ||
830 | |||
831 | Marshal.WriteIntPtr(native, symLoadContextOffset, managed.symLoadContext); | ||
832 | Marshal.WriteIntPtr(native, interleaveMapArrayOffset, PatchAPIMarshaler.CreateInterleaveMap(managed.interleaveMapArray)); | ||
833 | WriteUInt32(native, maxLzxWindowSizeOffset, managed.maxLzxWindowSize); | ||
834 | return native; | ||
835 | } | ||
836 | |||
837 | private IntPtr MarshalPOFIW_A(PatchOldFileInfoW[] managed) | ||
838 | { | ||
839 | if (null == managed) | ||
840 | { | ||
841 | throw new ArgumentNullException("managed"); | ||
842 | } | ||
843 | |||
844 | if (0 == managed.Length) | ||
845 | { | ||
846 | return IntPtr.Zero; | ||
847 | } | ||
848 | |||
849 | IntPtr native = this.CreateMainStruct(managed.Length); | ||
850 | |||
851 | for (int i = 0; i < managed.Length; ++i) | ||
852 | { | ||
853 | PatchAPIMarshaler.MarshalPOFIW(managed[i], (IntPtr)((Int64)native + i * patchOldFileInfoSize)); | ||
854 | } | ||
855 | |||
856 | return native; | ||
857 | } | ||
858 | |||
859 | private static void MarshalPOFIW(PatchOldFileInfoW managed, IntPtr native) | ||
860 | { | ||
861 | PatchAPIMarshaler.MarshalPOFI(managed, native); | ||
862 | Marshal.WriteIntPtr(native, oldFileOffset, PatchAPIMarshaler.OptionalUnicodeString(managed.oldFileName)); // OldFileName | ||
863 | } | ||
864 | |||
865 | private static void MarshalPOFI(PatchOldFileInfo managed, IntPtr native) | ||
866 | { | ||
867 | Marshal.WriteInt32(native, patchOldFileInfoSize); // SizeOfThisStruct | ||
868 | WriteUInt32(native, ignoreRangeCountOffset, | ||
869 | (null == managed.ignoreRange) ? 0 : (uint) managed.ignoreRange.Length); // IgnoreRangeCount // maximum 255 | ||
870 | Marshal.WriteIntPtr(native, ignoreRangeArrayOffset, MarshalPIRArray(managed.ignoreRange)); // IgnoreRangeArray | ||
871 | WriteUInt32(native, retainRangeCountOffset, | ||
872 | (null == managed.retainRange) ? 0 : (uint) managed.retainRange.Length); // RetainRangeCount // maximum 255 | ||
873 | Marshal.WriteIntPtr(native, retainRangeArrayOffset, MarshalPRRArray(managed.retainRange)); // RetainRangeArray | ||
874 | } | ||
875 | |||
876 | private static IntPtr MarshalPIRArray(PatchIgnoreRange[] array) | ||
877 | { | ||
878 | if (null == array) | ||
879 | { | ||
880 | return IntPtr.Zero; | ||
881 | } | ||
882 | |||
883 | if (0 == array.Length) | ||
884 | { | ||
885 | return IntPtr.Zero; | ||
886 | } | ||
887 | |||
888 | IntPtr native = Marshal.AllocCoTaskMem(array.Length*Marshal.SizeOf(typeof(PatchIgnoreRange))); | ||
889 | |||
890 | for (int i = 0; i < array.Length; ++i) | ||
891 | { | ||
892 | Marshal.StructureToPtr(array[i], (IntPtr)((Int64)native + (i*Marshal.SizeOf(typeof(PatchIgnoreRange)))), false); | ||
893 | } | ||
894 | |||
895 | return native; | ||
896 | } | ||
897 | |||
898 | private static IntPtr MarshalPRRArray(PatchRetainRange[] array) | ||
899 | { | ||
900 | if (null == array) | ||
901 | { | ||
902 | return IntPtr.Zero; | ||
903 | } | ||
904 | |||
905 | if (0 == array.Length) | ||
906 | { | ||
907 | return IntPtr.Zero; | ||
908 | } | ||
909 | |||
910 | IntPtr native = Marshal.AllocCoTaskMem(array.Length*Marshal.SizeOf(typeof(PatchRetainRange))); | ||
911 | |||
912 | for (int i = 0; i < array.Length; ++i) | ||
913 | { | ||
914 | Marshal.StructureToPtr(array[i], (IntPtr)((Int64)native + (i*Marshal.SizeOf(typeof(PatchRetainRange)))), false); | ||
915 | } | ||
916 | |||
917 | return native; | ||
918 | } | ||
919 | |||
920 | // CleanUp operations | ||
921 | |||
922 | private void CleanUpPOD(IntPtr native) | ||
923 | { | ||
924 | Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, newFileSymbolPathOffset)); | ||
925 | |||
926 | if (IntPtr.Zero != Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset)) | ||
927 | { | ||
928 | for (int i = 0; i < GetOldFileCount(native); ++i) | ||
929 | { | ||
930 | Marshal.FreeCoTaskMem( | ||
931 | Marshal.ReadIntPtr( | ||
932 | Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset), | ||
933 | i*Marshal.SizeOf(typeof(IntPtr)))); | ||
934 | } | ||
935 | |||
936 | Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, oldFileSymbolPathArrayOffset)); | ||
937 | } | ||
938 | |||
939 | if (IntPtr.Zero != Marshal.ReadIntPtr(native, interleaveMapArrayOffset)) | ||
940 | { | ||
941 | for (int i = 0; i < GetOldFileCount(native); ++i) | ||
942 | { | ||
943 | Marshal.FreeCoTaskMem( | ||
944 | Marshal.ReadIntPtr( | ||
945 | Marshal.ReadIntPtr(native, interleaveMapArrayOffset), | ||
946 | i*Marshal.SizeOf(typeof(IntPtr)))); | ||
947 | } | ||
948 | |||
949 | Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, interleaveMapArrayOffset)); | ||
950 | } | ||
951 | |||
952 | PatchAPIMarshaler.ReleaseMainStruct(native); | ||
953 | } | ||
954 | |||
955 | private void CleanUpPOFI_A(IntPtr native) | ||
956 | { | ||
957 | for (int i = 0; i < GetOldFileCount(native); ++i) | ||
958 | { | ||
959 | PatchAPIMarshaler.CleanUpPOFI((IntPtr)((Int64)native + i*patchOldFileInfoSize)); | ||
960 | } | ||
961 | |||
962 | PatchAPIMarshaler.ReleaseMainStruct(native); | ||
963 | } | ||
964 | |||
965 | private static void CleanUpPOFI(IntPtr native) | ||
966 | { | ||
967 | if (IntPtr.Zero != Marshal.ReadIntPtr(native, oldFileOffset)) | ||
968 | { | ||
969 | Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, oldFileOffset)); | ||
970 | } | ||
971 | |||
972 | PatchAPIMarshaler.CleanUpPOFIH(native); | ||
973 | } | ||
974 | |||
975 | private static void CleanUpPOFIH(IntPtr native) | ||
976 | { | ||
977 | if (IntPtr.Zero != Marshal.ReadIntPtr(native, ignoreRangeArrayOffset)) | ||
978 | { | ||
979 | Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, ignoreRangeArrayOffset)); | ||
980 | } | ||
981 | |||
982 | if (IntPtr.Zero != Marshal.ReadIntPtr(native, retainRangeArrayOffset)) | ||
983 | { | ||
984 | Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(native, retainRangeArrayOffset)); | ||
985 | } | ||
986 | } | ||
987 | } | ||
988 | } | ||
989 | } | ||