簡體   English   中英

C#Excel插件-跨域單例異常

[英]C# Excel Addin - Cross-domain singleton Exception

我正在開發一個excel加載項,並且在此加載項中有幾個AppDomain。 我需要訪問每個AppDomain中的某些共享數據,因此我決定使用跨AppDomain單例。 我遵循了此線程中描述的內容:

http://www.dolittle.com/blogs/einar/archive/2007/05/18/cross-appdomain-singleton.aspx

因為這是一個excel插件,所以在創建包含單例的AppDomain時必須對其進行一些修改,以便在搜索程序集時使用正確的基本目錄。 以下是我的修改版本:

public class CrossAppDomainSingleton<T> : MarshalByRefObject where T : new()
{
    private static readonly string AppDomainName = "Singleton AppDomain";
    private static T _instance;

    private static AppDomain GetAppDomain(string friendlyName)
    {
        IntPtr enumHandle = IntPtr.Zero;
        mscoree.CorRuntimeHostClass host = new mscoree.CorRuntimeHostClass();
        try
        {
            host.EnumDomains(out enumHandle);

            object domain = null;
            while (true)
            {
                host.NextDomain(enumHandle, out domain);
                if (domain == null)
                {
                    break;
                }
                AppDomain appDomain = (AppDomain)domain;
                if (appDomain.FriendlyName.Equals(friendlyName))
                {
                    return appDomain;
                }
            }
        }
        finally
        {
            host.CloseEnum(enumHandle);
            Marshal.ReleaseComObject(host);
            host = null;
        }
        return null;
    }


    public static T Instance
    {
        get
        {
            if (null == _instance)
            {
                AppDomain appDomain = GetAppDomain(AppDomainName);
                if (null == appDomain)
                {
                    string baseDir = AppDomain.CurrentDomain.BaseDirectory;
                    appDomain = AppDomain.CreateDomain(AppDomainName, null, baseDir, null, false);
                }
                Type type = typeof(T);
                T instance = (T)appDomain.GetData(type.FullName);
                if (null == instance)
                {
                    instance = (T)appDomain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
                    appDomain.SetData(type.FullName, instance);
                }
                _instance = instance;
            }

            return _instance;
        }
    }
}

這是我對CrossAppDomainSingleton的實現:

public class RealGlobal : CrossAppDomainSingleton<RealGlobal>
{
    //ExcelApp Value Shared
    private Microsoft.Office.Interop.Excel.Application s_excelApp = null;

    public Microsoft.Office.Interop.Excel.Application GetExcelApp()
    {
        return s_excelApp;
    }

    public void SetExcelApp(Microsoft.Office.Interop.Excel.Application app)
    {
        s_excelApp = app;
    }
}

一旦我嘗試使用get或set方法(我也嘗試過一個屬性,但沒有進一步嘗試),我就會系統地得到一個異常:

Nom inconnu。 (來自HRESULT的異常:0x80020006(DISP_E_UNKNOWNNAME))

或用英語:未知名稱。 (來自HRESULT的異常:0x80020006(DISP_E_UNKNOWNNAME))

當我保留內置類型時,編組工作正常,但是鑒於我要訪問的對象(Microsoft.Office.Interop.Excel.Application)是COM對象,我擔心這是問題所在。

我是遠程處理和編組的新手。 有任何想法嗎? 它與COM對象的序列化有關嗎?

提前謝謝了! 肖恩

您當然不應該傳遞該Application對象,否則將引起無盡的麻煩。

我建議您編寫一個小助手,可以從每個AppDomain調用該助手,以獲取正確的Application對象。 這樣做有一個小障礙,因為通常的CreateObject方法不會始終為您所在的進程獲取Excel Application實例。Andrew Whitechapel在此處提供了說明和正確的代碼: http : //blogs.officezealot.com/ whitechapel / archive / 2005/04/10 / 4514.aspx

最后,在其他語言環境中調用Excel COM對象時,應注意語言環境問題。 有時,調用需要本地化,或者您需要使用線程的UI語言。 此處的一些信息: http : //msdn.microsoft.com/zh-cn/library/aa168494 (v=office.11​​) .aspx以及此處有關在VSTO中所做的操作的一些信息: http : //blogs.msdn.com /b/eric_carter/archive/2005/06/15/429515.aspx

在C#中,遠程處理對象是以下兩種方法之一。 該對象要么繼承自MarshalByRefObject,要么需要可Serializable 由於您顯然不想序列化Excel Application對象(即使可以,它也會很大,並且不會在另一側引用Excel的實時副本),因此唯一的選擇是MarshalByRef。 不幸的是,您也不控制Application對象的源代碼,因此我認為這種操作方法是非入門級的。

您可能應該做的是使用MarshalByRef對象從外接程序主AppDomain中公開本機.NET API,然后在該對象內對Excel Application對象進行所需的調用。

因此,您得到的架構如下所示:

[Excel Application] <--> [.NET Object : MarshalByRef] !! <-- Remoting Boundary --> [Other AppDomains]

特別着重於使100%受管代碼(而不是遠程處理)公開的API,完全不公開或不依賴Excel。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM