retep998 / winapi-rs

Rust bindings to Windows API
https://crates.io/crates/winapi
Apache License 2.0
1.85k stars 392 forks source link

What means __out__ parameters in original C functions? #1010

Closed TarasBereznyak closed 3 years ago

TarasBereznyak commented 3 years ago

Look this function: https://docs.rs/winapi/0.3.9/winapi/um/winbase/fn.FormatMessageW.html It have parameter : lpBuffer: LPWSTR, In original documentation (https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessagew) parameter declared as [out] LPWSTR lpBuffer, "Out" means something like "&mut". But in Rust binging I dont see "&mut *u16" Looks like an error in declaration.

retep998 commented 3 years ago

The [out] means that it will write into the data pointed to by the pointer you provide. That parameter specifically is an LPWSTR which is an alias for *mut u16 which is a pointer type. You create your buffer with a fixed size array or a Vec and pass in .as_mut_ptr() from your buffer for that parameter to that function.

TarasBereznyak commented 3 years ago

You create your buffer with a fixed size array or a Vec and pass in .as_mut_ptr() from your buffer for that parameter to that function.

In real C++ example I see another usage: https://stackoverflow.com/questions/1387064/how-to-get-the-error-message-from-the-error-code-returned-by-getlasterror

LPSTR messageBuffer = nullptr;
    //Ask Win32 to give us the string version of that message ID.
    //The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
    size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                 NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);    

But I see strange cast (LPSTR)&messageBuffer, so looks like your binding is correct (the same as original), but this winapi function in original C headers was totally wrong. Ok, I agree, it is a winapi problem.

retep998 commented 3 years ago

Ah, that's specifically when you pass FORMAT_MESSAGE_ALLOCATE_BUFFER, in which case what you're actually supposed to do is let mut buf: LPWSTR = ptr::null_mut(); then pass in <*mut _>::cast(&mut buf) to that parameter since the pointer type of the parameter no longer matches the type that you're expected to pass in in that case.

From MSDN:

The function allocates a buffer large enough to hold the formatted message, and places a pointer to the allocated buffer at the address specified by lpBuffer. The lpBuffer parameter is a pointer to an LPTSTR; you must cast the pointer to an LPTSTR (for example, (LPTSTR)&lpBuffer). The nSize parameter specifies the minimum number of TCHARs to allocate for an output message buffer. The caller should use the LocalFree function to free the buffer when it is no longer needed.

TarasBereznyak commented 3 years ago

Thanks for explanation