diff --git a/Cargo.toml b/Cargo.toml index 179929d..3bdcb25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,15 +13,12 @@ categories = ["rendering", "rendering::graphics-api"] include = ["src", "LICENSE"] documentation = "https://docs.rs/hassle-rs" -[package.metadata.docs.rs] -default-target = "x86_64-pc-windows-msvc" - [dependencies] -libloading = "0.7.0" -com-rs = "0.2.1" bitflags = "1.2.1" -widestring = "1.0.1" +com = { version = "0.6", features = ["production"] } +libloading = "0.7.0" thiserror = "1.0" +widestring = "1.0.1" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.9", features = ["wtypes", "oleauto", "combaseapi"] } diff --git a/src/ffi.rs b/src/ffi.rs index 4e86f8b..345ddf2 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -2,11 +2,11 @@ #![allow(clippy::too_many_arguments)] use crate::os::{HRESULT, LPCWSTR, LPWSTR}; -use com_rs::{com_interface, iid, IUnknown, IID}; +use com::{interfaces, interfaces::IUnknown, IID}; use std::ffi::c_void; -pub type DxcCreateInstanceProc = - extern "system" fn(rclsid: &IID, riid: &IID, ppv: *mut *mut c_void) -> HRESULT; +pub type DxcCreateInstanceProc = + extern "system" fn(rclsid: &IID, riid: &IID, ppv: *mut Option) -> HRESULT; pub type DxcCreateInstanceProc2 = extern "system" fn( malloc: /* IMalloc */ *const c_void, @@ -17,77 +17,106 @@ pub type DxcCreateInstanceProc2 = extern "system" fn( pub const DFCC_DXIL: u32 = u32::from_le_bytes([b'D', b'X', b'I', b'L']); -iid!(pub IID_IDxcBlob = 0x8BA5_FB08, 0x5195, 0x40e2, 0xAC, 0x58, 0x0D, 0x98, 0x9C, 0x3A, 0x01, 0x02); -com_interface! { - interface IDxcBlob: IUnknown{ - iid: IID_IDxcBlob, - vtable: IDxcBlobVtbl, - fn get_buffer_pointer() -> *mut c_void; - fn get_buffer_size() -> usize; +interfaces! { + #[uuid("8ba5fb08-5195-40e2-ac58-0d989c3a0102")] + pub(crate) unsafe interface IDxcBlob: IUnknown { + pub(crate) fn get_buffer_pointer(&self) -> *mut c_void; + pub(crate) fn get_buffer_size(&self) -> usize; } -} -iid!(pub IID_IDxcBlobEncoding = 0x7241_d424, 0x2646, 0x4191, 0x97, 0xc0, 0x98, 0xe9, 0x6e, 0x42, 0xfc, 0x68); -com_interface! { - interface IDxcBlobEncoding: IDxcBlob, IUnknown{ - iid: IID_IDxcBlobEncoding, - vtable: IDxcBlobEncodingVtbl, - fn get_encoding(known: *mut u32, code_page: *mut u32) -> HRESULT; + #[uuid("7241d424-2646-4191-97c0-98e96e42fc68")] + pub(crate) unsafe interface IDxcBlobEncoding: IDxcBlob { + pub(crate) fn get_encoding(&self, known: *mut u32, code_page: *mut u32) -> HRESULT; } -} -iid!(pub IID_IDxcLibrary = 0xe520_4dc7, 0xd18c, 0x4c3c, 0xbd, 0xfb, 0x85, 0x16, 0x73, 0x98, 0x0f, 0xe7); -com_interface! { - interface IDxcLibrary: IUnknown{ - iid: IID_IDxcLibrary, - vtable: IDxcLibraryVtbl, - fn set_malloc(malloc: *const c_void) -> HRESULT; - fn create_blob_from_blob(blob: *const IDxcBlob, offset: u32, length: u32, result_blob: *mut *mut IDxcBlob) -> HRESULT; - fn create_blob_from_file(filename: LPCWSTR, code_page: *const u32, blob_encoding: *mut *mut IDxcBlobEncoding) -> HRESULT; - fn create_blob_with_encoding_from_pinned(text: *const c_void, size: u32, code_page: u32, blob_encoding: *mut *mut IDxcBlobEncoding) -> HRESULT; - fn create_blob_with_encoding_on_heap_copy(text: *const c_void, size: u32, code_page: u32, blob_encoding: *mut *mut IDxcBlobEncoding) -> HRESULT; - fn create_blob_with_encoding_on_malloc(text: *const c_void, malloc: /* IMalloc */ *const c_void, size: u32, code_page: u32, blob_encoding: *mut *mut IDxcBlobEncoding) -> HRESULT; - fn create_include_handler(include_handler: *mut *mut IDxcIncludeHandler) -> HRESULT; - fn create_stream_from_blob_read_only(blob: *const IDxcBlob, stream: /* IStream */ *mut *mut c_void) -> HRESULT; - fn get_blob_as_utf8(blob: *const IDxcBlob, blob_encoding: *mut *mut IDxcBlobEncoding) -> HRESULT; - fn get_blob_as_utf16(blob: *const IDxcBlob, blob_encoding: *mut *mut IDxcBlobEncoding) -> HRESULT; + #[uuid("e5204dc7-d18c-4c3c-bdfb-851673980fe7")] + pub(crate) unsafe interface IDxcLibrary: IUnknown { + pub(crate) fn set_malloc(&self, malloc: *const c_void) -> HRESULT; + pub(crate) fn create_blob_from_blob( + &self, + blob: IDxcBlob, + offset: u32, + length: u32, + result_blob: *mut Option, + ) -> HRESULT; + pub(crate) fn create_blob_from_file( + &self, + filename: LPCWSTR, + code_page: *const u32, + blob_encoding: *mut Option, + ) -> HRESULT; + pub(crate) fn create_blob_with_encoding_from_pinned( + &self, + text: *const c_void, + size: u32, + code_page: u32, + blob_encoding: *mut Option, + ) -> HRESULT; + pub(crate) fn create_blob_with_encoding_on_heap_copy( + &self, + text: *const c_void, + size: u32, + code_page: u32, + blob_encoding: *mut Option, + ) -> HRESULT; + pub(crate) fn create_blob_with_encoding_on_malloc( + &self, + text: *const c_void, + malloc: *const /* IMalloc */ c_void, + size: u32, + code_page: u32, + blob_encoding: *mut Option, + ) -> HRESULT; + pub(crate) fn create_include_handler( + &self, + include_handler: *mut Option, + ) -> HRESULT; + pub(crate) fn create_stream_from_blob_read_only( + &self, + blob: IDxcBlob, + stream: *mut *mut /* IStream */ c_void, + ) -> HRESULT; + pub(crate) fn get_blob_as_utf8( + &self, + blob: IDxcBlob, + blob_encoding: *mut Option, + ) -> HRESULT; + pub(crate) fn get_blob_as_utf16( + &self, + blob: IDxcBlob, + blob_encoding: *mut Option, + ) -> HRESULT; } -} -iid!(pub IID_IDxcOperationResult = 0xCEDB_484A, 0xD4E9, 0x445A, 0xB9, 0x91, 0xCA, 0x21, 0xCA, 0x15, 0x7D, 0xC2); -com_interface! { - interface IDxcOperationResult: IUnknown{ - iid: IID_IDxcOperationResult, - vtable: IDxcOperationResultVtbl, - fn get_status(status: *mut u32) -> HRESULT; - fn get_result(result: *mut *mut IDxcBlob) -> HRESULT; - fn get_error_buffer(errors: *mut *mut IDxcBlobEncoding) -> HRESULT; + #[uuid("cedb484a-d4e9-445a-b991-ca21ca157dc2")] + pub(crate) unsafe interface IDxcOperationResult: IUnknown { + pub(crate) fn get_status(&self, status: *mut u32) -> HRESULT; + pub(crate) fn get_result(&self, result: *mut Option) -> HRESULT; + pub(crate) fn get_error_buffer(&self, errors: *mut Option) -> HRESULT; } -} -iid!(pub IID_IDxcIncludeHandler = 0x7f61_fc7d, 0x950d, 0x467f, 0xb3, 0xe3, 0x3c, 0x02, 0xfb, 0x49, 0x18, 0x7c); -com_interface! { - interface IDxcIncludeHandler: IUnknown{ - iid: IID_IDxcIncludeHandler, - vtable: IDxcIncludeHandlerVtbl, - fn load_source(filename: LPCWSTR, include_source: *mut *mut IDxcBlob) -> HRESULT; + #[uuid("7f61fc7d-950d-467f-b3e3-3c02fb49187c")] + pub(crate) unsafe interface IDxcIncludeHandler: IUnknown { + pub(crate) fn load_source( + &self, + filename: LPCWSTR, + include_source: *mut Option, + ) -> HRESULT; } } #[repr(C)] -#[derive(Debug)] pub struct DxcDefine { pub name: LPCWSTR, pub value: LPCWSTR, } -iid!(pub IID_IDxcCompiler = 0x8c21_0bf3, 0x011f, 0x4422, 0x8d, 0x70, 0x6f, 0x9a, 0xcb, 0x8d, 0xb6, 0x17); -com_interface! { - interface IDxcCompiler: IUnknown{ - iid: IID_IDxcCompiler, - vtable: IDxcCompilerVtbl, - fn compile( - blob: *const IDxcBlob, +interfaces! { + #[uuid("8c210bf3-011f-4422-8d70-6f9acb8db617")] + pub(crate) unsafe interface IDxcCompiler: IUnknown { + pub(crate) fn compile( + &self, + blob: IDxcBlob, source_name: LPCWSTR, entry_point: LPCWSTR, target_profile: LPCWSTR, @@ -95,33 +124,34 @@ com_interface! { arg_count: u32, defines: *const DxcDefine, def_count: u32, - include_handler: *const IDxcIncludeHandler, - result: *mut *mut IDxcOperationResult) -> HRESULT; + include_handler: Option, + result: *mut Option, + ) -> HRESULT; - fn preprocess( - blob: *const IDxcBlob, + pub(crate) fn preprocess( + &self, + blob: IDxcBlob, source_name: LPCWSTR, arguments: *const LPCWSTR, arg_count: u32, defines: *const DxcDefine, def_count: u32, - include_handler: *const IDxcIncludeHandler, - result: *mut *mut IDxcOperationResult) -> HRESULT; - - fn disassemble( - blob: *const IDxcBlob, - disassembly: *mut *mut IDxcBlobEncoding) -> HRESULT; + include_handler: Option, + result: *mut Option, + ) -> HRESULT; + + pub(crate) fn disassemble( + &self, + blob: IDxcBlob, + disassembly: *mut Option, + ) -> HRESULT; } -} - -iid!(pub IID_IDxcCompiler2 = 0xA005_A9D9, 0xB8BB, 0x4594, 0xB5, 0xC9, 0x0E, 0x63, 0x3B, 0xEC, 0x4D, 0x37); -com_interface! { - interface IDxcCompiler2: IDxcCompiler, IUnknown{ - iid: IID_IDxcCompiler2, - vtable: IDxcCompiler2Vtbl, - fn compile_with_debug( - blob: *const IDxcBlob, + #[uuid("a005a9d9-b8bb-4594-b5c9-0e633bec4d37")] + pub(crate) unsafe interface IDxcCompiler2: IDxcCompiler { + pub(crate) fn compile_with_debug( + &self, + blob: IDxcBlob, source_name: LPCWSTR, entry_point: LPCWSTR, target_profile: LPCWSTR, @@ -129,29 +159,27 @@ com_interface! { arg_count: u32, defines: *const DxcDefine, def_count: u32, - include_handler: *const IDxcIncludeHandler, - result: *mut *mut IDxcOperationResult, + include_handler: Option, + result: *mut Option, debug_blob_name: *mut LPWSTR, - debug_blob: *mut *mut IDxcBlob) -> HRESULT; + debug_blob: *mut Option, + ) -> HRESULT; } -} - -iid!(pub IID_IDxcLinker = 0xF1B5_BE2A, 0x62DD, 0x4327, 0xA1, 0xC2, 0x42, 0xAC, 0x1E, 0x1E, 0x78, 0xE6); -com_interface! { - interface IDxcLinker: IUnknown{ - iid: IID_IDxcLinker, - vtable: IDxcLinkerVtbl, - fn register_library(lib_name: LPCWSTR, lib: *const IDxcBlob) -> HRESULT; + #[uuid("f1b5be2a-62dd-4327-a1c2-42ac1e1e78e6")] + pub(crate) unsafe interface IDxcLinker: IUnknown { + pub(crate) fn register_library(&self, lib_name: LPCWSTR, lib: IDxcBlob) -> HRESULT; - fn link( + pub(crate) fn link( + &self, entry_name: LPCWSTR, target_profile: LPCWSTR, lib_names: *const LPCWSTR, lib_count: u32, arguments: *const LPCWSTR, arg_count: u32, - result: *mut *mut IDxcOperationResult) -> HRESULT; + result: *mut Option, + ) -> HRESULT; } } @@ -161,82 +189,129 @@ pub const DXC_VALIDATOR_FLAGS_ROOT_SIGNATURE_ONLY: u32 = 2; pub const DXC_VALIDATOR_FLAGS_MODULE_ONLY: u32 = 4; pub const DXC_VALIDATOR_FLAGS_VALID_MASK: u32 = 0x7; -iid!(pub IID_IDxcValidator = 0xA6E8_2BD2, 0x1FD7, 0x4826, 0x98, 0x11, 0x28, 0x57, 0xE7, 0x97, 0xF4, 0x9A); -com_interface! { - interface IDxcValidator: IUnknown{ - iid: IID_IDxcValidator, - vtable: IDxcValidatorVtbl, - - fn validate(shader: *const IDxcBlob, flags: u32, result: *mut *mut IDxcOperationResult) -> HRESULT; +interfaces! { + #[uuid("a6e82bd2-1fd7-4826-9811-2857e797f49a")] + pub(crate) unsafe interface IDxcValidator: IUnknown { + pub(crate) fn validate( + &self, + shader: IDxcBlob, + flags: u32, + result: *mut Option, + ) -> HRESULT; } -} - -iid!(pub IID_IDxcContainerBuilder = 0x334b_1f50, 0x2292, 0x4b35, 0x99, 0xa1, 0x25, 0x58, 0x8d, 0x8c, 0x17, 0xfe); -com_interface! { - interface IDxcContainerBuilder: IUnknown{ - iid: IID_IDxcContainerBuilder, - vtable: IDxcContainerBuilderVtbl, - fn load(dxil_container_header: *const IDxcBlob) -> HRESULT; - fn add_part(four_cc: u32, source: *const IDxcBlob) -> HRESULT; - fn remove_part(four_cc: u32) -> HRESULT; - fn seralize_container(result: *mut *mut IDxcOperationResult) -> HRESULT; + #[uuid("334b1f50-2292-4b35-99a1-25588d8c17fe")] + pub(crate) unsafe interface IDxcContainerBuilder: IUnknown { + pub(crate) fn load(&self, dxil_container_header: IDxcBlob) -> HRESULT; + pub(crate) fn add_part(&self, four_cc: u32, source: IDxcBlob) -> HRESULT; + pub(crate) fn remove_part(&self, four_cc: u32) -> HRESULT; + pub(crate) fn seralize_container( + &self, + result: *mut Option, + ) -> HRESULT; } -} -iid!(pub IID_IDxcAssembler = 0x091f_7a26, 0x1c1f, 0x4948, 0x90, 0x4b, 0xe6, 0xe3, 0xa8, 0xa7, 0x71, 0xd5); -com_interface! { - interface IDxcAssembler: IUnknown{ - iid: IID_IDxcAssembler, - vtable: IDxcAssemblerVtbl, - - fn assemble_to_container(shader: *const IDxcBlob, result: *mut *mut IDxcOperationResult) -> HRESULT; + #[uuid("091f7a26-1c1f-4948-904b-e6e3a8a771d5")] + pub(crate) unsafe interface IDxcAssembler: IUnknown { + pub(crate) fn assemble_to_container( + &self, + shader: IDxcBlob, + result: *mut Option, + ) -> HRESULT; } -} -iid!(pub IID_IDxcContainerReflection = 0xd2c2_1b26, 0x8350, 0x4bdc, 0x97, 0x6a, 0x33, 0x1c, 0xe6, 0xf4, 0xc5, 0x4c); -com_interface! { - interface IDxcContainerReflection: IUnknown{ - iid: IID_IDxcContainerReflection, - vtable: IDxcContainerReflectionVtbl, - - fn load(container: *const IDxcBlob) -> HRESULT; - fn get_part_count(result: *mut u32) -> HRESULT; - fn get_part_kind(idx: u32, result: *mut u32) -> HRESULT; - fn get_part_content(idx: u32, result: *mut *mut IDxcBlob) -> HRESULT; - fn find_first_part_kind(kind: u32, result: *mut u32) -> HRESULT; - fn get_part_reflection(idx: u32, iid: &IID, object: *mut *mut c_void) -> HRESULT; + #[uuid("d2c21b26-8350-4bdc-976a-331ce6f4c54c")] + pub(crate) unsafe interface IDxcContainerReflection: IUnknown { + pub(crate) fn load(&self, container: IDxcBlob) -> HRESULT; + pub(crate) fn get_part_count(&self, result: *mut u32) -> HRESULT; + pub(crate) fn get_part_kind(&self, idx: u32, result: *mut u32) -> HRESULT; + pub(crate) fn get_part_content(&self, idx: u32, result: *mut Option) -> HRESULT; + pub(crate) fn find_first_part_kind(&self, kind: u32, result: *mut u32) -> HRESULT; + pub(crate) fn get_part_reflection( + &self, + idx: u32, + iid: *const IID, + object: *mut Option, + ) -> HRESULT; } -} -iid!(pub IID_IDxcOptimizerPass = 0xAE2C_D79F, 0xCC22, 0x453F, 0x9B, 0x6B, 0xB1, 0x24, 0xE7, 0xA5, 0x20, 0x4C); -com_interface! { - interface IDxcOptimizerPass: IUnknown{ - iid: IID_IDxcOptimizerPass, - vtable: IDxcOptimizerPassVtbl, - - fn get_option_name(result: *mut LPWSTR) -> HRESULT; - fn get_description(result: *mut LPWSTR) -> HRESULT; - fn get_option_arg_count(count: *mut u32) -> HRESULT; - fn get_option_arg_name(arg_idx: u32, result: *mut LPWSTR) -> HRESULT; - fn get_option_arg_description(arg_idx: u32, result: *mut LPWSTR) -> HRESULT; + #[uuid("5a58797d-a72c-478d-8ba2-efc6b0efe88e")] + pub(crate) unsafe interface ID3D12ShaderReflection: IUnknown { + pub(crate) fn get_desc(&self, p_desc: *mut c_void) -> HRESULT; + pub(crate) fn get_constant_buffer_by_index(&self, index: u32) -> *mut c_void; + pub(crate) fn get_constant_buffer_by_name(&self, name: *const c_void) -> *mut c_void; + pub(crate) fn get_resource_binding_desc( + &self, + resource_index: u32, + p_desc: *mut c_void, + ) -> HRESULT; + pub(crate) fn get_input_parameter_desc( + &self, + parameter_index: u32, + p_desc: *mut c_void, + ) -> HRESULT; + pub(crate) fn get_output_parameter_desc( + &self, + parameter_index: u32, + p_desc: *mut c_void, + ) -> HRESULT; + pub(crate) fn get_patch_constant_parameter_desc( + &self, + parameter_index: u32, + p_desc: *mut c_void, + ) -> HRESULT; + pub(crate) fn get_variable_by_name(&self, name: *const c_void) -> *mut c_void; + pub(crate) fn get_resource_binding_desc_by_name( + &self, + name: *const c_void, + p_desc: *mut c_void, + ) -> HRESULT; + pub(crate) fn get_mov_instruction_count(&self) -> u32; + pub(crate) fn get_movc_instruction_count(&self) -> u32; + pub(crate) fn get_conversion_instruction_count(&self) -> u32; + pub(crate) fn get_bitwise_instruction_count(&self) -> u32; + pub(crate) fn get_gs_input_primitive(&self) -> u32; + pub(crate) fn is_sample_frequency_shader(&self) -> bool; + pub(crate) fn get_num_interface_slots(&self) -> u32; + pub(crate) fn get_min_feature_level(&self, p_level: *mut c_void) -> HRESULT; + pub(crate) fn get_thread_group_size( + &self, + size_x: *mut u32, + size_y: *mut u32, + size_z: *mut u32, + ) -> u32; + pub(crate) fn get_requires_flags(&self) -> u64; } -} -iid!(pub IID_IDxcOptimizer = 0x2574_0E2E, 0x9CBA, 0x401B, 0x91, 0x19, 0x4F, 0xB4, 0x2F, 0x39, 0xF2, 0x70); -com_interface! { - interface IDxcOptimizer: IUnknown{ - iid: IID_IDxcOptimizer, - vtable: IDxcOptimizerVtbl, + #[uuid("ae2cd79f-cc22-453f-9b6b-b124e7a5204c")] + pub(crate) unsafe interface IDxcOptimizerPass: IUnknown { + pub(crate) fn get_option_name(&self, result: *mut LPWSTR) -> HRESULT; + pub(crate) fn get_description(&self, result: *mut LPWSTR) -> HRESULT; + pub(crate) fn get_option_arg_count(&self, count: *mut u32) -> HRESULT; + pub(crate) fn get_option_arg_name(&self, arg_idx: u32, result: *mut LPWSTR) -> HRESULT; + pub(crate) fn get_option_arg_description( + &self, + arg_idx: u32, + result: *mut LPWSTR, + ) -> HRESULT; + } - fn get_available_pass_count(count: *mut u32) -> HRESULT; - fn get_available_pass(index: u32, result: *mut *mut IDxcOptimizerPass) -> HRESULT; - fn run_optimizer( - blob: *const IDxcBlob, + #[uuid("25740e2e-9cba-401b-9119-4fb42f39f270")] + pub(crate) unsafe interface IDxcOptimizer: IUnknown { + pub(crate) fn get_available_pass_count(&self, count: *mut u32) -> HRESULT; + pub(crate) fn get_available_pass( + &self, + index: u32, + result: *mut Option, + ) -> HRESULT; + pub(crate) fn run_optimizer( + &self, + blob: IDxcBlob, options: *const LPCWSTR, option_count: u32, - output_module: *mut *mut IDxcBlob, - output_text: *mut *mut IDxcBlobEncoding) -> HRESULT; + output_module: *mut Option, + output_text: *mut Option, + ) -> HRESULT; } } @@ -244,60 +319,74 @@ pub const DXC_VERSION_INFO_FLAGS_NONE: u32 = 0; pub const DXC_VERSION_INFO_FLAGS_DEBUG: u32 = 1; // Matches VS_FF_DEBUG pub const DXC_VERSION_INFO_FLAGS_INTERNAL: u32 = 2; // Internal Validator (non-signing) -iid!(pub IID_IDxcVersionInfo = 0xb04f_5b50, 0x2059, 0x4f12, 0xa8, 0xff, 0xa1, 0xe0, 0xcd, 0xe1, 0xcc, 0x7e); -com_interface! { - interface IDxcVersionInfo: IUnknown{ - iid: IID_IDxcVersionInfo, - vtable: IDxcVersionInfoVtbl, - - fn get_version(major: *mut u32, minor: *mut u32) -> HRESULT; - fn get_flags(flags: *mut u32) -> HRESULT; - } -} - -iid!(pub IID_IDxcVersionInfo2 = 0xfb69_04c4, 0x42f0, 0x4b62, 0x9c, 0x46, 0x98, 0x3a, 0xf7, 0xda, 0x7c, 0x83); -com_interface! { - interface IDxcVersionInfo2: IUnknown{ - iid: IID_IDxcVersionInfo2, - vtable: IDxcVersionInfo2Vtbl, - - fn get_commit_info(commit_count: *mut u32, commit_hash: *mut *mut u8) -> HRESULT; +interfaces! { + #[uuid("b04f5b50-2059-4f12-a8ff-a1e0cde1cc7e")] + pub(crate) unsafe interface IDxcVersionInfo: IUnknown { + pub(crate) fn get_version(&self, major: *mut u32, minor: *mut u32) -> HRESULT; + pub(crate) fn get_flags(&self, flags: *mut u32) -> HRESULT; } -} -iid!(pub IID_ID3D12ShaderReflection = 0x5a58_797d, 0xa72c, 0x478d, 0x8b, 0xa2, 0xef, 0xc6, 0xb0, 0xef, 0xe8, 0x8e); -com_interface! { - interface ID3D12ShaderReflection: IUnknown { - iid: IID_ID3D12ShaderReflection, - vtable: ID3D12ShaderReflectionVtbl, - fn get_desc(p_desc: *mut c_void) -> HRESULT; - fn get_constant_buffer_by_index(index: u32) -> *mut c_void; - fn get_constant_buffer_by_name(name: *const c_void) -> *mut c_void; - fn get_resource_binding_desc(resource_index: u32, p_desc: *mut c_void) -> HRESULT; - fn get_input_parameter_desc(parameter_index: u32, p_desc: *mut c_void) -> HRESULT; - fn get_output_parameter_desc(parameter_index: u32, p_desc: *mut c_void) -> HRESULT; - fn get_patch_constant_parameter_desc(parameter_index: u32, p_desc: *mut c_void) -> HRESULT; - fn get_variable_by_name(name: *const c_void) -> *mut c_void; - fn get_resource_binding_desc_by_name(name: *const c_void, p_desc: *mut c_void) -> HRESULT; - fn get_mov_instruction_count() -> u32; - fn get_movc_instruction_count() -> u32; - fn get_conversion_instruction_count() -> u32; - fn get_bitwise_instruction_count() -> u32; - fn get_gs_input_primitive() -> u32; - fn is_sample_frequency_shader() -> bool; - fn get_num_interface_slots() -> u32; - fn get_min_feature_level(p_level: *mut c_void) -> HRESULT; - fn get_thread_group_size(size_x: *mut u32, size_y: *mut u32, size_z: *mut u32) -> u32; - fn get_requires_flags() -> u64; + #[uuid("fb6904c4-42f0-4b62-9c46-983af7da7c83")] + pub(crate) unsafe interface IDxcVersionInfo2: IUnknown { + pub(crate) fn get_commit_info( + &self, + commit_count: *mut u32, + commit_hash: *mut *mut u8, + ) -> HRESULT; } } -iid!(pub CLSID_DxcCompiler = 0x73e2_2d93, 0xe6ce, 0x47f3, 0xb5, 0xbf, 0xf0, 0x66, 0x4f, 0x39, 0xc1, 0xb0); -iid!(pub CLSID_DxcLinker = 0xef6a_8087, 0xb0ea, 0x4d56, 0x9e, 0x45, 0xd0, 0x7e, 0x1a, 0x8b, 0x78, 0x6); -iid!(pub CLSID_DxcDiaDataSource = 0xcd1f_6b73, 0x2ab0, 0x484d, 0x8e, 0xdc, 0xeb, 0xe7, 0xa4, 0x3c, 0xa0, 0x9f ); -iid!(pub CLSID_DxcLibrary = 0x6245_d6af, 0x66e0, 0x48fd, 0x80, 0xb4, 0x4d, 0x27, 0x17, 0x96, 0x74, 0x8c); -iid!(pub CLSID_DxcValidator = 0x8ca3_e215, 0xf728, 0x4cf3, 0x8c, 0xdd, 0x88, 0xaf, 0x91, 0x75, 0x87, 0xa1 ); -iid!(pub CLSID_DxcAssembler = 0xd728_db68, 0xf903, 0x4f80, 0x94, 0xcd, 0xdc, 0xcf, 0x76, 0xec, 0x71, 0x51); -iid!(pub CLSID_DxcContainerReflection = 0xb9f5_4489, 0x55b8, 0x400c, 0xba, 0x3a, 0x16, 0x75, 0xe4, 0x72, 0x8b, 0x91); -iid!(pub CLSID_DxcOptimizer = 0xae2c_d79f, 0xcc22, 0x453f, 0x9b, 0x6b, 0xb1, 0x24, 0xe7, 0xa5, 0x20, 0x4c); -iid!(pub CLSID_DxcContainerBuilder = 0x9413_4294, 0x411f, 0x4574, 0xb4, 0xd0, 0x87, 0x41, 0xe2, 0x52, 0x40, 0xd2 ); +pub const CLSID_DxcCompiler: IID = IID { + data1: 0x73e22d93, + data2: 0xe6ce, + data3: 0x47f3, + data4: [0xb5, 0xbf, 0xf0, 0x66, 0x4f, 0x39, 0xc1, 0xb0], +}; +pub const CLSID_DxcLinker: IID = IID { + data1: 0xef6a8087, + data2: 0xb0ea, + data3: 0x4d56, + data4: [0x9e, 0x45, 0xd0, 0x7e, 0x1a, 0x8b, 0x78, 0x6], +}; +pub const CLSID_DxcDiaDataSource: IID = IID { + data1: 0xcd1f6b73, + data2: 0x2ab0, + data3: 0x484d, + data4: [0x8e, 0xdc, 0xeb, 0xe7, 0xa4, 0x3c, 0xa0, 0x9f], +}; +pub const CLSID_DxcLibrary: IID = IID { + data1: 0x6245d6af, + data2: 0x66e0, + data3: 0x48fd, + data4: [0x80, 0xb4, 0x4d, 0x27, 0x17, 0x96, 0x74, 0x8c], +}; +pub const CLSID_DxcValidator: IID = IID { + data1: 0x8ca3e215, + data2: 0xf728, + data3: 0x4cf3, + data4: [0x8c, 0xdd, 0x88, 0xaf, 0x91, 0x75, 0x87, 0xa1], +}; +pub const CLSID_DxcAssembler: IID = IID { + data1: 0xd728db68, + data2: 0xf903, + data3: 0x4f80, + data4: [0x94, 0xcd, 0xdc, 0xcf, 0x76, 0xec, 0x71, 0x51], +}; +pub const CLSID_DxcContainerReflection: IID = IID { + data1: 0xb9f54489, + data2: 0x55b8, + data3: 0x400c, + data4: [0xba, 0x3a, 0x16, 0x75, 0xe4, 0x72, 0x8b, 0x91], +}; +pub const CLSID_DxcOptimizer: IID = IID { + data1: 0xae2cd79f, + data2: 0xcc22, + data3: 0x453f, + data4: [0x9b, 0x6b, 0xb1, 0x24, 0xe7, 0xa5, 0x20, 0x4c], +}; +pub const CLSID_DxcContainerBuilder: IID = IID { + data1: 0x94134294, + data2: 0x411f, + data3: 0x4574, + data4: [0xb4, 0xd0, 0x87, 0x41, 0xe2, 0x52, 0x40, 0xd2], +}; diff --git a/src/intellisense/ffi.rs b/src/intellisense/ffi.rs index 0959cb4..2ce0773 100644 --- a/src/intellisense/ffi.rs +++ b/src/intellisense/ffi.rs @@ -1,6 +1,22 @@ use crate::os::{BSTR, HRESULT, LPCSTR, LPSTR}; use bitflags::bitflags; -use com_rs::{com_interface, iid, IUnknown}; +use com::{interfaces, interfaces::IUnknown, AbiTransferable, IID}; + +macro_rules! abi_transferable { + ($t:ident) => { + unsafe impl AbiTransferable for $t { + type Abi = u32; + + fn get_abi(&self) -> Self::Abi { + self.bits + } + + fn set_abi(&mut self) -> *mut Self::Abi { + &mut self.bits + } + } + }; +} bitflags! { pub struct DxcGlobalOptions : u32 { @@ -12,6 +28,7 @@ bitflags! { | DxcGlobalOptions::THREAD_BACKGROUND_PRIORITY_FOR_EDITING.bits; } } +abi_transferable!(DxcGlobalOptions); bitflags! { pub struct DxcDiagnosticSeverity : u32 { @@ -101,6 +118,7 @@ bitflags! { const INCLUDE_NAMESPACE_KEYWORD = 0x8; } } +abi_transferable!(DxcCursorFormatting); bitflags! { pub struct DxcTranslationUnitFlags : u32 { @@ -116,6 +134,7 @@ bitflags! { const USE_CALLER_THREAD = 0x800; } } +abi_transferable!(DxcTranslationUnitFlags); bitflags! { pub struct DxcDiagnosticDisplayOptions : u32 { @@ -128,19 +147,20 @@ bitflags! { const DISPLAY_SEVERITY = 0x200; } } +abi_transferable!(DxcDiagnosticDisplayOptions); bitflags! { pub struct DxcCursorKindFlags : u32 { - const NONE = 0; - const DECLARATION = 0x1; - const REFERENCE = 0x2; - const EXPRESSION = 0x4; - const STATEMENT = 0x8; - const ATTRIBUTE = 0x10; - const INVALID = 0x20; - const TRANSLATION_UNIT = 0x40; - const PREPROCESSING = 0x80; - const UNEXPOSED = 0x100; + const NONE = 0; + const DECLARATION = 0x1; + const REFERENCE = 0x2; + const EXPRESSION = 0x4; + const STATEMENT = 0x8; + const ATTRIBUTE = 0x10; + const INVALID = 0x20; + const TRANSLATION_UNIT = 0x40; + const PREPROCESSING = 0x80; + const UNEXPOSED = 0x100; } } @@ -356,184 +376,293 @@ bitflags! { } } -iid!(pub IID_IDxcDiagnostic = 0x4f76b234, 0x3659, 0x4d33, 0x99, 0xb0, 0x3b, 0x0d, 0xb9, 0x94, 0xb5, 0x64); -com_interface! { - interface IDxcDiagnostic: IUnknown{ - iid: IID_IDxcDiagnostic, - vtable: IDxcDiagnosticVtbl, - fn format_diagnostic(options: DxcDiagnosticDisplayOptions, result: *mut LPSTR) -> HRESULT; - fn get_severity(result: *mut DxcDiagnosticSeverity) -> HRESULT; - fn get_location(result: *mut *mut IDxcSourceLocation) -> HRESULT; - fn get_spelling(result: *mut LPSTR) -> HRESULT; - fn get_category_text(result: *mut LPSTR) -> HRESULT; - fn get_num_ranges(result: *mut u32) -> HRESULT; - fn get_range_at(index: u32, result: *mut *mut IDxcSourceRange) -> HRESULT; - fn get_num_fix_its(result: *mut u32) -> HRESULT; - fn get_fix_it_at(index: u32, replacement_range: *mut *mut IDxcSourceRange, text: *mut LPSTR) -> HRESULT; +interfaces! { + #[uuid("4f76b234-3659-4d33-99b0-3b0db994b564")] + pub(crate) unsafe interface IDxcDiagnostic: IUnknown { + pub(crate) unsafe fn format_diagnostic( + &self, + options: DxcDiagnosticDisplayOptions, + result: *mut LPSTR, + ) -> HRESULT; + pub(crate) unsafe fn get_severity(&self, result: *mut DxcDiagnosticSeverity) -> HRESULT; + pub(crate) unsafe fn get_location( + &self, + result: *mut Option, + ) -> HRESULT; + pub(crate) unsafe fn get_spelling(&self, result: *mut LPSTR) -> HRESULT; + pub(crate) unsafe fn get_category_text(&self, result: *mut LPSTR) -> HRESULT; + pub(crate) unsafe fn get_num_ranges(&self, result: *mut u32) -> HRESULT; + pub(crate) unsafe fn get_range_at( + &self, + index: u32, + result: *mut Option, + ) -> HRESULT; + pub(crate) unsafe fn get_num_fix_its(&self, result: *mut u32) -> HRESULT; + pub(crate) unsafe fn get_fix_it_at( + &self, + index: u32, + replacement_range: *mut Option, + text: *mut LPSTR, + ) -> HRESULT; } -} -iid!(pub IID_IDxcInclusion = 0x0c364d65, 0xdf44, 0x4412, 0x88, 0x8e, 0x4e, 0x55, 0x2f, 0xc5, 0xe3, 0xd6); -com_interface! { - interface IDxcInclusion: IUnknown{ - iid: IID_IDxcInclusion, - vtable: IDxcInclusionVtbl, - fn get_included_file(result: *mut *mut IDxcFile) -> HRESULT; - fn get_stack_length(result: *mut u32) -> HRESULT; - fn get_stack_item(index: u32, result: *mut *mut IDxcSourceLocation) -> HRESULT; + #[uuid("0c364d65-df44-4412-888e-4e552fc5e3d6")] + pub(crate) unsafe interface IDxcInclusion: IUnknown { + pub(crate) unsafe fn get_included_file(&self, result: *mut Option) -> HRESULT; + pub(crate) unsafe fn get_stack_length(&self, result: *mut u32) -> HRESULT; + pub(crate) unsafe fn get_stack_item( + &self, + index: u32, + result: *mut Option, + ) -> HRESULT; } -} -iid!(pub IID_IDxcToken = 0x7f90b9ff, 0xa275, 0x4932, 0x97, 0xd8, 0x3c, 0xfd, 0x23, 0x44, 0x82, 0xa2); -com_interface! { - interface IDxcToken: IUnknown{ - iid: IID_IDxcToken, - vtable: IDxcTokenVtbl, - fn get_kind(value: *mut DxcTokenKind) -> HRESULT; - fn get_location(value: *mut *mut IDxcSourceLocation) -> HRESULT; - fn get_extent(value: *mut *mut IDxcSourceRange) -> HRESULT; - fn get_spelling(value: *mut LPSTR) -> HRESULT; + #[uuid("7f90b9ff-a275-4932-97d8-3cfd234482a2")] + pub(crate) unsafe interface IDxcToken: IUnknown { + pub(crate) unsafe fn get_kind(&self, value: *mut DxcTokenKind) -> HRESULT; + pub(crate) unsafe fn get_location(&self, value: *mut Option) + -> HRESULT; + pub(crate) unsafe fn get_extent(&self, value: *mut Option) -> HRESULT; + pub(crate) unsafe fn get_spelling(&self, value: *mut LPSTR) -> HRESULT; } -} -iid!(pub IID_IDxcType = 0x2ec912fd, 0xb144, 0x4a15, 0xad, 0x0d, 0x1c, 0x54, 0x39, 0xc8, 0x1e, 0x46); -com_interface! { - interface IDxcType: IUnknown{ - iid: IID_IDxcType, - vtable: IDxcTypeVtbl, - fn get_spelling(result: *mut LPSTR) -> HRESULT; - fn is_equal_to(other: *const IDxcType, result: *mut bool) -> HRESULT; - fn get_kind(result: *mut DxcTypeKind) -> HRESULT; + #[uuid("2ec912fd-b144-4a15-ad0d-1c5439c81e46")] + pub(crate) unsafe interface IDxcType: IUnknown { + pub(crate) unsafe fn get_spelling(&self, result: *mut LPSTR) -> HRESULT; + pub(crate) unsafe fn is_equal_to(&self, other: IDxcType, result: *mut bool) -> HRESULT; + pub(crate) unsafe fn get_kind(&self, result: *mut DxcCursorKind) -> HRESULT; } -} -iid!(pub IID_IDxcSourceLocation = 0x8e7ddf1c, 0xd7d3, 0x4d69, 0xb2, 0x86, 0x85, 0xfc, 0xcb, 0xa1, 0xe0, 0xcf); -com_interface! { - interface IDxcSourceLocation: IUnknown{ - iid: IID_IDxcSourceLocation, - vtable: IDxcSourceLocationVtbl, - fn is_equal_to(other: *const IDxcSourceLocation, result: *mut bool) -> HRESULT; - fn get_spelling_location(file: *mut *mut IDxcFile, line: *mut u32, col: *mut u32, offset: *mut u32) -> HRESULT; - fn is_null(result: *mut bool) -> HRESULT; + #[uuid("8e7ddf1c-d7d3-4d69-b286-85fccba1e0cf")] + pub(crate) unsafe interface IDxcSourceLocation: IUnknown { + pub(crate) unsafe fn is_equal_to( + &self, + other: IDxcSourceLocation, + result: *mut bool, + ) -> HRESULT; + pub(crate) unsafe fn get_spelling_location( + &self, + file: *mut Option, + line: *mut u32, + col: *mut u32, + offset: *mut u32, + ) -> HRESULT; + pub(crate) unsafe fn is_null(&self, result: *mut bool) -> HRESULT; } -} -iid!(pub IID_IDxcSourceRange = 0xf1359b36, 0xa53f, 0x4e81, 0xb5, 0x14, 0xb6, 0xb8, 0x41, 0x22, 0xa1, 0x3f); -com_interface! { - interface IDxcSourceRange: IUnknown{ - iid: IID_IDxcSourceRange, - vtable: IDxcSourceRangeVtbl, - fn is_null(value: *mut bool) -> HRESULT; - fn get_start(value: *mut *mut IDxcSourceLocation) -> HRESULT; - fn get_end(value: *mut *mut IDxcSourceLocation) -> HRESULT; - fn get_offsets(start_offset: *mut u32, end_offset: *mut u32) -> HRESULT; + #[uuid("f1359b36-a53f-4e81-b514-b6b84122a13f")] + pub(crate) unsafe interface IDxcSourceRange: IUnknown { + pub(crate) unsafe fn is_null(&self, value: *mut bool) -> HRESULT; + pub(crate) unsafe fn get_start(&self, value: *mut Option) -> HRESULT; + pub(crate) unsafe fn get_end(&self, value: *mut Option) -> HRESULT; + pub(crate) unsafe fn get_offsets( + &self, + start_offset: *mut u32, + end_offset: *mut u32, + ) -> HRESULT; } -} -iid!(pub IID_IDxcCursor = 0x1467b985, 0x288d, 0x4d2a, 0x80, 0xc1, 0xef, 0x89, 0xc4, 0x2c, 0x40, 0xbc); -com_interface! { - interface IDxcCursor: IUnknown{ - iid: IID_IDxcCursor, - vtable: IDxcCursorVtbl, - fn get_extent(range: *mut *mut IDxcSourceRange) -> HRESULT; - fn get_location(result: *mut *mut IDxcSourceLocation) -> HRESULT; - fn get_kind(result: *mut DxcCursorKind) -> HRESULT; - fn get_kind_flags(result: *mut DxcCursorKindFlags) -> HRESULT; - fn get_semantic_parent(result: *mut*mut IDxcCursor) -> HRESULT; - fn get_lexical_parent(result:*mut*mut IDxcCursor) -> HRESULT; - fn get_cursor_type(result:*mut*mut IDxcType) -> HRESULT; - fn get_num_arguments(result:*mut i32) -> HRESULT; - fn get_argument_at(index: i32, result: *mut *mut IDxcCursor) -> HRESULT; - fn get_referenced_cursor(result:*mut *mut IDxcCursor) -> HRESULT; - fn get_definition_cursor(result:*mut *mut IDxcCursor) -> HRESULT; - fn find_references_in_file(file: *const IDxcFile, skip: u32, top:u32, result_length: *mut u32, result: *mut *mut *mut IDxcCursor) -> HRESULT; - fn get_spelling(result: *mut LPSTR) -> HRESULT; - fn is_equal_to(other: *const IDxcCursor, result:*mut bool) -> HRESULT; - fn is_null(result:*mut bool) -> HRESULT; - fn is_definition(result:*mut bool) -> HRESULT; - fn get_display_name(result:*mut BSTR) -> HRESULT; - fn get_qualified_name(include_template_args:bool, result:*mut BSTR) -> HRESULT; - fn get_formatted_name(formatting: DxcCursorFormatting, result:*mut BSTR) -> HRESULT; - fn get_children(skip: u32, top: u32, result_length:*mut u32, result:*mut*mut*mut IDxcCursor) -> HRESULT; - fn get_snapped_child(location: *const IDxcSourceLocation, result:*mut*mut IDxcCursor) -> HRESULT; + #[uuid("1467b985-288d-4d2a-80c1-ef89c42c40bc")] + pub(crate) unsafe interface IDxcCursor: IUnknown { + pub(crate) unsafe fn get_extent(&self, range: *mut Option) -> HRESULT; + pub(crate) unsafe fn get_location( + &self, + result: *mut Option, + ) -> HRESULT; + pub(crate) unsafe fn get_kind(&self, result: *mut DxcCursorKind) -> HRESULT; + pub(crate) unsafe fn get_kind_flags(&self, result: *mut DxcCursorKindFlags) -> HRESULT; + pub(crate) unsafe fn get_semantic_parent(&self, result: *mut Option) + -> HRESULT; + pub(crate) unsafe fn get_lexical_parent(&self, result: *mut Option) -> HRESULT; + pub(crate) unsafe fn get_cursor_type(&self, result: *mut Option) -> HRESULT; + pub(crate) unsafe fn get_num_arguments(&self, result: *mut i32) -> HRESULT; + pub(crate) unsafe fn get_argument_at( + &self, + index: i32, + result: *mut Option, + ) -> HRESULT; + pub(crate) unsafe fn get_referenced_cursor( + &self, + result: *mut Option, + ) -> HRESULT; + pub(crate) unsafe fn get_definition_cursor( + &self, + result: *mut Option, + ) -> HRESULT; + pub(crate) unsafe fn find_references_in_file( + &self, + file: IDxcFile, + skip: u32, + top: u32, + result_length: *mut u32, + result: *mut *mut IDxcCursor, + ) -> HRESULT; + pub(crate) unsafe fn get_spelling(&self, result: *mut LPSTR) -> HRESULT; + pub(crate) unsafe fn is_equal_to(&self, other: IDxcCursor, result: *mut bool) -> HRESULT; + pub(crate) unsafe fn is_null(&self, result: *mut bool) -> HRESULT; + pub(crate) unsafe fn is_definition(&self, result: *mut bool) -> HRESULT; + pub(crate) unsafe fn get_display_name(&self, result: *mut BSTR) -> HRESULT; + pub(crate) unsafe fn get_qualified_name( + &self, + include_template_args: bool, + result: *mut BSTR, + ) -> HRESULT; + pub(crate) unsafe fn get_formatted_name( + &self, + formatting: DxcCursorFormatting, + result: *mut BSTR, + ) -> HRESULT; + pub(crate) unsafe fn get_children( + &self, + skip: u32, + top: u32, + result_length: *mut u32, + result: *mut *mut IDxcCursor, + ) -> HRESULT; + pub(crate) unsafe fn get_snapped_child( + &self, + location: IDxcSourceLocation, + result: *mut Option, + ) -> HRESULT; } -} -iid!(pub IID_IDxcUnsavedFile = 0x8ec00f98, 0x07d0, 0x4e60, 0x9d, 0x7c, 0x5a, 0x50, 0xb5, 0xb0, 0x01, 0x7f); -com_interface! { - interface IDxcUnsavedFile: IUnknown{ - iid: IID_IDxcUnsavedFile, - vtable: IDxcUnsavedFileVtbl, - fn get_file_name(file_name: *mut LPSTR) -> HRESULT; - fn get_contents(contents: *mut LPSTR) -> HRESULT; - fn get_length(length: *mut u32) -> HRESULT; + #[uuid("8ec00f98-07d0-4e60-9d7c-5a50b5b0017f")] + pub(crate) unsafe interface IDxcUnsavedFile: IUnknown { + pub(crate) unsafe fn get_file_name(&self, file_name: *mut LPSTR) -> HRESULT; + pub(crate) unsafe fn get_contents(&self, contents: *mut LPSTR) -> HRESULT; + pub(crate) unsafe fn get_length(&self, length: *mut u32) -> HRESULT; } -} -iid!(pub IID_IDxcFile = 0xbb2fca9e, 0x1478, 0x47ba, 0xb0, 0x8c, 0x2c, 0x50, 0x2a, 0xda, 0x48, 0x95); -com_interface! { - interface IDxcFile: IUnknown{ - iid: IID_IDxcFile, - vtable: IDxcFileVtbl, - fn get_name(result: *mut LPSTR) -> HRESULT; - fn is_equal_to(other: *const IDxcFile, result: *mut bool) -> HRESULT; + #[uuid("bb2fca9e-1478-47ba-b08c-2c502ada4895")] + pub(crate) unsafe interface IDxcFile: IUnknown { + pub(crate) unsafe fn get_name(&self, result: *mut LPSTR) -> HRESULT; + pub(crate) unsafe fn is_equal_to(&self, other: IDxcFile, result: *mut bool) -> HRESULT; } -} -iid!(pub IID_IDxcTranslationUnit = 0x9677dee0, 0xc0e5, 0x46a1, 0x8b, 0x40, 0x3d, 0xb3, 0x16, 0x8b, 0xe6, 0x3d); -com_interface! { - interface IDxcTranslationUnit: IUnknown{ - iid: IID_IDxcTranslationUnit, - vtable: IDxcTranslationUnitVtbl, - fn get_cursor(cursor: *mut *mut IDxcCursor) -> HRESULT; - fn tokenize(range: *const IDxcSourceRange, tokens: *mut *mut *mut IDxcToken, token_count: *mut u32) -> HRESULT; - fn get_location(file: *mut IDxcFile, line: u32, column: u32, result: *mut *mut IDxcSourceLocation) -> HRESULT; - fn get_num_diagnostics(value: *mut u32) -> HRESULT; - fn get_diagnostic(index: u32, value: *mut *mut IDxcDiagnostic) -> HRESULT; - fn get_file(name: *const u8, result: *mut *mut IDxcFile) -> HRESULT; - fn get_file_name(result: *mut LPSTR) -> HRESULT; - fn reparse(unsaved_files: *mut *mut IDxcUnsavedFile, num_unsaved_files: u32) -> HRESULT; - fn get_cursor_for_location(location: *const IDxcSourceLocation, result: *mut *mut IDxcCursor) -> HRESULT; - fn get_location_for_offset(file: *const IDxcFile, offset: u32, result: *mut *mut IDxcSourceLocation) -> HRESULT; - fn get_skipped_ranges(file: *const IDxcFile, result_count: *mut u32, result: *mut *mut *mut IDxcSourceRange) -> HRESULT; - fn get_diagnostic_details( - index: u32, options: DxcDiagnosticDisplayOptions, error_code: *mut u32, error_line: *mut u32, error_column: *mut u32, - error_file: *mut BSTR, error_offset: *mut u32, error_length: *mut u32, error_message: *mut BSTR) -> HRESULT; - fn get_inclusion_list(result_count: *mut u32, result: *mut *mut *mut IDxcInclusion) -> HRESULT; + #[uuid("9677dee0-c0e5-46a1-8b40-3db3168be63d")] + pub(crate) unsafe interface IDxcTranslationUnit: IUnknown { + pub(crate) unsafe fn get_cursor(&self, cursor: *mut Option) -> HRESULT; + pub(crate) unsafe fn tokenize( + &self, + range: IDxcSourceRange, + tokens: *mut *mut IDxcToken, + token_count: *mut u32, + ) -> HRESULT; + pub(crate) unsafe fn get_location( + &self, + file: IDxcFile, + line: u32, + column: u32, + result: *mut Option, + ) -> HRESULT; + pub(crate) unsafe fn get_num_diagnostics(&self, value: *mut u32) -> HRESULT; + pub(crate) unsafe fn get_diagnostic( + &self, + index: u32, + value: *mut Option, + ) -> HRESULT; + pub(crate) unsafe fn get_file( + &self, + name: *const u8, + result: *mut Option, + ) -> HRESULT; + pub(crate) unsafe fn get_file_name(&self, result: *mut LPSTR) -> HRESULT; + pub(crate) unsafe fn reparse( + &self, + unsaved_files: *mut Option, + num_unsaved_files: u32, + ) -> HRESULT; + pub(crate) unsafe fn get_cursor_for_location( + &self, + location: IDxcSourceLocation, + result: *mut Option, + ) -> HRESULT; + pub(crate) unsafe fn get_location_for_offset( + &self, + file: IDxcFile, + offset: u32, + result: *mut Option, + ) -> HRESULT; + pub(crate) unsafe fn get_skipped_ranges( + &self, + file: IDxcFile, + result_count: *mut u32, + result: *mut *mut IDxcSourceRange, + ) -> HRESULT; + pub(crate) unsafe fn get_diagnostic_details( + &self, + index: u32, + options: DxcDiagnosticDisplayOptions, + error_code: *mut u32, + error_line: *mut u32, + error_column: *mut u32, + error_file: *mut BSTR, + error_offset: *mut u32, + error_length: *mut u32, + error_message: *mut BSTR, + ) -> HRESULT; + pub(crate) unsafe fn get_inclusion_list( + &self, + result_count: *mut u32, + result: *mut *mut IDxcInclusion, + ) -> HRESULT; } -} -iid!(pub IID_IDxcIndex = 0x937824a0, 0x7f5a, 0x4815, 0x9b, 0xa, 0x7c, 0xc0, 0x42, 0x4f, 0x41, 0x73); -com_interface! { - interface IDxcIndex: IUnknown{ - iid: IID_IDxcIndex, - vtable: IDxcIndexVtbl, - fn set_global_options(options: DxcGlobalOptions) -> HRESULT; - fn get_global_options(options: *mut DxcGlobalOptions) -> HRESULT; - fn parse_translation_unit( + #[uuid("937824a0-7f5a-4815-9b0a-7cc0424f4173")] + pub(crate) unsafe interface IDxcIndex: IUnknown { + pub(crate) unsafe fn set_global_options(&self, options: DxcGlobalOptions) -> HRESULT; + pub(crate) unsafe fn get_global_options(&self, options: *mut DxcGlobalOptions) -> HRESULT; + pub(crate) unsafe fn parse_translation_unit( + &self, source_filename: *const u8, command_line_args: *const *const u8, num_command_line_args: i32, - unsaved_files: *const *const IDxcUnsavedFile, + // unsaved_files: *const *const dyn IDxcUnsavedFile, + unsaved_files: *const IDxcUnsavedFile, num_unsaved_files: u32, options: DxcTranslationUnitFlags, - translation_unit: *mut *mut IDxcTranslationUnit) -> HRESULT; + translation_unit: *mut Option, + ) -> HRESULT; } -} -iid!(pub IID_IDxcIntelliSense = 0xb1f99513, 0x46d6, 0x4112, 0x81, 0x69, 0xdd, 0x0d, 0x60, 0x53, 0xf1, 0x7d); -com_interface! { - interface IDxcIntelliSense: IUnknown{ - iid: IID_IDxcIntelliSense, - vtable: IDxcIntelliSenseVtbl, - fn create_index(index: *mut *mut IDxcIndex) -> HRESULT; - fn get_null_location(location: *mut *mut IDxcSourceLocation) -> HRESULT; - fn get_null_range(location: *mut *mut IDxcSourceRange) -> HRESULT; - fn get_range( start: *const IDxcSourceLocation, end: *const IDxcSourceLocation, location: *mut *mut IDxcSourceRange) -> HRESULT; - fn get_default_diagnostic_display_options(value: *mut DxcDiagnosticDisplayOptions) -> HRESULT; - fn get_default_editing_tu_options(value: *mut DxcTranslationUnitFlags) -> HRESULT; - fn create_unsaved_file(file_name: LPCSTR, contents: LPCSTR, content_length: u32 , result: *mut *mut IDxcUnsavedFile) -> HRESULT; + #[uuid("b1f99513-46d6-4112-8169-dd0d6053f17d")] + pub(crate) unsafe interface IDxcIntelliSense: IUnknown { + pub(crate) unsafe fn create_index(&self, index: *mut Option) -> HRESULT; + pub(crate) unsafe fn get_null_location( + &self, + location: *mut Option, + ) -> HRESULT; + pub(crate) unsafe fn get_null_range( + &self, + location: *mut Option, + ) -> HRESULT; + pub(crate) unsafe fn get_range( + &self, + start: IDxcSourceLocation, + end: IDxcSourceLocation, + location: *mut Option, + ) -> HRESULT; + pub(crate) unsafe fn get_default_diagnostic_display_options( + &self, + value: *mut DxcDiagnosticDisplayOptions, + ) -> HRESULT; + pub(crate) unsafe fn get_default_editing_tu_options( + &self, + value: *mut DxcTranslationUnitFlags, + ) -> HRESULT; + pub(crate) unsafe fn create_unsaved_file( + &self, + file_name: LPCSTR, + contents: LPCSTR, + content_length: u32, + result: *mut Option, + ) -> HRESULT; } } -iid!(pub CLSID_DxcIntelliSense = 0x3047833c, 0xd1c0, 0x4b8e, 0x9d, 0x40, 0x10, 0x28, 0x78, 0x60, 0x59, 0x85); +pub const CLSID_DxcIntelliSense: IID = IID { + data1: 0x3047833c, + data2: 0xd1c0, + data3: 0x4b8e, + data4: [0x9d, 0x40, 0x10, 0x28, 0x78, 0x60, 0x59, 0x85], +}; diff --git a/src/intellisense/wrapper.rs b/src/intellisense/wrapper.rs index c1d30b8..2f46935 100644 --- a/src/intellisense/wrapper.rs +++ b/src/intellisense/wrapper.rs @@ -1,17 +1,18 @@ +use com::Interface; + use crate::intellisense::ffi::*; use crate::os::{CoTaskMemFree, BSTR, LPSTR}; use crate::utils::Result; use crate::wrapper::Dxc; -use com_rs::ComPtr; use std::ffi::CString; +use std::mem::ManuallyDrop; -#[derive(Debug)] pub struct DxcIntellisense { - inner: ComPtr, + inner: IDxcIntelliSense, } impl DxcIntellisense { - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcIntelliSense) -> Self { Self { inner } } @@ -22,36 +23,35 @@ impl DxcIntellisense { } pub fn create_index(&self) -> Result { - let mut index: ComPtr = ComPtr::new(); - unsafe { self.inner.create_index(index.as_mut_ptr()) }.result()?; - Ok(DxcIndex::new(index)) + let mut index = None; + unsafe { self.inner.create_index(&mut index) }.result()?; + Ok(DxcIndex::new(index.unwrap())) } pub fn create_unsaved_file(&self, file_name: &str, contents: &str) -> Result { let c_file_name = CString::new(file_name).expect("Failed to convert `file_name`"); let c_contents = CString::new(contents).expect("Failed to convert `contents`"); - let mut file: ComPtr = ComPtr::new(); + let mut file = None; unsafe { self.inner.create_unsaved_file( c_file_name.as_ptr(), c_contents.as_ptr(), contents.len() as u32, - file.as_mut_ptr(), + &mut file, ) } .result()?; - Ok(DxcUnsavedFile::new(file)) + Ok(DxcUnsavedFile::new(file.unwrap())) } } -#[derive(Debug)] pub struct DxcIndex { - inner: ComPtr, + inner: IDxcIndex, } impl DxcIndex { - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcIndex) -> Self { Self { inner } } } @@ -67,11 +67,10 @@ impl DxcIndex { let c_source_filename = CString::new(source_filename).expect("Failed to convert `source_filename`"); - let mut uf = vec![]; - - for unsaved_file in unsaved_files { - uf.push(unsaved_file.inner.as_ptr()); - } + let uf = unsaved_files + .iter() + .map(|unsaved_file| unsaved_file.inner.clone()) + .collect::>(); let mut c_args: Vec = vec![]; let mut cliargs = vec![]; @@ -82,7 +81,7 @@ impl DxcIndex { c_args.push(c_arg); } - let mut tu: ComPtr = ComPtr::new(); + let mut tu = None; unsafe { self.inner.parse_translation_unit( @@ -92,17 +91,16 @@ impl DxcIndex { uf.as_ptr(), uf.len() as u32, options, - tu.as_mut_ptr(), + &mut tu, ) } .result()?; - Ok(DxcTranslationUnit::new(tu)) + Ok(DxcTranslationUnit::new(tu.unwrap())) } } -#[derive(Debug)] pub struct DxcUnsavedFile { - inner: ComPtr, + inner: IDxcUnsavedFile, } impl DxcUnsavedFile { @@ -111,46 +109,44 @@ impl DxcUnsavedFile { unsafe { self.inner.get_length(&mut length) }.result_with_success(length) } - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcUnsavedFile) -> Self { DxcUnsavedFile { inner } } } -#[derive(Debug)] pub struct DxcTranslationUnit { - inner: ComPtr, + inner: IDxcTranslationUnit, } impl DxcTranslationUnit { - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcTranslationUnit) -> Self { DxcTranslationUnit { inner } } pub fn get_file(&self, name: &[u8]) -> Result { - let mut file: ComPtr = ComPtr::new(); - unsafe { self.inner.get_file(name.as_ptr(), file.as_mut_ptr()) }.result()?; - Ok(DxcFile::new(file)) + let mut file = None; + unsafe { self.inner.get_file(name.as_ptr(), &mut file) }.result()?; + Ok(DxcFile::new(file.unwrap())) } pub fn get_cursor(&self) -> Result { - let mut cursor: ComPtr = ComPtr::new(); - unsafe { self.inner.get_cursor(cursor.as_mut_ptr()) }.result()?; - Ok(DxcCursor::new(cursor)) + let mut cursor = None; + unsafe { self.inner.get_cursor(&mut cursor) }.result()?; + Ok(DxcCursor::new(cursor.unwrap())) } } -#[derive(Debug)] pub struct DxcCursor { - inner: ComPtr, + inner: IDxcCursor, } impl DxcCursor { - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcCursor) -> Self { DxcCursor { inner } } pub fn get_children(&self, skip: u32, max_count: u32) -> Result> { - let mut result: *mut *mut IDxcCursor = std::ptr::null_mut(); + let mut result: *mut IDxcCursor = std::ptr::null_mut(); let mut result_length: u32 = 0; unsafe { @@ -160,14 +156,17 @@ impl DxcCursor { .result()?; // get_children allocates a buffer to pass the result in. - let child_cursors = unsafe { std::slice::from_raw_parts(result, result_length as usize) } - .iter() - .map(|&ptr| { - let mut childcursor = ComPtr::::new(); - *childcursor.as_mut_ptr() = ptr; - DxcCursor::new(childcursor) - }) - .collect::>(); + // Create a vector so that we get ownership of the `IDxcCursor(s) (received from get_children), instead of + // having to clone (copy is intentionally not implemented) them and leaving unowned COM references alive. + // It is wrapped in ManuallyDrop to free the underlying pointer by hand using CoTaskMemFree. + // TODO: switch to Vec::from_raw_parts_in with custom deallocator when this is stabilized + let child_cursors = ManuallyDrop::new(unsafe { + Vec::from_raw_parts(result, result_length as usize, result_length as usize) + }) + .drain(..) + .map(DxcCursor::new) + .collect::>(); + unsafe { CoTaskMemFree(result.cast()) }; Ok(child_cursors) } @@ -187,15 +186,15 @@ impl DxcCursor { } pub fn get_extent(&self) -> Result { - let mut range: ComPtr = ComPtr::new(); - unsafe { self.inner.get_extent(range.as_mut_ptr()) }.result()?; - Ok(DxcSourceRange::new(range)) + let mut range = None; + unsafe { self.inner.get_extent(&mut range) }.result()?; + Ok(DxcSourceRange::new(range.unwrap())) } pub fn get_location(&self) -> Result { - let mut location: ComPtr = ComPtr::new(); - unsafe { self.inner.get_location(location.as_mut_ptr()) }.result()?; - Ok(DxcSourceLocation::new(location)) + let mut location = None; + unsafe { self.inner.get_location(&mut location) }.result()?; + Ok(DxcSourceLocation::new(location.unwrap())) } pub fn get_display_name(&self) -> Result { @@ -232,21 +231,21 @@ impl DxcCursor { } pub fn get_semantic_parent(&self) -> Result { - let mut inner = ComPtr::::new(); - unsafe { self.inner.get_semantic_parent(inner.as_mut_ptr()) }.result()?; - Ok(DxcCursor::new(inner)) + let mut inner = None; + unsafe { self.inner.get_semantic_parent(&mut inner) }.result()?; + Ok(DxcCursor::new(inner.unwrap())) } pub fn get_lexical_parent(&self) -> Result { - let mut inner = ComPtr::::new(); - unsafe { self.inner.get_lexical_parent(inner.as_mut_ptr()) }.result()?; - Ok(DxcCursor::new(inner)) + let mut inner = None; + unsafe { self.inner.get_lexical_parent(&mut inner) }.result()?; + Ok(DxcCursor::new(inner.unwrap())) } pub fn get_cursor_type(&self) -> Result { - let mut inner = ComPtr::::new(); - unsafe { self.inner.get_cursor_type(inner.as_mut_ptr()) }.result()?; - Ok(DxcType::new(inner)) + let mut inner = None; + unsafe { self.inner.get_cursor_type(&mut inner) }.result()?; + Ok(DxcType::new(inner.unwrap())) } pub fn get_num_arguments(&self) -> Result { @@ -256,21 +255,21 @@ impl DxcCursor { } pub fn get_argument_at(&self, index: i32) -> Result { - let mut inner = ComPtr::::new(); - unsafe { self.inner.get_argument_at(index, inner.as_mut_ptr()) }.result()?; - Ok(DxcCursor::new(inner)) + let mut inner = None; + unsafe { self.inner.get_argument_at(index, &mut inner) }.result()?; + Ok(DxcCursor::new(inner.unwrap())) } pub fn get_referenced_cursor(&self) -> Result { - let mut inner = ComPtr::::new(); - unsafe { self.inner.get_referenced_cursor(inner.as_mut_ptr()) }.result()?; - Ok(DxcCursor::new(inner)) + let mut inner = None; + unsafe { self.inner.get_referenced_cursor(&mut inner) }.result()?; + Ok(DxcCursor::new(inner.unwrap())) } pub fn get_definition_cursor(&self) -> Result { - let mut inner = ComPtr::::new(); - unsafe { self.inner.get_definition_cursor(inner.as_mut_ptr()) }.result()?; - Ok(DxcCursor::new(inner)) + let mut inner = None; + unsafe { self.inner.get_definition_cursor(&mut inner) }.result()?; + Ok(DxcCursor::new(inner.unwrap())) } pub fn find_references_in_file( @@ -279,12 +278,12 @@ impl DxcCursor { skip: u32, top: u32, ) -> Result> { - let mut result: *mut *mut IDxcCursor = std::ptr::null_mut(); + let mut result: *mut IDxcCursor = std::ptr::null_mut(); let mut result_length: u32 = 0; unsafe { self.inner.find_references_in_file( - file.inner.as_ptr(), + &file.inner, skip, top, &mut result_length, @@ -294,14 +293,17 @@ impl DxcCursor { .result()?; // find_references_in_file allocates a buffer to pass the result in. - let child_cursors = unsafe { std::slice::from_raw_parts(result, result_length as usize) } - .iter() - .map(|&ptr| { - let mut childcursor = ComPtr::::new(); - *childcursor.as_mut_ptr() = ptr; - DxcCursor::new(childcursor) - }) - .collect::>(); + // Create a vector so that we get ownership of the `IDxcCursor(s) (received from find_references_in_file), instead + // of having to clone (copy is intentionally not implemented) them and leaving unowned COM references alive. + // It is wrapped in ManuallyDrop to free the underlying pointer by hand using CoTaskMemFree. + // TODO: switch to Vec::from_raw_parts_in with custom deallocator when this is stabilized + let child_cursors = ManuallyDrop::new(unsafe { + Vec::from_raw_parts(result, result_length as usize, result_length as usize) + }) + .drain(..) + .map(DxcCursor::new) + .collect::>(); + unsafe { CoTaskMemFree(result.cast()) }; Ok(child_cursors) } @@ -314,8 +316,7 @@ impl DxcCursor { pub fn is_equal_to(&self, other: &DxcCursor) -> Result { let mut result: bool = false; - unsafe { self.inner.is_equal_to(other.inner.as_ptr(), &mut result) } - .result_with_success(result) + unsafe { self.inner.is_equal_to(&other.inner, &mut result) }.result_with_success(result) } pub fn is_null(&mut self) -> Result { @@ -329,13 +330,9 @@ impl DxcCursor { } pub fn get_snapped_child(&self, location: &DxcSourceLocation) -> Result { - let mut inner = ComPtr::::new(); - unsafe { - self.inner - .get_snapped_child(location.inner.as_ptr(), inner.as_mut_ptr()) - } - .result()?; - Ok(DxcCursor::new(inner)) + let mut inner = None; + unsafe { self.inner.get_snapped_child(&location.inner, &mut inner) }.result()?; + Ok(DxcCursor::new(inner.unwrap())) } pub fn get_source<'a>(&self, source: &'a str) -> Result<&'a str> { @@ -352,13 +349,12 @@ impl DxcCursor { } } -#[derive(Debug)] pub struct DxcType { - inner: ComPtr, + inner: IDxcType, } impl DxcType { - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcType) -> Self { DxcType { inner } } @@ -369,13 +365,20 @@ impl DxcType { } } -#[derive(Debug)] pub struct DxcSourceLocation { - inner: ComPtr, + inner: IDxcSourceLocation, +} + +impl std::fmt::Debug for DxcSourceLocation { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("DxcSourceLocation") + .field("inner", &self.inner) + .finish() + } } impl DxcSourceLocation { - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcSourceLocation) -> Self { DxcSourceLocation { inner } } } @@ -386,9 +389,16 @@ pub struct DxcSourceOffsets { pub end_offset: u32, } -#[derive(Debug)] pub struct DxcSourceRange { - inner: ComPtr, + inner: IDxcSourceRange, +} + +impl std::fmt::Debug for DxcSourceRange { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("DxcSourceRange") + .field("inner", &self.inner) + .finish() + } } impl DxcSourceRange { @@ -405,32 +415,31 @@ impl DxcSourceRange { } impl DxcSourceRange { - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcSourceRange) -> Self { DxcSourceRange { inner } } } -#[derive(Debug)] pub struct DxcFile { - inner: ComPtr, + inner: IDxcFile, } impl DxcFile { - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcFile) -> Self { DxcFile { inner } } } impl Dxc { pub fn create_intellisense(&self) -> Result { - let mut intellisense: ComPtr = ComPtr::new(); + let mut intellisense = None; self.get_dxc_create_instance()?( &CLSID_DxcIntelliSense, - &IID_IDxcIntelliSense, - intellisense.as_mut_ptr(), + &IDxcIntelliSense::IID, + &mut intellisense, ) .result()?; - Ok(DxcIntellisense::new(intellisense)) + Ok(DxcIntellisense::new(intellisense.unwrap())) } } diff --git a/src/unknown.rs b/src/unknown.rs deleted file mode 100644 index d510e51..0000000 --- a/src/unknown.rs +++ /dev/null @@ -1,50 +0,0 @@ -#[cfg(not(windows))] -use crate::os::HRESULT; -use com_rs::{com_interface, IUnknown, IID}; - -extern "C" { - static IID_IUnknown: IID; -} - -#[cfg(not(windows))] -// Steal the interface ID from IUnknown: -com_interface! { - /// Insert complete object and deleting destructor on non-Windows platforms, where Dxc shims IUnknown in WinAdapter. - /// This requires a virtual destructor (delete is actually used on the base class) which unfortunately makes the struct - /// binary incompatible. - /// - /// See the third and fourth entry: - /// ```cmd - /// vtable for 'DxcLibrary' @ 0x7ffff7cbc5f8 (subobject @ 0x5555556bb9e0): - /// [0]: 0x7ffff6a56d40 - /// [1]: 0x7ffff6a56d20 - /// [2]: 0x7ffff6a56d30 - /// [3]: 0x7ffff6b36bc0 - /// [4]: 0x7ffff6a57130 - /// [5]: 0x7ffff6a56d50 - /// [6]: 0x7ffff6a56d60 - /// [7]: 0x7ffff6a56d70 - /// [8]: 0x7ffff6a56d80 - /// [9]: 0x7ffff6a56d90 - /// [10]: 0x7ffff6a56da0 - /// [11]: 0x7ffff6a56db0 - /// [12]: 0x7ffff6a56dc0 - /// [13]: 0x7ffff6a56dd0 - /// [14]: 0x7ffff6a56e90 - /// ``` - interface IDxcUnknownShim: IUnknown { - iid: IID_IUnknown, - vtable: IDxcUnknownShimVtbl, - fn complete_object_destructor() -> HRESULT; - fn deleting_destructor() -> HRESULT; - } -} - -#[cfg(windows)] -com_interface! { - /// Forwards to IUnknown. No-op on Windows - interface IDxcUnknownShim: IUnknown { - iid: IID_IUnknown, - vtable: IDxcUnknownShimVtbl, - } -} diff --git a/src/wrapper.rs b/src/wrapper.rs index fe35244..7ff8fee 100644 --- a/src/wrapper.rs +++ b/src/wrapper.rs @@ -7,18 +7,19 @@ use crate::ffi::*; use crate::os::{HRESULT, LPCWSTR, LPWSTR, WCHAR}; use crate::utils::{from_wide, to_wide, HassleError, Result}; -use com_rs::ComPtr; +use com::{class, interfaces::IUnknown, production::Class, production::ClassAllocation, Interface}; use libloading::{Library, Symbol}; +use std::cell::RefCell; +use std::ops::Deref; use std::path::{Path, PathBuf}; use std::pin::Pin; -#[derive(Debug)] pub struct DxcBlob { - inner: ComPtr, + inner: IDxcBlob, } impl DxcBlob { - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcBlob) -> Self { Self { inner } } @@ -60,30 +61,28 @@ impl AsMut<[u8]> for DxcBlob { } } -#[derive(Debug)] pub struct DxcBlobEncoding { - inner: ComPtr, + inner: IDxcBlobEncoding, } impl DxcBlobEncoding { - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcBlobEncoding) -> Self { Self { inner } } } impl From for DxcBlob { fn from(encoded_blob: DxcBlobEncoding) -> Self { - DxcBlob::new((&encoded_blob.inner).into()) + DxcBlob::new(encoded_blob.inner.query_interface::().unwrap()) } } -#[derive(Debug)] pub struct DxcOperationResult { - inner: ComPtr, + inner: IDxcOperationResult, } impl DxcOperationResult { - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcOperationResult) -> Self { Self { inner } } @@ -93,16 +92,16 @@ impl DxcOperationResult { } pub fn get_result(&self) -> Result { - let mut blob: ComPtr = ComPtr::new(); - unsafe { self.inner.get_result(blob.as_mut_ptr()) }.result()?; - Ok(DxcBlob::new(blob)) + let mut blob = None; + unsafe { self.inner.get_result(&mut blob) }.result()?; + Ok(DxcBlob::new(blob.unwrap())) } pub fn get_error_buffer(&self) -> Result { - let mut blob: ComPtr = ComPtr::new(); + let mut blob = None; - unsafe { self.inner.get_error_buffer(blob.as_mut_ptr()) }.result()?; - Ok(DxcBlobEncoding::new(blob)) + unsafe { self.inner.get_error_buffer(&mut blob) }.result()?; + Ok(DxcBlobEncoding::new(blob.unwrap())) } } @@ -110,85 +109,122 @@ pub trait DxcIncludeHandler { fn load_source(&mut self, filename: String) -> Option; } -#[repr(C)] -struct DxcIncludeHandlerWrapperVtbl { - query_interface: extern "system" fn( - *const com_rs::IUnknown, - &com_rs::IID, - *mut *mut core::ffi::c_void, - ) -> HRESULT, - add_ref: extern "system" fn(*const com_rs::IUnknown) -> HRESULT, - release: extern "system" fn(*const com_rs::IUnknown) -> HRESULT, - load_source: extern "system" fn(*mut com_rs::IUnknown, LPCWSTR, *mut *mut IDxcBlob) -> HRESULT, -} +class! { + #[no_class_factory] + class DxcIncludeHandlerWrapper: IDxcIncludeHandler { + // Com-rs intentionally does not support lifetimes in its class structs + // since they live on the heap and their lifetime can be prolonged for + // as long as someone keeps a reference through `add_ref()`. + // The only way for us to access the library and handler implementation, + // which are now intentionally behind a borrow to signify our promise + // regarding lifetime, is by transmuting them away and "ensuring" the + // class object is discarded at the end of our function call. -#[repr(C)] -struct DxcIncludeHandlerWrapper<'a, 'i> { - vtable: Box, - handler: &'i mut dyn DxcIncludeHandler, - pinned: Vec>, - library: &'a DxcLibrary, -} + library: &'static DxcLibrary, + handler: RefCell<&'static mut dyn DxcIncludeHandler>, -impl<'a, 'i> DxcIncludeHandlerWrapper<'a, 'i> { - extern "system" fn query_interface( - _me: *const com_rs::IUnknown, - _rrid: &com_rs::IID, - _ppv_obj: *mut *mut core::ffi::c_void, - ) -> HRESULT { - HRESULT(0) // dummy impl + pinned: RefCell>>, } - extern "system" fn add_ref(_me: *const com_rs::IUnknown) -> HRESULT { - HRESULT(0) // dummy impl - } + impl IDxcIncludeHandler for DxcIncludeHandlerWrapper { + fn load_source(&self, filename: LPCWSTR, include_source: *mut Option) -> HRESULT { + let filename = crate::utils::from_wide(filename); - extern "system" fn release(_me: *const com_rs::IUnknown) -> HRESULT { - HRESULT(0) // dummy impl - } + let mut handler = self.handler.borrow_mut(); + let source = handler.load_source(filename); - extern "system" fn load_source( - me: *mut com_rs::IUnknown, - filename: LPCWSTR, - include_source: *mut *mut IDxcBlob, - ) -> HRESULT { - let me = me.cast::(); + if let Some(source) = source { + let source = Pin::new(source); + let blob = self.library + .create_blob_with_encoding_from_str(&source) + .unwrap(); - let filename = crate::utils::from_wide(filename); + unsafe { *include_source = Some(DxcBlob::from(blob).inner) }; + self.pinned.borrow_mut().push(source); - let source = unsafe { (*me).handler.load_source(filename) }; + // NOERROR + 0 + } else { + -2_147_024_894 // ERROR_FILE_NOT_FOUND / 0x80070002 + } + .into() + } + } +} - if let Some(source) = source { - let source = Pin::new(source); - let mut blob = unsafe { - (*me) - .library - .create_blob_with_encoding_from_str(&source) - .unwrap() - }; +/// Represents a reference to a COM object that should only live as long as itself +/// +/// In other words, on [`drop()`] we assert that the refcount is decremented to zero, +/// rather than allowing it to be referenced externally (i.e. [`Class::dec_ref_count()`] +/// returning `> 0`). +/// This object functions a lot like [`ClassAllocation`]: see its similar [`drop()`] +/// implementation for details. +/// +/// Note that COM objects live on the heap by design, because of this refcount system. +struct LocalClassAllocation(core::pin::Pin>); + +impl LocalClassAllocation { + fn new(allocation: ClassAllocation) -> Self { + // TODO: There is no way to take the internal, owned box out of com-rs's + // allocation wrapper. + // https://github.com/microsoft/com-rs/issues/236 covers this issue as a whole, + // including lifetime support and this `LocalClassAllocation` upstream. + let inner: core::mem::ManuallyDrop>> = + unsafe { std::mem::transmute(allocation) }; + + Self(core::mem::ManuallyDrop::into_inner(inner)) + } + + // TODO: Return a borrow of this interface? + // query_interface() is not behind one of the traits + // fn query_interface(&self) -> Option { + // self.0.query_interface::().unwrap() + // } +} - unsafe { - blob.inner.add_ref(); - *include_source = *blob.inner.as_mut_ptr(); - (*me).pinned.push(source); - } +impl Deref for LocalClassAllocation { + type Target = core::pin::Pin>; - 0 - } else { - -2_147_024_894 // ERROR_FILE_NOT_FOUND / 0x80070002 - } - .into() + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Drop for LocalClassAllocation { + fn drop(&mut self) { + // Check if we are the only remaining reference to this object + assert_eq!( + unsafe { self.0.dec_ref_count() }, + 0, + "COM object is still referenced" + ); + // Now that we're the last one to give up our refcount, it is safe + // for the internal object to get dropped. + } +} + +impl DxcIncludeHandlerWrapper { + /// SAFETY: Make sure the returned object does _not_ outlive the lifetime + /// of either `library` nor `include_handler` + unsafe fn create_include_handler( + library: &'_ DxcLibrary, + include_handler: &'_ mut dyn DxcIncludeHandler, + ) -> LocalClassAllocation { + LocalClassAllocation::new(Self::allocate( + std::mem::transmute(library), + RefCell::new(std::mem::transmute(include_handler)), + RefCell::new(vec![]), + )) } } -#[derive(Debug)] pub struct DxcCompiler { - inner: ComPtr, + inner: IDxcCompiler2, library: DxcLibrary, } impl DxcCompiler { - fn new(inner: ComPtr, library: DxcLibrary) -> Self { + fn new(inner: IDxcCompiler2, library: DxcLibrary) -> Self { Self { inner, library } } @@ -223,29 +259,6 @@ impl DxcCompiler { } } - fn prep_include_handler<'a, 'i>( - library: &'a DxcLibrary, - include_handler: Option<&'i mut dyn DxcIncludeHandler>, - ) -> Option>> { - if let Some(include_handler) = include_handler { - let vtable = DxcIncludeHandlerWrapperVtbl { - query_interface: DxcIncludeHandlerWrapper::query_interface, - add_ref: DxcIncludeHandlerWrapper::add_ref, - release: DxcIncludeHandlerWrapper::release, - load_source: DxcIncludeHandlerWrapper::load_source, - }; - - Some(Box::new(DxcIncludeHandlerWrapper { - vtable: Box::new(vtable), - handler: include_handler, - library, - pinned: vec![], - })) - } else { - None - } - } - pub fn compile( &self, blob: &DxcBlobEncoding, @@ -264,12 +277,19 @@ impl DxcCompiler { let mut dxc_defines = vec![]; Self::prep_defines(defines, &mut wide_defines, &mut dxc_defines); - let handler_wrapper = Self::prep_include_handler(&self.library, include_handler); + // Keep alive on the stack + let include_handler = include_handler.map(|include_handler| unsafe { + DxcIncludeHandlerWrapper::create_include_handler(&self.library, include_handler) + }); + // TODO: query_interface() should have a borrow on LocalClassAllocation to prevent things going kaboom + let include_handler = include_handler + .as_ref() + .map(|i| i.query_interface().unwrap()); - let mut result: ComPtr = ComPtr::new(); + let mut result = None; let result_hr = unsafe { self.inner.compile( - blob.inner.as_ptr(), + &blob.inner, to_wide(source_name).as_ptr(), to_wide(entry_point).as_ptr(), to_wide(target_profile).as_ptr(), @@ -277,13 +297,13 @@ impl DxcCompiler { dxc_args.len() as u32, dxc_defines.as_ptr(), dxc_defines.len() as u32, - handler_wrapper - .as_ref() - .map_or(std::ptr::null(), |v| &**v as *const _ as *const _), - result.as_mut_ptr(), + &include_handler, + &mut result, ) }; + let result = result.unwrap(); + let mut compile_error = 0u32; let status_hr = unsafe { result.get_status(&mut compile_error) }; @@ -312,15 +332,21 @@ impl DxcCompiler { let mut dxc_defines = vec![]; Self::prep_defines(defines, &mut wide_defines, &mut dxc_defines); - let handler_wrapper = Self::prep_include_handler(&self.library, include_handler); + // Keep alive on the stack + let include_handler = include_handler.map(|include_handler| unsafe { + DxcIncludeHandlerWrapper::create_include_handler(&self.library, include_handler) + }); + let include_handler = include_handler + .as_ref() + .map(|i| i.query_interface().unwrap()); - let mut result: ComPtr = ComPtr::new(); - let mut debug_blob: ComPtr = ComPtr::new(); + let mut result = None; + let mut debug_blob = None; let mut debug_filename: LPWSTR = std::ptr::null_mut(); let result_hr = unsafe { self.inner.compile_with_debug( - blob.inner.as_ptr(), + &blob.inner, to_wide(source_name).as_ptr(), to_wide(entry_point).as_ptr(), to_wide(target_profile).as_ptr(), @@ -328,14 +354,14 @@ impl DxcCompiler { dxc_args.len() as u32, dxc_defines.as_ptr(), dxc_defines.len() as u32, - handler_wrapper - .as_ref() - .map_or(std::ptr::null(), |v| &**v as *const _ as *const _), - result.as_mut_ptr(), + include_handler, + &mut result, &mut debug_filename, - debug_blob.as_mut_ptr(), + &mut debug_blob, ) }; + let result = result.unwrap(); + let debug_blob = debug_blob.unwrap(); let mut compile_error = 0u32; let status_hr = unsafe { result.get_status(&mut compile_error) }; @@ -367,24 +393,30 @@ impl DxcCompiler { let mut dxc_defines = vec![]; Self::prep_defines(defines, &mut wide_defines, &mut dxc_defines); - let handler_wrapper = Self::prep_include_handler(&self.library, include_handler); + // Keep alive on the stack + let include_handler = include_handler.map(|include_handler| unsafe { + DxcIncludeHandlerWrapper::create_include_handler(&self.library, include_handler) + }); + let include_handler = include_handler + .as_ref() + .map(|i| i.query_interface().unwrap()); - let mut result: ComPtr = ComPtr::new(); + let mut result = None; let result_hr = unsafe { self.inner.preprocess( - blob.inner.as_ptr(), + &blob.inner, to_wide(source_name).as_ptr(), dxc_args.as_ptr(), dxc_args.len() as u32, dxc_defines.as_ptr(), dxc_defines.len() as u32, - handler_wrapper - .as_ref() - .map_or(std::ptr::null(), |v| &**v as *const _ as *const _), - result.as_mut_ptr(), + include_handler, + &mut result, ) }; + let result = result.unwrap(); + let mut compile_error = 0u32; let status_hr = unsafe { result.get_status(&mut compile_error) }; @@ -396,43 +428,39 @@ impl DxcCompiler { } pub fn disassemble(&self, blob: &DxcBlob) -> Result { - let mut result_blob: ComPtr = ComPtr::new(); - unsafe { - self.inner - .disassemble(blob.inner.as_ptr(), result_blob.as_mut_ptr()) - } - .result()?; - Ok(DxcBlobEncoding::new(result_blob)) + let mut result_blob = None; + unsafe { self.inner.disassemble(&blob.inner, &mut result_blob) }.result()?; + Ok(DxcBlobEncoding::new(result_blob.unwrap())) } } -#[derive(Debug)] +#[derive(Clone)] pub struct DxcLibrary { - inner: ComPtr, + inner: IDxcLibrary, } impl DxcLibrary { - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcLibrary) -> Self { Self { inner } } pub fn create_blob_with_encoding(&self, data: &[u8]) -> Result { - let mut blob: ComPtr = ComPtr::new(); + let mut blob = None; unsafe { self.inner.create_blob_with_encoding_from_pinned( data.as_ptr().cast(), data.len() as u32, 0, // Binary; no code page - blob.as_mut_ptr(), + &mut blob, ) } .result()?; - Ok(DxcBlobEncoding::new(blob)) + Ok(DxcBlobEncoding::new(blob.unwrap())) } pub fn create_blob_with_encoding_from_str(&self, text: &str) -> Result { - let mut blob: ComPtr = ComPtr::new(); + let mut blob = None; const CP_UTF8: u32 = 65001; // UTF-8 translation unsafe { @@ -440,23 +468,21 @@ impl DxcLibrary { text.as_ptr().cast(), text.len() as u32, CP_UTF8, - blob.as_mut_ptr(), + &mut blob, ) } .result()?; - Ok(DxcBlobEncoding::new(blob)) + Ok(DxcBlobEncoding::new(blob.unwrap())) } pub fn get_blob_as_string(&self, blob: &DxcBlob) -> Result { - let mut blob_utf8: ComPtr = ComPtr::new(); + let mut blob_utf8 = None; - unsafe { - self.inner - .get_blob_as_utf8(blob.inner.as_ptr(), blob_utf8.as_mut_ptr()) - } - .result()?; + unsafe { self.inner.get_blob_as_utf8(&blob.inner, &mut blob_utf8) }.result()?; - Ok(String::from_utf8(DxcBlob::new((&blob_utf8).into()).to_vec()).unwrap()) + let blob_utf8 = blob_utf8.unwrap(); + + Ok(String::from_utf8(DxcBlob::new(blob_utf8.query_interface().unwrap()).to_vec()).unwrap()) } } @@ -502,63 +528,57 @@ impl Dxc { Ok(Self { dxc_lib }) } - pub(crate) fn get_dxc_create_instance(&self) -> Result> { + pub(crate) fn get_dxc_create_instance(&self) -> Result>> { Ok(unsafe { self.dxc_lib.get(b"DxcCreateInstance\0")? }) } pub fn create_compiler(&self) -> Result { - let mut compiler: ComPtr = ComPtr::new(); + let mut compiler = None; - self.get_dxc_create_instance()?( - &CLSID_DxcCompiler, - &IID_IDxcCompiler2, - compiler.as_mut_ptr(), - ) - .result()?; - Ok(DxcCompiler::new(compiler, self.create_library()?)) + self.get_dxc_create_instance()?(&CLSID_DxcCompiler, &IDxcCompiler2::IID, &mut compiler) + .result()?; + Ok(DxcCompiler::new( + compiler.unwrap(), + self.create_library().unwrap(), + )) } pub fn create_library(&self) -> Result { - let mut library: ComPtr = ComPtr::new(); - - self.get_dxc_create_instance()?(&CLSID_DxcLibrary, &IID_IDxcLibrary, library.as_mut_ptr()) + let mut library = None; + self.get_dxc_create_instance()?(&CLSID_DxcLibrary, &IDxcLibrary::IID, &mut library) .result()?; - Ok(DxcLibrary::new(library)) + Ok(DxcLibrary::new(library.unwrap())) } pub fn create_reflector(&self) -> Result { - let mut reflector: ComPtr = ComPtr::new(); + let mut reflector = None; self.get_dxc_create_instance()?( &CLSID_DxcContainerReflection, - &IID_IDxcContainerReflection, - reflector.as_mut_ptr(), + &IDxcContainerReflection::IID, + &mut reflector, ) .result()?; - Ok(DxcReflector::new(reflector)) + Ok(DxcReflector::new(reflector.unwrap())) } } -#[derive(Debug)] pub struct DxcValidator { - inner: ComPtr, + inner: IDxcValidator, } pub type DxcValidatorVersion = (u32, u32); impl DxcValidator { - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcValidator) -> Self { Self { inner } } pub fn version(&self) -> Result { - let mut version: ComPtr = ComPtr::new(); - - HRESULT::from(unsafe { - self.inner - .query_interface(&IID_IDxcVersionInfo, version.as_mut_ptr()) - }) - .result()?; + let version = self + .inner + .query_interface::() + .ok_or(HassleError::Win32Error(HRESULT(com::sys::E_NOINTERFACE)))?; let mut major = 0; let mut minor = 0; @@ -567,15 +587,14 @@ impl DxcValidator { } pub fn validate(&self, blob: DxcBlob) -> Result { - let mut result: ComPtr = ComPtr::new(); + let mut result = None; let result_hr = unsafe { - self.inner.validate( - blob.inner.as_ptr(), - DXC_VALIDATOR_FLAGS_IN_PLACE_EDIT, - result.as_mut_ptr(), - ) + self.inner + .validate(&blob.inner, DXC_VALIDATOR_FLAGS_IN_PLACE_EDIT, &mut result) }; + let result = result.unwrap(); + let mut validate_status = 0u32; let status_hr = unsafe { result.get_status(&mut validate_status) }; @@ -591,10 +610,10 @@ impl DxcValidator { } pub struct Reflection { - inner: ComPtr, + inner: ID3D12ShaderReflection, } impl Reflection { - fn new(inner: ComPtr) -> Self { + fn new(inner: ID3D12ShaderReflection) -> Self { Self { inner } } @@ -609,15 +628,15 @@ impl Reflection { } pub struct DxcReflector { - inner: ComPtr, + inner: IDxcContainerReflection, } impl DxcReflector { - fn new(inner: ComPtr) -> Self { + fn new(inner: IDxcContainerReflection) -> Self { Self { inner } } pub fn reflect(&self, blob: DxcBlob) -> Result { - let result_hr = unsafe { self.inner.load(blob.inner.as_ptr()) }; + let result_hr = unsafe { self.inner.load(blob.inner) }; if result_hr.is_err() { return Err(HassleError::Win32Error(result_hr)); } @@ -628,19 +647,21 @@ impl DxcReflector { return Err(HassleError::Win32Error(result_hr)); } - let mut reflection: ComPtr = ComPtr::new(); + let mut reflection = None::; let result_hr = unsafe { self.inner.get_part_reflection( shader_idx, - &IID_ID3D12ShaderReflection, - reflection.as_mut_ptr(), + &ID3D12ShaderReflection::IID, + &mut reflection, ) }; if result_hr.is_err() { return Err(HassleError::Win32Error(result_hr)); } - Ok(Reflection::new(reflection)) + Ok(Reflection::new( + reflection.unwrap().query_interface().unwrap(), + )) } } @@ -680,19 +701,14 @@ impl Dxil { Ok(Self { dxil_lib }) } - fn get_dxc_create_instance(&self) -> Result> { + fn get_dxc_create_instance(&self) -> Result>> { Ok(unsafe { self.dxil_lib.get(b"DxcCreateInstance\0")? }) } pub fn create_validator(&self) -> Result { - let mut validator: ComPtr = ComPtr::new(); - - self.get_dxc_create_instance()?( - &CLSID_DxcValidator, - &IID_IDxcValidator, - validator.as_mut_ptr(), - ) - .result()?; - Ok(DxcValidator::new(validator)) + let mut validator = None; + self.get_dxc_create_instance()?(&CLSID_DxcValidator, &IDxcValidator::IID, &mut validator) + .result()?; + Ok(DxcValidator::new(validator.unwrap())) } }