It appears that COM interfaces that inherit from other interfaces don't properly express it in their vtable layout. Take ID3D11Texture2D for example:
#[repr(C)]
pub struct ID3D11Texture2D_abi(
pub unsafe extern "system" fn(
this: ::windows::RawPtr,
iid: &::windows::Guid,
interface: *mut ::windows::RawPtr,
) -> ::windows::ErrorCode,
pub unsafe extern "system" fn(this: ::windows::RawPtr) -> u32,
pub unsafe extern "system" fn(this: ::windows::RawPtr) -> u32,
pub unsafe extern "system" fn(
this: ::windows::RawPtr,
p_desc: *mut D3D11_TEXTURE2D_DESC,
),
);
In order to call GetDesc correctly, I had to define a custom vtable:
#[repr(C)]
pub struct ID3D11Texture2DCustom_abi(
pub unsafe extern "system" fn(
this: ::windows::RawPtr,
iid: &::windows::Guid,
interface: *mut ::windows::RawPtr,
) -> ::windows::ErrorCode,
pub unsafe extern "system" fn(this: ::windows::RawPtr) -> u32,
pub unsafe extern "system" fn(this: ::windows::RawPtr) -> u32,
// ID3D11DeviceChild
pub unsafe extern "system" fn(
this: ::windows::RawPtr,
pp_device: *mut ::std::option::Option<ID3D11Device>,
),
pub unsafe extern "system" fn(
this: ::windows::RawPtr,
guid: *const ::windows::Guid,
p_data_size: *mut u32,
p_data: *mut ::std::ffi::c_void,
) -> ::windows::ErrorCode,
pub unsafe extern "system" fn(
this: ::windows::RawPtr,
guid: *const ::windows::Guid,
data_size: u32,
p_data: *const ::std::ffi::c_void,
) -> ::windows::ErrorCode,
pub unsafe extern "system" fn(
this: ::windows::RawPtr,
guid: *const ::windows::Guid,
p_data: ::std::option::Option<::windows::IUnknown>,
) -> ::windows::ErrorCode,
// ID3D11Resource
pub unsafe extern "system" fn(
this: ::windows::RawPtr,
p_resource_dimension: *mut bindings::windows::win32::direct3d11::D3D11_RESOURCE_DIMENSION,
),
pub unsafe extern "system" fn(this: ::windows::RawPtr, eviction_priority: u32),
pub unsafe extern "system" fn(this: ::windows::RawPtr) -> u32,
// ID3D11Texture2D
pub unsafe extern "system" fn(
this: ::windows::RawPtr,
p_desc: *mut D3D11_TEXTURE2D_DESC,
),
);
I have a repro here: https://github.com/robmikh/rustd3d/tree/f01f73781dc0f2565c5b033cc603fb65d278b12c
Hey Robert, this is a known issue. I haven't got around to chaining the base interfaces yet. I plan to address this asap.
I just got it working. A bit more polish needed, but it's looking good. 馃槈 Here's an example:
use bindings::windows::win32::direct2d::*;
use windows::Abi;
use windows::Interface;
fn main() -> windows::Result<()> {
let factory = create_factory()?;
let mut dpi_x = 0.0;
let mut dpi_y = 0.0;
factory.GetDesktopDpi(&mut dpi_x, &mut dpi_y);
println!("DPI x={} y={}", dpi_x, dpi_y);
Ok(())
}
fn create_factory() -> windows::Result<ID2D1Factory7> {
let mut options = D2D1_FACTORY_OPTIONS::default();
if cfg!(debug_assertions) {
options.debug_level = D2D1_DEBUG_LEVEL::D2D1_DEBUG_LEVEL_INFORMATION;
}
let mut result = None;
unsafe {
D2D1CreateFactory(
D2D1_FACTORY_TYPE::D2D1_FACTORY_TYPE_SINGLE_THREADED,
&ID2D1Factory7::IID,
&options,
result.set_abi(),
)
.and_some(result)
}
}
I'm trying to call seek on an IStream interface, and get a crash (access violation.) If I use the same pointer and call seek from C++ it works correctly.
Is this due to IStream inheriting from ISquentialStream and thus the vtable being incorrectly laid out?
Yes, I should have a PR out tomorrow with support for this. Hang tight.
Most helpful comment
I just got it working. A bit more polish needed, but it's looking good. 馃槈 Here's an example: