Dynamic Link Libraries or the DLLs are components which are called by a process through the loader when needed during runtime.
DLLs are specially useful so that you're not writing a piece of code again and again and again...
We'll look at writing a DLL in rust just because writing rust is fun. This should be useful whether you're someone starting on the journey of wielding the power of DLLs or looking for some exposure to the Win32 Api in rust.
Executable for loading the DLL
- Create a binary rust application package using the cargo package manager.
cargo new LoadDll
To load a dynamic library, we'll need the
LoadLibrarymethod from the Win32 Api.After the DLL has been loaded, we'll need to pass it to the
GetProcAddesswith the name of the function to be loaded which in our case is a function named 'main'(This function will be present int the DLL).
fn main() {
if let Ok(hellodll)=unsafe{LoadLibraryA(PCSTR("hellodll.dll\0".as_ptr()))}{
let dllmain=unsafe{GetProcAddress(hellodll
, PCSTR("main\0".as_ptr()))};
if let Some(dllmain)=dllmain{
unsafe{dllmain()};
}else{
println!("NO SUCH FUNC IN DLL\0");
}
}else {
println!("DLL not found\0");
}
}
Remember that all the methods from the Win32 need to be wrapped in an unsafe block which implies that the rust compiler can't guarantee the memory safety of the functions.
- Imports in the
cargo.tomlfile:
[dependencies.windows]
version = "0.51.1"
features = ["Win32_System_LibraryLoader", "Win32_Foundation"]
Now, build the exe using the cargo package manager:
cargo build --releaseIf everything has been built correctly, on running the executable we should get:
Dll not founderror message because we have not yet created a DLL!
To be sure that our exe is actually looking for the DLL, fire up the SysInternals' Process Monitor.
To view just the information related to whether our exe is searching for the DLL, we'll set 3 filters.
Process Name,ResultandPathas:
- Now clicking on
applyand starting the "monitoring", runloaddll.exeand we should be getting something like:

This gives us the order of the subdirectories the executable tried to search for the DLL and found it at neither. But now we're sure that our exe is looking for a dll named hellodll.
DLL for loaddll.exe
First we create a rust library using:
cargo new hellodll --lib. This creates a lib.rs in our rust project without a main.Then write the necessary information in the
cargo.tomlfile.We have to specify in the
tomlfile that we're trying to write a DLL.
[lib]
crate-type = ["cdylib"]
This specifies that this is a C Dynamic Library.
- Next, we'll make the necessary imports from the windows crate.
[dependencies.windows]
version = "0.51.1"
features = [
"Win32_Foundation"
,"Win32_System_Services"
,"Win32_System_Console"
,"Win32_Security"
,"Win32_System_Memory"
,"Win32_System_Threading"
,"Win32_System_WindowsProgramming"
,"Win32_System_Diagnostics_Debug"
,"Win32_UI_WindowsAndMessaging"
]
- We'll open a simple
MessageBoxfrom the function which is being imported by theloaddll.exeand call it "main"(remember that this can be called anything). In order to have this function called from the executable, it also needs to be anextern "C"function.
extern "C" fn main(){
unsafe{
MessageBoxA(
HWND(0)
, PCSTR("Hello from DLL\0".as_ptr())
, PCSTR("HI\0".as_ptr())
, MESSAGEBOX_STYLE(0))
};
}
- Next, to load a dll into the memory at runtime, it has to have a
DllMainfunction which is like the entry-point to a DLL.
extern "system" fn DllMain(
dll_module:HANDLE
,call_reason:u32
,lpv_reserved:&u32
)->BOOL{
match call_reason{
_=>{
return BOOL(1);
}
}
}
Since we aren't looking to do something special right now when the DLL is loaded, we'll put a place holder _=> in place of attach and detach.
For Reference: MSDN DllMain Documentation

Now, we also need to specify that the rust compiler should not mess up the function names themselves. This can be done by the
#[no_mangle]attribute above both the "main" and the "DllMain".Now we're all done and we'll
cargo build --releaseto build the DLL inside thereleasefolder of our project directory.Lastly, to be sure that our DLL is exporting the functions according to our requirements, we can inspect the DLL using the NT Core's CFF Explorer Suite.

Sure enough, out hellodll exports two fucntions main and DllMain.
- Finally, place both the executable and the dll in the same directory
and on running the the exe, we get a message box indicating the expected behaviour of ourDLLcalled from theexe.
I hope you've found this enjoyable and useful, and I'm look forward for the amazing things you'll build if you decide to delve deeper into Rust and Windows development.






Top comments (0)