这个类的设计背景是:
注意:XlFileFormat.xlExcel8 这个枚举值是从Office PIA 2007中开始出现的,在Office PIA 2003中不存在这个枚举值。
// ----------------------------------------------------------------------- // <copyright file="ExcelApp.cs" company="*****"> // Excel 2007/2010 application interop class. // </copyright> // ----------------------------------------------------------------------- namespace *****.Reporting.Excel { using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Threading; using Excel = Microsoft.Office.Interop.Excel; /// <summary> /// Excel application interop class. /// </summary> public class ExcelApp : IDisposable { #region Const definition /// <summary>Default Excel document file format</summary> private const Excel.XlFileFormat DefaultFileFormat = Excel.XlFileFormat.xlExcel8; /// <summary>Default Excel document SaveAs access mode</summary> private const Excel.XlSaveAsAccessMode DefaultSaveAsAccessMode = Excel.XlSaveAsAccessMode.xlExclusive; /// <summary>Microsoft Excel application process name.</summary> private const string ExcelProcessName = "EXCEL"; #endregion #region Private variables for IDisposable /// <summary>Indicates disposing status.</summary> private bool disposed = false; #endregion #region Private variables /// <summary>Excel application instance.</summary> private Excel.Application app = null; /// <summary>Excel report path.</summary> private string pathName = string.Empty; /// <summary>Excel report file name.</summary> private string fileName = string.Empty; /// <summary>Excel report file format.</summary> private Excel.XlFileFormat currentFileFormat = DefaultFileFormat; /// <summary>Range cursor dictionary.</summary> private Dictionary<string, Excel.Range> rangeCursorDict = new Dictionary<string, Excel.Range>(); /// <summary>Original culture info</summary> private CultureInfo originalCultureInfo = null; /// <summary>Original Excel Application processes before launching new Excel process.</summary> private Process[] originalExcelProcess = null; #endregion #region Initializations and Finalizations /// <summary> /// Initializes a new instance of the ExcelApp class. /// </summary> public ExcelApp() { this.originalCultureInfo = Thread.CurrentThread.CurrentCulture; this.SetCurrentCultureAsENU(); this.originalExcelProcess = Process.GetProcessesByName(ExcelProcessName); } /// <summary> /// Finalizes an instance of the ExcelApp class. /// </summary> ~ExcelApp() { this.Dispose(false); } #endregion #region Properties for IDisposable /// <summary> /// Gets a value indicating whether this instance is disposed. /// </summary> public bool Disposed { get { return this.disposed; } } #endregion #region Properties for Excel Application /// <summary> /// Gets excel application instance. /// </summary> public Excel.Application Application { get { if (this.app == null) { this.app = new Excel.Application(); this.app.Visible = false; } return this.app; } } /// <summary> /// Gets excel report path name /// </summary> public string PathName { get { return this.pathName; } } /// <summary> /// Gets excel report file name /// </summary> public string FileName { get { return this.fileName; } } /// <summary> /// Gets current workbook instance. /// </summary> public Excel.Workbook CurrentWorkbook { get; private set; } /// <summary> /// Gets latest Worksheet instance in last operating. /// </summary> public Excel.Worksheet LatestWorksheet { get; private set; } /// <summary> /// Gets latest Worksheet name in last operating. /// </summary> public string LastWorksheetName { get { return this.LatestWorksheet != null ? this.LatestWorksheet.Name : string.Empty; } } /// <summary> /// Gets current Worksheet instance. /// </summary> public Excel.Worksheet CurrentWorksheet { get; private set; } /// <summary> /// Gets ActiveSheet in current workbook /// </summary> public Excel.Worksheet ActiveWorksheet { get { return this.CurrentWorkbook.ActiveSheet as Excel.Worksheet; } } /// <summary> /// Gets current range instance. /// </summary> public Excel.Range CurrentRange { get; private set; } #endregion #region IDisposable members /// <summary> /// Close method. /// </summary> public void Close() { if (this.app != null) { this.app.Quit(); this.CurrentWorksheet = null; this.LatestWorksheet = null; this.CurrentWorkbook = null; this.app = null; } } /// <summary> /// Implement Dispose method in IDisposable /// </summary> public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } #endregion #region Public Excel methods - Workbook /// <summary> /// Creates the excel doc. /// </summary> /// <param name="fileName">the excel doc filename</param> public void CreateWorkbook(string fileName) { try { this.CurrentWorkbook = this.Application.Workbooks.Add(Excel.XlWBATemplate.xlWBATWorksheet); this.LatestWorksheet = this.CurrentWorkbook.Sheets[1] as Excel.Worksheet; this.CurrentWorksheet = this.LatestWorksheet; string fullPath = this.GetActualFullPath(fileName); this.LatestWorksheet.SaveAs( fullPath, this.currentFileFormat, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Excel.XlSaveAsAccessMode.xlExclusive, Type.Missing /* 28591 */ /* ISO 8859-1 Latin 1; Western European (ISO) */, Type.Missing, Type.Missing); } catch (Exception ex) { this.Dispose(); throw ex; } } /// <summary> /// Save current workbook /// </summary> public void Save() { this.CurrentWorkbook.Save(); } #endregion #region Public Excel methods - Worksheet /// <summary> /// Switch current worksheet to the one with specific name. /// </summary> /// <param name="worksheetName">the specific worksheet's name</param> public void SwitchToWorksheet(string worksheetName) { if (this.CurrentWorkbook == null || this.CurrentWorkbook.Worksheets.Count == 0) { goto EXIT; } foreach (Excel.Worksheet sheet in this.CurrentWorkbook.Worksheets) { if (sheet.Name.Equals(worksheetName)) { this.CurrentWorksheet = sheet; return; } } EXIT: this.CurrentWorksheet = null; return; } /// <summary> /// Switch current worksheet to the one with specific indexer. /// </summary> /// <param name="indexer">the specific worksheet's indexer (start with 1)</param> public void SwitchToWorksheet(int indexer) { if (this.CurrentWorkbook == null || this.CurrentWorkbook.Worksheets.Count == 0) { goto EXIT; } try { this.CurrentWorksheet = this.CurrentWorkbook.Worksheets[indexer] as Excel.Worksheet; } catch { goto EXIT; } EXIT: this.CurrentWorksheet = null; return; } /// <summary> /// Switch current worksheet to the latest one. /// </summary> public void SwitchToLastWorksheet() { this.CurrentWorksheet = this.LatestWorksheet; } /// <summary> /// Rename current worksheet. /// </summary> /// <param name="worksheetName">worksheet name</param> public void RenameWorksheet(string worksheetName) { this.CurrentWorksheet.Name = worksheetName; } /// <summary> /// Create new worksheet and insert it after current worksheet. /// </summary> /// <param name="worksheetName">name of the new worksheet</param> public void AddWorksheetAfter(object worksheetName) { this.LatestWorksheet = this.CurrentWorkbook.Worksheets.Add(Type.Missing, worksheetName, Type.Missing, Type.Missing) as Excel.Worksheet; this.Save(); } /// <summary> /// Create new worksheet and insert it before current worksheet. /// </summary> /// <param name="worksheetName">name of the new worksheet</param> public void AddWorksheetBefore(object worksheetName) { this.LatestWorksheet = this.CurrentWorkbook.Worksheets.Add(worksheetName, Type.Missing, Type.Missing, Type.Missing) as Excel.Worksheet; this.Save(); } /// <summary> /// Active latest worksheet. /// </summary> public void ActiveLastWorksheet() { if (this.LatestWorksheet != null) { ((Excel._Worksheet)this.LatestWorksheet).Activate(); } } #endregion #region Excel methods - Range /// <summary> /// Set current range as specific address in current worksheet. /// Notice: the range address should be provided as string "$E$2:$G$7" or "E2:G7" /// </summary> /// <param name="address">range address</param> public void SetCurrentRange(string address) { this.CurrentRange = !string.IsNullOrEmpty(address) ? this.CurrentWorksheet.get_Range(address, Type.Missing) : this.CurrentWorksheet.Cells; } /// <summary> /// Set offset of current range /// </summary> /// <param name="columnOffset">column offset</param> /// <param name="rowOffset">row offset</param> public void SetCurrentRangeOffset(int? columnOffset, int? rowOffset) { Excel.Range range = this.CurrentRange.get_Offset( rowOffset != null ? (int)rowOffset : Type.Missing, columnOffset != null ? (int)columnOffset : Type.Missing); this.CurrentRange = range; } /// <summary> /// Set current range to rectangle area. /// </summary> /// <param name="columnOffset">column offset to the opposite side</param> /// <param name="rowOffset">row offset to the opposite side</param> public void SetCurrentRangeRectangle(int? columnOffset, int? rowOffset) { this.SetCurrentRangeRectangle(this.GetRangeAddress(this.CurrentRange), columnOffset, rowOffset); } /// <summary> /// Set current range to rectangle area. /// </summary> /// <param name="sideAddress">address of one of the rectangle side</param> /// <param name="columnOffset">column offset to the opposite side</param> /// <param name="rowOffset">row offset to the opposite side</param> public void SetCurrentRangeRectangle(string sideAddress, int? columnOffset, int? rowOffset) { if (columnOffset == null && rowOffset == null) { throw new ArgumentException( "At least one of arguments columnOffset and rowOffset should has value."); } this.SetCurrentRange(sideAddress); Excel.Range range0 = this.CurrentRange; this.SetCurrentRangeOffset(columnOffset, rowOffset); Excel.Range range1 = this.CurrentRange; Excel.Range cell0 = range0.Cells[1, 1] as Excel.Range; Excel.Range cell1 = range1.Cells[range1.Rows.Count, range1.Columns.Count] as Excel.Range; string rectangleAddress = string.Format("{0}:{1}", this.GetRangeAddress(cell0), this.GetRangeAddress(cell1)); this.SetCurrentRange(rectangleAddress); } /// <summary> /// Set or add range to the range cursor dictionary. /// </summary> /// <param name="key">key value</param> /// <param name="address">range address</param> public void SetRangeCursor(string key, string address) { Excel.Range range = !string.IsNullOrEmpty(address) ? this.CurrentWorksheet.get_Range(address, Type.Missing) : this.CurrentWorksheet.Cells; if (this.rangeCursorDict.ContainsKey(key)) { this.rangeCursorDict[key] = range; } else { this.rangeCursorDict.Add(key, range); } } /// <summary> /// Set current range to the value in range cursor. /// </summary> /// <param name="key">range cursor key</param> public void SetCurrentRangeToCursor(string key) { if (this.rangeCursorDict.ContainsKey(key)) { this.CurrentRange = this.rangeCursorDict[key]; } else { throw new ArgumentOutOfRangeException("key"); } if (this.CurrentRange == null) { throw new NullReferenceException( string.Format("The range in cursor[{0}] is NULL.", key)); } } /// <summary> /// Set the value in range cursor to current range. /// </summary> /// <param name="key">range cursor key</param> public void SetCursorToCurrentRange(string key) { if (this.CurrentRange == null) { throw new NullReferenceException( string.Format("The range in cursor[{0}] is NULL.", key)); } if (this.rangeCursorDict.ContainsKey(key)) { this.rangeCursorDict[key] = this.CurrentRange; } else { this.rangeCursorDict.Add(key, this.CurrentRange); } } /// <summary> /// Clear range cursor /// </summary> public void RangeCursorClear() { this.rangeCursorDict.Clear(); } /// <summary> /// Remove specific item in range cursor. /// </summary> /// <param name="key">cursor key</param> public void RangeCursorClear(string key) { if (this.rangeCursorDict.ContainsKey(key)) { this.rangeCursorDict.Remove(key); } } /// <summary> /// Set cells size in current range. /// </summary> /// <param name="columnWidth">column width (in points)</param> /// <param name="rowHeight">row height (in points)</param> public void SetRangeCellsSize(float? columnWidth, float? rowHeight) { if (columnWidth != null) { this.CurrentRange.ColumnWidth = (float)columnWidth; } if (rowHeight != null) { this.CurrentRange.RowHeight = (float)rowHeight; } } /// <summary> /// Merge cells in current range. /// </summary> public void MergeRange() { this.CurrentRange.Merge(Type.Missing); } /// <summary> /// Merge cells in specific range. /// </summary> /// <param name="address">range address</param> public void MergeRange(string address) { this.SetCurrentRange(address); this.CurrentRange.Merge(Type.Missing); } /// <summary> /// Batch merge cells from original range to offset range. /// </summary> /// <param name="originalAddress">original address</param> /// <param name="columnOffset">column offset value</param> /// <param name="rowOffset">row offset value</param> /// <param name="count">offset times count</param> public void MergeRangeBatch(string originalAddress, int? columnOffset, int? rowOffset, int count) { if (count <= 0) { return; } this.SetCurrentRange(originalAddress); Excel.Range range = this.CurrentRange; Excel.Range nextRange = range; for (int i = 0; i < count; i++) { nextRange = range.get_Offset( rowOffset != null ? (int)rowOffset : Type.Missing, columnOffset != null ? (int)columnOffset : Type.Missing); range.Merge(Type.Missing); range = nextRange; } } /// <summary> /// Batch merge cells from current range to table. /// </summary> /// <param name="rowsCount">rows count</param> /// <param name="columnSeperators">column seperators (indexer base from 0)</param> public void MergeRangeToTable(int rowsCount, params int[] columnSeperators) { this.MergeRangeToTable(this.GetRangeAddress(this.CurrentRange), rowsCount, columnSeperators); } /// <summary> /// Batch merge cells from original range to table. /// </summary> /// <param name="originalAddress">original address</param> /// <param name="rowsCount">rows count</param> /// <param name="columnSeperators">column seperators (indexer base from 0)</param> public void MergeRangeToTable(string originalAddress, int rowsCount, params int[] columnSeperators) { if (rowsCount <= 0) { throw new ArgumentException("rowsCount should be greater than 0.", "rowsCount"); } if (columnSeperators.Length < 2) { throw new ArgumentException( "columnSeperators.Length should be greater than 1.", "columnSeperators.Length"); } for (int i = 0; i < columnSeperators.Length - 1; i++) { if (columnSeperators[i] < 0) { throw new ArgumentException( "Items of columnSeperators should be greater or equal to 0.", string.Format("columnSeperators[{0}]", i)); } } for (int i = 0; i < columnSeperators.Length - 2; i++) { if (columnSeperators[i] >= columnSeperators[i + 1]) { throw new ArgumentException( "Please make sure that columnSeperators are unique and from little to large.", "columnSeperators"); } } Excel.Range range = this.CurrentWorksheet.get_Range(originalAddress, Type.Missing); Excel.Range cellBasePoint = range.Cells[1, 1] as Excel.Range; Excel.Range cell0 = cellBasePoint; Excel.Range cell1 = cellBasePoint; string cellsRangeAddress = null; cell1 = cellBasePoint.get_Offset(0, columnSeperators[columnSeperators.Length - 1] - 1); for (int i = columnSeperators.Length - 2; i >= 0; i--) { cell0 = cellBasePoint.get_Offset(0, columnSeperators[i]); cellsRangeAddress = string.Format("{0}:{1}", this.GetRangeAddress(cell0), this.GetRangeAddress(cell1)); this.MergeRangeBatch(cellsRangeAddress, 0, 1, rowsCount); if (i > 0) { cell1 = cellBasePoint.get_Offset(0, columnSeperators[i] - 1); } } } /// <summary> /// Switch to specific cell in current range /// </summary> /// <param name="columnIndex">cell column index</param> /// <param name="rowIndex">cell row index</param> public void SwitchToRangeCell(int columnIndex, int rowIndex) { Excel.Range cell = this.CurrentRange.Cells[rowIndex, columnIndex] as Excel.Range; this.CurrentRange = cell; } /// <summary> /// select current range. (Make Selection to be current range) /// </summary> public void SelectCurrentRange() { this.CurrentRange.Select(); } #endregion #region Excel methods - Range border /// <summary> /// Set current range boders as outside borders. /// </summary> public void SetRangeBordersAsOutsideBorders() { this.CurrentRange.Borders[Excel.XlBordersIndex.xlDiagonalDown].LineStyle = Excel.XlLineStyle.xlLineStyleNone; this.CurrentRange.Borders[Excel.XlBordersIndex.xlDiagonalUp].LineStyle = Excel.XlLineStyle.xlLineStyleNone; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeLeft].LineStyle = Excel.XlLineStyle.xlContinuous; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeLeft].ColorIndex = 0; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeLeft].Weight = Excel.XlBorderWeight.xlThin; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeTop].LineStyle = Excel.XlLineStyle.xlContinuous; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeTop].ColorIndex = 0; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeTop].Weight = Excel.XlBorderWeight.xlThin; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeBottom].LineStyle = Excel.XlLineStyle.xlContinuous; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeBottom].ColorIndex = 0; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeBottom].Weight = Excel.XlBorderWeight.xlThin; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeRight].LineStyle = Excel.XlLineStyle.xlContinuous; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeRight].ColorIndex = 0; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeRight].Weight = Excel.XlBorderWeight.xlThin; this.CurrentRange.Borders[Excel.XlBordersIndex.xlInsideVertical].LineStyle = Excel.XlLineStyle.xlLineStyleNone; this.CurrentRange.Borders[Excel.XlBordersIndex.xlInsideHorizontal].LineStyle = Excel.XlLineStyle.xlLineStyleNone; } /// <summary> /// Set current range boders as all borders. /// </summary> public void SetRangeBordersAsAllBorders() { this.CurrentRange.Borders[Excel.XlBordersIndex.xlDiagonalDown].LineStyle = Excel.XlLineStyle.xlLineStyleNone; this.CurrentRange.Borders[Excel.XlBordersIndex.xlDiagonalUp].LineStyle = Excel.XlLineStyle.xlLineStyleNone; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeLeft].LineStyle = Excel.XlLineStyle.xlContinuous; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeLeft].ColorIndex = 0; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeLeft].Weight = Excel.XlBorderWeight.xlThin; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeTop].LineStyle = Excel.XlLineStyle.xlContinuous; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeTop].ColorIndex = 0; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeTop].Weight = Excel.XlBorderWeight.xlThin; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeBottom].LineStyle = Excel.XlLineStyle.xlContinuous; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeBottom].ColorIndex = 0; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeBottom].Weight = Excel.XlBorderWeight.xlThin; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeRight].LineStyle = Excel.XlLineStyle.xlContinuous; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeRight].ColorIndex = 0; this.CurrentRange.Borders[Excel.XlBordersIndex.xlEdgeRight].Weight = Excel.XlBorderWeight.xlThin; this.CurrentRange.Borders[Excel.XlBordersIndex.xlInsideVertical].LineStyle = Excel.XlLineStyle.xlContinuous; this.CurrentRange.Borders[Excel.XlBordersIndex.xlInsideVertical].ColorIndex = 0; this.CurrentRange.Borders[Excel.XlBordersIndex.xlInsideVertical].Weight = Excel.XlBorderWeight.xlThin; this.CurrentRange.Borders[Excel.XlBordersIndex.xlInsideHorizontal].LineStyle = Excel.XlLineStyle.xlContinuous; this.CurrentRange.Borders[Excel.XlBordersIndex.xlInsideHorizontal].ColorIndex = 0; this.CurrentRange.Borders[Excel.XlBordersIndex.xlInsideHorizontal].Weight = Excel.XlBorderWeight.xlThin; } #endregion #region Excel methods - Cell Value and Formatting /// <summary> /// Set value to current range /// </summary> /// <param name="value">value to set</param> public void SetValue(string value) { this.CurrentRange.set_Value(Excel.XlRangeValueDataType.xlRangeValueDefault, value); }/// <summary> /// Set range vertical alignment to be Center. /// </summary> public void SetRangeAlign_VerticalCenter() { this.CurrentRange.HorizontalAlignment = Excel.Constants.xlGeneral; this.CurrentRange.VerticalAlignment = Excel.Constants.xlCenter; } /// <summary> /// Set range alignment to be Middle Center. /// </summary> public void SetRangeAlign_MiddleCenter() { this.CurrentRange.HorizontalAlignment = Excel.Constants.xlCenter; this.CurrentRange.VerticalAlignment = Excel.Constants.xlCenter; } /// <summary> /// Set current range format as Text /// </summary> public void SetRangeFormat_Text() { this.SetRangeFormat("@"); } /// <summary> /// Set current range format /// </summary> /// <param name="format">range format</param> public void SetRangeFormat(string format) { this.CurrentRange.NumberFormat = format; } #endregion #region Private methods for IDisposable /// <summary> /// Dispose method /// </summary> /// <param name="disposing">Disposing status</param> protected void Dispose(bool disposing) { if (this.disposed) { return; } if (disposing) { this.Close(); } this.RestoreCurrentCulture(); this.CleanUnhandledAppInstance(); this.disposed = true; } #endregion #region Private methods /// <summary> /// Get actual excel report full path. /// </summary> /// <param name="fileFullPath">inputed full path</param> /// <returns>actual full path</returns> private string GetActualFullPath(string fileFullPath) { this.pathName = Path.GetDirectoryName(fileFullPath); this.fileName = Path.GetFileName(fileFullPath); if (string.IsNullOrEmpty(this.fileName)) { throw new ArgumentException("Excel reporting file name cannot be empty.", "fileFullPath"); } string extName = Path.GetExtension(fileFullPath).ToLower(); if (extName.Equals(".xls")) { this.currentFileFormat = DefaultFileFormat; } else { throw new NotSupportedException(string.Format("the file extension {0} is not supported.", extName)); } if (string.IsNullOrEmpty(this.pathName)) { this.pathName = Environment.CurrentDirectory; } return Path.Combine(this.pathName, this.fileName); } /// <summary> /// Get range address. /// </summary> /// <param name="range">Excel range</param> /// <returns>range address</returns> private string GetRangeAddress(Excel.Range range) { return this.GetRangeAddress(range, Excel.XlReferenceStyle.xlA1); } /// <summary> /// Get range address. /// </summary> /// <param name="range">Excel range</param> /// <param name="referenceStyle">reference style</param> /// <returns>range address</returns> private string GetRangeAddress(Excel.Range range, Excel.XlReferenceStyle referenceStyle) { return range.get_Address( Type.Missing, Type.Missing, referenceStyle, Type.Missing, Type.Missing); } #endregion #region Private Excel methods - Application /// <summary> /// clean up unhandled Excel application instances. /// </summary> private void CleanUnhandledAppInstance() { Process[] currentExcelProcess = Process.GetProcessesByName(ExcelProcessName); if (currentExcelProcess == null || currentExcelProcess.Length == 0) { return; } List<Process> killList = null; if (this.originalExcelProcess == null || this.originalExcelProcess.Length == 0) { killList = new List<Process>(currentExcelProcess); } else { killList = new List<Process>(); bool isExists; foreach (Process process in currentExcelProcess) { isExists = false; foreach (Process originalProcess in this.originalExcelProcess) { if (originalProcess.Id == process.Id) { isExists = true; break; } } if (!isExists) { killList.Add(process); } } } if (killList != null || killList.Count > 0) { foreach (Process process in killList) { process.Kill(); } } } #endregion #region Private methods for Office PIA bug fixing /// <summary> /// Set current culture as en-US to resolve the bug described in Notice. /// Notice: this method is to avoid Microsoft Office PIA bug Q320369: /// BUG: "Old format or invalid type library" error when automating Excel /// Link: http://support.microsoft.com/default.aspx?scid=kb;en-us;320369 /// </summary> private void SetCurrentCultureAsENU() { Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); } /// <summary> /// Restore original culture. /// </summary> private void RestoreCurrentCulture() { Thread.CurrentThread.CurrentCulture = this.originalCultureInfo; } #endregion } }