检查.NET托管代码中的本机库

时间:2010-06-22 18:44:21

标签: c#

我有一个用C#编写的.NET应用程序。我的应用程序使用第三方库,它使用第三方库,而第三方库又依赖于sqlceme35.dll(Microsoft SSCE)的存在。在某个地方,对sqlceme35.dll的依赖性没有得到解决,我们已经在很多情况下将我的软件安装在没有这个库的计算机上,该应用程序似乎对大多数功能运行良好,但崩溃当我们尝试调用sqlceme35.dll时,我们会以惊人的方式使用含有错误的错误消息。

即使我们现在知道当库不存在时效果如何,我仍然希望更加主动地检测库何时不可用并向用户提供友好的错误消息“这是问题所在,这是解决方案“。

当前的问题是:如何在运行时检测到sqlceme35.dll库的存在?

更大的问题是:如何在运行时检测任何.dll文件的存在,无论是本机代码还是托管代码库?

3 个答案:

答案 0 :(得分:1)

您可以使用PInvoke来使用LoadLibrary功能,该功能应搜索Windows所在的相同位置。

答案 1 :(得分:0)

您可以检查dll可能存在的所有位置。

http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx

答案 2 :(得分:0)

我们将非托管dll嵌入到程序集中,然后将它们复制到执行的dll位置(对于Web应用程序,可以使用shadow copy bin文件夹)。这可以保证为特定版本的应用程序运行正确的版本。不幸的是,根据您的各种应用程序的许可条款,这可能不可行(合法)。在这些情况下,您最好的选择可能是使用LoadLibrary来验证是否找到了库,但要注意加载错误的版本(另请参阅:DLL hell);这可能是也可能不是你甚至可以解决的问题(对我们来说,唯一的解决方案是嵌入dll并从需要的程序集中提取它们。)

以下是Sybase ASE ADO驱动程序的相关代码:

public static class SybaseResourceExtractor {
    public static void ExtractSybaseDependencies() {
        ExtractSybaseDependency("QueryLibrary.Unmanaged.sybdrvado20.dll", "sybdrvado20.dll");
        ExtractSybaseDependency("QueryLibrary.Unmanaged.msvcr80.dll", "msvcr80.dll");
        ExtractSybaseDependency("QueryLibrary.Unmanaged.sybcsi_certicom_fips26.dll", "sybcsi_certicom_fips26.dll");
        ExtractSybaseDependency("QueryLibrary.Unmanaged.sybcsi_core26.dll", "sybcsi_core26.dll");
        ExtractSybaseDependency("QueryLibrary.Unmanaged.sbgse2.dll", "sbgse2.dll");
    }

    /// <summary>
    /// Extracts a resource to a file.
    /// </summary>
    /// <param name="resourceName">Name of the resource.</param>
    /// <param name="filename">The filename including absolute path.</param>
    static void ExtractSybaseDependency(string resourceName, string filename) {
        try {
            var assembly = Assembly.GetAssembly(typeof(AseConnection));
            var executingAssembly = Assembly.GetExecutingAssembly();
            filename = Path.GetDirectoryName(assembly.Location) + "\\" + filename;

            if (File.Exists(filename)) {
                File.Delete(filename);    
            }

            if (!File.Exists(filename)) {
                using (Stream s = executingAssembly.GetManifestResourceStream(resourceName)) {
                    using (var fs = new FileStream(filename, FileMode.Create)) {
                        if (s == null) {
                            throw new Exception("Failed to get resource stream for " + resourceName);
                        }

                        var b = new byte[s.Length];
                        s.Read(b, 0, b.Length);
                        fs.Write(b, 0, b.Length);
                    }
                }
            }
        } catch {
            //Doing nothing
        }
    }