|
| 1 | +use widestring::U16CStr; |
| 2 | + |
1 | 3 | use crate::{ |
2 | 4 | bindings::hostfxr::{hostfxr_handle, hostfxr_initialize_parameters}, |
3 | 5 | error::{HostingError, HostingResult, HostingSuccess}, |
@@ -395,4 +397,50 @@ impl Hostfxr { |
395 | 397 | ) |
396 | 398 | }) |
397 | 399 | } |
| 400 | + |
| 401 | + /// Sets a callback which is to be used to write errors to. |
| 402 | + /// |
| 403 | + /// # Arguments |
| 404 | + /// * `error_writer` |
| 405 | + /// A callback function which will be invoked every time an error is to be reported. |
| 406 | + /// Or [`None`] to unregister previously registered callbacks and return to the default behavior. |
| 407 | + /// |
| 408 | + /// # Remarks |
| 409 | + /// The error writer is registered per-thread, so the registration is thread-local. On each thread |
| 410 | + /// only one callback can be registered. Subsequent registrations overwrite the previous ones. |
| 411 | + /// |
| 412 | + /// By default no callback is registered in which case the errors are written to stderr. |
| 413 | + /// |
| 414 | + /// Each call to the error writer is sort of like writing a single line (the EOL character is omitted). |
| 415 | + /// Multiple calls to the error writer may occure for one failure. |
| 416 | + /// |
| 417 | + /// If the hostfxr invokes functions in hostpolicy as part of its operation, the error writer |
| 418 | + /// will be propagated to hostpolicy for the duration of the call. This means that errors from |
| 419 | + /// both hostfxr and hostpolicy will be reporter through the same error writer. |
| 420 | + #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "netcore3_0")))] |
| 421 | + pub fn set_error_writer(&self, error_writer: Option<ErrorWriter>) { |
| 422 | + let new_raw_error_writer = error_writer |
| 423 | + .as_ref() |
| 424 | + .map(|_| error_writer_trampoline as hostfxr_sys::hostfxr_error_writer_fn); |
| 425 | + unsafe { self.lib.hostfxr_set_error_writer(new_raw_error_writer) }; |
| 426 | + |
| 427 | + CURRENT_ERROR_WRITER.with(|current_writer| { |
| 428 | + *current_writer.borrow_mut() = error_writer; |
| 429 | + }); |
| 430 | + } |
| 431 | +} |
| 432 | + |
| 433 | +type ErrorWriter = Box<dyn FnMut(&U16CStr)>; |
| 434 | + |
| 435 | +thread_local! { |
| 436 | + static CURRENT_ERROR_WRITER: std::cell::RefCell<Option<ErrorWriter>> = std::cell::RefCell::new(None); |
| 437 | +} |
| 438 | + |
| 439 | +extern "C" fn error_writer_trampoline(raw_error: *const u16) { |
| 440 | + CURRENT_ERROR_WRITER.with(|writer_holder| { |
| 441 | + if let Some(writer) = writer_holder.borrow_mut().as_mut() { |
| 442 | + let error_message = unsafe { U16CStr::from_ptr_str(raw_error) }; |
| 443 | + writer(error_message); |
| 444 | + } |
| 445 | + }); |
398 | 446 | } |
0 commit comments