/// If the record is passed to , it is formatted
/// by looking up the string in the current database. If there is no installation
/// session, the formatted error message may be obtained by a query on the Error table using
/// the error code, followed by a call to .
/// Alternatively, the standard MSI message can by retrieved by calling the
/// method.
///
/// The following methods and properties may report extended error data:
///
/// - (constructor)
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - (constructor)
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
/// - .
///
///
/// The Record object should be d after use.
/// It is best that the handle be closed manually as soon as it is no longer
/// needed, as leaving lots of unused handles open can degrade performance.
///
/// Win32 MSI API:
/// MsiGetLastErrorRecord
///
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
public Record GetErrorRecord()
{
return this.errorData != null ? new Record(this.errorData) : null;
}
internal static Exception ExceptionFromReturnCode(uint errorCode)
{
return ExceptionFromReturnCode(errorCode, null);
}
internal static Exception ExceptionFromReturnCode(uint errorCode, string msg)
{
msg = Combine(GetSystemMessage(errorCode), msg);
switch (errorCode)
{
case (uint) NativeMethods.Error.FILE_NOT_FOUND:
case (uint) NativeMethods.Error.PATH_NOT_FOUND: return new FileNotFoundException(msg);
case (uint) NativeMethods.Error.INVALID_PARAMETER:
case (uint) NativeMethods.Error.DIRECTORY:
case (uint) NativeMethods.Error.UNKNOWN_PROPERTY:
case (uint) NativeMethods.Error.UNKNOWN_PRODUCT:
case (uint) NativeMethods.Error.UNKNOWN_FEATURE:
case (uint) NativeMethods.Error.UNKNOWN_COMPONENT: return new ArgumentException(msg);
case (uint) NativeMethods.Error.BAD_QUERY_SYNTAX: return new BadQuerySyntaxException(msg);
case (uint) NativeMethods.Error.INVALID_HANDLE_STATE:
case (uint) NativeMethods.Error.INVALID_HANDLE:
InvalidHandleException ihex = new InvalidHandleException(msg);
ihex.errorCode = (int) errorCode;
return ihex;
case (uint) NativeMethods.Error.INSTALL_USEREXIT: return new InstallCanceledException(msg);
case (uint) NativeMethods.Error.CALL_NOT_IMPLEMENTED: return new NotImplementedException(msg);
default: return new InstallerException((int) errorCode, msg);
}
}
internal static string GetSystemMessage(uint errorCode)
{
const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
StringBuilder buf = new StringBuilder(1024);
uint formatCount = NativeMethods.FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
IntPtr.Zero,
(uint) errorCode,
0,
buf,
(uint) buf.Capacity,
IntPtr.Zero);
if (formatCount != 0)
{
return buf.ToString().Trim();
}
else
{
return null;
}
}
internal void SaveErrorRecord()
{
// TODO: pass an affinity handle here?
int recordHandle = RemotableNativeMethods.MsiGetLastErrorRecord(0);
if (recordHandle != 0)
{
using (Record errorRec = new Record((IntPtr) recordHandle, true, null))
{
this.errorData = new object[errorRec.FieldCount];
for (int i = 0; i < this.errorData.Length; i++)
{
this.errorData[i] = errorRec[i + 1];
}
}
}
else
{
this.errorData = null;
}
}
private static string Combine(string msg1, string msg2)
{
if (msg1 == null) return msg2;
if (msg2 == null) return msg1;
return msg1 + " " + msg2;
}
}
///