Raskolnikov
Raskolnikov

Reputation: 3999

How to read dll from specific path in C#

I need to import SglW32.dll to my solution.

But I get:

AccessViolation exeption : Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

I could not use just DllImport. In that case dll is not found.

This is whole example.

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;
        }
    }
}

I am using load function to get dll from any path. After that I crate delegate from required function. In my case function is SglAuthentA. This solution in working with one other dll, but not for SglW32.dll.

Product: http://www.sg-lock.com/us/

Required dll : http://www.sg-lock.com/download/sglw32_v2_28.zip

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

Source 1: https://stackoverflow.com/a/8836228/2451446


EDIT: Solution thanks to Hans Passant answer and ja72 comment


See How to import 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);
    }

}

Upvotes: 3

Views: 1523

Answers (1)

Hans Passant
Hans Passant

Reputation: 941287

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

The delegate declaration is not correct and does not match the api function signature. An ULONG in C is an uint in C#. An ULONG* in C is ambiguous, could be a ref uint or it could be a uint[]. Since you are supposed to pass a 48 byte authentication code, you know it is an array. Fix:

private delegate uint SglAuthentA(uint[] authentCode);

Be sure to pass the proper authentication code. It is not 5, the array must have 12 elements. If you don't have one then call the manufacturer to acquire one.


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

Do beware that this is not a workaround for not being able to use [DllImport]. Hardcoding the path is a problem, the file is not going to be present in that directory on the user's machine. The DLL itself does not have any dependencies that prevents it from loading, the only plausible reason for having trouble is you just forgetting to copy the DLL into the proper place. There is only one such place, the same directory as your EXE.

Fix this the right way, use Project > Add Existing Item > select the DLL. Select the added file in the Solution Explorer window. In the Properties window, change the Copy to Output Directory setting to "Copy if newer". Rebuild your project and note that you'll now get the DLL in your project's bin\Debug directory. Now [DllImport] will work.


A caution about the manual, it lists code samples in Visual Basic. Which is in general what you'd normally use as a guide on learning how to use the api. The code is however not VB.NET code, it is VB6 code. Where ever you see Long in the sample code, you should use uint or int instead.

Very sloppy, it casts a big question mark on the quality of the product. Something else they don't seem to address at all is how to get your own code secure. Very important when you use a dongle. Beware it is very trivial for anybody to reverse-engineer your authentication code. And worse, to decompile your program and remove the authentication check. You need to use an obfuscator.

Upvotes: 6

Related Questions