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