Skip to main content

aviutl2\generic\binding/
host_app.rs

1use crate::AviUtl2Info;
2use pastey::paste;
3use std::num::NonZeroIsize;
4
5/// ホストアプリケーションのハンドル。
6/// プラグインの初期化処理で使用します。
7///
8/// # Panics
9///
10/// この型がプラグインの初期化処理の外で使用された場合はPanicします。
11pub struct HostAppHandle<'a> {
12    internal: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
13    global_leak_manager: &'a mut crate::common::LeakManager,
14    kill_switch: std::sync::Arc<std::sync::atomic::AtomicBool>,
15    plugin_registry: &'a mut crate::generic::PluginRegistry,
16    is_registerplugin_done: std::sync::Arc<std::sync::atomic::AtomicBool>,
17}
18
19/// プラグインの初期化状態を管理するためのハンドル。
20pub struct SubPlugin<T> {
21    plugin: std::marker::PhantomData<T>,
22    internal: std::sync::Arc<InternalReferenceHandle>,
23}
24struct InternalReferenceHandle {
25    uninitialize_fn: fn(),
26}
27impl Drop for InternalReferenceHandle {
28    fn drop(&mut self) {
29        (self.uninitialize_fn)();
30    }
31}
32
33impl<'plugin> HostAppHandle<'plugin> {
34    pub(crate) unsafe fn new(
35        internal: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
36        global_leak_manager: &'plugin mut crate::common::LeakManager,
37        kill_switch: std::sync::Arc<std::sync::atomic::AtomicBool>,
38        plugin_registry: &'plugin mut crate::generic::PluginRegistry,
39        is_registerplugin_done: std::sync::Arc<std::sync::atomic::AtomicBool>,
40    ) -> Self {
41        Self {
42            internal,
43            global_leak_manager,
44            kill_switch,
45            plugin_registry,
46            is_registerplugin_done,
47        }
48    }
49
50    fn assert_not_killed(&self) {
51        if self.kill_switch.load(std::sync::atomic::Ordering::SeqCst) {
52            panic!("This HostAppHandle is no longer valid.");
53        }
54    }
55
56    /// プロジェクトデータ編集用のハンドルを登録します。
57    pub fn create_edit_handle(&mut self) -> crate::generic::EditHandle {
58        self.assert_not_killed();
59        let raw_handle = unsafe { ((*self.internal).create_edit_handle)() };
60        unsafe { crate::generic::EditHandle::new(raw_handle, self.is_registerplugin_done.clone()) }
61    }
62
63    /// インポートメニューを登録します。
64    ///
65    /// # See Also
66    ///
67    /// - [`crate::generic::menus`]
68    pub fn register_import_menu<F>(&mut self, name: &str, callback: F)
69    where
70        F: Fn() + 'static + Send + Sync,
71    {
72        self.register_menu_internal(name, callback, unsafe {
73            (*self.internal).register_import_menu_param
74        });
75    }
76
77    /// エクスポートメニューを登録します。
78    ///
79    /// # See Also
80    ///
81    /// - [`crate::generic::menus`]
82    pub fn register_export_menu<F>(&mut self, name: &str, callback: F)
83    where
84        F: Fn() + 'static + Send + Sync,
85    {
86        self.register_menu_internal(name, callback, unsafe {
87            (*self.internal).register_export_menu_param
88        });
89    }
90
91    /// レイヤーメニューを登録します。
92    /// レイヤー編集でオブジェクト未選択時の右クリックメニューに追加されます。
93    /// 名前に`\\`を含めるとサブメニューとして登録されます。
94    ///
95    /// # See Also
96    ///
97    /// - [`crate::generic::menus`]
98    pub fn register_layer_menu<F>(&mut self, name: &str, callback: F)
99    where
100        F: Fn() + 'static + Send + Sync,
101    {
102        self.register_menu_internal(name, callback, unsafe {
103            (*self.internal).register_layer_menu_param
104        });
105    }
106
107    /// オブジェクトメニューを登録します。
108    /// レイヤー編集でオブジェクト選択時の右クリックメニューに追加されます。
109    /// 名前に`\\`を含めるとサブメニューとして登録されます。
110    ///
111    /// # See Also
112    ///
113    /// - [`crate::generic::menus`]
114    pub fn register_object_menu<F>(&mut self, name: &str, callback: F)
115    where
116        F: Fn() + 'static + Send + Sync,
117    {
118        self.register_menu_internal(name, callback, unsafe {
119            (*self.internal).register_object_menu_param
120        });
121    }
122
123    /// 編集メニューを登録します。
124    /// 名前に`\\`を含めるとサブメニューとして登録されます。
125    ///
126    /// # See Also
127    ///
128    /// - [`crate::generic::menus`]
129    pub fn register_edit_menu<F>(&mut self, name: &str, callback: F)
130    where
131        F: Fn() + 'static + Send + Sync,
132    {
133        self.register_menu_internal(name, callback, unsafe {
134            (*self.internal).register_edit_menu_param
135        });
136    }
137
138    /// 設定メニューを登録します。
139    /// 設定メニューの登録後にウィンドウクライアントを登録するとシステムメニューに「設定」が追加されます。
140    ///
141    /// # See Also
142    ///
143    /// - [`crate::generic::menus`]
144    pub fn register_config_menu(
145        &mut self,
146        name: &str,
147        callback: extern "C" fn(aviutl2_sys::plugin2::HWND, aviutl2_sys::plugin2::HINSTANCE),
148    ) {
149        self.assert_not_killed();
150        unsafe {
151            ((*self.internal).register_config_menu)(
152                self.global_leak_manager.leak_as_wide_string(name),
153                callback,
154            )
155        };
156    }
157
158    /// オブジェクト編集の設定項目メニューを登録します。
159    /// オブジェクト編集の右クリックメニューに追加されます。
160    /// 名前に`\\`を含めるとサブメニューとして登録されます。
161    /// [Self::register_object_item_and_effect_menu]と違い、これはエフェクトそのものに対してはメニューが表示されず、設定項目に対してのみメニューが表示されるようになります。
162    ///
163    /// # Arguments
164    ///
165    /// - `name`: メニューの名称。
166    /// - `callback`: メニューが選択されたときのコールバック関数。
167    ///
168    /// # Note
169    ///
170    /// `register_object_item_menu`の`allow_effect_only = false`に相当します。
171    pub fn register_object_item_menu<F>(&mut self, name: &str, callback: F)
172    where
173        F: Fn(crate::generic::ObjectHandle, &str, usize, &str) + 'static + Send + Sync,
174    {
175        self.assert_not_killed();
176        let trampoline_param: Box<F> = Box::new(callback);
177        let trampoline_param_ptr = Box::into_raw(trampoline_param);
178        let name_wide = self.global_leak_manager.leak_as_wide_string(name);
179        unsafe {
180            ((*self.internal).register_object_item_menu_param)(
181                name_wide,
182                false,
183                trampoline_param_ptr as *mut std::ffi::c_void,
184                trampoline::<F>,
185            );
186        }
187
188        unsafe extern "C" fn trampoline<F>(
189            param: *mut std::ffi::c_void,
190            object_handle: aviutl2_sys::plugin2::OBJECT_HANDLE,
191            name_and_index: aviutl2_sys::common::LPCWSTR,
192            item_name: aviutl2_sys::common::LPCWSTR,
193        ) where
194            F: Fn(crate::generic::ObjectHandle, &str, usize, &str) + 'static + Send + Sync,
195        {
196            let callback = unsafe { &mut *(param as *mut F) };
197            let object_handle = crate::generic::ObjectHandle::from(object_handle);
198            let name_and_index_str = unsafe { crate::common::load_wide_string(name_and_index) };
199            let (name_str, index) = parse_name_and_index(&name_and_index_str);
200            let item_name_str = unsafe { crate::common::load_wide_string(item_name) };
201            if let Err(panic_info) =
202                crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(|| {
203                    callback(object_handle, name_str, index, &item_name_str);
204                }))
205            {
206                tracing::error!(
207                    "Panic occurred in object item menu callback: {}",
208                    panic_info
209                );
210                let _ = crate::logger::write_error_log(&panic_info);
211            }
212        }
213    }
214
215    /// オブジェクト編集の設定項目メニューを登録します。
216    /// オブジェクト編集の右クリックメニューに追加されます。
217    /// 名前に`\\`を含めるとサブメニューとして登録されます。
218    /// [Self::register_object_item_menu]と違い、これはエフェクトそのものに対してもメニューが表示されるようになります。
219    ///
220    /// # Arguments
221    ///
222    /// - `name`: メニューの名称。
223    /// - `callback`: メニューが選択されたときのコールバック関数。
224    ///
225    /// # Note
226    ///
227    /// `register_object_item_menu`の`allow_effect_only = true`に相当します。
228    pub fn register_object_item_and_effect_menu<F>(&mut self, name: &str, callback: F)
229    where
230        F: Fn(crate::generic::ObjectHandle, &str, usize, Option<&str>) + 'static + Send + Sync,
231    {
232        self.assert_not_killed();
233        let trampoline_param: Box<F> = Box::new(callback);
234        let trampoline_param_ptr = Box::into_raw(trampoline_param);
235        let name_wide = self.global_leak_manager.leak_as_wide_string(name);
236        unsafe {
237            ((*self.internal).register_object_item_menu_param)(
238                name_wide,
239                true,
240                trampoline_param_ptr as *mut std::ffi::c_void,
241                trampoline::<F>,
242            );
243        }
244
245        unsafe extern "C" fn trampoline<F>(
246            param: *mut std::ffi::c_void,
247            object_handle: aviutl2_sys::plugin2::OBJECT_HANDLE,
248            effect_name_and_index: aviutl2_sys::common::LPCWSTR,
249            item_name: aviutl2_sys::common::LPCWSTR,
250        ) where
251            F: Fn(crate::generic::ObjectHandle, &str, usize, Option<&str>) + 'static + Send + Sync,
252        {
253            let callback = unsafe { &mut *(param as *mut F) };
254            let object_handle = crate::generic::ObjectHandle::from(object_handle);
255            let effect_name_and_index =
256                unsafe { crate::common::load_wide_string(effect_name_and_index) };
257            let item_name = (!item_name.is_null())
258                .then(|| unsafe { crate::common::load_wide_string(item_name) });
259
260            let (effect_name_str, index) = parse_name_and_index(&effect_name_and_index);
261            let item_name_option = item_name.as_deref();
262            if let Err(panic_info) =
263                crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(|| {
264                    callback(object_handle, effect_name_str, index, item_name_option);
265                }))
266            {
267                tracing::error!(
268                    "Panic occurred in object item menu with effect callback: {}",
269                    panic_info
270                );
271                let _ = crate::logger::write_error_log(&panic_info);
272            }
273        }
274    }
275
276    /// ファイルをドロップしたときの処理を登録します。
277    ///
278    /// # Arguments
279    ///
280    /// - `name`: ドラッグ時のツールチップや入力プラグインの設定で表示する名称。
281    /// - `file_filter`: 対応するファイルフィルタ。
282    /// - `callback`: ドロップされたファイルのパスを受け取るコールバック関数。
283    pub fn register_file_drop_handler<F>(
284        &mut self,
285        name: &str,
286        file_filters: &[crate::common::FileFilter],
287        callback: F,
288    ) where
289        F: Fn(std::path::PathBuf) + 'static + Send + Sync,
290    {
291        self.assert_not_killed();
292        let callback_box = Box::new(callback);
293        let callback_ptr = Box::into_raw(callback_box);
294        let name_wide = self.global_leak_manager.leak_as_wide_string(name);
295        let file_filter_wide = self
296            .global_leak_manager
297            .leak_as_wide_string(&crate::common::format_file_filters(file_filters));
298        unsafe {
299            ((*self.internal).register_file_drop_param_handler)(
300                name_wide,
301                file_filter_wide,
302                callback_ptr as *mut std::ffi::c_void,
303                file_drop_trampoline::<F>,
304            );
305        }
306    }
307
308    /// ウィンドウクライアントを登録します。
309    ///
310    /// # Panics
311    ///
312    /// Win32のウィンドウハンドル以外が渡された場合はPanicします。
313    pub fn register_window_client<T: raw_window_handle::HasWindowHandle>(
314        &mut self,
315        name: &str,
316        instance: &T,
317    ) -> Result<(), raw_window_handle::HandleError> {
318        self.assert_not_killed();
319        let raw_handle = instance.window_handle()?;
320        let hwnd = match raw_handle.as_raw() {
321            raw_window_handle::RawWindowHandle::Win32(handle) => handle.hwnd,
322            _ => panic!("Only Win32WindowHandle is supported"),
323        };
324        unsafe {
325            ((*self.internal).register_window_client)(
326                self.global_leak_manager.leak_as_wide_string(name),
327                hwnd.get() as *mut std::ffi::c_void,
328            );
329        }
330        Ok(())
331    }
332
333    /// メニューを一括登録します。
334    ///
335    /// # See Also
336    ///
337    /// - [`crate::generic::menus`]
338    pub fn register_menus<T: GenericPluginMenus>(&mut self) {
339        self.assert_not_killed();
340        T::register_menus(self);
341    }
342
343    /// プロジェクトファイルをロードした直後に呼ばれる関数を登録します。
344    /// また、プロジェクトの初期化時にも呼ばれます。
345    ///
346    /// # Note
347    ///
348    /// [`crate::generic::GenericPlugin::on_project_load`] が自動的に登録されるため、
349    /// 通常はこの関数を直接使用する必要はありません。
350    pub fn register_project_load_handler(
351        &mut self,
352        callback: extern "C" fn(*mut aviutl2_sys::plugin2::PROJECT_FILE),
353    ) {
354        self.assert_not_killed();
355        unsafe {
356            ((*self.internal).register_project_load_handler)(callback);
357        }
358    }
359
360    /// プロジェクトファイルを保存する直前に呼ばれる関数を登録します。
361    ///
362    /// # Note
363    ///
364    /// [`crate::generic::GenericPlugin::on_project_save`] が自動的に登録されるため、
365    /// 通常はこの関数を直接使用する必要はありません。
366    pub fn register_project_save_handler(
367        &mut self,
368        callback: extern "C" fn(*mut aviutl2_sys::plugin2::PROJECT_FILE),
369    ) {
370        self.assert_not_killed();
371        unsafe {
372            ((*self.internal).register_project_save_handler)(callback);
373        }
374    }
375
376    /// 「キャッシュを破棄」が呼ばれたときに呼ばれる関数を登録します。
377    ///
378    /// # Note
379    ///
380    /// [`crate::generic::GenericPlugin::on_clear_cache`] が自動的に登録されるため、
381    /// 通常はこの関数を直接使用する必要はありません。
382    pub fn register_clear_cache_handler(
383        &mut self,
384        callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION),
385    ) {
386        self.assert_not_killed();
387        unsafe {
388            ((*self.internal).register_clear_cache_handler)(callback);
389        }
390    }
391
392    /// シーンを変更した直後に呼ばれる関数を登録します。
393    ///
394    /// # Note
395    ///
396    /// [`crate::generic::GenericPlugin::on_change_scene`] が自動的に登録されるため、
397    /// 通常はこの関数を直接使用する必要はありません。
398    pub fn register_change_scene_handler(
399        &mut self,
400        callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION),
401    ) {
402        self.assert_not_killed();
403        unsafe {
404            ((*self.internal).register_change_scene_handler)(callback);
405        }
406    }
407
408    fn register_menu_internal<F>(
409        &mut self,
410        name: &str,
411        callback: F,
412        register_fn: unsafe extern "C" fn(
413            aviutl2_sys::common::LPCWSTR,
414            *mut std::ffi::c_void,
415            unsafe extern "C" fn(*mut std::ffi::c_void),
416        ),
417    ) where
418        F: Fn() + 'static + Send + Sync,
419    {
420        self.assert_not_killed();
421        let trampoline_param: Box<MenuTrampolineParam<F>> = Box::new(callback);
422        let trampoline_param_ptr = Box::into_raw(trampoline_param);
423        unsafe {
424            register_fn(
425                self.global_leak_manager.leak_as_wide_string(name),
426                trampoline_param_ptr as *mut std::ffi::c_void,
427                menu_trampoline::<F>,
428            );
429        }
430    }
431}
432
433fn parse_name_and_index(name_and_index: &str) -> (&str, usize) {
434    let Some(pos) = name_and_index.rfind(':') else {
435        return (name_and_index, 0);
436    };
437    let index_str = &name_and_index[pos + 1..];
438    if let Ok(index) = index_str.parse::<usize>() {
439        let name = &name_and_index[..pos];
440        (name, index)
441    } else {
442        (name_and_index, 0)
443    }
444}
445
446type MenuTrampolineParam<F> = F;
447
448unsafe extern "C" fn menu_trampoline<F>(param: *mut std::ffi::c_void)
449where
450    F: Fn() + 'static + Send + Sync,
451{
452    let callback = unsafe { &mut *(param as *mut MenuTrampolineParam<F>) };
453    if let Err(panic_info) =
454        crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(callback))
455    {
456        tracing::error!("Panic occurred in menu callback: {}", panic_info);
457        let _ = crate::logger::write_error_log(&panic_info);
458    }
459}
460
461unsafe extern "C" fn file_drop_trampoline<F>(
462    param: *mut std::ffi::c_void,
463    file_path: aviutl2_sys::common::LPCWSTR,
464) where
465    F: Fn(std::path::PathBuf) + 'static + Send + Sync,
466{
467    let callback = unsafe { &mut *(param as *mut F) };
468    let path_str = unsafe { crate::common::load_wide_string(file_path) };
469    let path = std::path::PathBuf::from(path_str);
470    if let Err(panic_info) =
471        crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(|| {
472            callback(path);
473        }))
474    {
475        tracing::error!("Panic occurred in file drop callback: {}", panic_info);
476        let _ = crate::logger::write_error_log(&panic_info);
477    }
478}
479
480/// 汎用プラグインのメニュー登録用トレイト。
481///
482/// <div class="warning">
483///
484/// このトレイトは [`crate::generic::menus`] マクロで自動的に実装されます。
485/// 通常は手動で実装する必要はありません。
486///
487/// </div>
488pub trait GenericPluginMenus {
489    fn register_menus(host: &mut crate::generic::HostAppHandle);
490}
491
492#[doc(inline)]
493pub use aviutl2_macros::generic_menus as menus;
494
495#[derive(Default)]
496pub(crate) struct PluginRegistry {
497    #[cfg(feature = "input")]
498    input_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
499    #[cfg(feature = "output")]
500    output_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
501    #[cfg(feature = "filter")]
502    filter_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
503    #[cfg(feature = "module")]
504    script_modules: Vec<std::sync::Arc<InternalReferenceHandle>>,
505}
506impl PluginRegistry {
507    pub(crate) fn new() -> Self {
508        Self::default()
509    }
510}
511
512macro_rules! impl_plugin_registry {
513    (
514        $description:literal,
515        $feature:literal,
516        $module:ident,
517        $name:ident,
518        $register_method:ident,
519        $PluginTrait:path,
520        $SingletonTrait:path,
521        $TableType:ty
522    ) => {
523        paste! {
524            impl<T> SubPlugin<T> {
525                #[cfg(feature = $feature)]
526                #[doc = concat!($description, "の新しいインスタンスを作成します。")]
527                pub fn [<new_ $name>](info: &AviUtl2Info) -> crate::AnyResult<Self>
528                where
529                    T: $PluginTrait + $SingletonTrait + 'static
530                {
531                    crate::$module::__bridge::initialize_plugin::<T>(info.version.into())?;
532                    let internal = std::sync::Arc::new(InternalReferenceHandle {
533                        uninitialize_fn: || {
534                            unsafe {
535                                crate::$module::__bridge::uninitialize_plugin::<T>();
536                            }
537                        },
538                    });
539                    Ok(Self {
540                        plugin: std::marker::PhantomData,
541                        internal,
542                    })
543                }
544            }
545            #[cfg(feature = $feature)]
546            impl<'a> HostAppHandle<'a> {
547                #[doc = concat!($description, "を登録します。")]
548                pub fn [<register_ $name>]<T: $PluginTrait + $SingletonTrait + 'static>(
549                    &mut self,
550                    handle: &SubPlugin<T>,
551                ) {
552                    self.assert_not_killed();
553                    unsafe { ((*self.internal).$register_method)(crate::$module::__bridge::create_table_unwind::<T>()) };
554                    self.plugin_registry
555                        .[<$name s>]
556                        .push(std::sync::Arc::clone(&handle.internal));
557                }
558                #[doc = concat!("unwindなしで", $description, "を登録します。")]
559                pub fn [<register_ $name _nounwind>]<T: $PluginTrait + $SingletonTrait + 'static>(
560                    &mut self,
561                    handle: &SubPlugin<T>,
562                ) {
563                    self.assert_not_killed();
564                    unsafe { ((*self.internal).$register_method)(crate::$module::__bridge::create_table::<T>()) };
565                    self.plugin_registry
566                        .[<$name s>]
567                        .push(std::sync::Arc::clone(&handle.internal));
568                }
569            }
570        }
571    };
572}
573
574impl_plugin_registry!(
575    "入力プラグイン",
576    "input",
577    input,
578    input_plugin,
579    register_input_plugin,
580    crate::input::InputPlugin,
581    crate::input::__bridge::InputSingleton,
582    aviutl2_sys::input2::INPUT_PLUGIN_TABLE
583);
584impl_plugin_registry!(
585    "出力プラグイン",
586    "output",
587    output,
588    output_plugin,
589    register_output_plugin,
590    crate::output::OutputPlugin,
591    crate::output::__bridge::OutputSingleton,
592    aviutl2_sys::output2::OUTPUT_PLUGIN_TABLE
593);
594impl_plugin_registry!(
595    "フィルタープラグイン",
596    "filter",
597    filter,
598    filter_plugin,
599    register_filter_plugin,
600    crate::filter::FilterPlugin,
601    crate::filter::__bridge::FilterSingleton,
602    aviutl2_sys::filter2::FILTER_PLUGIN_TABLE
603);
604#[cfg(feature = "module")]
605impl<T> SubPlugin<T> {
606    /// スクリプトモジュールの新しいインスタンスを作成します。
607    pub fn new_script_module(info: &AviUtl2Info) -> crate::AnyResult<Self>
608    where
609        T: crate::module::ScriptModule + crate::module::__bridge::ScriptModuleSingleton + 'static,
610    {
611        crate::module::__bridge::initialize_plugin::<T>(info.version.into())?;
612        let internal = std::sync::Arc::new(InternalReferenceHandle {
613            uninitialize_fn: || unsafe {
614                crate::module::__bridge::uninitialize_plugin::<T>();
615            },
616        });
617        Ok(Self {
618            plugin: std::marker::PhantomData,
619            internal,
620        })
621    }
622}
623
624#[cfg(feature = "module")]
625impl<'a> HostAppHandle<'a> {
626    /// スクリプトモジュールを登録します。
627    ///
628    /// # Arguments
629    ///
630    /// - `name`: モジュール名。
631    pub fn register_script_module<
632        T: crate::module::ScriptModule + crate::module::__bridge::ScriptModuleSingleton + 'static,
633    >(
634        &mut self,
635        name: Option<&str>,
636        handle: &SubPlugin<T>,
637    ) {
638        self.assert_not_killed();
639        unsafe {
640            if let Some(name_str) = name {
641                ((*self.internal).register_script_module_name)(
642                    crate::module::__bridge::create_table_unwind::<T>(),
643                    self.global_leak_manager.leak_as_wide_string(name_str),
644                )
645            } else {
646                ((*self.internal).register_script_module)(
647                    crate::module::__bridge::create_table_unwind::<T>(),
648                )
649            }
650        };
651        self.plugin_registry
652            .script_modules
653            .push(std::sync::Arc::clone(&handle.internal));
654    }
655
656    /// unwindなしでスクリプトモジュールを登録します。
657    ///
658    /// # Arguments
659    ///
660    /// - `name`: モジュール名。
661    pub fn register_script_module_nounwind<
662        T: crate::module::ScriptModule + crate::module::__bridge::ScriptModuleSingleton + 'static,
663    >(
664        &mut self,
665        name: Option<&str>,
666        handle: &SubPlugin<T>,
667    ) {
668        self.assert_not_killed();
669        unsafe {
670            if let Some(name_str) = name {
671                ((*self.internal).register_script_module_name)(
672                    crate::module::__bridge::create_table::<T>(),
673                    self.global_leak_manager.leak_as_wide_string(name_str),
674                )
675            } else {
676                ((*self.internal).register_script_module)(
677                    crate::module::__bridge::create_table::<T>(),
678                );
679            }
680        };
681        self.plugin_registry
682            .script_modules
683            .push(std::sync::Arc::clone(&handle.internal));
684    }
685}
686
687#[doc(hidden)]
688pub unsafe fn __internal_rwh_from_raw(
689    hwnd: aviutl2_sys::plugin2::HWND,
690    hinstance: aviutl2_sys::plugin2::HINSTANCE,
691) -> raw_window_handle::Win32WindowHandle {
692    let mut handle =
693        raw_window_handle::Win32WindowHandle::new(NonZeroIsize::new(hwnd as isize).unwrap());
694    handle.hinstance = Some(NonZeroIsize::new(hinstance as isize).unwrap());
695    handle
696}