Office PIA:绕过Bug Q320369:Old format or invalid type library" error when automating Excel

测试一定要充分!接上回书,话说我提交了Office PIA的代码以后,测试的同学就展开了充分的测试。在此之前我可是信心满满的,自以为已经做了充分的测试了,应该测不出什么bug来了。可是,很快,测试的同学就报了一个Exception issue给我:

System.Runtime.InteropServices.COMException (0x80028018): Old format or invalid type library. (Exception from HRESULT: 0x80028018 (TYPE_E_INVDATAREAD))
   at ******.Excel.ExcelApp.CreateWorkbook(String fileName) in C:\svnroot\******\Trunk\Development\Software\******\Excel\ExcelApp.cs:line 213


(以上******是故意打的马赛克,你懂的。 微笑


这个问题在我本地从不重现,在测试的机器上也不总是可重现。经比对,发现重现此issue的测试机,其语言和区域设置(Clock, Language, and Region)中的Format设置的是Chinese (Simplified, PRC)。简单地说,就是涉及到中文环境时能复现这个问题。在此要说明一下,本人就职于某大型外企,大家平时的的计算机都是英文的系统和英文的语言、区域、格式设置。

总算发现一定能复现这个exception issue的条件了,但是乍一看这个问题真是匪夷所思,我编程当中没有用到什么涉及到不同的Culture的地方,也不曾hard code地传入什么字符串内容,怎么会单单在非英语环境中出错呢?但是不管怎么说,我还是要检讨一下,说明我之前做的测试很不充分,没有做国际性/本地化测试。


好,问题的背景介绍到此。既然有了线索,那就好办了。借助万能的Google和MSDN,很快就找到了root cause。MSDN中已经有文章说明此事,微软承认这是Microsoft Office PIA的Bug:


BUG: "Old format or invalid type library" error when automating Excel

Link: http://support.microsoft.com/kb/320369

If you automate Microsoft Excel with Microsoft Visual Basic .NET, Microsoft Visual C# .NET, or Microsoft Visual C++, you may receive the following error when calling certain methods:

Error: 0x80028018 (-2147647512)
Description: Old Format or Invalid Type Library


......
......


此文中说到,当前线程的Culture不是英语(“en-US”)的时候,就会遭遇此问题。


怎么解决这个问题呢?其实这个问题我肯定没有办法解决,我只能说绕开这个问题(Workaround)。


首先我做的尝试是,在出问题的地方(Excel.Worksheet.SaveAs),前后分别设置当前Culture为“en-US”和恢复原有Culture属性。但是程序执行到其它的地方又报出同样的问题。可见,这个Office PIA Bug影响的绝不仅仅是SaveAs()这个方法,还有很多其他的方法。具体是哪些方法我就不去较这个劲了,我直接在类的初始化中设置当前线程的Culture为“en-US”,然后在类的Dispose方法中恢复原有Culture属性:


    using System;
    using System.Collections.Generic;
    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 Private variables
        /// <summary>Original culture info</summary>
        private CultureInfo originalCultureInfo = 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();
        }

        /// <summary>
        /// Finalizes an instance of the ExcelApp class.
        /// </summary>
        ~ExcelApp()
        {
            this.Dispose(false);
        }
        #endregion

        ......
        ......

        /// <summary>
        /// Implement Dispose method in IDisposable
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }
        #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.disposed = true;
        }
        #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
    }

这样,就成功地绕过了这个Office PIA Bug。






你可能感兴趣的:(exception,Excel,Microsoft,测试,Office,library)