Calling dynamically loaded Windows function fails (GetProcAddress)


#1

I’m trying to dynamically load functions from Windows DLLs using GetProcAddress and calling them. I can load the function but calling it fails with an AccessViolation exception.

Here’s an example that tries to load the MessageBox function:

https://play.rust-lang.org/?gist=2b479465af276d62afcc299783b1c633&version=stable

Note that calling the function when linked (by declaring an external "stdcall" block) works well. However, casting to a function pointer and calling that fails. Here’s the error I get when running in Visual Studio 14:

I’m a bit at a loss why one approach works and the other doesn’t? Did I do something wrong with the pointer casting? Is there some Windows security feature I’m running up against?

Here’s a Gist that also includes the Cargo.toml file: https://gist.github.com/fdb/6a2cdab149d5367db3fba0db0c6382e1


#2

What values are LoadLibraryA and GetProcAddress returning? It appears to be documented to return NULL on failure, at which point you can use io::Error::last_os_error to get more information about what happened.


#3

They actually return sensible address values:

module 140713597403136
MessageBoxA 140713597857792

#4

Have you tried std::mem::transmute'ing h_message_box to FnMessageBox?


#5

It works!
I changed the GetProcAddress function signature to return *const usize:

pub fn GetProcAddress(hModule: *const usize, lpProcName: *const u8) -> *const usize;

And then cast to FnMessageBox as follows:

let message_box = std::mem::transmute::<*const usize, FnMessageBox>(h_message_box);

Now calling it like this works:

message_box(ptr::null(), MESSAGE.as_ptr() as *const u8, TITLE.as_ptr() as *const u8, 0);

Here’s the updated code:

Thanks for the help! :+1:


#6

I don’t think you need to change the return type to *const usize - *const c_void is fine and more appropriately describes the FFI type.

You can shorten the transmute to just:

let message_box: FnMessageBox = std::mem::transmute(h_message_box);

#7

Awesome! Didn’t know Rust’s type inference could pick this up as well.