-
Notifications
You must be signed in to change notification settings - Fork 54
Compatibility with Windows SDK / winapi crate #196
Description
In this issue I want to suggest an API change that would allow interoperability between this package and the COM interfaces defined in the winapi crate. This is desired as it would allow us to easily work with COM classes and extend COM interfaces defined in the Windows API using this package.
Introduction
The winapi
create defines COM interfaces using an RIDL!{} macro which is very similar to our com::interface!{}, and in theory we only have to add an implementation of the com::Interface trait to RIDL! to get everything working. I have written a set of patches to winapi
that do exactly that, as a POC.
However, it turns out that the API this package exports is fundamentally incompatible with the winapi
crate. For example, if we look at the implementation of some ISomething interface, we find that it is of the following form:
type ISomethingVPtr = ::std::ptr::NonNull<ISomethingVTable>
struct ISomething {
inner: ::std::ptr::NonNull<ISomethingVPtr>
}
While the winapi
create implementation of that ISomething would be of the form:
struct ISomething {
lpVtbl: *const ISomethingVtbl
}
Meaning, a vtable pointer instead of our vtable pointer pointer.
Our definition is also incompatible with the Windows SDK for C/C++, which defines interfaces as structs with a vtable pointer. On top of being an incompatible definition of the interface, this causes weirdness, for example, in com::runtime::create_raw_instance
, where we call CoCreateInstance and pass *mut Option<ISomething>
(which is pretty much identical to *mut ISomething
due to null-pointer optimization), whereas CoCreateInstance expects a *mut *mut ISomething for its output argument.
Possible solutions
To remediate this, I wish to implement a more compatible definition of interfaces and classes for this package, and I want to discuss possible solutions with the maintainers before I start to work on this. I've thought of two possible way to go about this:
- drop the inner field completely, and have
com::runtime::create_instance
return a Box or something of the sort. - drop the inner field from interfaces but implement a wrapper type with the "inner" field, similar to how we have ComPtr in C++.
@rylev or anyone else working on this, please let me know what you think.