New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding windows pointer/integer data types #254
Comments
I've started looking into this. There are some surprises for me (having never programmed for Windows)! It looks like in my Linux environment both gcc and clang consider #include <cstdint>
static_assert(sizeof(unsigned long) == sizeof(uint64_t), ""); // passes
void f(unsigned long) {}
//void f(uint64_t) {} // not allowed
int main() {
void (*f$)(uint64_t) = f; // okay
(void)f$;
} Whereas from toying around in https://msvc.godbolt.org it looks like MSVC considers them distinct types. error C2440: 'initializing': cannot convert from 'void (__cdecl *)(unsigned long)' to 'void (__cdecl *)(uint32_t)' Confusingly, it does appear to consider That means we're likely to have to introduce some Rust type that the code generator recognizes as equivalent to unsigned long (c_ulong in Rust, going by the terminology in std::os::raw and the libc crate). For the minwindef.h types in particular, ideally unsafe impl ExternType for DWORD {
type Id = type_id!("DWORD");
} but it doesn't quite yet, because we don't support passing them by value yet even with an ExternType impl present. I expect that restriction will be lifted with some more design work. error[cxxbridge]: passing C++ type by value is not supported
┌─ src/main.rs:19:17
│
19 │ fn doit(d: DWORD);
│ ^^^^^^^^ passing C++ type by value is not supported For now I guess the only immediate way to unblock signatures that involve DWORD would be for you to write some wrappers expressed in terms of uint32_t which perform (probably implicit) casts to call the original function, and only bind the wrappers from cxx, but this is obviously not great. |
Since the comment above, cxx has gained the ability to do this: unsafe impl ExternType for DWORD {
type Id = cxx::type_id!("DWORD");
type Kind = cxx::kind::Trivial; // the new bit!
} This isn't quite perfect though.
(I didn't know about I'm going to try the latter approach until a better plan occurs to me! |
The newtype wrapper approach works (i.e. the second bullet above plus an implementation of |
Specifically here's what I did, for others who end up needing to do this before/unless support lands natively in cxx. typedef unsigned long c_ulong; // etc. because macro_rules! ctype_wrapper {
($r:ident, $c:expr) => {
/// Newtype wrapper for a `$c`
#[derive(Debug,Eq,Clone,PartialEq,Hash)]
#[allow(non_camel_case_types)]
#[repr(transparent)]
pub struct $r(pub ::std::os::raw::$r);
unsafe impl autocxx_engine::cxx::ExternType for $r {
type Id = autocxx_engine::cxx::type_id!($c);
type Kind = autocxx_engine::cxx::kind::Trivial;
}
};
}
ctype_wrapper!(c_ulong, "c_ulong");
ctype_wrapper!(c_long, "c_long");
ctype_wrapper!(c_ushort, "c_ushort");
ctype_wrapper!(c_short, "c_short");
ctype_wrapper!(c_uint, "c_uint");
ctype_wrapper!(c_int, "c_int");
ctype_wrapper!(c_uchar, "c_uchar");
ctype_wrapper!(c_char, "c_char"); There may be a way to get rid of the second parameter using Then in the |
Related to supporting those without a wrapper: #529. |
I'm not sure that #529 really helps here: it would allow the I'm assuming that checking the If so, then perhaps we could add an attribute to indicate to the #[cxx::bridge]
mod ffi {
extern "C++" {
#[renamed]
type DWORD = u32;
fn UseDWord(value: DWORD);
}
} Applying that attribute would cause pub fn verify_extern_type_renamed<T: ExternType>() {} |
I have been trying to access a 3rd-party win32 API using
cxx
. One of the first things I am coming across is that the library contains extensive use of windows-specific type aliases likeDWORD
,WPARAM
,LPARAM
,HINSTANCE
etc. most of which are equivalent to an unsigned integer of some size (u32 in case of 32-bit windows). Now obviously, sincecxx
is unaware of this, I am unable to pass or return these by value.If I try to use
u32
inside of the extern "C" block, I get errors like:Is there any workaround to this to make
cxx
"aware" of that these types are interchangeable with unsigned integers? I believe most of these are defined inminwindef.h
in the windows SDK.The text was updated successfully, but these errors were encountered: