diff options
Diffstat (limited to '')
-rw-r--r-- | src/dtf/WixToolset.Dtf.WindowsInstaller/Exceptions.cs | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/src/dtf/WixToolset.Dtf.WindowsInstaller/Exceptions.cs b/src/dtf/WixToolset.Dtf.WindowsInstaller/Exceptions.cs new file mode 100644 index 00000000..4954cda0 --- /dev/null +++ b/src/dtf/WixToolset.Dtf.WindowsInstaller/Exceptions.cs | |||
@@ -0,0 +1,573 @@ | |||
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.Dtf.WindowsInstaller | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using System.Text; | ||
8 | using System.Collections.Generic; | ||
9 | using System.Globalization; | ||
10 | using System.Runtime.Serialization; | ||
11 | using System.Diagnostics.CodeAnalysis; | ||
12 | |||
13 | /// <summary> | ||
14 | /// Base class for Windows Installer exceptions. | ||
15 | /// </summary> | ||
16 | [Serializable] | ||
17 | public class InstallerException : SystemException | ||
18 | { | ||
19 | private int errorCode; | ||
20 | private object[] errorData; | ||
21 | |||
22 | /// <summary> | ||
23 | /// Creates a new InstallerException with a specified error message and a reference to the | ||
24 | /// inner exception that is the cause of this exception. | ||
25 | /// </summary> | ||
26 | /// <param name="msg">The message that describes the error.</param> | ||
27 | /// <param name="innerException">The exception that is the cause of the current exception. If the | ||
28 | /// innerException parameter is not a null reference (Nothing in Visual Basic), the current exception | ||
29 | /// is raised in a catch block that handles the inner exception.</param> | ||
30 | public InstallerException(string msg, Exception innerException) | ||
31 | : this(0, msg, innerException) | ||
32 | { | ||
33 | } | ||
34 | |||
35 | /// <summary> | ||
36 | /// Creates a new InstallerException with a specified error message. | ||
37 | /// </summary> | ||
38 | /// <param name="msg">The message that describes the error.</param> | ||
39 | public InstallerException(string msg) | ||
40 | : this(0, msg) | ||
41 | { | ||
42 | } | ||
43 | |||
44 | /// <summary> | ||
45 | /// Creates a new InstallerException. | ||
46 | /// </summary> | ||
47 | public InstallerException() | ||
48 | : this(0, null) | ||
49 | { | ||
50 | } | ||
51 | |||
52 | internal InstallerException(int errorCode, string msg, Exception innerException) | ||
53 | : base(msg, innerException) | ||
54 | { | ||
55 | this.errorCode = errorCode; | ||
56 | this.SaveErrorRecord(); | ||
57 | } | ||
58 | |||
59 | internal InstallerException(int errorCode, string msg) | ||
60 | : this(errorCode, msg, null) | ||
61 | { | ||
62 | } | ||
63 | |||
64 | /// <summary> | ||
65 | /// Initializes a new instance of the InstallerException class with serialized data. | ||
66 | /// </summary> | ||
67 | /// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param> | ||
68 | /// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param> | ||
69 | protected InstallerException(SerializationInfo info, StreamingContext context) : base(info, context) | ||
70 | { | ||
71 | if (info == null) | ||
72 | { | ||
73 | throw new ArgumentNullException("info"); | ||
74 | } | ||
75 | |||
76 | this.errorCode = info.GetInt32("msiErrorCode"); | ||
77 | } | ||
78 | |||
79 | /// <summary> | ||
80 | /// Gets the system error code that resulted in this exception, or 0 if not applicable. | ||
81 | /// </summary> | ||
82 | public int ErrorCode | ||
83 | { | ||
84 | get | ||
85 | { | ||
86 | return this.errorCode; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /// <summary> | ||
91 | /// Gets a message that describes the exception. This message may contain detailed | ||
92 | /// formatted error data if it was available. | ||
93 | /// </summary> | ||
94 | public override String Message | ||
95 | { | ||
96 | get | ||
97 | { | ||
98 | string msg = base.Message; | ||
99 | using (Record errorRec = this.GetErrorRecord()) | ||
100 | { | ||
101 | if (errorRec != null) | ||
102 | { | ||
103 | string errorMsg = Installer.GetErrorMessage(errorRec, CultureInfo.InvariantCulture); | ||
104 | msg = Combine(msg, errorMsg); | ||
105 | } | ||
106 | } | ||
107 | return msg; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | /// <summary> | ||
112 | /// Sets the SerializationInfo with information about the exception. | ||
113 | /// </summary> | ||
114 | /// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param> | ||
115 | /// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param> | ||
116 | public override void GetObjectData(SerializationInfo info, StreamingContext context) | ||
117 | { | ||
118 | if (info == null) | ||
119 | { | ||
120 | throw new ArgumentNullException("info"); | ||
121 | } | ||
122 | |||
123 | info.AddValue("msiErrorCode", this.errorCode); | ||
124 | base.GetObjectData(info, context); | ||
125 | } | ||
126 | |||
127 | /// <summary> | ||
128 | /// Gets extended information about the error, or null if no further information | ||
129 | /// is available. | ||
130 | /// </summary> | ||
131 | /// <returns>A Record object. Field 1 of the Record contains the installer | ||
132 | /// message code. Other fields contain data specific to the particular error.</returns> | ||
133 | /// <remarks><p> | ||
134 | /// If the record is passed to <see cref="Session.Message"/>, it is formatted | ||
135 | /// by looking up the string in the current database. If there is no installation | ||
136 | /// session, the formatted error message may be obtained by a query on the Error table using | ||
137 | /// the error code, followed by a call to <see cref="Record.ToString()"/>. | ||
138 | /// Alternatively, the standard MSI message can by retrieved by calling the | ||
139 | /// <see cref="Installer.GetErrorMessage(Record,CultureInfo)"/> method. | ||
140 | /// </p><p> | ||
141 | /// The following methods and properties may report extended error data: | ||
142 | /// <list type="bullet"> | ||
143 | /// <item><see cref="Database"/> (constructor)</item> | ||
144 | /// <item><see cref="Database"/>.<see cref="Database.ApplyTransform(string,TransformErrors)"/></item> | ||
145 | /// <item><see cref="Database"/>.<see cref="Database.Commit"/></item> | ||
146 | /// <item><see cref="Database"/>.<see cref="Database.Execute(string,object[])"/></item> | ||
147 | /// <item><see cref="Database"/>.<see cref="Database.ExecuteQuery(string,object[])"/></item> | ||
148 | /// <item><see cref="Database"/>.<see cref="Database.ExecuteIntegerQuery(string,object[])"/></item> | ||
149 | /// <item><see cref="Database"/>.<see cref="Database.ExecuteStringQuery(string,object[])"/></item> | ||
150 | /// <item><see cref="Database"/>.<see cref="Database.Export"/></item> | ||
151 | /// <item><see cref="Database"/>.<see cref="Database.ExportAll"/></item> | ||
152 | /// <item><see cref="Database"/>.<see cref="Database.GenerateTransform"/></item> | ||
153 | /// <item><see cref="Database"/>.<see cref="Database.Import"/></item> | ||
154 | /// <item><see cref="Database"/>.<see cref="Database.ImportAll"/></item> | ||
155 | /// <item><see cref="Database"/>.<see cref="Database.Merge(Database,string)"/></item> | ||
156 | /// <item><see cref="Database"/>.<see cref="Database.OpenView"/></item> | ||
157 | /// <item><see cref="Database"/>.<see cref="Database.SummaryInfo"/></item> | ||
158 | /// <item><see cref="Database"/>.<see cref="Database.ViewTransform"/></item> | ||
159 | /// <item><see cref="View"/>.<see cref="View.Assign"/></item> | ||
160 | /// <item><see cref="View"/>.<see cref="View.Delete"/></item> | ||
161 | /// <item><see cref="View"/>.<see cref="View.Execute(Record)"/></item> | ||
162 | /// <item><see cref="View"/>.<see cref="View.Insert"/></item> | ||
163 | /// <item><see cref="View"/>.<see cref="View.InsertTemporary"/></item> | ||
164 | /// <item><see cref="View"/>.<see cref="View.Merge"/></item> | ||
165 | /// <item><see cref="View"/>.<see cref="View.Modify"/></item> | ||
166 | /// <item><see cref="View"/>.<see cref="View.Refresh"/></item> | ||
167 | /// <item><see cref="View"/>.<see cref="View.Replace"/></item> | ||
168 | /// <item><see cref="View"/>.<see cref="View.Seek"/></item> | ||
169 | /// <item><see cref="View"/>.<see cref="View.Update"/></item> | ||
170 | /// <item><see cref="View"/>.<see cref="View.Validate"/></item> | ||
171 | /// <item><see cref="View"/>.<see cref="View.ValidateFields"/></item> | ||
172 | /// <item><see cref="View"/>.<see cref="View.ValidateDelete"/></item> | ||
173 | /// <item><see cref="View"/>.<see cref="View.ValidateNew"/></item> | ||
174 | /// <item><see cref="SummaryInfo"/> (constructor)</item> | ||
175 | /// <item><see cref="Record"/>.<see cref="Record.SetStream(int,string)"/></item> | ||
176 | /// <item><see cref="Session"/>.<see cref="Session.SetInstallLevel"/></item> | ||
177 | /// <item><see cref="Session"/>.<see cref="Session.GetSourcePath"/></item> | ||
178 | /// <item><see cref="Session"/>.<see cref="Session.GetTargetPath"/></item> | ||
179 | /// <item><see cref="Session"/>.<see cref="Session.SetTargetPath"/></item> | ||
180 | /// <item><see cref="ComponentInfo"/>.<see cref="ComponentInfo.CurrentState"/></item> | ||
181 | /// <item><see cref="FeatureInfo"/>.<see cref="FeatureInfo.CurrentState"/></item> | ||
182 | /// <item><see cref="FeatureInfo"/>.<see cref="FeatureInfo.ValidStates"/></item> | ||
183 | /// <item><see cref="FeatureInfo"/>.<see cref="FeatureInfo.GetCost"/></item> | ||
184 | /// </list> | ||
185 | /// </p><p> | ||
186 | /// The Record object should be <see cref="InstallerHandle.Close"/>d after use. | ||
187 | /// It is best that the handle be closed manually as soon as it is no longer | ||
188 | /// needed, as leaving lots of unused handles open can degrade performance. | ||
189 | /// </p><p> | ||
190 | /// Win32 MSI API: | ||
191 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msigetlasterrorrecord.asp">MsiGetLastErrorRecord</a> | ||
192 | /// </p></remarks> | ||
193 | [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] | ||
194 | public Record GetErrorRecord() | ||
195 | { | ||
196 | return this.errorData != null ? new Record(this.errorData) : null; | ||
197 | } | ||
198 | |||
199 | internal static Exception ExceptionFromReturnCode(uint errorCode) | ||
200 | { | ||
201 | return ExceptionFromReturnCode(errorCode, null); | ||
202 | } | ||
203 | |||
204 | internal static Exception ExceptionFromReturnCode(uint errorCode, string msg) | ||
205 | { | ||
206 | msg = Combine(GetSystemMessage(errorCode), msg); | ||
207 | switch (errorCode) | ||
208 | { | ||
209 | case (uint) NativeMethods.Error.FILE_NOT_FOUND: | ||
210 | case (uint) NativeMethods.Error.PATH_NOT_FOUND: return new FileNotFoundException(msg); | ||
211 | |||
212 | case (uint) NativeMethods.Error.INVALID_PARAMETER: | ||
213 | case (uint) NativeMethods.Error.DIRECTORY: | ||
214 | case (uint) NativeMethods.Error.UNKNOWN_PROPERTY: | ||
215 | case (uint) NativeMethods.Error.UNKNOWN_PRODUCT: | ||
216 | case (uint) NativeMethods.Error.UNKNOWN_FEATURE: | ||
217 | case (uint) NativeMethods.Error.UNKNOWN_COMPONENT: return new ArgumentException(msg); | ||
218 | |||
219 | case (uint) NativeMethods.Error.BAD_QUERY_SYNTAX: return new BadQuerySyntaxException(msg); | ||
220 | |||
221 | case (uint) NativeMethods.Error.INVALID_HANDLE_STATE: | ||
222 | case (uint) NativeMethods.Error.INVALID_HANDLE: | ||
223 | InvalidHandleException ihex = new InvalidHandleException(msg); | ||
224 | ihex.errorCode = (int) errorCode; | ||
225 | return ihex; | ||
226 | |||
227 | case (uint) NativeMethods.Error.INSTALL_USEREXIT: return new InstallCanceledException(msg); | ||
228 | |||
229 | case (uint) NativeMethods.Error.CALL_NOT_IMPLEMENTED: return new NotImplementedException(msg); | ||
230 | |||
231 | default: return new InstallerException((int) errorCode, msg); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | internal static string GetSystemMessage(uint errorCode) | ||
236 | { | ||
237 | const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; | ||
238 | const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; | ||
239 | |||
240 | StringBuilder buf = new StringBuilder(1024); | ||
241 | uint formatCount = NativeMethods.FormatMessage( | ||
242 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | ||
243 | IntPtr.Zero, | ||
244 | (uint) errorCode, | ||
245 | 0, | ||
246 | buf, | ||
247 | (uint) buf.Capacity, | ||
248 | IntPtr.Zero); | ||
249 | |||
250 | if (formatCount != 0) | ||
251 | { | ||
252 | return buf.ToString().Trim(); | ||
253 | } | ||
254 | else | ||
255 | { | ||
256 | return null; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | internal void SaveErrorRecord() | ||
261 | { | ||
262 | // TODO: pass an affinity handle here? | ||
263 | int recordHandle = RemotableNativeMethods.MsiGetLastErrorRecord(0); | ||
264 | if (recordHandle != 0) | ||
265 | { | ||
266 | using (Record errorRec = new Record((IntPtr) recordHandle, true, null)) | ||
267 | { | ||
268 | this.errorData = new object[errorRec.FieldCount]; | ||
269 | for (int i = 0; i < this.errorData.Length; i++) | ||
270 | { | ||
271 | this.errorData[i] = errorRec[i + 1]; | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | else | ||
276 | { | ||
277 | this.errorData = null; | ||
278 | } | ||
279 | } | ||
280 | |||
281 | private static string Combine(string msg1, string msg2) | ||
282 | { | ||
283 | if (msg1 == null) return msg2; | ||
284 | if (msg2 == null) return msg1; | ||
285 | return msg1 + " " + msg2; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | /// <summary> | ||
290 | /// User Canceled the installation. | ||
291 | /// </summary> | ||
292 | [Serializable] | ||
293 | public class InstallCanceledException : InstallerException | ||
294 | { | ||
295 | /// <summary> | ||
296 | /// Creates a new InstallCanceledException with a specified error message and a reference to the | ||
297 | /// inner exception that is the cause of this exception. | ||
298 | /// </summary> | ||
299 | /// <param name="msg">The message that describes the error.</param> | ||
300 | /// <param name="innerException">The exception that is the cause of the current exception. If the | ||
301 | /// innerException parameter is not a null reference (Nothing in Visual Basic), the current exception | ||
302 | /// is raised in a catch block that handles the inner exception.</param> | ||
303 | public InstallCanceledException(string msg, Exception innerException) | ||
304 | : base((int) NativeMethods.Error.INSTALL_USEREXIT, msg, innerException) | ||
305 | { | ||
306 | } | ||
307 | |||
308 | /// <summary> | ||
309 | /// Creates a new InstallCanceledException with a specified error message. | ||
310 | /// </summary> | ||
311 | /// <param name="msg">The message that describes the error.</param> | ||
312 | public InstallCanceledException(string msg) | ||
313 | : this(msg, null) | ||
314 | { | ||
315 | } | ||
316 | |||
317 | /// <summary> | ||
318 | /// Creates a new InstallCanceledException. | ||
319 | /// </summary> | ||
320 | public InstallCanceledException() | ||
321 | : this(null, null) | ||
322 | { | ||
323 | } | ||
324 | |||
325 | /// <summary> | ||
326 | /// Initializes a new instance of the InstallCanceledException class with serialized data. | ||
327 | /// </summary> | ||
328 | /// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param> | ||
329 | /// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param> | ||
330 | protected InstallCanceledException(SerializationInfo info, StreamingContext context) | ||
331 | : base(info, context) | ||
332 | { | ||
333 | } | ||
334 | } | ||
335 | |||
336 | /// <summary> | ||
337 | /// A bad SQL query string was passed to <see cref="Database.OpenView"/> or <see cref="Database.Execute(string,object[])"/>. | ||
338 | /// </summary> | ||
339 | [Serializable] | ||
340 | public class BadQuerySyntaxException : InstallerException | ||
341 | { | ||
342 | /// <summary> | ||
343 | /// Creates a new BadQuerySyntaxException with a specified error message and a reference to the | ||
344 | /// inner exception that is the cause of this exception. | ||
345 | /// </summary> | ||
346 | /// <param name="msg">The message that describes the error.</param> | ||
347 | /// <param name="innerException">The exception that is the cause of the current exception. If the | ||
348 | /// innerException parameter is not a null reference (Nothing in Visual Basic), the current exception | ||
349 | /// is raised in a catch block that handles the inner exception.</param> | ||
350 | public BadQuerySyntaxException(string msg, Exception innerException) | ||
351 | : base((int) NativeMethods.Error.BAD_QUERY_SYNTAX, msg, innerException) | ||
352 | { | ||
353 | } | ||
354 | |||
355 | /// <summary> | ||
356 | /// Creates a new BadQuerySyntaxException with a specified error message. | ||
357 | /// </summary> | ||
358 | /// <param name="msg">The message that describes the error.</param> | ||
359 | public BadQuerySyntaxException(string msg) | ||
360 | : this(msg, null) | ||
361 | { | ||
362 | } | ||
363 | |||
364 | /// <summary> | ||
365 | /// Creates a new BadQuerySyntaxException. | ||
366 | /// </summary> | ||
367 | public BadQuerySyntaxException() | ||
368 | : this(null, null) | ||
369 | { | ||
370 | } | ||
371 | |||
372 | /// <summary> | ||
373 | /// Initializes a new instance of the BadQuerySyntaxException class with serialized data. | ||
374 | /// </summary> | ||
375 | /// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param> | ||
376 | /// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param> | ||
377 | protected BadQuerySyntaxException(SerializationInfo info, StreamingContext context) | ||
378 | : base(info, context) | ||
379 | { | ||
380 | } | ||
381 | } | ||
382 | |||
383 | /// <summary> | ||
384 | /// A method was called on an invalid installer handle. The handle may have been already closed. | ||
385 | /// </summary> | ||
386 | [Serializable] | ||
387 | public class InvalidHandleException : InstallerException | ||
388 | { | ||
389 | /// <summary> | ||
390 | /// Creates a new InvalidHandleException with a specified error message and a reference to the | ||
391 | /// inner exception that is the cause of this exception. | ||
392 | /// </summary> | ||
393 | /// <param name="msg">The message that describes the error.</param> | ||
394 | /// <param name="innerException">The exception that is the cause of the current exception. If the | ||
395 | /// innerException parameter is not a null reference (Nothing in Visual Basic), the current exception | ||
396 | /// is raised in a catch block that handles the inner exception.</param> | ||
397 | public InvalidHandleException(string msg, Exception innerException) | ||
398 | : base((int) NativeMethods.Error.INVALID_HANDLE, msg, innerException) | ||
399 | { | ||
400 | } | ||
401 | |||
402 | /// <summary> | ||
403 | /// Creates a new InvalidHandleException with a specified error message. | ||
404 | /// </summary> | ||
405 | /// <param name="msg">The message that describes the error.</param> | ||
406 | public InvalidHandleException(string msg) | ||
407 | : this(msg, null) | ||
408 | { | ||
409 | } | ||
410 | |||
411 | /// <summary> | ||
412 | /// Creates a new InvalidHandleException. | ||
413 | /// </summary> | ||
414 | public InvalidHandleException() | ||
415 | : this(null, null) | ||
416 | { | ||
417 | } | ||
418 | |||
419 | /// <summary> | ||
420 | /// Initializes a new instance of the InvalidHandleException class with serialized data. | ||
421 | /// </summary> | ||
422 | /// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param> | ||
423 | /// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param> | ||
424 | protected InvalidHandleException(SerializationInfo info, StreamingContext context) | ||
425 | : base(info, context) | ||
426 | { | ||
427 | } | ||
428 | } | ||
429 | |||
430 | /// <summary> | ||
431 | /// A failure occurred when executing <see cref="Database.Merge(Database,string)"/>. The exception may contain | ||
432 | /// details about the merge conflict. | ||
433 | /// </summary> | ||
434 | [Serializable] | ||
435 | public class MergeException : InstallerException | ||
436 | { | ||
437 | private IList<string> conflictTables; | ||
438 | private IList<int> conflictCounts; | ||
439 | |||
440 | /// <summary> | ||
441 | /// Creates a new MergeException with a specified error message and a reference to the | ||
442 | /// inner exception that is the cause of this exception. | ||
443 | /// </summary> | ||
444 | /// <param name="msg">The message that describes the error.</param> | ||
445 | /// <param name="innerException">The exception that is the cause of the current exception. If the | ||
446 | /// innerException parameter is not a null reference (Nothing in Visual Basic), the current exception | ||
447 | /// is raised in a catch block that handles the inner exception.</param> | ||
448 | public MergeException(string msg, Exception innerException) | ||
449 | : base(msg, innerException) | ||
450 | { | ||
451 | } | ||
452 | |||
453 | /// <summary> | ||
454 | /// Creates a new MergeException with a specified error message. | ||
455 | /// </summary> | ||
456 | /// <param name="msg">The message that describes the error.</param> | ||
457 | public MergeException(string msg) | ||
458 | : base(msg) | ||
459 | { | ||
460 | } | ||
461 | |||
462 | /// <summary> | ||
463 | /// Creates a new MergeException. | ||
464 | /// </summary> | ||
465 | public MergeException() | ||
466 | : base() | ||
467 | { | ||
468 | } | ||
469 | |||
470 | internal MergeException(Database db, string conflictsTableName) | ||
471 | : base("Merge failed.") | ||
472 | { | ||
473 | if (conflictsTableName != null) | ||
474 | { | ||
475 | IList<string> conflictTableList = new List<string>(); | ||
476 | IList<int> conflictCountList = new List<int>(); | ||
477 | |||
478 | using (View view = db.OpenView("SELECT `Table`, `NumRowMergeConflicts` FROM `" + conflictsTableName + "`")) | ||
479 | { | ||
480 | view.Execute(); | ||
481 | |||
482 | foreach (Record rec in view) using (rec) | ||
483 | { | ||
484 | conflictTableList.Add(rec.GetString(1)); | ||
485 | conflictCountList.Add((int) rec.GetInteger(2)); | ||
486 | } | ||
487 | } | ||
488 | |||
489 | this.conflictTables = conflictTableList; | ||
490 | this.conflictCounts = conflictCountList; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | /// <summary> | ||
495 | /// Initializes a new instance of the MergeException class with serialized data. | ||
496 | /// </summary> | ||
497 | /// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param> | ||
498 | /// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param> | ||
499 | protected MergeException(SerializationInfo info, StreamingContext context) : base(info, context) | ||
500 | { | ||
501 | if (info == null) | ||
502 | { | ||
503 | throw new ArgumentNullException("info"); | ||
504 | } | ||
505 | |||
506 | this.conflictTables = (string[]) info.GetValue("mergeConflictTables", typeof(string[])); | ||
507 | this.conflictCounts = (int[]) info.GetValue("mergeConflictCounts", typeof(int[])); | ||
508 | } | ||
509 | |||
510 | /// <summary> | ||
511 | /// Gets the number of merge conflicts in each table, corresponding to the tables returned by | ||
512 | /// <see cref="ConflictTables"/>. | ||
513 | /// </summary> | ||
514 | public IList<int> ConflictCounts | ||
515 | { | ||
516 | get | ||
517 | { | ||
518 | return new List<int>(this.conflictCounts); | ||
519 | } | ||
520 | } | ||
521 | |||
522 | /// <summary> | ||
523 | /// Gets the list of tables containing merge conflicts. | ||
524 | /// </summary> | ||
525 | public IList<string> ConflictTables | ||
526 | { | ||
527 | get | ||
528 | { | ||
529 | return new List<string>(this.conflictTables); | ||
530 | } | ||
531 | } | ||
532 | |||
533 | /// <summary> | ||
534 | /// Gets a message that describes the merge conflits. | ||
535 | /// </summary> | ||
536 | public override String Message | ||
537 | { | ||
538 | get | ||
539 | { | ||
540 | StringBuilder msg = new StringBuilder(base.Message); | ||
541 | if (this.conflictTables != null) | ||
542 | { | ||
543 | for (int i = 0; i < this.conflictTables.Count; i++) | ||
544 | { | ||
545 | msg.Append(i == 0 ? " Conflicts: " : ", "); | ||
546 | msg.Append(this.conflictTables[i]); | ||
547 | msg.Append('('); | ||
548 | msg.Append(this.conflictCounts[i]); | ||
549 | msg.Append(')'); | ||
550 | } | ||
551 | } | ||
552 | return msg.ToString(); | ||
553 | } | ||
554 | } | ||
555 | |||
556 | /// <summary> | ||
557 | /// Sets the SerializationInfo with information about the exception. | ||
558 | /// </summary> | ||
559 | /// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param> | ||
560 | /// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param> | ||
561 | public override void GetObjectData(SerializationInfo info, StreamingContext context) | ||
562 | { | ||
563 | if (info == null) | ||
564 | { | ||
565 | throw new ArgumentNullException("info"); | ||
566 | } | ||
567 | |||
568 | info.AddValue("mergeConflictTables", this.conflictTables); | ||
569 | info.AddValue("mergeConflictCounts", this.conflictCounts); | ||
570 | base.GetObjectData(info, context); | ||
571 | } | ||
572 | } | ||
573 | } | ||