diff options
Diffstat (limited to 'src/dtf/WixToolset.Dtf.WindowsInstaller/Exceptions.cs')
| -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 | } | ||
