C#-我的应用程序和与外部应用程序的互操作性(DLL / COM)

|| 我一直在开发一个使用DLL互操作到外部数据库应用程序的C#应用​​程序。 该外部应用程序与我的C#应用​​程序同时启动,并且只要我的C#应用​​程序正在运行就可以使用。 现在真正的问题与管理与外部应用程序交互所需创建的对象有关。 当我声明可从引用的DLL \获得的对象时,这些对象具有与文件一起操作(专有)并运行一些查询的方法(例如是否由此外部应用程序GUI进行了处理)。这些对象使用ѭ0销毁,而其他对象在不同的​​应用程序域中运行,通过使用ѭ1进行操作并调用
AppDomain.Unload(\"A_DOMAIN\")
,释放用于该操作的DLL ... 采取这些变通办法是为了确保此外部应用程序不会“阻止”这些操作中使用的文件,从而允许从文件夹中删除或移动它们。 例如
private static ClientClass objApp = new ClientClass();

public bool ImportDelimitedFile(
                string fileToImport, 
                string outputFile, 
                string rdfFile)    

{
    GENERICIMPORTLib import = new GENERICIMPORTLibClass();

    try
    {
        import.ImportDelimFile(fileToImport, outputFile, 0, \"\", rdfFile, 0);
        return true;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
        return false;
    }
    finally
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(import);
        import = null;
    }
}

public int DbNumRecs(string file)
{
    if (!File.Exists(file))
    {
        return -1;
    }

    System.AppDomain newDomain = System.AppDomain.CreateDomain();
    COMMONIDEACONTROLSLib db = new COMMONIDEACONTROLSLibClass();
    try
    {
        db = objApp.OpenDatabase(file);
        int count = (int)db.Count;

        db.Close();
        objApp.CloseDatabase(file);

        return count;
    }
    catch (Exception ex)
    {
        return -1;
    }
    finally
    {
        System.AppDomain.Unload(newDomain);
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}
由于我没有任何种类的API手册,因此这两个“解决方案”都是通过反复试验得出的。这些解决方案正确吗?你能解释我的区别吗?我是否真的需要同时使用这两种解决方案? 谢谢!     
已邀请:
您对AppDomains的使用是错误的。仅仅因为您在X行之前创建了一个新的AppDomain并不意味着X行实际上在该AppDomain中执行。 您需要将代理类编组回整个AppDomain,并在当前类中使用它。
public sealed class DatabaseProxy : MarshallByRefObject
{
    public int NumberOfRecords()
    {    
        COMMONIDEACONTROLSLib db = new COMMONIDEACONTROLSLibClass();
        try
        {
            db = objApp.OpenDatabase(file);
            int count = (int)db.Count;

            db.Close();
            objApp.CloseDatabase(file);

            return count;
        }
        catch (Exception ex)
        {
            return -1;
        }
    }
}
public int NumberOfRecords()
{    

    System.AppDomain newDomain = null;

    try
    {
        newDomain = System.AppDomain.CreateDomain();
        var proxy = newDomain.CreateInstanceAndUnwrap(
                                  typeof(DatabaseProxy).Assembly.FullName,
                                  typeof(DatabaseProxy).FullName);
        return proxy.NumberOfRecords();
    }
    finally
    {
        System.AppDomain.Unload(newDomain);
    }
}
实际上,您可以创建回送COM对象本身的封送处理,而不是通过代理实例化它。此代码已在此处完全编写且未经测试,因此可能有问题。     
第一个解决方案是最好的。非托管COM使用引用计数方案。 IUnknown是基础引用计数接口:http://msdn.microsoft.com/zh-cn/library/ms680509(VS.85).aspx。当参考计数达到零时,将其释放。 在.NET中创建COM对象时,将在COM对象周围创建包装器。包装器维护指向基础IUnknown的指针。发生垃圾回收时,包装器将调用基础IUnknown :: Release()函数以在完成过程中释放COM对象。正如您所注意到的,问题在于,有时COM对象会锁定某些关键资源。通过调用Marshal.ReleaseComObject,可以强制立即调用IUnknown :: Release,而无需等待(或启动)常规垃圾回收。如果没有保留对COM对象的其他引用,则它将立即被释放。当然,此后,.NET包装器将变得无效。 第二种解决方案显然是有效的,因为调用了GC.Collect()。该解决方案更笨拙,更慢且可靠性更低(COM对象不一定要被垃圾回收:行为取决于特定的.NET Framework版本)。 AppDomain的使用无济于事,因为您的代码除了创建一个空域然后将其卸载外实际上并没有做任何事情。 AppDomain对于隔离加载的.NET Framework程序集很有用。由于涉及非托管COM代码,因此AppDomains并不会真正有用(如果需要隔离,请使用进程隔离)。第二个函数可能可以重写为:
    public int DbNumRecs(string file) {
        if (!File.Exists(file)) {
            return -1;
        }
        // don\'t need to use AppDomain
        COMMONIDEACONTROLSLib db = null; // don\'t need to initialize class here
        try {
            db = objApp.OpenDatabase(file);
            return (int)db.Count;
        } catch (Exception) } // don\'t need to declare unused ex variable
            return -1;
        } finally {
            try {
                if (db != null) {
                    db.Close();
                    Marshal.ReleaseComObject(db);
                }
                objApp.CloseDatabase(file); // is this line really needed?
            } catch (Exception) {} // silently ignore exceptions when closing
        }
    }
    

要回复问题请先登录注册