如何在C#中从特定路径读取dll文件

3
我需要将SglW32.dll导入我的解决方案中。
但是我收到了这个错误信息:
AccessViolation异常:试图读取或写入受保护的内存。这通常表明其他内存已损坏。
如果使用DllImport,我无法使用。在这种情况下,dll找不到。
以下是完整示例。
using System;
using System.Runtime.InteropServices;
namespace TestDllimport
{
    class Program
    {
        static void Main(string[] args)
        {
            var a = new MyClass();
            var result = a.getValue();
        }
    }
    class FunctionLoader
    {
        [DllImport("Kernel32.dll")]
        private static extern IntPtr LoadLibrary(string path);

        [DllImport("Kernel32.dll")]
        private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

        public static Delegate LoadFunction<T>(string dllPath, string functionName)
        {
            var hModule = LoadLibrary(dllPath);
            var functionAddress = GetProcAddress(hModule, functionName);
            return Marshal.GetDelegateForFunctionPointer(functionAddress, typeof(T));
        }
    }

    public class MyClass
    {
        //Define your path to dll.
        //Get dll from: http://www.sg-lock.com/download/sglw32_v2_28.zip
        private const string DLL_Path = @"C:\Users\admin123\Desktop\MyDlls\SglW32.dll";

        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        private delegate ulong SglAuthentA(IntPtr AuthentCode);
        static MyClass()
        {
            sglAuthentA = (SglAuthentA)FunctionLoader.LoadFunction<SglAuthentA>(DLL_Path, "SglAuthentA");
        }

        static private SglAuthentA sglAuthentA;

        unsafe public ulong getValue()
        {
            IntPtr d = new IntPtr(5);
            var a1 = sglAuthentA(d); // Exception IS HERE !!!!!
            return a1;
        }
    }
}

我正在使用load函数从任何路径获取dll。之后,我从所需函数创建委托。在我的情况下,这个函数是SglAuthentA。

这个解决方案可以与另一个dll一起使用,但不能与SglW32.dll一起使用。

产品:http://www.sg-lock.com/us/

所需的dll:http://www.sg-lock.com/download/sglw32_v2_28.zip

手册:http://www.sg-lock.com/download/SG-Lock_Manual_Eng.pdf

来源1:https://dev59.com/q2ox5IYBdhLWcg3w_ZV0#8836228


编辑:感谢Hans Passant回答和ja72评论的解决方案


请参见如何导入dll

using System.Runtime.InteropServices;

namespace TestDllimport
{
    class Program
    {
        static void Main(string[] args)
        {
            var testA = DllImportClass.SglAuthentA(new uint[] { 5, 6, 7 }, new uint[] { 5, 6, 7 }, new uint[] { 5, 6, 7 });
            var testB = DllImportClass.SglAuthentB(new uint[] { 5, 6, 7 });
        }
    }

    static class DllImportClass
    {
        [DllImport("SglW32.dll")]
        public static extern uint SglAuthentA(uint[] AuthentCode0, uint[] AuthentCode1, uint[] AuthentCode2);

        [DllImport("SglW32.dll")]
        public static extern uint SglAuthentB(uint[] AuthentCode);
    }

}

4
为什么不像你对于 Win32 API 函数所做的那样使用 [DllImport]?只需确保将 DLL 与您的 exe 文件放在同一文件夹中(无论如何,您应该这样做)。即使是开发过程中,将 DLL 放在桌面上也是错误的做法。 - Panagiotis Kanavos
由于某些原因找不到 DLL 文件。我不知道为什么。 - Raskolnikov
你是否在使用Visual Studio?你能否将dll文件添加到你的项目中呢?右键点击项目中的“References”文件夹,选择“Add Reference”,然后使用浏览器定位到你的.dll文件,选中它并点击“OK”。 - Fuzzybear
我正在使用 AnyCPU,x86 也有同样的问题。操作系统为 Windows Server 2012 R2 - Azure 虚拟机。 - Raskolnikov
2
请参考此答案,了解如何始终将DLL与编译器输出一起使用。 - John Alexiou
显示剩余4条评论
1个回答

6
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate ulong SglAuthentA(IntPtr AuthentCode);

委托声明不正确,与API函数签名不匹配。在C中,ULONG是uint,在C#中。在C中,ULONG*是不明确的,可能是ref uint或uint[]。由于您需要传递48字节的身份验证代码,所以您知道它是一个数组。修复方法:
private delegate uint SglAuthentA(uint[] authentCode);

请确保传递正确的身份验证代码。它不是5,数组必须有12个元素。如果您没有一个,请致电制造商获取一个。


private const string DLL_Path = @"C:\Users\admin123\Desktop\MyDlls\SglW32.dll";

请注意,这并不是无法使用[ DllImport ]的解决方法。硬编码路径会有问题,因为该文件在用户的计算机上不存在相同的目录中。DLL本身没有任何依赖项阻止其加载,唯一可能遇到问题的原因是您忘记将DLL复制到正确的位置。只有一个这样的位置,即与EXE相同的目录。
用正确的方法解决此问题,使用“项目”>“添加现有项”>选择DLL。在“解决方案资源管理器”窗口中选择添加的文件。在“属性”窗口中,将“复制到输出目录”设置更改为“仅在较新时复制”。重新构建您的项目,注意现在将在您的项目的bin \ Debug目录中获取DLL。现在[ DllImport ] 将可以工作。
关于手册的警告,它列出了Visual Basic的代码示例。这通常是您学习如何使用api的指南。然而,代码不是VB.NET代码,而是VB6代码。在示例代码中任何地方看到Long ,您应该改用 uint int
非常潦草,给产品的质量带来了大问题。他们似乎根本没有解决如何使您自己的代码安全。当您使用加密狗时,这非常重要。请注意,任何人都可以轻松地逆向您的身份验证代码。更糟糕的是,反编译您的程序并删除身份验证检查很容易。您需要使用混淆器。

谢谢你的帮助。你的回答非常好。我无法在今天奖励你,这是 Stack Overflow 的限制。 - Raskolnikov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接