mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
Merge pull request #628 from fufesou/simple_rc
Fix WCHAR Path & Add Resources Integration Lib
This commit is contained in:
@@ -63,6 +63,8 @@ extern crate objc;
|
||||
mod win;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use win::Enigo;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use win::ENIGO_INPUT_EXTRA_VALUE;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod macos;
|
||||
|
||||
@@ -2,3 +2,4 @@ mod win_impl;
|
||||
|
||||
pub mod keycodes;
|
||||
pub use self::win_impl::Enigo;
|
||||
pub use self::win_impl::ENIGO_INPUT_EXTRA_VALUE;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use winapi;
|
||||
|
||||
use self::winapi::ctypes::c_int;
|
||||
use self::winapi::shared::{minwindef::*, windef::*};
|
||||
use self::winapi::shared::{basetsd::ULONG_PTR, minwindef::*, windef::*};
|
||||
use self::winapi::um::winbase::*;
|
||||
use self::winapi::um::winuser::*;
|
||||
|
||||
@@ -18,6 +18,9 @@ extern "system" {
|
||||
pub struct Enigo;
|
||||
static mut LAYOUT: HKL = std::ptr::null_mut();
|
||||
|
||||
/// The dwExtraInfo value in keyboard and mouse structure that used in SendInput()
|
||||
pub const ENIGO_INPUT_EXTRA_VALUE: ULONG_PTR = 100;
|
||||
|
||||
fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD {
|
||||
let mut input = INPUT {
|
||||
type_: INPUT_MOUSE,
|
||||
@@ -28,7 +31,7 @@ fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD {
|
||||
mouseData: data,
|
||||
dwFlags: flags,
|
||||
time: 0,
|
||||
dwExtraInfo: 0,
|
||||
dwExtraInfo: ENIGO_INPUT_EXTRA_VALUE,
|
||||
})
|
||||
},
|
||||
};
|
||||
@@ -56,7 +59,7 @@ fn keybd_event(flags: u32, vk: u16, scan: u16) -> DWORD {
|
||||
wScan: scan,
|
||||
dwFlags: flags,
|
||||
time: 0,
|
||||
dwExtraInfo: 0,
|
||||
dwExtraInfo: ENIGO_INPUT_EXTRA_VALUE,
|
||||
})
|
||||
},
|
||||
};
|
||||
|
||||
@@ -65,6 +65,10 @@ message LoginRequest {
|
||||
|
||||
message ChatMessage { string text = 1; }
|
||||
|
||||
message Features {
|
||||
bool privacy_mode = 1;
|
||||
}
|
||||
|
||||
message PeerInfo {
|
||||
string username = 1;
|
||||
string hostname = 2;
|
||||
@@ -74,6 +78,7 @@ message PeerInfo {
|
||||
bool sas_enabled = 6;
|
||||
string version = 7;
|
||||
int32 conn_id = 8;
|
||||
Features features = 9;
|
||||
}
|
||||
|
||||
message LoginResponse {
|
||||
@@ -442,11 +447,6 @@ message OptionMessage {
|
||||
BoolOption enable_file_transfer = 9;
|
||||
}
|
||||
|
||||
message OptionResponse {
|
||||
OptionMessage opt = 1;
|
||||
string error = 2;
|
||||
}
|
||||
|
||||
message TestDelay {
|
||||
int64 time = 1;
|
||||
bool from_client = 2;
|
||||
@@ -469,6 +469,44 @@ message AudioFrame {
|
||||
int64 timestamp = 2;
|
||||
}
|
||||
|
||||
message BackNotification {
|
||||
// no need to consider block input by someone else
|
||||
enum BlockInputState {
|
||||
StateUnknown = 1;
|
||||
OnSucceeded = 2;
|
||||
OnFailed = 3;
|
||||
OffSucceeded = 4;
|
||||
OffFailed = 5;
|
||||
}
|
||||
enum PrivacyModeState {
|
||||
StateUnknown = 1;
|
||||
// Privacy mode on by someone else
|
||||
OnByOther = 2;
|
||||
// Privacy mode is not supported on the remote side
|
||||
NotSupported = 3;
|
||||
// Privacy mode on by self
|
||||
OnSucceeded = 4;
|
||||
// Privacy mode on by self, but denied
|
||||
OnFailedDenied = 5;
|
||||
// Some plugins are not found
|
||||
OnFailedPlugin = 6;
|
||||
// Privacy mode on by self, but failed
|
||||
OnFailed = 7;
|
||||
// Privacy mode off by self
|
||||
OffSucceeded = 8;
|
||||
// Ctrl + P
|
||||
OffByPeer = 9;
|
||||
// Privacy mode off by self, but failed
|
||||
OffFailed = 10;
|
||||
OffUnknown = 11;
|
||||
}
|
||||
|
||||
oneof union {
|
||||
PrivacyModeState privacy_mode_state = 1;
|
||||
BlockInputState block_input_state = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message Misc {
|
||||
oneof union {
|
||||
ChatMessage chat_message = 4;
|
||||
@@ -478,8 +516,8 @@ message Misc {
|
||||
AudioFormat audio_format = 8;
|
||||
string close_reason = 9;
|
||||
bool refresh_video = 10;
|
||||
OptionResponse option_response = 11;
|
||||
bool video_received = 12;
|
||||
BackNotification back_notification = 13;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,12 @@ block = "0.1"
|
||||
cfg-if = "1.0"
|
||||
libc = "0.2"
|
||||
num_cpus = "1.13"
|
||||
lazy_static = "1.4"
|
||||
|
||||
[dependencies.winapi]
|
||||
version = "0.3"
|
||||
default-features = true
|
||||
features = ["dxgi", "dxgi1_2", "dxgi1_5", "d3d11", "winuser"]
|
||||
features = ["dxgi", "dxgi1_2", "dxgi1_5", "d3d11", "winuser", "winerror", "errhandlingapi", "libloaderapi"]
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
android_logger = "0.10"
|
||||
|
||||
105
libs/scrap/examples/capture_mag.rs
Normal file
105
libs/scrap/examples/capture_mag.rs
Normal file
@@ -0,0 +1,105 @@
|
||||
extern crate repng;
|
||||
extern crate scrap;
|
||||
|
||||
use std::fs::File;
|
||||
|
||||
#[cfg(windows)]
|
||||
use scrap::CapturerMag;
|
||||
use scrap::{i420_to_rgb, Display};
|
||||
|
||||
fn main() {
|
||||
let n = Display::all().unwrap().len();
|
||||
for i in 0..n {
|
||||
#[cfg(windows)]
|
||||
record(i);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_display(i: usize) -> Display {
|
||||
Display::all().unwrap().remove(i)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn record(i: usize) {
|
||||
for d in Display::all().unwrap() {
|
||||
println!("{:?} {} {}", d.origin(), d.width(), d.height());
|
||||
}
|
||||
|
||||
let display = get_display(i);
|
||||
let (w, h) = (display.width(), display.height());
|
||||
|
||||
{
|
||||
let mut capture_mag =
|
||||
CapturerMag::new(display.origin(), display.width(), display.height(), false)
|
||||
.expect("Couldn't begin capture.");
|
||||
let wnd_cls = "";
|
||||
let wnd_name = "RustDeskPrivacyWindow";
|
||||
if false == capture_mag.exclude(wnd_cls, wnd_name).unwrap() {
|
||||
println!("No window found for cls {} name {}", wnd_cls, wnd_name);
|
||||
} else {
|
||||
println!("Filter window for cls {} name {}", wnd_cls, wnd_name);
|
||||
}
|
||||
|
||||
let frame = capture_mag.frame(0).unwrap();
|
||||
println!("Capture data len: {}, Saving...", frame.len());
|
||||
|
||||
let mut bitflipped = Vec::with_capacity(w * h * 4);
|
||||
let stride = frame.len() / h;
|
||||
|
||||
for y in 0..h {
|
||||
for x in 0..w {
|
||||
let i = stride * y + 4 * x;
|
||||
bitflipped.extend_from_slice(&[frame[i + 2], frame[i + 1], frame[i], 255]);
|
||||
}
|
||||
}
|
||||
// Save the image.
|
||||
let name = format!("capture_mag_{}_1.png", i);
|
||||
repng::encode(
|
||||
File::create(name.clone()).unwrap(),
|
||||
w as u32,
|
||||
h as u32,
|
||||
&bitflipped,
|
||||
)
|
||||
.unwrap();
|
||||
println!("Image saved to `{}`.", name);
|
||||
}
|
||||
|
||||
{
|
||||
let mut capture_mag =
|
||||
CapturerMag::new(display.origin(), display.width(), display.height(), true)
|
||||
.expect("Couldn't begin capture.");
|
||||
let wnd_cls = "";
|
||||
let wnd_title = "RustDeskPrivacyWindow";
|
||||
if false == capture_mag.exclude(wnd_cls, wnd_title).unwrap() {
|
||||
println!("No window found for cls {} title {}", wnd_cls, wnd_title);
|
||||
} else {
|
||||
println!("Filter window for cls {} title {}", wnd_cls, wnd_title);
|
||||
}
|
||||
|
||||
let buffer = capture_mag.frame(0).unwrap();
|
||||
println!("Capture data len: {}, Saving...", buffer.len());
|
||||
|
||||
let mut frame = Default::default();
|
||||
i420_to_rgb(w, h, &buffer, &mut frame);
|
||||
|
||||
let mut bitflipped = Vec::with_capacity(w * h * 4);
|
||||
let stride = frame.len() / h;
|
||||
|
||||
for y in 0..h {
|
||||
for x in 0..w {
|
||||
let i = stride * y + 3 * x;
|
||||
bitflipped.extend_from_slice(&[frame[i], frame[i + 1], frame[i + 2], 255]);
|
||||
}
|
||||
}
|
||||
let name = format!("capture_mag_{}_2.png", i);
|
||||
repng::encode(
|
||||
File::create(name.clone()).unwrap(),
|
||||
w as u32,
|
||||
h as u32,
|
||||
&bitflipped,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
println!("Image saved to `{}`.", name);
|
||||
}
|
||||
}
|
||||
@@ -46,8 +46,7 @@ fn record(i: usize) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
println!("Captured! Saving...");
|
||||
println!("Captured data len: {}, Saving...", buffer.len());
|
||||
|
||||
// Flip the BGRA image into a RGBA image.
|
||||
|
||||
@@ -96,8 +95,7 @@ fn record(i: usize) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
println!("Captured! Saving...");
|
||||
println!("Captured data len: {}, Saving...", buffer.len());
|
||||
|
||||
let mut frame = Default::default();
|
||||
i420_to_rgb(w, h, &buffer, &mut frame);
|
||||
|
||||
@@ -111,3 +111,32 @@ impl Display {
|
||||
self.origin() == (0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CapturerMag {
|
||||
inner: dxgi::mag::CapturerMag,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl CapturerMag {
|
||||
pub fn is_supported() -> bool {
|
||||
dxgi::mag::CapturerMag::is_supported()
|
||||
}
|
||||
|
||||
pub fn new(origin: (i32, i32), width: usize, height: usize, use_yuv: bool) -> io::Result<Self> {
|
||||
Ok(CapturerMag {
|
||||
inner: dxgi::mag::CapturerMag::new(origin, width, height, use_yuv)?,
|
||||
data: Vec::new(),
|
||||
})
|
||||
}
|
||||
pub fn exclude(&mut self, cls: &str, name: &str) -> io::Result<bool> {
|
||||
self.inner.exclude(cls, name)
|
||||
}
|
||||
// ((x, y), w, h)
|
||||
pub fn get_rect(&self) -> ((i32, i32), usize, usize) {
|
||||
self.inner.get_rect()
|
||||
}
|
||||
pub fn frame<'a>(&'a mut self, _timeout_ms: u32) -> io::Result<Frame<'a>> {
|
||||
self.inner.frame(&mut self.data)?;
|
||||
Ok(Frame(&self.data))
|
||||
}
|
||||
}
|
||||
|
||||
662
libs/scrap/src/dxgi/mag.rs
Normal file
662
libs/scrap/src/dxgi/mag.rs
Normal file
@@ -0,0 +1,662 @@
|
||||
// logic from webrtc -- https://github.com/shiguredo/libwebrtc/blob/main/modules/desktop_capture/win/screen_capturer_win_magnifier.cc
|
||||
use lazy_static;
|
||||
use std::{
|
||||
ffi::CString,
|
||||
io::{Error, ErrorKind, Result},
|
||||
mem::size_of,
|
||||
sync::Mutex,
|
||||
};
|
||||
use winapi::{
|
||||
shared::{
|
||||
basetsd::SIZE_T,
|
||||
guiddef::{IsEqualGUID, GUID},
|
||||
minwindef::{BOOL, DWORD, FALSE, FARPROC, HINSTANCE, HMODULE, HRGN, TRUE, UINT},
|
||||
ntdef::{LONG, NULL},
|
||||
windef::{HWND, RECT},
|
||||
winerror::ERROR_CLASS_ALREADY_EXISTS,
|
||||
},
|
||||
um::{
|
||||
errhandlingapi::GetLastError,
|
||||
libloaderapi::{FreeLibrary, GetModuleHandleExA, GetProcAddress, LoadLibraryExA},
|
||||
winuser::*,
|
||||
},
|
||||
};
|
||||
|
||||
pub const MW_FILTERMODE_EXCLUDE: u32 = 0;
|
||||
pub const MW_FILTERMODE_INCLUDE: u32 = 1;
|
||||
pub const GET_MODULE_HANDLE_EX_FLAG_PIN: u32 = 1;
|
||||
pub const GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT: u32 = 2;
|
||||
pub const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 4;
|
||||
pub const LOAD_LIBRARY_AS_DATAFILE: u32 = 2;
|
||||
pub const LOAD_WITH_ALTERED_SEARCH_PATH: u32 = 8;
|
||||
pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: u32 = 16;
|
||||
pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: u32 = 32;
|
||||
pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: u32 = 64;
|
||||
pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: u32 = 128;
|
||||
pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: u32 = 256;
|
||||
pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: u32 = 512;
|
||||
pub const LOAD_LIBRARY_SEARCH_USER_DIRS: u32 = 1024;
|
||||
pub const LOAD_LIBRARY_SEARCH_SYSTEM32: u32 = 2048;
|
||||
pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: u32 = 4096;
|
||||
pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: u32 = 8192;
|
||||
pub const LOAD_LIBRARY_SEARCH_SYSTEM32_NO_FORWARDER: u32 = 16384;
|
||||
pub const LOAD_LIBRARY_OS_INTEGRITY_CONTINUITY: u32 = 32768;
|
||||
|
||||
extern "C" {
|
||||
pub static GUID_WICPixelFormat32bppRGBA: GUID;
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref MAG_BUFFER: Mutex<(bool, Vec<u8>)> = Default::default();
|
||||
}
|
||||
|
||||
pub type REFWICPixelFormatGUID = *const GUID;
|
||||
pub type WICPixelFormatGUID = GUID;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct tagMAGIMAGEHEADER {
|
||||
pub width: UINT,
|
||||
pub height: UINT,
|
||||
pub format: WICPixelFormatGUID,
|
||||
pub stride: UINT,
|
||||
pub offset: UINT,
|
||||
pub cbSize: SIZE_T,
|
||||
}
|
||||
pub type MAGIMAGEHEADER = tagMAGIMAGEHEADER;
|
||||
pub type PMAGIMAGEHEADER = *mut tagMAGIMAGEHEADER;
|
||||
|
||||
// Function types
|
||||
pub type MagImageScalingCallback = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
hwnd: HWND,
|
||||
srcdata: *mut ::std::os::raw::c_void,
|
||||
srcheader: MAGIMAGEHEADER,
|
||||
destdata: *mut ::std::os::raw::c_void,
|
||||
destheader: MAGIMAGEHEADER,
|
||||
unclipped: RECT,
|
||||
clipped: RECT,
|
||||
dirty: HRGN,
|
||||
) -> BOOL,
|
||||
>;
|
||||
|
||||
extern "C" {
|
||||
pub fn MagShowSystemCursor(fShowCursor: BOOL) -> BOOL;
|
||||
}
|
||||
pub type MagInitializeFunc = ::std::option::Option<unsafe extern "C" fn() -> BOOL>;
|
||||
pub type MagUninitializeFunc = ::std::option::Option<unsafe extern "C" fn() -> BOOL>;
|
||||
pub type MagSetWindowSourceFunc =
|
||||
::std::option::Option<unsafe extern "C" fn(hwnd: HWND, rect: RECT) -> BOOL>;
|
||||
pub type MagSetWindowFilterListFunc = ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
hwnd: HWND,
|
||||
dwFilterMode: DWORD,
|
||||
count: ::std::os::raw::c_int,
|
||||
pHWND: *mut HWND,
|
||||
) -> BOOL,
|
||||
>;
|
||||
pub type MagSetImageScalingCallbackFunc = ::std::option::Option<
|
||||
unsafe extern "C" fn(hwnd: HWND, callback: MagImageScalingCallback) -> BOOL,
|
||||
>;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
struct MagInterface {
|
||||
init_succeeded: bool,
|
||||
lib_handle: HINSTANCE,
|
||||
pub mag_initialize_func: MagInitializeFunc,
|
||||
pub mag_uninitialize_func: MagUninitializeFunc,
|
||||
pub set_window_source_func: MagSetWindowSourceFunc,
|
||||
pub set_window_filter_list_func: MagSetWindowFilterListFunc,
|
||||
pub set_image_scaling_callback_func: MagSetImageScalingCallbackFunc,
|
||||
}
|
||||
|
||||
// NOTE: MagInitialize and MagUninitialize should not be called in global init and uninit.
|
||||
// If so, strange errors occur.
|
||||
impl MagInterface {
|
||||
fn new() -> Result<Self> {
|
||||
let mut s = MagInterface {
|
||||
init_succeeded: false,
|
||||
lib_handle: NULL as _,
|
||||
mag_initialize_func: None,
|
||||
mag_uninitialize_func: None,
|
||||
set_window_source_func: None,
|
||||
set_window_filter_list_func: None,
|
||||
set_image_scaling_callback_func: None,
|
||||
};
|
||||
s.init_succeeded = false;
|
||||
unsafe {
|
||||
if GetSystemMetrics(SM_CMONITORS) != 1 {
|
||||
// Do not try to use the magnifier in multi-screen setup (where the API
|
||||
// crashes sometimes).
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"Magnifier capturer cannot work on multi-screen system.",
|
||||
));
|
||||
}
|
||||
|
||||
// load lib
|
||||
let lib_file_name = "Magnification.dll";
|
||||
let lib_file_name_c = CString::new(lib_file_name).unwrap();
|
||||
s.lib_handle = LoadLibraryExA(
|
||||
lib_file_name_c.as_ptr() as _,
|
||||
NULL,
|
||||
LOAD_WITH_ALTERED_SEARCH_PATH,
|
||||
);
|
||||
if s.lib_handle.is_null() {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!(
|
||||
"Failed to LoadLibraryExA {}, error: {}",
|
||||
lib_file_name,
|
||||
GetLastError()
|
||||
),
|
||||
));
|
||||
};
|
||||
|
||||
// load functions
|
||||
s.mag_initialize_func = Some(std::mem::transmute(Self::load_func(
|
||||
s.lib_handle,
|
||||
"MagInitialize",
|
||||
)?));
|
||||
s.mag_uninitialize_func = Some(std::mem::transmute(Self::load_func(
|
||||
s.lib_handle,
|
||||
"MagUninitialize",
|
||||
)?));
|
||||
s.set_window_source_func = Some(std::mem::transmute(Self::load_func(
|
||||
s.lib_handle,
|
||||
"MagSetWindowSource",
|
||||
)?));
|
||||
s.set_window_filter_list_func = Some(std::mem::transmute(Self::load_func(
|
||||
s.lib_handle,
|
||||
"MagSetWindowFilterList",
|
||||
)?));
|
||||
s.set_image_scaling_callback_func = Some(std::mem::transmute(Self::load_func(
|
||||
s.lib_handle,
|
||||
"MagSetImageScalingCallback",
|
||||
)?));
|
||||
|
||||
// MagInitialize
|
||||
if let Some(init_func) = s.mag_initialize_func {
|
||||
if FALSE == init_func() {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Failed to MagInitialize, error: {}", GetLastError()),
|
||||
));
|
||||
} else {
|
||||
s.init_succeeded = true;
|
||||
}
|
||||
} else {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"Unreachable, mag_initialize_func should not be none",
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
unsafe fn load_func(lib_module: HMODULE, func_name: &str) -> Result<FARPROC> {
|
||||
let func_name_c = CString::new(func_name).unwrap();
|
||||
let func = GetProcAddress(lib_module, func_name_c.as_ptr() as _);
|
||||
if func.is_null() {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!(
|
||||
"Failed to GetProcAddress {}, error: {}",
|
||||
func_name,
|
||||
GetLastError()
|
||||
),
|
||||
));
|
||||
}
|
||||
Ok(func)
|
||||
}
|
||||
|
||||
pub(super) fn uninit(&mut self) {
|
||||
if self.init_succeeded {
|
||||
if let Some(uninit_func) = self.mag_uninitialize_func {
|
||||
unsafe {
|
||||
if FALSE == uninit_func() {
|
||||
println!("Failed MagUninitialize {}", GetLastError())
|
||||
}
|
||||
}
|
||||
}
|
||||
if !self.lib_handle.is_null() {
|
||||
unsafe {
|
||||
if FALSE == FreeLibrary(self.lib_handle) {
|
||||
println!("Failed FreeLibrary {}", GetLastError())
|
||||
}
|
||||
}
|
||||
self.lib_handle = NULL as _;
|
||||
}
|
||||
}
|
||||
self.init_succeeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MagInterface {
|
||||
fn drop(&mut self) {
|
||||
self.uninit();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CapturerMag {
|
||||
mag_interface: MagInterface,
|
||||
host_window: HWND,
|
||||
magnifier_window: HWND,
|
||||
|
||||
magnifier_host_class: CString,
|
||||
host_window_name: CString,
|
||||
magnifier_window_class: CString,
|
||||
magnifier_window_name: CString,
|
||||
|
||||
rect: RECT,
|
||||
width: usize,
|
||||
height: usize,
|
||||
|
||||
use_yuv: bool,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Drop for CapturerMag {
|
||||
fn drop(&mut self) {
|
||||
self.destroy_windows();
|
||||
self.mag_interface.uninit();
|
||||
}
|
||||
}
|
||||
|
||||
impl CapturerMag {
|
||||
pub(crate) fn is_supported() -> bool {
|
||||
MagInterface::new().is_ok()
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
origin: (i32, i32),
|
||||
width: usize,
|
||||
height: usize,
|
||||
use_yuv: bool,
|
||||
) -> Result<Self> {
|
||||
unsafe {
|
||||
let x = GetSystemMetrics(SM_XVIRTUALSCREEN);
|
||||
let y = GetSystemMetrics(SM_YVIRTUALSCREEN);
|
||||
let w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
||||
let h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
||||
if !(origin.0 == x as _ && origin.1 == y as _ && width == w as _ && height == h as _) {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!(
|
||||
"Failed Check screen rect ({}, {}, {} , {}) to ({}, {}, {}, {})",
|
||||
origin.0,
|
||||
origin.1,
|
||||
origin.0 + width as i32,
|
||||
origin.1 + height as i32,
|
||||
x,
|
||||
y,
|
||||
x + w,
|
||||
y + h
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let mut s = Self {
|
||||
mag_interface: MagInterface::new()?,
|
||||
host_window: 0 as _,
|
||||
magnifier_window: 0 as _,
|
||||
magnifier_host_class: CString::new("ScreenCapturerWinMagnifierHost")?,
|
||||
host_window_name: CString::new("MagnifierHost")?,
|
||||
magnifier_window_class: CString::new("Magnifier")?,
|
||||
magnifier_window_name: CString::new("MagnifierWindow")?,
|
||||
rect: RECT {
|
||||
left: origin.0 as _,
|
||||
top: origin.1 as _,
|
||||
right: origin.0 + width as LONG,
|
||||
bottom: origin.1 + height as LONG,
|
||||
},
|
||||
width,
|
||||
height,
|
||||
use_yuv,
|
||||
data: Vec::new(),
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let mut instance = 0 as HMODULE;
|
||||
if 0 == GetModuleHandleExA(
|
||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|
||||
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
DefWindowProcA as _,
|
||||
&mut instance as _,
|
||||
) {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Failed to GetModuleHandleExA, error: {}", GetLastError()),
|
||||
));
|
||||
}
|
||||
|
||||
// Register the host window class. See the MSDN documentation of the
|
||||
// Magnification API for more infomation.
|
||||
let wcex = WNDCLASSEXA {
|
||||
cbSize: size_of::<WNDCLASSEXA>() as _,
|
||||
style: 0,
|
||||
lpfnWndProc: Some(DefWindowProcA),
|
||||
cbClsExtra: 0,
|
||||
cbWndExtra: 0,
|
||||
hInstance: instance,
|
||||
hIcon: 0 as _,
|
||||
hCursor: LoadCursorA(NULL as _, IDC_ARROW as _),
|
||||
hbrBackground: 0 as _,
|
||||
lpszClassName: s.magnifier_host_class.as_ptr() as _,
|
||||
lpszMenuName: 0 as _,
|
||||
hIconSm: 0 as _,
|
||||
};
|
||||
|
||||
// Ignore the error which may happen when the class is already registered.
|
||||
if 0 == RegisterClassExA(&wcex) {
|
||||
let code = GetLastError();
|
||||
if code != ERROR_CLASS_ALREADY_EXISTS {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Failed to RegisterClassExA, error: {}", code),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Create the host window.
|
||||
s.host_window = CreateWindowExA(
|
||||
WS_EX_LAYERED,
|
||||
s.magnifier_host_class.as_ptr(),
|
||||
s.host_window_name.as_ptr(),
|
||||
WS_POPUP,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL as _,
|
||||
NULL as _,
|
||||
instance,
|
||||
NULL,
|
||||
);
|
||||
if s.host_window.is_null() {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!(
|
||||
"Failed to CreateWindowExA host_window, error: {}",
|
||||
GetLastError()
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
// Create the magnifier control.
|
||||
s.magnifier_window = CreateWindowExA(
|
||||
0,
|
||||
s.magnifier_window_class.as_ptr(),
|
||||
s.magnifier_window_name.as_ptr(),
|
||||
WS_CHILD | WS_VISIBLE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
s.host_window,
|
||||
NULL as _,
|
||||
instance,
|
||||
NULL,
|
||||
);
|
||||
if s.magnifier_window.is_null() {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!(
|
||||
"Failed CreateWindowA magnifier_window, error: {}",
|
||||
GetLastError()
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
// Hide the host window.
|
||||
let _ = ShowWindow(s.host_window, SW_HIDE);
|
||||
|
||||
// Set the scaling callback to receive captured image.
|
||||
if let Some(set_callback_func) = s.mag_interface.set_image_scaling_callback_func {
|
||||
if FALSE
|
||||
== set_callback_func(
|
||||
s.magnifier_window,
|
||||
Some(Self::on_gag_image_scaling_callback),
|
||||
)
|
||||
{
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!(
|
||||
"Failed to MagSetImageScalingCallback, error: {}",
|
||||
GetLastError()
|
||||
),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"Unreachable, set_image_scaling_callback_func should not be none",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
pub(crate) fn exclude(&mut self, cls: &str, name: &str) -> Result<bool> {
|
||||
let name_c = CString::new(name).unwrap();
|
||||
unsafe {
|
||||
let mut hwnd = if cls.len() == 0 {
|
||||
FindWindowExA(NULL as _, NULL as _, NULL as _, name_c.as_ptr())
|
||||
} else {
|
||||
let cls_c = CString::new(cls).unwrap();
|
||||
FindWindowExA(NULL as _, NULL as _, cls_c.as_ptr(), name_c.as_ptr())
|
||||
};
|
||||
|
||||
if hwnd.is_null() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
if let Some(set_window_filter_list_func) =
|
||||
self.mag_interface.set_window_filter_list_func
|
||||
{
|
||||
if FALSE
|
||||
== set_window_filter_list_func(
|
||||
self.magnifier_window,
|
||||
MW_FILTERMODE_EXCLUDE,
|
||||
1,
|
||||
&mut hwnd,
|
||||
)
|
||||
{
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!(
|
||||
"Failed MagSetWindowFilterList for cls {} name {}, err: {}",
|
||||
cls,
|
||||
name,
|
||||
GetLastError()
|
||||
),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"Unreachable, MagSetWindowFilterList should not be none",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub(crate) fn get_rect(&self) -> ((i32, i32), usize, usize) {
|
||||
(
|
||||
(self.rect.left as _, self.rect.top as _),
|
||||
self.width as _,
|
||||
self.height as _,
|
||||
)
|
||||
}
|
||||
|
||||
fn clear_data() {
|
||||
let mut lock = MAG_BUFFER.lock().unwrap();
|
||||
lock.0 = false;
|
||||
lock.1.clear();
|
||||
}
|
||||
|
||||
pub(crate) fn frame(&mut self, data: &mut Vec<u8>) -> Result<()> {
|
||||
Self::clear_data();
|
||||
|
||||
unsafe {
|
||||
let x = GetSystemMetrics(SM_XVIRTUALSCREEN);
|
||||
let y = GetSystemMetrics(SM_YVIRTUALSCREEN);
|
||||
let w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
||||
let h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
||||
if !(self.rect.left == x as _
|
||||
&& self.rect.top == y as _
|
||||
&& self.rect.right == (x + w) as _
|
||||
&& self.rect.bottom == (y + h) as _)
|
||||
{
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!(
|
||||
"Failed Check screen rect ({}, {}, {} , {}) to ({}, {}, {}, {})",
|
||||
self.rect.left,
|
||||
self.rect.top,
|
||||
self.rect.right,
|
||||
self.rect.bottom,
|
||||
x,
|
||||
y,
|
||||
x + w,
|
||||
y + h
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if FALSE
|
||||
== SetWindowPos(
|
||||
self.magnifier_window,
|
||||
HWND_TOP,
|
||||
self.rect.left,
|
||||
self.rect.top,
|
||||
self.rect.right,
|
||||
self.rect.bottom,
|
||||
0,
|
||||
)
|
||||
{
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!(
|
||||
"Failed SetWindowPos (x, y, w , h) - ({}, {}, {}, {}), error {}",
|
||||
self.rect.left,
|
||||
self.rect.top,
|
||||
self.rect.right,
|
||||
self.rect.bottom,
|
||||
GetLastError()
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
// on_gag_image_scaling_callback will be called and fill in the
|
||||
// frame before set_window_source_func_ returns.
|
||||
if let Some(set_window_source_func) = self.mag_interface.set_window_source_func {
|
||||
if FALSE == set_window_source_func(self.magnifier_window, self.rect) {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Failed to MagSetWindowSource, error: {}", GetLastError()),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"Unreachable, set_window_source_func should not be none",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let mut lock = MAG_BUFFER.lock().unwrap();
|
||||
if !lock.0 {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"No data captured by magnifier",
|
||||
));
|
||||
}
|
||||
|
||||
if self.use_yuv {
|
||||
self.data.resize(lock.1.len(), 0);
|
||||
unsafe {
|
||||
std::ptr::copy_nonoverlapping(&mut lock.1[0], &mut self.data[0], self.data.len());
|
||||
}
|
||||
crate::common::bgra_to_i420(
|
||||
self.width as usize,
|
||||
self.height as usize,
|
||||
&self.data,
|
||||
data,
|
||||
);
|
||||
} else {
|
||||
data.resize(lock.1.len(), 0);
|
||||
unsafe {
|
||||
std::ptr::copy_nonoverlapping(&mut lock.1[0], &mut data[0], data.len());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn destroy_windows(&mut self) {
|
||||
if !self.magnifier_window.is_null() {
|
||||
unsafe {
|
||||
if FALSE == DestroyWindow(self.magnifier_window) {
|
||||
//
|
||||
println!("Failed DestroyWindow magnifier window {}", GetLastError())
|
||||
}
|
||||
}
|
||||
}
|
||||
self.magnifier_window = NULL as _;
|
||||
|
||||
if !self.host_window.is_null() {
|
||||
unsafe {
|
||||
if FALSE == DestroyWindow(self.host_window) {
|
||||
//
|
||||
println!("Failed DestroyWindow host window {}", GetLastError())
|
||||
}
|
||||
}
|
||||
}
|
||||
self.host_window = NULL as _;
|
||||
}
|
||||
|
||||
unsafe extern "C" fn on_gag_image_scaling_callback(
|
||||
_hwnd: HWND,
|
||||
srcdata: *mut ::std::os::raw::c_void,
|
||||
srcheader: MAGIMAGEHEADER,
|
||||
_destdata: *mut ::std::os::raw::c_void,
|
||||
_destheader: MAGIMAGEHEADER,
|
||||
_unclipped: RECT,
|
||||
_clipped: RECT,
|
||||
_dirty: HRGN,
|
||||
) -> BOOL {
|
||||
Self::clear_data();
|
||||
|
||||
if !IsEqualGUID(&srcheader.format, &GUID_WICPixelFormat32bppRGBA) {
|
||||
// log warning?
|
||||
return FALSE;
|
||||
}
|
||||
let mut lock = MAG_BUFFER.lock().unwrap();
|
||||
lock.1.resize(srcheader.cbSize, 0);
|
||||
std::ptr::copy_nonoverlapping(srcdata as _, &mut lock.1[0], srcheader.cbSize);
|
||||
lock.0 = true;
|
||||
TRUE
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test() {
|
||||
let mut capture_mag = CapturerMag::new((0, 0), 1920, 1080, false).unwrap();
|
||||
capture_mag.exclude("", "RustDeskPrivacyWindow").unwrap();
|
||||
std::thread::sleep(std::time::Duration::from_millis(1000 * 10));
|
||||
let mut data = Vec::new();
|
||||
capture_mag.frame(&mut data).unwrap();
|
||||
println!("capture data len: {}", data.len());
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::{io, mem, ptr, slice};
|
||||
pub mod gdi;
|
||||
pub use gdi::CapturerGDI;
|
||||
pub mod mag;
|
||||
|
||||
use winapi::{
|
||||
shared::{
|
||||
|
||||
13
libs/simple_rc/Cargo.toml
Normal file
13
libs/simple_rc/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "simple_rc"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde_derive = "1.0"
|
||||
serde = "1.0"
|
||||
walkdir = "2"
|
||||
confy = { git = "https://github.com/open-trade/confy" }
|
||||
hbb_common = { path = "../hbb_common" }
|
||||
23
libs/simple_rc/examples/generate.rs
Normal file
23
libs/simple_rc/examples/generate.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
extern crate simple_rc;
|
||||
|
||||
use simple_rc::*;
|
||||
|
||||
fn main() {
|
||||
{
|
||||
const CONF_FILE: &str = "simple_rc.toml";
|
||||
generate(CONF_FILE).unwrap();
|
||||
}
|
||||
|
||||
{
|
||||
generate_with_conf(&Config {
|
||||
outfile: "src/rc.rs".to_owned(),
|
||||
confs: vec![ConfigItem {
|
||||
inc: "D:/projects/windows/RustDeskTempTopMostWindow/x64/Release/xxx".to_owned(),
|
||||
// exc: vec!["*.dll".to_owned(), "*.exe".to_owned()],
|
||||
exc: vec![],
|
||||
suppressed_front: "D:/projects/windows".to_owned(),
|
||||
}],
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
12
libs/simple_rc/simple_rc.toml
Normal file
12
libs/simple_rc/simple_rc.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
# The output source file
|
||||
outfile = "src/rc.rs"
|
||||
|
||||
# The resource config list.
|
||||
[[confs]]
|
||||
# The file or director to integrate.
|
||||
inc = "D:/projects/windows/RustDeskTempTopMostWindow/x64/Release/xxx"
|
||||
# The exclusions.
|
||||
exc = ["*.dll", "*.exe"]
|
||||
# The front path that will ignore for extracting.
|
||||
# The following config will make base output path to be "RustDeskTempTopMostWindow/x64/Release/xxx".
|
||||
suppressed_front = "D:/projects/windows"
|
||||
208
libs/simple_rc/src/lib.rs
Normal file
208
libs/simple_rc/src/lib.rs
Normal file
@@ -0,0 +1,208 @@
|
||||
use hbb_common::{bail, ResultType};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, fs::File, io::prelude::*, path::Path};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
//mod rc;
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Serialize, Deserialize, Clone)]
|
||||
pub struct ConfigItem {
|
||||
// include directory or file
|
||||
pub inc: String,
|
||||
// exclude files
|
||||
pub exc: Vec<String>,
|
||||
// out_path = origin_path - suppressed_front
|
||||
pub suppressed_front: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Serialize, Deserialize, Clone)]
|
||||
pub struct Config {
|
||||
// output source file
|
||||
pub outfile: String,
|
||||
// config items
|
||||
pub confs: Vec<ConfigItem>,
|
||||
}
|
||||
|
||||
pub fn get_outin_files<'a>(item: &'a ConfigItem) -> ResultType<HashMap<String, String>> {
|
||||
let mut outin_filemap = HashMap::new();
|
||||
|
||||
for entry in WalkDir::new(&item.inc).follow_links(true) {
|
||||
let path = entry?.into_path();
|
||||
if path.is_file() {
|
||||
let mut exclude = false;
|
||||
for excfile in item.exc.iter() {
|
||||
if excfile.starts_with("*.") {
|
||||
if let Some(ext) = path.extension().and_then(|x| x.to_str()) {
|
||||
if excfile.ends_with(&format!(".{}", ext)) {
|
||||
exclude = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if path.ends_with(Path::new(excfile)) {
|
||||
exclude = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if exclude {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut suppressed_front = item.suppressed_front.clone();
|
||||
if !suppressed_front.is_empty() && suppressed_front.ends_with('/') {
|
||||
suppressed_front.push('/');
|
||||
}
|
||||
let outpath = path.strip_prefix(Path::new(&suppressed_front))?;
|
||||
let outfile = if outpath.is_absolute() {
|
||||
match outpath
|
||||
.file_name()
|
||||
.and_then(|f| f.to_str())
|
||||
.map(|f| f.to_string())
|
||||
{
|
||||
None => {
|
||||
bail!("Failed to get filename of {}", outpath.display());
|
||||
}
|
||||
Some(s) => s,
|
||||
}
|
||||
} else {
|
||||
match outpath.to_str() {
|
||||
None => {
|
||||
bail!("Failed to convert {} to string", outpath.display());
|
||||
}
|
||||
// Simple replace \ to / here.
|
||||
// A better way is to use lib [path-slash](https://github.com/rhysd/path-slash)
|
||||
Some(s) => s.to_string().replace("\\", "/"),
|
||||
}
|
||||
};
|
||||
let infile = match path.canonicalize()?.to_str() {
|
||||
None => {
|
||||
bail!("Failed to get file path of {}", path.display());
|
||||
}
|
||||
Some(s) => s.to_string(),
|
||||
};
|
||||
if let Some(_) = outin_filemap.insert(outfile.clone(), infile) {
|
||||
bail!("outfile {} is set before", outfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(outin_filemap)
|
||||
}
|
||||
|
||||
pub fn generate(conf_file: &str) -> ResultType<()> {
|
||||
let conf = confy::load_path(conf_file)?;
|
||||
generate_with_conf(&conf)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn generate_with_conf<'a>(conf: &'a Config) -> ResultType<()> {
|
||||
let mut outfile = File::create(&conf.outfile)?;
|
||||
|
||||
outfile.write(
|
||||
br##"use hbb_common::{bail, ResultType};
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
io::prelude::*,
|
||||
path::Path,
|
||||
};
|
||||
|
||||
"##,
|
||||
)?;
|
||||
|
||||
outfile.write(b"#[allow(dead_code)]\n")?;
|
||||
outfile.write(b"pub fn extract_resources(root_path: &str) -> ResultType<()> {\n")?;
|
||||
outfile.write(b" let mut resources: Vec<(&str, &[u8])> = Vec::new();\n")?;
|
||||
|
||||
let mut outin_files = HashMap::new();
|
||||
for item in conf.confs.iter() {
|
||||
for (o, i) in get_outin_files(item)?.into_iter() {
|
||||
if let Some(_) = outin_files.insert(o.clone(), i) {
|
||||
bail!("outfile {} is set before", o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut count = 1;
|
||||
for (o, i) in outin_files.iter() {
|
||||
let mut infile = File::open(&i)?;
|
||||
let mut buffer = Vec::<u8>::new();
|
||||
infile.read_to_end(&mut buffer)?;
|
||||
|
||||
let var_outfile = format!("outfile_{}", count);
|
||||
let var_outdata = format!("outdata_{}", count);
|
||||
|
||||
write!(outfile, " let {} = \"{}\";\n", var_outfile, o)?;
|
||||
write!(outfile, " let {}: &[u8] = &[\n ", var_outdata)?;
|
||||
|
||||
let mut line_num = 20;
|
||||
for v in buffer {
|
||||
if line_num == 0 {
|
||||
write!(outfile, "\n ")?;
|
||||
line_num = 20;
|
||||
}
|
||||
write!(outfile, "{:#04x}, ", v)?;
|
||||
line_num -= 1;
|
||||
}
|
||||
write!(outfile, "\n ];\n")?;
|
||||
|
||||
write!(
|
||||
outfile,
|
||||
" resources.push(({}, &{}));\n",
|
||||
var_outfile, var_outdata
|
||||
)?;
|
||||
|
||||
count += 1;
|
||||
}
|
||||
|
||||
outfile.write(b" do_extract(root_path, resources)?;\n")?;
|
||||
outfile.write(b" Ok(())\n")?;
|
||||
outfile.write(b"}\n")?;
|
||||
|
||||
outfile.write(
|
||||
br##"
|
||||
#[allow(dead_code)]
|
||||
fn do_extract(root_path: &str, resources: Vec<(&str, &[u8])>) -> ResultType<()> {
|
||||
let mut root_path = root_path.replace("\\", "/");
|
||||
if !root_path.ends_with('/') {
|
||||
root_path.push('/');
|
||||
}
|
||||
let root_path = Path::new(&root_path);
|
||||
for (outfile, data) in resources {
|
||||
let outfile_path = root_path.join(outfile);
|
||||
match outfile_path.parent().and_then(|p| p.to_str()) {
|
||||
None => {
|
||||
bail!("Failed to get parent of {}", outfile_path.display());
|
||||
}
|
||||
Some(p) => {
|
||||
fs::create_dir_all(p)?;
|
||||
let mut of = File::create(outfile_path)?;
|
||||
of.write_all(data)?;
|
||||
of.flush()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
"##,
|
||||
)?;
|
||||
|
||||
outfile.flush()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = 2 + 2;
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_extract() {
|
||||
// use super::*;
|
||||
// rc::extract_resources("D:").unwrap();
|
||||
// }
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
#[cfg(windows)]
|
||||
use virtual_display::win10::{idd, DRIVER_INSTALL_PATH};
|
||||
|
||||
#[cfg(windows)]
|
||||
use std::{
|
||||
ffi::{CStr, CString},
|
||||
ffi::CStr,
|
||||
io::{self, Read},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
#[cfg(windows)]
|
||||
fn prompt_input() -> u8 {
|
||||
println!("Press key execute:");
|
||||
println!(" 1. 'x' 1. exit");
|
||||
@@ -24,6 +26,7 @@ fn prompt_input() -> u8 {
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe fn plug_in(index: idd::UINT, edid: idd::UINT) {
|
||||
println!("Plug in monitor begin");
|
||||
if idd::FALSE == idd::MonitorPlugIn(index, edid, 25) {
|
||||
@@ -48,6 +51,7 @@ unsafe fn plug_in(index: idd::UINT, edid: idd::UINT) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe fn plug_out(index: idd::UINT) {
|
||||
println!("Plug out monitor begin");
|
||||
if idd::FALSE == idd::MonitorPlugOut(index) {
|
||||
@@ -58,81 +62,91 @@ unsafe fn plug_out(index: idd::UINT) {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let abs_path = Path::new(DRIVER_INSTALL_PATH).canonicalize().unwrap();
|
||||
let full_inf_path = abs_path.to_str().unwrap();
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let abs_path = Path::new(DRIVER_INSTALL_PATH).canonicalize().unwrap();
|
||||
|
||||
unsafe {
|
||||
let invalid_device = 0 as idd::HSWDEVICE;
|
||||
let mut h_sw_device = invalid_device;
|
||||
let full_inf_path = CString::new(full_inf_path).unwrap().into_raw();
|
||||
loop {
|
||||
match prompt_input() as char {
|
||||
'x' => break,
|
||||
'i' => {
|
||||
println!("Install or update driver begin");
|
||||
let mut reboot_required = idd::FALSE;
|
||||
if idd::InstallUpdate(full_inf_path, &mut reboot_required) == idd::FALSE {
|
||||
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
|
||||
} else {
|
||||
println!(
|
||||
"Install or update driver done, reboot is {} required",
|
||||
if reboot_required == idd::FALSE {
|
||||
"not"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
);
|
||||
unsafe {
|
||||
let invalid_device = 0 as idd::HSWDEVICE;
|
||||
let mut h_sw_device = invalid_device;
|
||||
|
||||
let full_inf_path: Vec<u16> = abs_path
|
||||
.to_string_lossy()
|
||||
.as_ref()
|
||||
.encode_utf16()
|
||||
.chain(Some(0).into_iter())
|
||||
.collect();
|
||||
|
||||
loop {
|
||||
match prompt_input() as char {
|
||||
'x' => break,
|
||||
'i' => {
|
||||
println!("Install or update driver begin, {}", abs_path.display());
|
||||
let mut reboot_required = idd::FALSE;
|
||||
if idd::InstallUpdate(full_inf_path.as_ptr() as _, &mut reboot_required)
|
||||
== idd::FALSE
|
||||
{
|
||||
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
|
||||
} else {
|
||||
println!(
|
||||
"Install or update driver done, reboot is {} required",
|
||||
if reboot_required == idd::FALSE {
|
||||
"not"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
'u' => {
|
||||
println!("Uninstall driver begin");
|
||||
let mut reboot_required = idd::FALSE;
|
||||
if idd::Uninstall(full_inf_path, &mut reboot_required) == idd::FALSE {
|
||||
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
|
||||
} else {
|
||||
println!(
|
||||
"Uninstall driver done, reboot is {} required",
|
||||
if reboot_required == idd::FALSE {
|
||||
"not"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
);
|
||||
'u' => {
|
||||
println!("Uninstall driver begin {}", abs_path.display());
|
||||
let mut reboot_required = idd::FALSE;
|
||||
if idd::Uninstall(full_inf_path.as_ptr() as _, &mut reboot_required)
|
||||
== idd::FALSE
|
||||
{
|
||||
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
|
||||
} else {
|
||||
println!(
|
||||
"Uninstall driver done, reboot is {} required",
|
||||
if reboot_required == idd::FALSE {
|
||||
"not"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
'c' => {
|
||||
println!("Create device begin");
|
||||
if h_sw_device != invalid_device {
|
||||
println!("Device created before");
|
||||
continue;
|
||||
'c' => {
|
||||
println!("Create device begin");
|
||||
if h_sw_device != invalid_device {
|
||||
println!("Device created before");
|
||||
continue;
|
||||
}
|
||||
if idd::FALSE == idd::DeviceCreate(&mut h_sw_device) {
|
||||
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
|
||||
idd::DeviceClose(h_sw_device);
|
||||
h_sw_device = invalid_device;
|
||||
} else {
|
||||
println!("Create device done");
|
||||
}
|
||||
}
|
||||
if idd::FALSE == idd::DeviceCreate(&mut h_sw_device) {
|
||||
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
|
||||
'd' => {
|
||||
println!("Close device begin");
|
||||
idd::DeviceClose(h_sw_device);
|
||||
h_sw_device = invalid_device;
|
||||
} else {
|
||||
println!("Create device done");
|
||||
println!("Close device done");
|
||||
}
|
||||
'1' => plug_in(0, 0),
|
||||
'2' => plug_in(1, 0),
|
||||
'3' => plug_in(2, 0),
|
||||
'4' => plug_out(0),
|
||||
'5' => plug_out(1),
|
||||
'6' => plug_out(2),
|
||||
_ => {}
|
||||
}
|
||||
'd' => {
|
||||
println!("Close device begin");
|
||||
idd::DeviceClose(h_sw_device);
|
||||
h_sw_device = invalid_device;
|
||||
println!("Close device done");
|
||||
}
|
||||
'1' => plug_in(0, 0),
|
||||
'2' => plug_in(1, 0),
|
||||
'3' => plug_in(2, 0),
|
||||
'4' => plug_out(0),
|
||||
'5' => plug_out(1),
|
||||
'6' => plug_out(2),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if !full_inf_path.is_null() {
|
||||
let _ = CString::from_raw(full_inf_path);
|
||||
}
|
||||
|
||||
idd::DeviceClose(h_sw_device);
|
||||
idd::DeviceClose(h_sw_device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
pub mod win10;
|
||||
|
||||
use hbb_common::{bail, lazy_static, ResultType};
|
||||
use std::{ffi::CString, path::Path, sync::Mutex};
|
||||
use std::{path::Path, sync::Mutex};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
// If device is uninstalled though "Device Manager" Window.
|
||||
@@ -33,16 +33,24 @@ pub fn install_update_driver(_reboot_required: &mut bool) -> ResultType<()> {
|
||||
bail!("{} not exists", install_path)
|
||||
}
|
||||
|
||||
let _full_install_path = match abs_path.to_str() {
|
||||
Some(p) => CString::new(p)?.into_raw(),
|
||||
None => bail!("{} not exists", install_path),
|
||||
};
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
{
|
||||
// Device must be created before install driver.
|
||||
// https://github.com/fufesou/RustDeskIddDriver/issues/1
|
||||
if let Err(e) = create_device() {
|
||||
bail!("{}", e);
|
||||
}
|
||||
|
||||
let full_install_path: Vec<u16> = abs_path
|
||||
.to_string_lossy()
|
||||
.as_ref()
|
||||
.encode_utf16()
|
||||
.chain(Some(0).into_iter())
|
||||
.collect();
|
||||
|
||||
let mut reboot_required_tmp = win10::idd::FALSE;
|
||||
if win10::idd::InstallUpdate(_full_install_path, &mut reboot_required_tmp)
|
||||
if win10::idd::InstallUpdate(full_install_path.as_ptr() as _, &mut reboot_required_tmp)
|
||||
== win10::idd::FALSE
|
||||
{
|
||||
bail!("{}", win10::get_last_msg()?);
|
||||
@@ -65,16 +73,18 @@ pub fn uninstall_driver(_reboot_required: &mut bool) -> ResultType<()> {
|
||||
bail!("{} not exists", install_path)
|
||||
}
|
||||
|
||||
let _full_install_path = match abs_path.to_str() {
|
||||
Some(p) => CString::new(p)?.into_raw(),
|
||||
None => bail!("{} not exists", install_path),
|
||||
};
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
{
|
||||
let full_install_path: Vec<u16> = abs_path
|
||||
.to_string_lossy()
|
||||
.as_ref()
|
||||
.encode_utf16()
|
||||
.chain(Some(0).into_iter())
|
||||
.collect();
|
||||
|
||||
let mut reboot_required_tmp = win10::idd::FALSE;
|
||||
if win10::idd::Uninstall(_full_install_path, &mut reboot_required_tmp)
|
||||
if win10::idd::Uninstall(full_install_path.as_ptr() as _, &mut reboot_required_tmp)
|
||||
== win10::idd::FALSE
|
||||
{
|
||||
bail!("{}", win10::get_last_msg()?);
|
||||
|
||||
@@ -64,14 +64,14 @@ const char* GetLastMsg()
|
||||
return g_lastMsg;
|
||||
}
|
||||
|
||||
BOOL InstallUpdate(LPCTSTR fullInfPath, PBOOL rebootRequired)
|
||||
BOOL InstallUpdate(LPCWSTR fullInfPath, PBOOL rebootRequired)
|
||||
{
|
||||
SetLastMsg("Sucess");
|
||||
|
||||
// UpdateDriverForPlugAndPlayDevices may return FALSE while driver was successfully installed...
|
||||
if (FALSE == UpdateDriverForPlugAndPlayDevices(
|
||||
// UpdateDriverForPlugAndPlayDevicesW may return FALSE while driver was successfully installed...
|
||||
if (FALSE == UpdateDriverForPlugAndPlayDevicesW(
|
||||
NULL,
|
||||
_T("RustDeskIddDriver"), // match hardware id in the inf file
|
||||
L"RustDeskIddDriver", // match hardware id in the inf file
|
||||
fullInfPath,
|
||||
INSTALLFLAG_FORCE
|
||||
// | INSTALLFLAG_NONINTERACTIVE // INSTALLFLAG_NONINTERACTIVE may cause error 0xe0000247
|
||||
@@ -82,7 +82,7 @@ BOOL InstallUpdate(LPCTSTR fullInfPath, PBOOL rebootRequired)
|
||||
DWORD error = GetLastError();
|
||||
if (error != 0)
|
||||
{
|
||||
SetLastMsg("UpdateDriverForPlugAndPlayDevices failed, last error 0x%x\n", error);
|
||||
SetLastMsg("UpdateDriverForPlugAndPlayDevicesW failed, last error 0x%x\n", error);
|
||||
if (g_printMsg)
|
||||
{
|
||||
printf(g_lastMsg);
|
||||
@@ -94,11 +94,11 @@ BOOL InstallUpdate(LPCTSTR fullInfPath, PBOOL rebootRequired)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Uninstall(LPCTSTR fullInfPath, PBOOL rebootRequired)
|
||||
BOOL Uninstall(LPCWSTR fullInfPath, PBOOL rebootRequired)
|
||||
{
|
||||
SetLastMsg("Sucess");
|
||||
|
||||
if (FALSE == DiUninstallDriver(
|
||||
if (FALSE == DiUninstallDriverW(
|
||||
NULL,
|
||||
fullInfPath,
|
||||
0,
|
||||
@@ -108,7 +108,7 @@ BOOL Uninstall(LPCTSTR fullInfPath, PBOOL rebootRequired)
|
||||
DWORD error = GetLastError();
|
||||
if (error != 0)
|
||||
{
|
||||
SetLastMsg("DiUninstallDriver failed, last error 0x%x\n", error);
|
||||
SetLastMsg("DiUninstallDriverW failed, last error 0x%x\n", error);
|
||||
if (g_printMsg)
|
||||
{
|
||||
printf(g_lastMsg);
|
||||
|
||||
Reference in New Issue
Block a user