pass rust args to flutter

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2022-10-09 21:10:41 +08:00
parent 089cf41a2f
commit 2ced73cdda
3 changed files with 90 additions and 12 deletions

View File

@ -7,7 +7,8 @@
#include "utils.h"
// #include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
typedef bool (*FUNC_RUSTDESK_CORE_MAIN)(void);
typedef char** (*FUNC_RUSTDESK_CORE_MAIN)(int*);
typedef void (*FUNC_RUSTDESK_FREE_ARGS)( char**, int);
// auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP);
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
@ -26,11 +27,23 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
std::cout << "Failed to get rustdesk_core_main" << std::endl;
return EXIT_FAILURE;
}
if (!rustdesk_core_main())
FUNC_RUSTDESK_FREE_ARGS free_c_args =
(FUNC_RUSTDESK_FREE_ARGS)GetProcAddress(hInstance, "free_c_args");
if (!free_c_args)
{
std::cout << "Failed to get free_c_args" << std::endl;
return EXIT_FAILURE;
}
int args_len = 0;
char** c_args = rustdesk_core_main(&args_len);
if (!c_args)
{
std::cout << "Rustdesk core returns false, exiting without launching Flutter app" << std::endl;
return EXIT_SUCCESS;
}
std::vector<std::string> rust_args(c_args, c_args + args_len);
free_c_args(c_args, args_len);
// Attach to console when present (e.g., 'flutter run') or create a
// new console when running with a debugger.
@ -48,6 +61,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
std::vector<std::string> command_line_arguments =
GetCommandLineArguments();
command_line_arguments.insert(command_line_arguments.end(), rust_args.begin(), rust_args.end());
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
FlutterWindow window(project);

View File

@ -1,5 +1,7 @@
use std::{
collections::HashMap,
ffi::CString,
os::raw::{c_char, c_int},
sync::{Arc, RwLock},
};
@ -24,6 +26,78 @@ lazy_static::lazy_static! {
pub static ref GLOBAL_EVENT_STREAM: RwLock<HashMap<String, StreamSink<String>>> = Default::default(); // rust to dart event channel
}
/// FFI for rustdesk core's main entry.
/// Return true if the app should continue running with UI(possibly Flutter), false if the app should exit.
#[cfg(not(windows))]
#[no_mangle]
pub extern "C" fn rustdesk_core_main() -> bool {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
return crate::core_main::core_main().is_some();
#[cfg(any(target_os = "android", target_os = "ios"))]
false
}
#[cfg(windows)]
#[no_mangle]
pub extern "C" fn rustdesk_core_main(args_len: *mut c_int) -> *mut *mut c_char {
unsafe { std::ptr::write(args_len, 0) };
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
if let Some(args) = crate::core_main::core_main() {
return rust_args_to_c_args(args, args_len);
}
return std::ptr::null_mut() as _;
}
#[cfg(any(target_os = "android", target_os = "ios"))]
return std::ptr::null_mut() as _;
}
// https://gist.github.com/iskakaushik/1c5b8aa75c77479c33c4320913eebef6
fn rust_args_to_c_args(args: Vec<String>, outlen: *mut c_int) -> *mut *mut c_char {
let mut v = vec![];
// Let's fill a vector with null-terminated strings
for s in args {
v.push(CString::new(s).unwrap());
}
// Turning each null-terminated string into a pointer.
// `into_raw` takes ownershop, gives us the pointer and does NOT drop the data.
let mut out = v.into_iter().map(|s| s.into_raw()).collect::<Vec<_>>();
// Make sure we're not wasting space.
out.shrink_to_fit();
assert!(out.len() == out.capacity());
// Get the pointer to our vector.
let len = out.len();
let ptr = out.as_mut_ptr();
std::mem::forget(out);
// Let's write back the length the caller can expect
unsafe { std::ptr::write(outlen, len as c_int) };
// Finally return the data
ptr
}
#[no_mangle]
pub unsafe extern "C" fn free_c_args(ptr: *mut *mut c_char, len: c_int) {
let len = len as usize;
// Get back our vector.
// Previously we shrank to fit, so capacity == length.
let v = Vec::from_raw_parts(ptr, len, len);
// Now drop one string at a time.
for elem in v {
let s = CString::from_raw(elem);
std::mem::drop(s);
}
// Afterwards the vector will be dropped and thus freed.
}
#[derive(Default, Clone)]
pub struct FlutterHandler {
pub event_stream: Arc<RwLock<Option<StreamSink<EventToUI>>>>,

View File

@ -43,16 +43,6 @@ fn initialize(app_dir: &str) {
}
}
/// FFI for rustdesk core's main entry.
/// Return true if the app should continue running with UI(possibly Flutter), false if the app should exit.
#[no_mangle]
pub extern "C" fn rustdesk_core_main() -> bool {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
return crate::core_main::core_main().is_some();
#[cfg(any(target_os = "android", target_os = "ios"))]
false
}
pub enum EventToUI {
Event(String),
Rgba(ZeroCopyBuffer<Vec<u8>>),