#![warn(missing_docs)]
use proc_macro::TokenStream;
use proc_macro2::TokenTree;
use quote::{quote, ToTokens};
#[proc_macro_attribute]
pub fn winmain(a: TokenStream, b: TokenStream) -> TokenStream {
if !a.is_empty() {
return quote! {
compile_error!("winmain attribute does not take any parameters");
}.into()
};
let Ok(tokens) = syn::parse::<syn::ItemFn>(b.clone()) else {
return b;
};
let rval = tokens.sig.output.into_token_stream();
let function_name = &tokens.sig.ident;
let handle_rval = if !rval.is_empty() && rval.to_string() != "()" {
TokenTree::Ident(proc_macro2::Ident::new("_rval", proc_macro2::Span::call_site()))
}
else {
TokenTree::Literal(proc_macro2::Literal::i32_suffixed(0))
};
let inputs = tokens.sig.inputs.to_token_stream();
let function_call = if inputs.is_empty() {
quote! { super::#function_name () }
}
else {
quote! {
super::#function_name (
_hInstance as windows_sys::Win32::Foundation::HANDLE,
_hPrevInstance as windows_sys::Win32::Foundation::HANDLE,
_commandLine,
_nShowCmd
)
}
};
let winmain: TokenStream = quote! {
mod __private_winmain_impl {
#[unsafe(no_mangle)]
extern "system" fn WinMain(
_hInstance: usize,
_hPrevInstance: usize,
_commandLine: *const core::ffi::c_char,
_nShowCmd: core::ffi::c_int
) -> core::ffi::c_int {
let _rval = unsafe { #function_call };
#handle_rval as core::ffi::c_int
}
}
}.into();
TokenStream::from_iter([winmain, b].into_iter())
}
#[proc_macro_attribute]
pub fn dllmain(a: TokenStream, b: TokenStream) -> TokenStream {
if !a.is_empty() {
return quote! {
compile_error!("dllmain attribute does not take any parameters")
}.into()
};
let Ok(tokens) = syn::parse::<syn::ItemFn>(b.clone()) else {
return b;
};
let rval = tokens.sig.output.into_token_stream();
let function_name = &tokens.sig.ident;
let inputs = tokens.sig.inputs.to_token_stream();
if inputs.is_empty() {
return quote! {
compile_error!("DllMain functions must take three parameters");
}.into()
};
let handle_rval = if !rval.is_empty() && rval.to_string() != "()" {
quote! { _rval as i32 }
}
else {
TokenTree::Literal(proc_macro2::Literal::i32_suffixed(1)).to_token_stream()
};
let function_call = quote! {
super::#function_name (
_hInstance as windows_sys::Win32::Foundation::HANDLE,
_fdwReason,
_lpvReserved
)
};
let dllmain: TokenStream = quote! {
mod __private_dllmain_impl {
#[unsafe(no_mangle)]
extern "system" fn DllMain(
_hInstance: usize,
_fdwReason: u32,
_lpvReserved: *mut core::ffi::c_void
) -> core::ffi::c_int {
let _rval = unsafe { #function_call };
#handle_rval
}
}
}.into();
TokenStream::from_iter([dllmain, b].into_iter())
}