Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting value of a char* exported by unmanaged dll in .NET

Tags:

c#

.net

pinvoke

Im trying to get a value of a string exported by an unmanaged dll.

The string in the dll is declared as

extern "C" __declspec(dllexport) const char* _Version = "0.1";

The code I'm using to get the value is below. I get the address for the variable from the call to GetProcAddress but Marshal.PtrToStringAuto returns garbage...

Whats wrong?

    public string GetDllVersion()
    {
            IntPtr lib = LoadLibrary(@"some.dll");
            if(lib == IntPtr.Zero)
                    throw new Win32Exception(Marshal.GetLastWin32Error());

            IntPtr procAddress = GetProcAddress(lib, "_Version");
            var ver2 = Marshal.PtrToStringAuto(procAddress);

            if(!FreeLibrary(lib))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
            return ver2;
    }

    [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
    static extern IntPtr LoadLibrary(string lpFileName);

    [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
    static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool FreeLibrary(IntPtr hModule);
like image 757
rickythefox Avatar asked Sep 08 '11 08:09

rickythefox


3 Answers

You have to use Marshal.PtrToStringAnsi() here.

"Auto" means "operating system default". With Windows 98 and ME on the endangered species list, that's very likely Unicode on your machine. Your string isn't const wchar_t*.

like image 137
Hans Passant Avatar answered Nov 07 '22 18:11

Hans Passant


Here is my solution; checked-it, it works.

IntPtr procAddress = GetProcAddress(lib, "_Version");
IntPtr verAddress = Marshal.ReadIntPtr(procAddress);
var ver2 = Marshal.PtrToStringAnsi(verAddress);
like image 4
odalet Avatar answered Nov 07 '22 19:11

odalet


Fixed this by dereferencing the pointer from GetProcAddress:

procAddress = Marshal.ReadIntPtr(GetProcAddress(lib, "_Version"));

Also changed the way to read the string per suggestion from Hans Passant (other answer):

var ver2 = Marshal.PtrToStringAnsi(procAddress);
like image 3
rickythefox Avatar answered Nov 07 '22 20:11

rickythefox