1
0

feat: finish cdylib ffi and improve ffi C header

This commit is contained in:
2026-05-18 13:33:57 +08:00
parent f1a7cb89e5
commit 91c7fdda70
6 changed files with 164 additions and 143 deletions

View File

@@ -5,7 +5,7 @@
# This module requires the user to set wfassoc_ROOT to the installation # This module requires the user to set wfassoc_ROOT to the installation
# directory of wfassoc. The directory structure under wfassoc_ROOT must be: # directory of wfassoc. The directory structure under wfassoc_ROOT must be:
# bin/ - contains wfassoc_cdylib.dll # bin/ - contains wfassoc_cdylib.dll
# include/ - contains wfassoc.h and wfassoc.hpp # include/ - contains wfassoc.h
# lib/ - contains wfassoc_cdylib.dll.lib (import library) # lib/ - contains wfassoc_cdylib.dll.lib (import library)
# #
# This module defines the following variables: # This module defines the following variables:
@@ -36,7 +36,7 @@ set(wfassoc_LIB_DIR ${wfassoc_ROOT}/lib)
set(wfassoc_BIN_DIR ${wfassoc_ROOT}/bin) set(wfassoc_BIN_DIR ${wfassoc_ROOT}/bin)
# Find header files # 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}) set(wfassoc_INCLUDE_DIRS ${wfassoc_INCLUDE_DIR})
else() else()
message(SEND_ERROR "Missing wfassoc header files in ${wfassoc_INCLUDE_DIR}") message(SEND_ERROR "Missing wfassoc header files in ${wfassoc_INCLUDE_DIR}")

View File

@@ -2,28 +2,50 @@
#ifndef __WFASSOC_H__ #ifndef __WFASSOC_H__
#define __WFASSOC_H__ #define __WFASSOC_H__
#include <stdarg.h> #ifdef __cplusplus
#include <cstddef>
#include <cstdint>
#else // __cplusplus
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #endif // __cplusplus
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
#ifdef __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" { extern "C" {
#endif // __cplusplus #endif // __cplusplus
@@ -35,6 +57,8 @@ CStyleString WFGetLastError(void);
bool WFHasPrivilege(void); bool WFHasPrivilege(void);
Token WFInvalidToken(void);
bool WFSchemaCreate(Token *out_schema); bool WFSchemaCreate(Token *out_schema);
bool WFSchemaDestroy(Token in_schema); bool WFSchemaDestroy(Token in_schema);
@@ -67,18 +91,27 @@ bool WFProgramCreate(Token in_schema, Token *out_program);
bool WFProgramDestroy(Token in_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 #ifdef __cplusplus
} // extern "C" } // extern "C"
} // namespace wfassoc
#endif // __cplusplus #endif // __cplusplus
#endif // __WFASSOC_H__ #endif // __WFASSOC_H__

View File

@@ -1,74 +0,0 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <string>
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);
}

View File

@@ -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<Scope> 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<View> 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

View File

@@ -1,16 +1,13 @@
mod cstr_ffi; mod cstr_ffi;
mod last_error; mod last_error;
mod object_pool; mod object_pool;
mod ffi_types;
use num_enum::TryFromPrimitive;
use object_pool::ObjectPool; use object_pool::ObjectPool;
use std::sync::{LazyLock, RwLock}; use std::sync::{LazyLock, RwLock};
use thiserror::Error as TeError; use thiserror::Error as TeError;
use wfassoc::highlevel::{Program, Schema}; use wfassoc::highlevel::{Program, Schema};
pub use cstr_ffi::CStyleString;
pub use object_pool::Token;
// region: Error // region: Error
/// Error occurs in this crate. /// Error occurs in this crate.
@@ -198,39 +195,9 @@ static EXT_STATUE_POOL: LazyLock<RwLock<ObjectPool<wfassoc::highlevel::ProgramEx
// region: Exposed Types // region: Exposed Types
#[repr(u32)] pub use cstr_ffi::CStyleString;
#[derive(Debug, Copy, Clone, TryFromPrimitive)] pub use object_pool::Token;
pub enum Scope { pub use ffi_types::{HICON, Scope, View};
User = 0,
System = 1,
}
impl From<Scope> 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<View> 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 // endregion
@@ -273,6 +240,11 @@ pub extern "C" fn WFHasPrivilege() -> bool {
wfassoc::win32::utilities::has_privilege() wfassoc::win32::utilities::has_privilege()
} }
#[unsafe(no_mangle)]
pub extern "C" fn WFInvalidToken() -> Token {
object_pool::invalid_token()
}
// endregion // endregion
// region: Schema // region: Schema
@@ -583,9 +555,14 @@ pub extern "C" fn WFProgramQueryExt(
let view = resolve_enum!(View, in_view)?; let view = resolve_enum!(View, in_view)?;
let ext_status = program.query_ext(view.into(), in_index)?; let ext_status = program.query_ext(view.into(), in_index)?;
todo!(); let token = match ext_status {
Some(ext_status) => {
let mut pool = pull_writer!(EXT_STATUE_POOL)?; let mut pool = pull_writer!(EXT_STATUE_POOL)?;
Ok(pool.allocate(ext_status)?) pool.allocate(ext_status)?
},
None => object_pool::invalid_token(),
};
Ok(token)
}) })
} }
@@ -600,7 +577,10 @@ pub extern "C" fn WFExtStatusDestroy(in_ext_status: in_param_ty!(Token)) -> bool
} }
#[unsafe(no_mangle)] #[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) { cffi_wrapper!(|in_ext_status: Token| -> (out_name: CStyleString) {
let pool = pull_reader!(EXT_STATUE_POOL)?; let pool = pull_reader!(EXT_STATUE_POOL)?;
let ext_status = pool.get(in_ext_status)?; let ext_status = pool.get(in_ext_status)?;
@@ -611,11 +591,19 @@ pub extern "C" fn WFExtStatuGetName(in_ext_status: in_param_ty!(Token), out_name
} }
#[unsafe(no_mangle)] #[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) { cffi_wrapper!(|in_ext_status: Token| -> (out_icon: HICON) {
let pool = pull_reader!(EXT_STATUE_POOL)?; let pool = pull_reader!(EXT_STATUE_POOL)?;
let ext_status = pool.get(in_ext_status)?; 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)
}) })
} }

View File

@@ -17,6 +17,14 @@ pub enum Error {
/// The token for fetching object in [ObjectPool]. /// The token for fetching object in [ObjectPool].
pub type Token = u64; 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. /// A pool for managing objects with unique tokens.
/// ///
/// It is highly suggested to use this pool with [std::sync::RwLock] guard. /// It is highly suggested to use this pool with [std::sync::RwLock] guard.