From 91c7fdda70a8e8ee72fd9fecdb49886bb5bc85f9 Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Mon, 18 May 2026 13:33:57 +0800 Subject: [PATCH] feat: finish cdylib ffi and improve ffi C header --- wfassoc-cdylib/codegen/Findwfassoc.cmake | 4 +- wfassoc-cdylib/codegen/wfassoc.h | 77 ++++++++++++++++------- wfassoc-cdylib/codegen/wfassoc.hpp | 74 ---------------------- wfassoc-cdylib/src/ffi_types.rs | 66 ++++++++++++++++++++ wfassoc-cdylib/src/lib.rs | 78 ++++++++++-------------- wfassoc-cdylib/src/object_pool.rs | 8 +++ 6 files changed, 164 insertions(+), 143 deletions(-) delete mode 100644 wfassoc-cdylib/codegen/wfassoc.hpp create mode 100644 wfassoc-cdylib/src/ffi_types.rs diff --git a/wfassoc-cdylib/codegen/Findwfassoc.cmake b/wfassoc-cdylib/codegen/Findwfassoc.cmake index e0744c2..7bab1ca 100644 --- a/wfassoc-cdylib/codegen/Findwfassoc.cmake +++ b/wfassoc-cdylib/codegen/Findwfassoc.cmake @@ -5,7 +5,7 @@ # This module requires the user to set wfassoc_ROOT to the installation # directory of wfassoc. The directory structure under wfassoc_ROOT must be: # bin/ - contains wfassoc_cdylib.dll -# include/ - contains wfassoc.h and wfassoc.hpp +# include/ - contains wfassoc.h # lib/ - contains wfassoc_cdylib.dll.lib (import library) # # This module defines the following variables: @@ -36,7 +36,7 @@ set(wfassoc_LIB_DIR ${wfassoc_ROOT}/lib) set(wfassoc_BIN_DIR ${wfassoc_ROOT}/bin) # Find header files -if(EXISTS ${wfassoc_INCLUDE_DIR}/wfassoc.h AND EXISTS ${wfassoc_INCLUDE_DIR}/wfassoc.hpp) +if(EXISTS ${wfassoc_INCLUDE_DIR}/wfassoc.h) set(wfassoc_INCLUDE_DIRS ${wfassoc_INCLUDE_DIR}) else() message(SEND_ERROR "Missing wfassoc header files in ${wfassoc_INCLUDE_DIR}") diff --git a/wfassoc-cdylib/codegen/wfassoc.h b/wfassoc-cdylib/codegen/wfassoc.h index 0fc1dc8..20da9ac 100644 --- a/wfassoc-cdylib/codegen/wfassoc.h +++ b/wfassoc-cdylib/codegen/wfassoc.h @@ -2,28 +2,50 @@ #ifndef __WFASSOC_H__ #define __WFASSOC_H__ -#include +#ifdef __cplusplus +#include +#include +#else // __cplusplus #include #include #include -#include - - -typedef const char *CStyleString; - -typedef uint64_t Token; - -typedef uint32_t Scope; -#define SCOPE_USER 0u -#define SCOPE_SYSTEM 1u - -typedef uint32_t View; -#define VIEW_USER 0u -#define VIEW_SYSTEM 1u -#define VIEW_HYBRID 2u +#endif // __cplusplus #ifdef __cplusplus +using CStyleString = const char*; +using Token = uint64_t; +using HICON = void*; +#else // __cplusplus +typedef const char *CStyleString; +typedef uint64_t Token; +typedef void *HICON; +#endif // __cplusplus + + +#ifdef __cplusplus +enum class Scope : uint32_t { + User = 0u, + System = 1u +}; +enum class View : uint32_t { + User = 0u, + System = 1u, + Hybrid = 2u +}; +#else // __cplusplus +typedef uint32_t Scope; +static const Scope SCOPE_USER = 0u; +static const Scope SCOPE_SYSTEM = 1u; +typedef uint32_t View; +static const View VIEW_USER = 0u; +static const View VIEW_SYSTEM = 1u; +static const View VIEW_HYBRID = 2u; +#endif // __cplusplus + + +#ifdef __cplusplus +namespace wfassoc { extern "C" { #endif // __cplusplus @@ -35,6 +57,8 @@ CStyleString WFGetLastError(void); bool WFHasPrivilege(void); +Token WFInvalidToken(void); + bool WFSchemaCreate(Token *out_schema); bool WFSchemaDestroy(Token in_schema); @@ -67,18 +91,27 @@ bool WFProgramCreate(Token in_schema, Token *out_program); bool WFProgramDestroy(Token in_program); -bool WFProgramRegister(Token in_program, uint32_t in_scope); +bool WFProgramRegister(Token in_program, Scope in_scope); -bool WFProgramUnregister(Token in_program, uint32_t in_scope); +bool WFProgramUnregister(Token in_program, Scope in_scope); -bool WFProgramIsRegistered(Token in_program, uint32_t in_scope, bool *out_is_registered); +bool WFProgramIsRegistered(Token in_program, Scope in_scope, bool *out_is_registered); -bool WFProgramLinkExt(Token in_program, uint32_t in_scope, size_t in_index); +bool WFProgramLinkExt(Token in_program, Scope in_scope, size_t in_index); -bool WFProgramUnlinkExt(Token in_program, uint32_t in_scope, size_t in_index); +bool WFProgramUnlinkExt(Token in_program, Scope in_scope, size_t in_index); + +bool WFProgramQueryExt(Token in_program, View in_view, size_t in_index, Token *out_ext_status); + +bool WFExtStatusDestroy(Token in_ext_status); + +bool WFExtStatuGetName(Token in_ext_status, CStyleString *out_name); + +bool WFExtStatuGetIcon(Token in_ext_status, HICON *out_icon); #ifdef __cplusplus } // extern "C" +} // namespace wfassoc #endif // __cplusplus -#endif // __WFASSOC_H__ +#endif // __WFASSOC_H__ diff --git a/wfassoc-cdylib/codegen/wfassoc.hpp b/wfassoc-cdylib/codegen/wfassoc.hpp deleted file mode 100644 index c2480d6..0000000 --- a/wfassoc-cdylib/codegen/wfassoc.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include -#include -#include - -enum class Scope : uint32_t { - User = 0u, - System = 1u -}; - -enum class View : uint32_t { - User = 0u, - System = 1u, - Hybrid = 2u -}; - -using Token = uint64_t; - -using CStyleString = const char*; - -extern "C" { - -bool WFStartup(void); - -bool WFShutdown(void); - -CStyleString WFGetLastError(void); - -bool WFHasPrivilege(void); - -bool WFSchemaCreate(Token *out_schema); - -bool WFSchemaDestroy(Token in_schema); - -bool WFSchemaSetIdentifier(Token in_schema, CStyleString in_value); - -bool WFSchemaSetPath(Token in_schema, CStyleString in_value); - -bool WFSchemaSetClsid(Token in_schema, CStyleString in_value); - -bool WFSchemaSetName(Token in_schema, CStyleString in_value); - -bool WFSchemaSetIcon(Token in_schema, CStyleString in_value); - -bool WFSchemaSetBehavior(Token in_schema, CStyleString in_value); - -bool WFSchemaAddStr(Token in_schema, CStyleString in_name, CStyleString in_value); - -bool WFSchemaAddIcon(Token in_schema, CStyleString in_name, CStyleString in_value); - -bool WFSchemaAddBehavior(Token in_schema, CStyleString in_name, CStyleString in_value); - -bool WFSchemaAddExt(Token in_schema, - CStyleString in_ext, - CStyleString in_ext_name, - CStyleString in_ext_icon, - CStyleString in_ext_behavior); - -bool WFProgramCreate(Token in_schema, Token *out_program); - -bool WFProgramDestroy(Token in_program); - -bool WFProgramRegister(Token in_program, uint32_t in_scope); - -bool WFProgramUnregister(Token in_program, uint32_t in_scope); - -bool WFProgramIsRegistered(Token in_program, uint32_t in_scope, bool *out_is_registered); - -bool WFProgramLinkExt(Token in_program, uint32_t in_scope, size_t in_index); - -bool WFProgramUnlinkExt(Token in_program, uint32_t in_scope, size_t in_index); - -} \ No newline at end of file diff --git a/wfassoc-cdylib/src/ffi_types.rs b/wfassoc-cdylib/src/ffi_types.rs new file mode 100644 index 0000000..e62b482 --- /dev/null +++ b/wfassoc-cdylib/src/ffi_types.rs @@ -0,0 +1,66 @@ +//! The module including all FFI types used by this crate. + +use std::ffi::c_void; +use num_enum::TryFromPrimitive; + +// region: HICON + +/// The type representing Win32 HICON handle. +/// +/// In theory, we can fetch HICON type from "windows_sys" crate. +/// However, I don't want to add it as this crate's dependency, +/// because I don't use anything within it except this type. +/// So I check Microsoft document, re-define it in there for this crate. +/// Reference: https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types +pub type HICON = *mut c_void; + +/// The invalid value of Win32 HICON handle. +/// +/// The same reason like [HICON] to re-define it in there. +pub const INVALID_ICON: HICON = std::ptr::null_mut(); + +// endregion + +// region: Scope + +/// The FFI wrapper for [wfassoc::Scope]. +#[repr(u32)] +#[derive(Debug, Copy, Clone, TryFromPrimitive)] +pub enum Scope { + User = 0, + System = 1, +} + +impl From for wfassoc::Scope { + fn from(value: Scope) -> Self { + match value { + Scope::User => wfassoc::Scope::User, + Scope::System => wfassoc::Scope::System, + } + } +} + +// endregion + +// region: View + +/// The FFI wrapper for [wfassoc::View]. +#[repr(u32)] +#[derive(Debug, Copy, Clone, TryFromPrimitive)] +pub enum View { + User = 0, + System = 1, + Hybrid = 2, +} + +impl From for wfassoc::View { + fn from(value: View) -> Self { + match value { + View::User => wfassoc::View::User, + View::System => wfassoc::View::System, + View::Hybrid => wfassoc::View::Hybrid, + } + } +} + +// endregion diff --git a/wfassoc-cdylib/src/lib.rs b/wfassoc-cdylib/src/lib.rs index 55ff353..982d2a5 100644 --- a/wfassoc-cdylib/src/lib.rs +++ b/wfassoc-cdylib/src/lib.rs @@ -1,16 +1,13 @@ mod cstr_ffi; mod last_error; mod object_pool; +mod ffi_types; -use num_enum::TryFromPrimitive; use object_pool::ObjectPool; use std::sync::{LazyLock, RwLock}; use thiserror::Error as TeError; use wfassoc::highlevel::{Program, Schema}; -pub use cstr_ffi::CStyleString; -pub use object_pool::Token; - // region: Error /// Error occurs in this crate. @@ -198,39 +195,9 @@ static EXT_STATUE_POOL: LazyLock for wfassoc::Scope { - fn from(value: Scope) -> Self { - match value { - Scope::User => wfassoc::Scope::User, - Scope::System => wfassoc::Scope::System, - } - } -} - -#[repr(u32)] -#[derive(Debug, Copy, Clone, TryFromPrimitive)] -pub enum View { - User = 0, - System = 1, - Hybrid = 2, -} - -impl From for wfassoc::View { - fn from(value: View) -> Self { - match value { - View::User => wfassoc::View::User, - View::System => wfassoc::View::System, - View::Hybrid => wfassoc::View::Hybrid, - } - } -} +pub use cstr_ffi::CStyleString; +pub use object_pool::Token; +pub use ffi_types::{HICON, Scope, View}; // endregion @@ -273,6 +240,11 @@ pub extern "C" fn WFHasPrivilege() -> bool { wfassoc::win32::utilities::has_privilege() } +#[unsafe(no_mangle)] +pub extern "C" fn WFInvalidToken() -> Token { + object_pool::invalid_token() +} + // endregion // region: Schema @@ -581,11 +553,16 @@ pub extern "C" fn WFProgramQueryExt( let pool = pull_reader!(PROGRAM_POOL)?; let program = pool.get(in_program)?; let view = resolve_enum!(View, in_view)?; - + let ext_status = program.query_ext(view.into(), in_index)?; - todo!(); - let mut pool = pull_writer!(EXT_STATUE_POOL)?; - Ok(pool.allocate(ext_status)?) + let token = match ext_status { + Some(ext_status) => { + let mut pool = pull_writer!(EXT_STATUE_POOL)?; + pool.allocate(ext_status)? + }, + None => object_pool::invalid_token(), + }; + Ok(token) }) } @@ -600,22 +577,33 @@ pub extern "C" fn WFExtStatusDestroy(in_ext_status: in_param_ty!(Token)) -> bool } #[unsafe(no_mangle)] -pub extern "C" fn WFExtStatuGetName(in_ext_status: in_param_ty!(Token), out_name: out_param_ty!(CStyleString)) -> bool { +pub extern "C" fn WFExtStatuGetName( + in_ext_status: in_param_ty!(Token), + out_name: out_param_ty!(CStyleString), +) -> bool { cffi_wrapper!(|in_ext_status: Token| -> (out_name: CStyleString) { let pool = pull_reader!(EXT_STATUE_POOL)?; let ext_status = pool.get(in_ext_status)?; - + cstr_ffi::set_ffi_string(ext_status.get_name())?; Ok(cstr_ffi::get_ffi_string()) }) } #[unsafe(no_mangle)] -pub extern "C" fn WFExtStatuGetIcon(in_ext_status: in_param_ty!(Token), out_icon: out_param_ty!(HICON)) -> bool { +pub extern "C" fn WFExtStatuGetIcon( + in_ext_status: in_param_ty!(Token), + out_icon: out_param_ty!(HICON), +) -> bool { cffi_wrapper!(|in_ext_status: Token| -> (out_icon: HICON) { let pool = pull_reader!(EXT_STATUE_POOL)?; let ext_status = pool.get(in_ext_status)?; - Ok(ext_status.get_icon()) + + let icon = match ext_status.get_icon() { + Some(icon) => icon.get_icon(), + None => ffi_types::INVALID_ICON, + }; + Ok(icon) }) } diff --git a/wfassoc-cdylib/src/object_pool.rs b/wfassoc-cdylib/src/object_pool.rs index 5f5374b..380cc50 100644 --- a/wfassoc-cdylib/src/object_pool.rs +++ b/wfassoc-cdylib/src/object_pool.rs @@ -17,6 +17,14 @@ pub enum Error { /// The token for fetching object in [ObjectPool]. pub type Token = u64; +/// Get the invalid token. +/// +/// Invalid token is always invalid for fetching object in pool, +/// And can be useful in FFI scenario. +pub fn invalid_token() -> Token { + DefaultKey::null().data().as_ffi() +} + /// A pool for managing objects with unique tokens. /// /// It is highly suggested to use this pool with [std::sync::RwLock] guard.