diff --git a/Cargo.toml b/Cargo.toml index e5ce84f..155fd3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,8 @@ default-target = "x86_64-pc-windows-msvc" [dependencies] libloading = "0.7.0" -com-rs = "0.2.1" +# https://github.com/microsoft/com-rs/pull/234 +com = { git = "https://github.com/MarijnS95/com-rs", rev = "c8256cb", features = ["production"] } bitflags = "1.2.1" widestring = "0.5.0" thiserror = "1.0" diff --git a/src/ffi.rs b/src/ffi.rs index 67e06eb..e0108ec 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -3,11 +3,11 @@ use crate::os::{HRESULT, LPCWSTR, LPWSTR}; pub(crate) use crate::unknown::IDxcUnknownShim; -use com_rs::{com_interface, iid, IUnknown, IID}; +use com::{interfaces, 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, @@ -16,77 +16,106 @@ pub type DxcCreateInstanceProc2 = extern "system" fn( ppv: *mut *mut c_void, ) -> HRESULT; -iid!(pub IID_IDxcBlob = 0x8BA5_FB08, 0x5195, 0x40e2, 0xAC, 0x58, 0x0D, 0x98, 0x9C, 0x3A, 0x01, 0x02); -com_interface! { - interface IDxcBlob: IDxcUnknownShim, 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: IDxcUnknownShim { + 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, IDxcUnknownShim, 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, IUnknown { - iid: IID_IDxcCompiler, - vtable: IDxcCompilerVtbl, - fn compile( - blob: *const IDxcBlob, +interfaces! { + #[uuid("8c210bf3-011f-4422-8d70-6f9acb8db617")] + pub(crate) unsafe interface IDxcCompiler: IDxcUnknownShim { + pub(crate) fn compile( + &self, + blob: IDxcBlob, source_name: LPCWSTR, entry_point: LPCWSTR, target_profile: LPCWSTR, @@ -94,33 +123,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, IDxcUnknownShim, 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, @@ -128,29 +158,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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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; } } @@ -160,82 +188,77 @@ 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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 *mut c_void, + ) -> HRESULT; } -} - -iid!(pub IID_IDxcOptimizerPass = 0xAE2C_D79F, 0xCC22, 0x453F, 0x9B, 0x6B, 0xB1, 0x24, 0xE7, 0xA5, 0x20, 0x4C); -com_interface! { - interface IDxcOptimizerPass: IDxcUnknownShim, 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("AE2CD79F-CC22-453F-9B6B-B124E7A5204C")] + pub(crate) unsafe interface IDxcOptimizerPass: IDxcUnknownShim { + 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; } -} - -iid!(pub IID_IDxcOptimizer = 0x2574_0E2E, 0x9CBA, 0x401B, 0x91, 0x19, 0x4F, 0xB4, 0x2F, 0x39, 0xF2, 0x70); -com_interface! { - interface IDxcOptimizer: IDxcUnknownShim, IUnknown { - iid: IID_IDxcOptimizer, - vtable: IDxcOptimizerVtbl, - 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: IDxcUnknownShim { + 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; } } @@ -243,33 +266,70 @@ 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: IDxcUnknownShim, IUnknown { - iid: IID_IDxcVersionInfo, - vtable: IDxcVersionInfoVtbl, - - fn get_version(major: *mut u32, minor: *mut u32) -> HRESULT; - fn get_flags(flags: *mut u32) -> HRESULT; +interfaces! { + #[uuid("b04f5b50-2059-4f12-a8ff-a1e0cde1cc7e")] + pub(crate) unsafe interface IDxcVersionInfo: IDxcUnknownShim { + 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_IDxcVersionInfo2 = 0xfb69_04c4, 0x42f0, 0x4b62, 0x9c, 0x46, 0x98, 0x3a, 0xf7, 0xda, 0x7c, 0x83); -com_interface! { - interface IDxcVersionInfo2: IDxcUnknownShim, IUnknown { - iid: IID_IDxcVersionInfo2, - vtable: IDxcVersionInfo2Vtbl, - fn get_commit_info(commit_count: *mut u32, commit_hash: *mut *mut u8) -> HRESULT; + #[uuid("fb6904c4-42f0-4b62-9c46-983af7da7c83")] + pub(crate) unsafe interface IDxcVersionInfo2: IDxcUnknownShim { + 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 8e29e6b..e955cbf 100644 --- a/src/intellisense/ffi.rs +++ b/src/intellisense/ffi.rs @@ -1,7 +1,19 @@ use crate::os::{BSTR, HRESULT, LPCSTR, LPSTR}; pub(crate) use crate::unknown::IDxcUnknownShim; use bitflags::bitflags; -use com_rs::{com_interface, iid, IUnknown}; +use com::{interfaces, AbiTransferable, IID}; + +macro_rules! abi_transferable { + ($t:ident) => { + unsafe impl AbiTransferable for $t { + type Abi = u32; + + fn get_abi(&self) -> Self::Abi { + self.bits + } + } + }; +} bitflags! { pub struct DxcGlobalOptions : u32 { @@ -13,6 +25,7 @@ bitflags! { | DxcGlobalOptions::THREAD_BACKGROUND_PRIORITY_FOR_EDITING.bits; } } +abi_transferable!(DxcGlobalOptions); bitflags! { pub struct DxcDiagnosticSeverity : u32 { @@ -38,7 +51,7 @@ bitflags! { bitflags! { pub struct DxcTypeKind : u32 { - const Invalid = 0; // Reprents an invalid type (e.g., where no type is available). + const Invalid = 0; // Represents an invalid type (e.g., where no type is available). const Unexposed = 1; // A type whose specific kind is not exposed via this interface. // Builtin types const Void = 2; @@ -102,6 +115,7 @@ bitflags! { const INCLUDE_NAMESPACE_KEYWORD = 0x8; } } +abi_transferable!(DxcCursorFormatting); bitflags! { pub struct DxcTranslationUnitFlags : u32 { @@ -117,6 +131,7 @@ bitflags! { const USE_CALLER_THREAD = 0x800; } } +abi_transferable!(DxcTranslationUnitFlags); bitflags! { pub struct DxcDiagnosticDisplayOptions : u32 { @@ -129,19 +144,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; } } @@ -357,184 +373,293 @@ bitflags! { } } -iid!(pub IID_IDxcDiagnostic = 0x4f76b234, 0x3659, 0x4d33, 0x99, 0xb0, 0x3b, 0x0d, 0xb9, 0x94, 0xb5, 0x64); -com_interface! { - interface IDxcDiagnostic: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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(lenth : *mut u32) -> HRESULT; + #[uuid("8EC00F98-07D0-4E60-9D7C-5A50B5B0017F")] + pub(crate) unsafe interface IDxcUnsavedFile: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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: IDxcUnknownShim, 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: IDxcUnknownShim { + 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 index d510e51..dba6806 100644 --- a/src/unknown.rs +++ b/src/unknown.rs @@ -1,14 +1,9 @@ #[cfg(not(windows))] use crate::os::HRESULT; -use com_rs::{com_interface, IUnknown, IID}; - -extern "C" { - static IID_IUnknown: IID; -} +use com::{interfaces, interfaces::IUnknown}; #[cfg(not(windows))] -// Steal the interface ID from IUnknown: -com_interface! { +interfaces! { /// 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. @@ -32,19 +27,20 @@ com_interface! { /// [13]: 0x7ffff6a56dd0 /// [14]: 0x7ffff6a56e90 /// ``` - interface IDxcUnknownShim: IUnknown { - iid: IID_IUnknown, - vtable: IDxcUnknownShimVtbl, - fn complete_object_destructor() -> HRESULT; - fn deleting_destructor() -> HRESULT; + // Steal the interface ID from IUnknown: + #[uuid("00000000-0000-0000-C000-000000000046")] + pub(crate) unsafe interface IDxcUnknownShim: IUnknown { + fn complete_object_destructor(&self) -> HRESULT; + fn deleting_destructor(&self) -> HRESULT; } } #[cfg(windows)] -com_interface! { +// pub(crate) type IDxcUnknownShim = IUnknown; +interfaces! { /// Forwards to IUnknown. No-op on Windows - interface IDxcUnknownShim: IUnknown { - iid: IID_IUnknown, - vtable: IDxcUnknownShimVtbl, + // Steal the interface ID from IUnknown: + #[uuid("00000000-0000-0000-C000-000000000046")] + pub(crate) unsafe interface IDxcUnknownShim: IUnknown { } } diff --git a/src/wrapper.rs b/src/wrapper.rs index 919a146..1bd2936 100644 --- a/src/wrapper.rs +++ b/src/wrapper.rs @@ -7,18 +7,20 @@ 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::production::Class; +use com::{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 +62,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 +93,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 +110,131 @@ 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, - #[cfg(not(windows))] - complete_object_destructor: extern "system" fn(*const com_rs::IUnknown) -> HRESULT, - #[cfg(not(windows))] - deleting_destructor: 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(IDxcUnknownShim) { + // 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 dummy(_me: *const com_rs::IUnknown) -> HRESULT { - HRESULT(0) // dummy impl + impl IDxcUnknownShim for DxcIncludeHandlerWrapper { + #[cfg(not(windows))] + fn complete_object_destructor(&self) -> HRESULT { + HRESULT(0) + } + #[cfg(not(windows))] + fn deleting_destructor(&self) -> HRESULT { + HRESULT(0) + } } - extern "system" fn load_source( - me: *mut com_rs::IUnknown, - filename: LPCWSTR, - include_source: *mut *mut IDxcBlob, - ) -> HRESULT { - let me = me.cast::(); - - let filename = crate::utils::from_wide(filename); + impl IDxcIncludeHandler for DxcIncludeHandlerWrapper { + fn load_source(&self, filename: LPCWSTR, include_source: *mut Option) -> HRESULT { + let filename = crate::utils::from_wide(filename); - let source = unsafe { (*me).handler.load_source(filename) }; + let mut handler = self.handler.borrow_mut(); + let source = handler.load_source(filename); - if let Some(source) = source { - let source = Pin::new(source); - let mut blob = unsafe { - (*me) - .library + if let Some(source) = source { + let source = Pin::new(source); + let blob = self.library .create_blob_with_encoding_from_str(&source) - .unwrap() - }; + .unwrap(); - unsafe { - blob.inner.add_ref(); - *include_source = *blob.inner.as_mut_ptr(); - (*me).pinned.push(source); - } + unsafe { *include_source = Some(DxcBlob::from(blob).inner) }; + self.pinned.borrow_mut().push(source); - 0 - } else { - -2_147_024_894 // ERROR_FILE_NOT_FOUND / 0x80070002 + // NOERROR + 0 + } else { + -2_147_024_894 // ERROR_FILE_NOT_FOUND / 0x80070002 + } + .into() } - .into() } } -#[derive(Debug)] +/// Represents a reference to a COM object that should only live as long as itself +/// +/// In other words, on [`drop()`] we should be able to decrement the refcount to zero. +/// 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() + // } +} + +impl Deref for LocalClassAllocation { + type Target = core::pin::Pin>; + + 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![]), + )) + } +} + 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,33 +269,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::dummy, - release: DxcIncludeHandlerWrapper::dummy, - #[cfg(not(windows))] - complete_object_destructor: DxcIncludeHandlerWrapper::dummy, - #[cfg(not(windows))] - deleting_destructor: DxcIncludeHandlerWrapper::dummy, - 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, @@ -268,12 +287,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(), @@ -281,13 +307,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) }; @@ -316,15 +342,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(), @@ -332,14 +364,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) }; @@ -371,24 +403,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) }; @@ -400,43 +438,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 { @@ -444,23 +478,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()?; + + let blob_utf8 = blob_utf8.unwrap(); - Ok(String::from_utf8(DxcBlob::new((&blob_utf8).into()).to_vec()).unwrap()) + Ok(String::from_utf8(DxcBlob::new(blob_utf8.query_interface().unwrap()).to_vec()).unwrap()) } } @@ -506,51 +538,45 @@ 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())) } } -#[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; @@ -559,15 +585,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) }; @@ -618,19 +643,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())) } }