1use crate::{
2 exports::raw::{
3 Export0, Export3, Export5, Export6, Export7, Export8, Export9, Export10,
4 ExportAddExtension, ExportFreeExtension, ExportListExtension,
5 },
6 util::str_from_cstr,
7};
8use std::{
9 ffi::c_char,
10 io,
11 mem::{self, transmute},
12 ptr,
13 sync::OnceLock,
14};
15use windows::{
16 Win32::{
17 Foundation::HMODULE,
18 System::{
19 LibraryLoader::GetProcAddress, ProcessStatus::EnumProcessModules,
20 Threading::GetCurrentProcess,
21 },
22 },
23 core::{PCSTR, s},
24};
25
26#[inline]
28pub unsafe fn init_arc(arc_handle: HMODULE, version: *const c_char) {
29 unsafe { ArcGlobals::init(arc_handle, str_from_cstr(version)) };
30}
31
32#[inline]
38pub unsafe fn search_and_init_arc() -> Result<(), io::Error> {
39 let arc_handle = search_arc_handle()?;
40 unsafe { ArcGlobals::init(arc_handle, None) };
41 Ok(())
42}
43
44pub fn search_arc_handle() -> Result<HMODULE, io::Error> {
46 const EXPORT: PCSTR = s!("arcdps_identifier_export"); const MAX_MODULES: usize = 1024;
48
49 let mut modules = const { [HMODULE(ptr::null_mut()); MAX_MODULES] };
50 let mut needed = 0;
51 unsafe {
52 EnumProcessModules(
53 GetCurrentProcess(),
54 modules.as_mut_ptr(),
55 mem::size_of_val(&modules) as _,
56 &mut needed,
57 )
58 }?;
59
60 let len = needed as usize / mem::size_of::<HMODULE>();
61 modules
62 .into_iter()
63 .take(len)
64 .find(|module| unsafe { GetProcAddress(*module, EXPORT) }.is_some())
65 .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "module not found"))
66}
67
68static ARC_GLOBALS: OnceLock<ArcGlobals> = OnceLock::new();
70
71#[derive(Debug)]
74pub struct ArcGlobals {
75 pub handle: HMODULE,
77
78 pub version: Option<&'static str>,
80
81 pub e0: Option<Export0>,
83
84 pub e3: Option<Export3>,
86
87 pub e5: Option<Export5>,
89
90 pub e6: Option<Export6>,
92
93 pub e7: Option<Export7>,
95
96 pub e8: Option<Export8>,
98
99 pub e9: Option<Export9>,
101
102 pub e10: Option<Export10>,
104
105 pub add_extension: Option<ExportAddExtension>,
107
108 pub free_extension: Option<ExportFreeExtension>,
110
111 pub list_extension: Option<ExportListExtension>,
113}
114
115impl ArcGlobals {
116 pub unsafe fn new(handle: HMODULE, version: Option<&'static str>) -> Self {
118 #![allow(clippy::missing_transmute_annotations)]
119 unsafe {
120 Self {
121 handle,
122 version,
123 e0: transmute(GetProcAddress(handle, s!("e0"))),
124 e3: transmute(GetProcAddress(handle, s!("e3"))),
125 e5: transmute(GetProcAddress(handle, s!("e5"))),
126 e6: transmute(GetProcAddress(handle, s!("e6"))),
127 e7: transmute(GetProcAddress(handle, s!("e7"))),
128 e8: transmute(GetProcAddress(handle, s!("e8"))),
129 e9: transmute(GetProcAddress(handle, s!("e9"))),
130 e10: transmute(GetProcAddress(handle, s!("e10"))),
131 add_extension: transmute(GetProcAddress(handle, s!("addextension2"))),
132 free_extension: transmute(GetProcAddress(handle, s!("freeextension2"))),
133 list_extension: transmute(GetProcAddress(handle, s!("listextension"))),
134 }
135 }
136 }
137
138 pub unsafe fn init(handle: HMODULE, version: Option<&'static str>) -> &'static Self {
140 ARC_GLOBALS.get_or_init(|| unsafe { Self::new(handle, version) })
141 }
142
143 #[inline]
145 pub fn get() -> &'static Self {
146 Self::try_get().expect("arcdps globals not initialized")
147 }
148
149 #[inline]
151 pub fn try_get() -> Option<&'static Self> {
152 ARC_GLOBALS.get()
153 }
154}
155
156unsafe impl Send for ArcGlobals {}
157
158unsafe impl Sync for ArcGlobals {}