nagisa / rust_libloading

Bindings around the platform's dynamic library loading primitives with greatly improved memory safety.

Home Page:https://docs.rs/libloading

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Load the same dll multiple times

chaoxi24 opened this issue · comments

Load the same dll multiple times
Autohotkey is a scripting language for the win platform. I use libloading to load autohotkey.dll, which constitutes an independent autohotkey interpreter.
I need to load multiple autohotkey.dll, each of which is a separate thread.

Autohotkey has a built-in method to load multiple dlls:

dll:=fileread("AutoHotkey.dll")
loop 3
{
ahk:=MemoryLoadLibrary(&dll)
ahktextdll:=MemoryGetProcAddress(ahk, "ahktextdll")
DllCall(ahktextdll,"Str","MsgBox test-" a_index,"Str","","Str","")
}

https://github.com/HotKeyIt/ahkdll/blob/ff2448bc7443c91ab0848761642f6c96007923ae/source/MemoryModule.cpp#L762

How to use libloading to achieve?

The underlying native APIs (https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw) used by libloading do not support loading multiple instances of the same library.

Load AHK and use its Memory* APIs, I guess? An alternative option would be to make differently named copies of the AHK dll and load those – that way the reference counting implemented by native APIs won't kick in.

An alternative option would be to make differently named copies of the AHK dll and load those

This is the function of "MemoryLoadLibrary". It directly modifies the name of the dll in the memory, then loads the dll, and reads out the addresses of all functions. Therefore, even if you don't know the name of the dll, you can call the function normally.

From what I can tell that's not at all what the code does – instead they appear to implement an entire custom loader, which is way out of scope for libloading, at least currently.

From what I can tell that's not at all what the code does – instead they appear to implement an entire custom loader, which is way out of scope for libloading, at least currently.

No, this is achieved purely by winapi. Because in the old version, this feature is not built-in, but exists in an .ahk library.
It is not limited to loading AutoHotkey.dll, it can load any dll from memory. I often use it to load python.dll.

https://github.com/HotKeyIt/ahkdll-v2-release/blob/aa019cbccfde5ad2e0dfd8148cdacc0b00851040/lib/_MemoryLibrary.ahk

Although this may be beyond the scope of libloading, but I still hope that libloading can achieve it. I'm very sorry that I am new to rust, and I don't have a programming foundation, I don't know how to convert it into rust code.

No, this is achieved purely by winapi.

The MemoryLoadLibraryEx clearly implements an entire custom loader and AFAICT the only reliance on windows APIs is to load transitive library dependencies. It also ends up relying on a number of internal implementation details of the NT/Windows that I'm not sure are stable or intended to be user-visible. It is a horrible hack.

I don't know what they used to do in the past, before this code existed, but if I had to guess, it is something along the lines of making copies of the dll file in some temporary directory and loading those, much like what I suggested you should do above in this issue.

If you do not want to copy dll files and load the copies, then the most straightforward way for you to achieve what you want to do is to call the MemoryLoadLibrary in the first place. You could do this in a couple of different ways. First is by linking to the library normally and calling its functions via FFI. You can do same via libloading too:

let library = libloading::Library::new("whatever_contains_memoryloadlibrary.dll").expect("foo");
let memory_load_library = library.get::<unsafe "C" fn(*const u8, usize, bool)>(b"MemoryLoadLibrary\0").expect("mll");
let copied_library = memory_load_library(...);

Thank you. I think I get it.
But I have another question. If I get the address of a function (e.g. 3222) through memoryloadlibrary, how do I convert this address into a function that can be called in rust? 3222 →??→ rust-func()

You can use std::mem::transmute like such. Or, equivalently, libloading does this.

thank you for your help.

I will close this now. In the future you may be able to reach a wider community when asking questions on users.rust-lang.org or similar user-oriented forums.