├── .gitignore ├── src ├── macos │ ├── mod.rs │ └── gui.rs ├── win32 │ ├── mod.rs │ ├── com_pointer.rs │ ├── gui.rs │ ├── ffi.rs │ └── client_site.rs └── lib.rs ├── webview-sys ├── Cargo.toml ├── lib.rs ├── webview.h ├── build.rs └── webview.c ├── Cargo.toml ├── License.txt └── examples └── synth.rs /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | target/ 3 | .DS_Store 4 | Cargo.lock 5 | -------------------------------------------------------------------------------- /src/macos/mod.rs: -------------------------------------------------------------------------------- 1 | mod gui; 2 | 3 | pub use macos::gui::new_plugin_gui; 4 | -------------------------------------------------------------------------------- /src/win32/mod.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code, non_snake_case)] 2 | mod client_site; 3 | mod com_pointer; 4 | mod gui; 5 | #[allow(dead_code, non_snake_case, non_upper_case_globals)] 6 | mod ffi; 7 | 8 | pub use win32::gui::new_plugin_gui; 9 | -------------------------------------------------------------------------------- /webview-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "webview-sys" 3 | version = "0.0.1" 4 | license = "MIT" 5 | description = "Rust native ffi bindings for webview" 6 | build = "build.rs" 7 | links = "webview" 8 | 9 | [lib] 10 | name = "webview_sys" 11 | path = "lib.rs" 12 | 13 | [dependencies] 14 | libc = "0.2" 15 | cocoa = "0.20.0" 16 | 17 | [build-dependencies] 18 | cc = "1" 19 | pkg-config = "0.3" 20 | -------------------------------------------------------------------------------- /webview-sys/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate cocoa; 2 | 3 | use std::os::raw::*; 4 | 5 | extern "C" { 6 | pub fn create_webview( 7 | parent: *const c_void, 8 | width: c_int, 9 | height: c_int, 10 | html: *const c_char, 11 | data: *const c_void, 12 | callback: *const c_void, 13 | ) -> *const c_void; 14 | pub fn eval_webview(webview: *const c_void, js: *const c_char); 15 | pub fn destroy_webview(webview: *const c_void); 16 | } 17 | -------------------------------------------------------------------------------- /webview-sys/webview.h: -------------------------------------------------------------------------------- 1 | #ifndef WEBVIEW_H 2 | #define WEBVIEW_H 3 | 4 | #include 5 | #include 6 | 7 | typedef const char *(*callback)(const void* data, const char* string); 8 | 9 | id create_webview(const void *parent, int width, int height, const char *html, const void* data, const void* callback); 10 | 11 | void eval_webview(id webview, const char *js); 12 | 13 | void destroy_webview(id webview); 14 | 15 | #endif // WEBVIEW_H 16 | -------------------------------------------------------------------------------- /webview-sys/build.rs: -------------------------------------------------------------------------------- 1 | extern crate cc; 2 | extern crate pkg_config; 3 | 4 | use std::env; 5 | 6 | fn main() { 7 | let mut build = cc::Build::new(); 8 | 9 | build 10 | .include("webview.h") 11 | .flag_if_supported("-std=c11") 12 | .flag_if_supported("-w"); 13 | 14 | if env::var("DEBUG").is_err() { 15 | build.define("NDEBUG", None); 16 | } else { 17 | build.define("DEBUG", None); 18 | } 19 | 20 | build 21 | .file("webview.c") 22 | .define("OBJC_OLD_DISPATCH_PROTOTYPES", "1") 23 | .flag("-x") 24 | .flag("objective-c"); 25 | println!("cargo:rustc-link-lib=framework=Cocoa"); 26 | println!("cargo:rustc-link-lib=framework=WebKit"); 27 | 28 | build.compile("webview"); 29 | } 30 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vst-gui" 3 | version = "0.2.0" 4 | authors = ["Alexander Agafonov "] 5 | description = "An extension to the 'rust-vst' crate to create VST plugin GUIs" 6 | license = "MIT" 7 | keywords = ["gui", "plugin", "vst", "vst2"] 8 | 9 | [dependencies] 10 | vst = "^0.2" 11 | 12 | [target.'cfg(target_os = "macos")'.dependencies] 13 | cocoa = "0.20.0" 14 | webview-sys = { path = "webview-sys", version = "0.0.1" } 15 | 16 | [target.'cfg(windows)'.dependencies] 17 | memoffset = "0.2.1" 18 | 19 | [target.'cfg(windows)'.dependencies.winapi] 20 | version = "0.3.4" 21 | features = [ 22 | "combaseapi", 23 | "libloaderapi", 24 | "oaidl", 25 | "oleauto", 26 | "winbase", 27 | "winerror", 28 | "winuser" 29 | ] 30 | 31 | [[example]] 32 | name = "synth" 33 | crate-type = ["cdylib"] 34 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Alexander Agafonov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/win32/com_pointer.rs: -------------------------------------------------------------------------------- 1 | use std::ptr::null_mut; 2 | 3 | use winapi::Interface; 4 | use winapi::shared::winerror::S_OK; 5 | use winapi::shared::minwindef::LPVOID; 6 | use winapi::um::unknwnbase::IUnknown; 7 | 8 | pub struct ComPointer { 9 | pointer: *mut T, 10 | } 11 | 12 | impl ComPointer { 13 | pub fn new() -> Self { 14 | ComPointer { 15 | pointer: null_mut(), 16 | } 17 | } 18 | 19 | pub fn from_raw(pointer: *mut T) -> Self { 20 | ComPointer { 21 | pointer: pointer, 22 | } 23 | } 24 | 25 | // Note: this method doesn't modify the reference counter 26 | pub fn as_ptr(&self) -> *mut T { 27 | self.pointer 28 | } 29 | 30 | // Note: this method doesn't modify the reference counter 31 | pub fn as_mut_ptr(&mut self) -> &mut *mut T { 32 | &mut self.pointer 33 | } 34 | 35 | pub fn get(&self) -> Option<&T> { 36 | if self.pointer != null_mut() { 37 | unsafe { 38 | Some(&*self.pointer) 39 | } 40 | } else { 41 | None 42 | } 43 | } 44 | 45 | pub fn query_interface(&self) -> ComPointer { 46 | let mut result = ComPointer::::new(); 47 | 48 | let success = if self.pointer != null_mut() { 49 | unsafe { 50 | let result_pointer = result.as_mut_ptr() 51 | as *mut *mut I 52 | as *mut LPVOID; 53 | 54 | (*(self.pointer as *mut IUnknown)).QueryInterface( 55 | &I::uuidof(), result_pointer) == S_OK 56 | } 57 | } else { 58 | false 59 | }; 60 | 61 | match success { 62 | true => result, 63 | false => ComPointer::::new(), 64 | } 65 | } 66 | } 67 | 68 | impl Drop for ComPointer { 69 | fn drop(&mut self) { 70 | if self.pointer != null_mut() { 71 | unsafe { 72 | (*(self.pointer as *mut IUnknown)).Release(); 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(windows)] 2 | #[macro_use] 3 | extern crate memoffset; 4 | #[cfg(windows)] 5 | #[macro_use] 6 | extern crate winapi; 7 | extern crate vst; 8 | 9 | #[cfg(target_os = "macos")] 10 | extern crate cocoa; 11 | 12 | #[cfg(target_os = "macos")] 13 | extern crate webview_sys; 14 | 15 | use std::error::Error; 16 | use std::os::raw::c_void; 17 | 18 | #[cfg(windows)] 19 | mod win32; 20 | 21 | #[cfg(target_os = "macos")] 22 | mod macos; 23 | 24 | mod lib { 25 | use std::error::Error; 26 | use std::os::raw::c_void; 27 | 28 | pub type JavascriptCallback = Box String>; 29 | 30 | pub trait PluginGui { 31 | fn size(&self) -> (i32, i32); 32 | fn position(&self) -> (i32, i32); 33 | fn close(&mut self); 34 | fn open(&mut self, parent_handle: *mut c_void) -> bool; 35 | fn is_open(&mut self) -> bool; 36 | fn execute(&self, javascript_code: &str) -> Result<(), Box>; 37 | } 38 | } 39 | 40 | pub struct PluginGui { 41 | gui: Box, 42 | } 43 | 44 | impl PluginGui { 45 | // Calls the Javascript 'eval' function with the specified argument. 46 | // This method always returns an error when the plugin window is closed. 47 | pub fn execute(&self, javascript_code: &str) -> Result<(), Box> { 48 | self.gui.execute(javascript_code) 49 | } 50 | } 51 | 52 | impl vst::editor::Editor for PluginGui { 53 | fn size(&self) -> (i32, i32) { 54 | self.gui.size() 55 | } 56 | 57 | fn position(&self) -> (i32, i32) { 58 | self.gui.position() 59 | } 60 | 61 | fn close(&mut self) { 62 | self.gui.close() 63 | } 64 | 65 | fn open(&mut self, parent_handle: *mut c_void) -> bool { 66 | self.gui.open(parent_handle) 67 | } 68 | 69 | fn is_open(&mut self) -> bool { 70 | self.gui.is_open() 71 | } 72 | } 73 | 74 | pub use lib::JavascriptCallback; 75 | 76 | pub fn new_plugin_gui( 77 | html_document: String, js_callback: JavascriptCallback, window_size: Option<(i32, i32)>) -> PluginGui 78 | { 79 | #[cfg(windows)] 80 | { 81 | PluginGui {gui: win32::new_plugin_gui(html_document, js_callback, window_size) } 82 | } 83 | #[cfg(target_os = "macos")] 84 | { 85 | PluginGui {gui: macos::new_plugin_gui(html_document, js_callback, window_size) } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/macos/gui.rs: -------------------------------------------------------------------------------- 1 | //#![windows_subsystem = "windows"] 2 | 3 | use lib::{JavascriptCallback, PluginGui}; 4 | use std::os::raw::{c_void, c_char}; 5 | use std::error::Error; 6 | use std::ffi::{CStr, CString}; 7 | use std::rc::Rc; 8 | use std::str; 9 | use webview_sys::*; 10 | 11 | #[no_mangle] 12 | extern "C" fn listener(this: *const c_void, result: *const c_char) -> *mut c_char { 13 | unsafe { 14 | let that = this as *const Gui; 15 | let res = CStr::from_ptr(result).to_string_lossy().into_owned(); 16 | let str = (*(*that).js_callback)(res); 17 | let c_str = CString::new(str).unwrap(); 18 | c_str.into_raw() 19 | } 20 | } 21 | 22 | struct Gui { 23 | html_content: String, 24 | window_size: Option<(i32, i32)>, 25 | is_open: bool, 26 | web_view: Option<*const c_void>, 27 | js_callback: Rc, 28 | } 29 | 30 | impl PluginGui for Gui { 31 | fn size(&self) -> (i32, i32) { 32 | match self.window_size { 33 | Some(inner) => inner, 34 | None => (0, 0) 35 | } 36 | } 37 | 38 | fn position(&self) -> (i32, i32) { 39 | (0, 0) 40 | } 41 | 42 | fn close(&mut self) { 43 | unsafe { 44 | match self.web_view { 45 | Some(inner) => { 46 | destroy_webview(inner); 47 | self.web_view = None; 48 | }, 49 | None => () 50 | } 51 | } 52 | self.is_open = false; 53 | } 54 | 55 | fn open(&mut self, parent_handle: *mut c_void) -> bool { 56 | unsafe { 57 | let html = CString::new(self.html_content.as_str()).expect(""); 58 | let ptr: *const Gui = self; 59 | let (width, height) = self.window_size.unwrap(); 60 | self.web_view = Some(create_webview(parent_handle, width, height, html.as_ptr(), ptr as *const c_void, listener as *const c_void)); 61 | } 62 | true 63 | } 64 | 65 | fn is_open(&mut self) -> bool { 66 | self.is_open 67 | } 68 | 69 | fn execute(&self, javascript_code: &str) -> Result<(), Box> { 70 | unsafe { 71 | let js = CString::new(javascript_code)?; 72 | match self.web_view { 73 | Some(inner) => { 74 | eval_webview(inner, js.as_ptr()); 75 | }, 76 | None => () 77 | } 78 | } 79 | Ok(()) 80 | } 81 | } 82 | 83 | pub fn new_plugin_gui( 84 | html_document: String, 85 | js_callback: JavascriptCallback, 86 | window_size: Option<(i32, i32)>) -> Box 87 | { 88 | Box::new( 89 | Gui { 90 | html_content: html_document, 91 | is_open: false, 92 | js_callback: Rc::new(js_callback), 93 | window_size: window_size, 94 | web_view: None, 95 | }) 96 | } 97 | 98 | -------------------------------------------------------------------------------- /webview-sys/webview.c: -------------------------------------------------------------------------------- 1 | #include "webview.h" 2 | #include 3 | #include 4 | 5 | #define WKUserScriptInjectionTimeAtDocumentStart 0 6 | 7 | #define _cls(s) ((id)objc_getClass(s)) 8 | #define _sel(s) (sel_registerName(s)) 9 | #define _str(s) (objc_msgSend((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), s)) 10 | 11 | void eval_webview(id webview, const char *js) { 12 | objc_msgSend(webview, _sel("evaluateJavaScript:completionHandler:"), _str(js), nil); 13 | } 14 | 15 | void prompt_listener(id self, SEL cmd, id webView, id message, id defaultText, id frame, void (^completionHandler)(id)) { 16 | // TODO null check strings (message) 17 | // TODO handle cases where we actually need a prompt window 18 | const char *body = (const char *)objc_msgSend(message, _sel("UTF8String")); 19 | callback cb = (callback)objc_getAssociatedObject(self, "callback"); 20 | const void *data = (const void *)objc_getAssociatedObject(self, "data"); 21 | const char *retval = cb(data, body); 22 | completionHandler(_str(retval)); 23 | } 24 | 25 | id create_webview(const void *parent, int width, int height, const char *html, const void* data, const void* callback) { 26 | id config = objc_msgSend(_cls("WKWebViewConfiguration"), _sel("new")); 27 | id manager = objc_msgSend(config, _sel("userContentController")); 28 | 29 | // Web View 30 | id webview = objc_msgSend(_cls("WKWebView"), _sel("alloc")); 31 | 32 | objc_msgSend(webview, _sel("initWithFrame:configuration:"), CGRectMake(0, 0, width, height), config); 33 | objc_msgSend(webview, _sel("loadHTMLString:baseURL:"), _str(html), nil); 34 | 35 | objc_msgSend((id)parent, _sel("addSubview:"), webview); 36 | 37 | // TODO make this disabled by default 38 | objc_msgSend(objc_msgSend(config, _sel("preferences")), _sel("setValue:forKey:"), objc_msgSend(_cls("NSNumber"), _sel("numberWithBool:"), 1), _str("developerExtrasEnabled")); 39 | 40 | // Delegate 41 | static Class __WKUIDelegate; 42 | if(__WKUIDelegate == NULL) { 43 | __WKUIDelegate = objc_allocateClassPair((Class) _cls("NSObject"), "__WKUIDelegate", 0); 44 | class_addProtocol(__WKUIDelegate, objc_getProtocol("WKUIDelegate")); 45 | class_addMethod(__WKUIDelegate, _sel("webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:"), (IMP)(prompt_listener), "v@:@@@@?"); 46 | objc_registerClassPair(__WKUIDelegate); 47 | } 48 | 49 | id uiDel = objc_msgSend((id)__WKUIDelegate, _sel("new")); 50 | objc_setAssociatedObject(uiDel, "callback", callback, OBJC_ASSOCIATION_ASSIGN); 51 | objc_setAssociatedObject(uiDel, "data", data, OBJC_ASSOCIATION_ASSIGN); 52 | objc_msgSend(webview, _sel("setUIDelegate:"), uiDel); 53 | 54 | // inject invoke function that uses window.prompt hack (https://stackoverflow.com/a/39728672) 55 | char *js = "external = {invoke:(s) => {console.log('sending:', s); return prompt(s);}}"; 56 | objc_msgSend(manager, _sel("addUserScript:"), 57 | objc_msgSend(objc_msgSend(_cls("WKUserScript"), _sel("alloc")), 58 | _sel("initWithSource:injectionTime:forMainFrameOnly:"), 59 | _str(js), 60 | WKUserScriptInjectionTimeAtDocumentStart, 1)); 61 | 62 | return webview; 63 | } 64 | 65 | void destroy_webview(id webview) { 66 | // TODO remove if not needed 67 | } 68 | -------------------------------------------------------------------------------- /examples/synth.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate vst; 3 | extern crate vst_gui; 4 | 5 | use std::f32::consts::PI; 6 | use std::sync::{Arc, Mutex}; 7 | 8 | use vst::buffer::AudioBuffer; 9 | use vst::editor::Editor; 10 | use vst::plugin::{Category, Plugin, Info}; 11 | 12 | const HTML: &'static str = r#" 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 27 | 28 | 29 | 30 |
31 | 32 |
33 | 34 |
35 | 36 | 37 | 38 | 52 | 53 | "#; 54 | 55 | struct Oscillator { 56 | pub frequency: f32, 57 | pub waveform: f32, 58 | pub phase: f32, 59 | pub amplitude: f32, 60 | } 61 | 62 | fn create_javascript_callback( 63 | oscillator: Arc>) -> vst_gui::JavascriptCallback 64 | { 65 | Box::new(move |message: String| { 66 | let mut tokens = message.split_whitespace(); 67 | 68 | let command = tokens.next().unwrap_or(""); 69 | let argument = tokens.next().unwrap_or("").parse::(); 70 | 71 | let mut locked_oscillator = oscillator.lock().unwrap(); 72 | 73 | match command { 74 | "getWaveform" => { 75 | return locked_oscillator.waveform.to_string(); 76 | }, 77 | "getFrequency" => { 78 | return locked_oscillator.frequency.to_string(); 79 | }, 80 | "setWaveform" => { 81 | if argument.is_ok() { 82 | locked_oscillator.waveform = argument.unwrap(); 83 | } 84 | }, 85 | "setFrequency" => { 86 | if argument.is_ok() { 87 | locked_oscillator.frequency = argument.unwrap(); 88 | } 89 | }, 90 | _ => {} 91 | } 92 | 93 | String::new() 94 | }) 95 | } 96 | 97 | struct ExampleSynth { 98 | sample_rate: f32, 99 | // We access this object both from a UI thread and from an audio processing 100 | // thread. 101 | oscillator: Arc>, 102 | } 103 | 104 | impl Default for ExampleSynth { 105 | fn default() -> ExampleSynth { 106 | let oscillator = Arc::new(Mutex::new( 107 | Oscillator { 108 | frequency: 440.0, 109 | waveform: 0.0, 110 | phase: 0.0, 111 | amplitude: 0.1, 112 | } 113 | )); 114 | 115 | ExampleSynth { 116 | sample_rate: 44100.0, 117 | oscillator: oscillator.clone(), 118 | } 119 | } 120 | } 121 | 122 | impl Plugin for ExampleSynth { 123 | fn get_info(&self) -> Info { 124 | Info { 125 | name: "Example Synth".to_string(), 126 | vendor: "rust-vst-gui".to_string(), 127 | unique_id: 9614, 128 | category: Category::Synth, 129 | inputs: 2, 130 | outputs: 2, 131 | parameters: 0, 132 | initial_delay: 0, 133 | f64_precision: false, 134 | ..Info::default() 135 | } 136 | } 137 | 138 | fn set_sample_rate(&mut self, sample_rate: f32) { 139 | self.sample_rate = sample_rate as f32; 140 | } 141 | 142 | fn process(&mut self, buffer: &mut AudioBuffer) { 143 | let mut oscillator = self.oscillator.lock().unwrap(); 144 | 145 | let actual_phase = oscillator.phase; 146 | let actual_frequency = oscillator.frequency; 147 | 148 | let phase = |sample_index: usize| { 149 | actual_phase + 2.0 * PI * actual_frequency * 150 | (sample_index as f32) / self.sample_rate 151 | }; 152 | 153 | for (_, output) in buffer.zip() { 154 | for (index, sample) in output.iter_mut().enumerate() { 155 | let sine_wave = phase(index).sin(); 156 | let square_wave = phase(index).cos().signum(); 157 | 158 | *sample = oscillator.amplitude * ( 159 | sine_wave * (1.0 - oscillator.waveform) + 160 | square_wave * oscillator.waveform); 161 | } 162 | } 163 | 164 | oscillator.phase = phase(buffer.samples()) % (2.0 * PI); 165 | } 166 | 167 | fn get_editor(&mut self) -> Option> { 168 | let gui = vst_gui::new_plugin_gui( 169 | String::from(HTML), 170 | create_javascript_callback(self.oscillator.clone()), 171 | Some((480, 320))); 172 | Some(Box::new(gui)) 173 | } 174 | } 175 | 176 | plugin_main!(ExampleSynth); 177 | -------------------------------------------------------------------------------- /src/win32/gui.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::ffi::OsStr; 3 | use std::mem::uninitialized; 4 | use std::os::raw::c_void; 5 | use std::os::windows::ffi::OsStrExt; 6 | use std::ptr::{null, null_mut}; 7 | use std::rc::Rc; 8 | 9 | use winapi::Interface; 10 | use winapi::shared::guiddef::*; 11 | use winapi::shared::minwindef::*; 12 | use winapi::shared::windef::*; 13 | use winapi::shared::winerror::*; 14 | use winapi::shared::wtypes::*; 15 | use winapi::um::combaseapi::*; 16 | use winapi::um::libloaderapi::*; 17 | use winapi::um::oaidl::*; 18 | use winapi::um::oaidl::DISPID; // Required to eliminate ambiguity 19 | use winapi::um::objidlbase::*; 20 | use winapi::um::oleauto::*; 21 | use winapi::um::winnt::*; 22 | use winapi::um::winuser::*; 23 | 24 | use lib::{JavascriptCallback, PluginGui}; 25 | use win32::client_site::*; 26 | use win32::com_pointer::*; 27 | use win32::ffi::*; 28 | 29 | fn error(message: &str) -> Box { 30 | From::from(message) 31 | } 32 | 33 | struct Window { 34 | handle: HWND, 35 | } 36 | 37 | impl Window { 38 | // The "plugin_window" string in utf16. 39 | const CLASS_NAME: [u16; 14] = [ 40 | 0x0070, 0x006c, 0x0075, 0x0067, 0x0069, 0x006e, 0x005f, 0x0077, 41 | 0x0069, 0x006e, 0x0064, 0x006f, 0x0077, 0x0000]; 42 | 43 | pub fn new(parent: HWND, size: Option<(i32, i32)>) -> Window { 44 | Window::register_window_class(); 45 | let window_size = size.unwrap_or_else(|| Window::default_size()); 46 | let handle = unsafe { 47 | const STYLE: DWORD = WS_CHILD | WS_VISIBLE; 48 | const STYLE_EXTENDED: DWORD = 0; 49 | 50 | CreateWindowExW( 51 | STYLE_EXTENDED, 52 | Window::CLASS_NAME.as_ptr(), 53 | null(), /*window_name*/ 54 | STYLE, 55 | 0, /*x*/ 56 | 0, /*y*/ 57 | window_size.0, 58 | window_size.1, 59 | parent, 60 | null_mut(), /*menu*/ 61 | GetModuleHandleW(null()), 62 | null_mut()) 63 | }; 64 | 65 | Window { 66 | handle: handle, 67 | } 68 | } 69 | 70 | fn size(&self) -> (i32, i32) { 71 | let mut rectangle = 72 | RECT {left: 0, top: 0, right: 0, bottom: 0}; 73 | 74 | unsafe { 75 | GetWindowRect(self.handle, &mut rectangle); 76 | } 77 | 78 | let width = (rectangle.right - rectangle.left) as i32; 79 | let height = (rectangle.bottom - rectangle.top) as i32; 80 | 81 | (width, height) 82 | } 83 | 84 | fn default_size() -> (i32, i32) { 85 | unsafe { 86 | let width = GetSystemMetrics(SM_CXSCREEN) / 2; 87 | let height = GetSystemMetrics(SM_CYSCREEN) / 2; 88 | 89 | (width, height) 90 | } 91 | } 92 | 93 | fn register_window_class() { 94 | let class = WNDCLASSW { 95 | style: CS_DBLCLKS, 96 | lpfnWndProc: Some(Window::window_procedure), 97 | cbClsExtra: 0, 98 | cbWndExtra: 0, 99 | hInstance: unsafe { GetModuleHandleW(null()) }, 100 | hIcon: null_mut(), 101 | hCursor: unsafe { LoadCursorW(null_mut(), IDC_ARROW) }, 102 | hbrBackground: null_mut(), 103 | lpszMenuName: null(), 104 | lpszClassName: Window::CLASS_NAME.as_ptr() 105 | }; 106 | 107 | unsafe { 108 | RegisterClassW(&class); 109 | } 110 | } 111 | 112 | extern "system" fn window_procedure( 113 | handle: HWND, message: UINT, wparam: WPARAM, lparam: LPARAM) -> LRESULT 114 | { 115 | match message { 116 | WM_GETDLGCODE => { 117 | return DLGC_WANTALLKEYS; 118 | }, 119 | _ => {} 120 | } 121 | unsafe { 122 | DefWindowProcW(handle, message, wparam, lparam) 123 | } 124 | } 125 | } 126 | 127 | struct WebBrowser { 128 | browser: ComPointer, 129 | } 130 | 131 | impl WebBrowser { 132 | fn new( 133 | window_handle: HWND, 134 | html_document: String, 135 | js_callback: Rc) -> Result> 136 | { 137 | unsafe { 138 | OleInitialize(null_mut()); 139 | } 140 | 141 | let browser = WebBrowser { 142 | browser: WebBrowser::new_browser_com_object()? 143 | }; 144 | 145 | browser.embed(window_handle, js_callback)?; 146 | 147 | // https://msdn.microsoft.com/library/aa752047 148 | browser.open_blank_page()?; 149 | browser.load_html_document(html_document)?; 150 | 151 | Ok(browser) 152 | } 153 | 154 | fn new_browser_com_object() -> 155 | Result, Box> 156 | { 157 | let mut web_browser = ComPointer::::new(); 158 | 159 | let result = unsafe { 160 | CoCreateInstance( 161 | &CLSID_WebBrowser, 162 | null_mut(), 163 | CLSCTX_INPROC, 164 | &IWebBrowser2::uuidof(), 165 | web_browser.as_mut_ptr() 166 | as *mut *mut IWebBrowser2 167 | as *mut LPVOID) 168 | }; 169 | 170 | if result == S_OK && web_browser.get().is_some() { 171 | Ok(web_browser) 172 | } else { 173 | Err(error("Couldn't get an instance of the 'IWebBrowser2' class")) 174 | } 175 | } 176 | 177 | fn browser(&self) -> &IWebBrowser2 { 178 | self.browser 179 | .get() 180 | .unwrap() 181 | } 182 | 183 | fn open_blank_page(&self) -> Result<(), Box> { 184 | use std::ffi::OsStr; 185 | use std::os::windows::ffi::OsStrExt; 186 | 187 | let url_buffer: Vec = 188 | OsStr::new("about:blank").encode_wide().collect(); 189 | 190 | unsafe { 191 | let url = SysAllocStringLen( 192 | url_buffer.as_ptr(), 193 | url_buffer.len() as u32); 194 | 195 | if self.browser().Navigate( 196 | url, 197 | null_mut(), 198 | null_mut(), 199 | null_mut(), 200 | null_mut()) != S_OK 201 | { 202 | return Err(error("Couldn't open a blank page")) 203 | } 204 | 205 | SysFreeString(url); 206 | } 207 | 208 | Ok(()) 209 | } 210 | 211 | fn document_dispatch(&self) -> Result, Box> { 212 | let mut result = ComPointer::::new(); 213 | 214 | let success = unsafe { 215 | self.browser().get_Document(result.as_mut_ptr()) == S_OK && 216 | result.get().is_some() 217 | }; 218 | 219 | match success { 220 | true => Ok(result), 221 | false => Err( 222 | error( 223 | "The 'IWebBrowser2::get_Document' method returned an \ 224 | error")), 225 | } 226 | } 227 | 228 | fn window_dispatch(&self) -> Result, Box> { 229 | let document_dispatch = self.document_dispatch()?; 230 | 231 | let window_dispatch = document_dispatch 232 | .query_interface::() 233 | .get() 234 | .map(|document| { 235 | let mut window = ComPointer::::new(); 236 | 237 | unsafe { 238 | if document.get_parentWindow(window.as_mut_ptr()) == S_OK { 239 | window 240 | } else { 241 | ComPointer::::new() 242 | } 243 | } 244 | }) 245 | .map(|window| { 246 | window.query_interface::() 247 | }) 248 | .unwrap_or(ComPointer::::new()); 249 | 250 | if window_dispatch.get().is_some() { 251 | Ok(window_dispatch) 252 | } else { 253 | Err( 254 | error( 255 | "Couldn't get an instance of the 'IDispatch' class \ 256 | for the document window")) 257 | } 258 | } 259 | 260 | fn load_html_document( 261 | &self, html_document: String) -> Result<(), Box> 262 | { 263 | // TODO: do not assume the document is ready 264 | let document_dispatch = self.document_dispatch()?; 265 | 266 | let stream = ComPointer::::from_raw( 267 | unsafe { 268 | SHCreateMemStream( 269 | html_document.as_ptr(), 270 | html_document.len() as u32) 271 | }); 272 | 273 | stream 274 | .get() 275 | .ok_or(error("Couldn't get an instance of the 'IStream' class"))?; 276 | 277 | let success = document_dispatch 278 | .query_interface::() 279 | .get() 280 | .map(|persist_stream| { 281 | unsafe { 282 | persist_stream.InitNew() == S_OK && 283 | persist_stream.Load(stream.as_ptr()) == S_OK 284 | } 285 | }) 286 | .ok_or( 287 | error( 288 | "Couldn't get an instance of the 'IPersistStreamInit' \ 289 | class"))?; 290 | 291 | match success { 292 | true => Ok(()), 293 | false => Err(error("Couldn't load an HTML document")), 294 | } 295 | } 296 | 297 | fn embed( 298 | &self, 299 | window_handle: HWND, 300 | js_callback: Rc) -> Result<(), Box> 301 | { 302 | let ole_object = self.browser.query_interface::(); 303 | 304 | ole_object 305 | .get() 306 | .ok_or( 307 | error("Couldn't get an instance of the 'IOleObject' class"))?; 308 | 309 | let ole_in_place_object = 310 | ole_object.query_interface::(); 311 | 312 | ole_in_place_object 313 | .get() 314 | .ok_or( 315 | error( 316 | "Couldn't get an instance of the 'IOleInPlaceObject' \ 317 | class"))?; 318 | 319 | let client_site = new_client_site( 320 | window_handle, ole_in_place_object, js_callback); 321 | 322 | let success = { 323 | let mut rectangle = RECT {left: 0, top: 0, right: 0, bottom: 0}; 324 | 325 | unsafe { 326 | GetClientRect(window_handle, &mut rectangle); 327 | 328 | ole_object.get().unwrap().SetClientSite( 329 | client_site.as_ptr()) == S_OK && 330 | ole_object.get().unwrap().DoVerb( 331 | OLEIVERB_INPLACEACTIVATE, 332 | null_mut(), 333 | client_site.as_ptr(), 334 | 0, 335 | window_handle, 336 | &rectangle) == S_OK && 337 | self.browser().put_Width(rectangle.right) == S_OK && 338 | self.browser().put_Height(rectangle.bottom) == S_OK && 339 | self.browser().put_Visible(TRUE as VARIANT_BOOL) == S_OK 340 | } 341 | }; 342 | 343 | match success { 344 | true => Ok(()), 345 | false => Err(error("Couldn't reveal an HTML browser")), 346 | } 347 | } 348 | 349 | fn execute(&self, javascript_code: &str) -> Result<(), Box> { 350 | let window_dispatch = self.window_dispatch()?; 351 | 352 | let argument_value: Vec = OsStr::new(javascript_code) 353 | .encode_wide() 354 | .collect(); 355 | 356 | unsafe { 357 | let mut argument: VARIANT = uninitialized(); 358 | 359 | VariantInit(&mut argument); 360 | 361 | argument.n1.n2_mut().vt = VT_BSTR as u16; 362 | *argument.n1.n2_mut().n3.bstrVal_mut() = SysAllocStringLen( 363 | argument_value.as_ptr(), 364 | argument_value.len() as u32); 365 | 366 | let mut parameters = DISPPARAMS { 367 | rgvarg: &mut argument, 368 | rgdispidNamedArgs: null_mut(), 369 | cArgs: 1, 370 | cNamedArgs: 0, 371 | }; 372 | 373 | // TODO: cache the 'window_dispatch' object and the method id 374 | 375 | let result = if window_dispatch 376 | .get() 377 | .unwrap() 378 | .Invoke( 379 | WebBrowser::window_eval_method_id(&window_dispatch)?, 380 | &IID_NULL, 381 | LOCALE_SYSTEM_DEFAULT, 382 | DISPATCH_METHOD, 383 | &mut parameters, 384 | null_mut(), 385 | null_mut(), 386 | null_mut()) == S_OK 387 | { 388 | Ok(()) 389 | } else { 390 | Err(error("Execution of the Javascript code failed")) 391 | }; 392 | 393 | VariantClear(&mut argument); 394 | result 395 | } 396 | } 397 | 398 | fn window_eval_method_id(window_dispatch: &ComPointer) -> 399 | Result> 400 | { 401 | assert!(window_dispatch.get().is_some()); 402 | 403 | // The "eval" string in utf16. 404 | let mut method_name: Vec = 405 | vec![0x0065, 0x0076, 0x0061, 0x006c, 0x0000]; 406 | let mut id: DISPID = 0; 407 | 408 | let result = unsafe { 409 | window_dispatch 410 | .get() 411 | .unwrap() 412 | .GetIDsOfNames( 413 | &IID_NULL, 414 | &mut method_name.as_mut_ptr(), 1, LOCALE_SYSTEM_DEFAULT, 415 | &mut id) 416 | }; 417 | 418 | if result == S_OK { 419 | Ok(id) 420 | } else { 421 | Err(error("Couldn't get an ID for the 'eval' method")) 422 | } 423 | } 424 | } 425 | 426 | struct Gui { 427 | html_document: String, 428 | js_callback: Rc, 429 | web_browser: Option, 430 | window: Option, 431 | window_size: Option<(i32, i32)>, 432 | } 433 | 434 | impl PluginGui for Gui { 435 | fn size(&self) -> (i32, i32) { 436 | match self.window { 437 | Some(ref window) => window.size(), 438 | None => (0, 0) 439 | } 440 | } 441 | 442 | fn position(&self) -> (i32, i32) { 443 | (0, 0) 444 | } 445 | 446 | fn close(&mut self) { 447 | self.web_browser = None; 448 | self.window = None; 449 | } 450 | 451 | fn open(&mut self, parent_handle: *mut c_void) -> bool { 452 | let window = Window::new(parent_handle as HWND, self.window_size); 453 | 454 | match WebBrowser::new( 455 | window.handle, 456 | self.html_document.clone(), 457 | self.js_callback.clone()) { 458 | Ok(browser) => { 459 | self.window = Some(window); 460 | self.web_browser = Some(browser); 461 | true 462 | }, 463 | Err(e) => false // TODO: Display errors 464 | } 465 | } 466 | 467 | fn is_open(&mut self) -> bool { 468 | self.window.is_some() 469 | } 470 | 471 | fn execute(&self, javascript_code: &str) -> Result<(), Box> { 472 | if let Some(ref web_browser) = self.web_browser { 473 | web_browser.execute(javascript_code) 474 | } else { 475 | Err(error("The plugin window is closed")) 476 | } 477 | } 478 | } 479 | 480 | pub fn new_plugin_gui( 481 | html_document: String, 482 | js_callback: JavascriptCallback, 483 | window_size: Option<(i32, i32)>) -> Box 484 | { 485 | Box::new( 486 | Gui { 487 | html_document: html_document, 488 | js_callback: Rc::new(js_callback), 489 | web_browser: None, 490 | window: None, 491 | window_size: window_size, 492 | }) 493 | } 494 | -------------------------------------------------------------------------------- /src/win32/ffi.rs: -------------------------------------------------------------------------------- 1 | // This module contains declarations which are missing from the 'winapi' crate. 2 | 3 | use std::os::raw::*; 4 | 5 | // Non-asterisk imports are required to eliminate ambiguity 6 | use winapi::shared::guiddef::*; 7 | use winapi::shared::minwindef::*; 8 | use winapi::shared::windef::*; 9 | use winapi::shared::windef::SIZE; 10 | use winapi::shared::wtypes::*; 11 | use winapi::shared::wtypesbase::*; 12 | use winapi::um::oaidl::*; 13 | use winapi::um::objidl::{IMoniker, IPersist, IPersistVtbl}; 14 | use winapi::um::objidlbase::*; 15 | use winapi::um::unknwnbase::*; 16 | use winapi::um::winnt::*; 17 | use winapi::um::winuser::*; 18 | 19 | #[link(name = "ole32")] 20 | extern "system" { 21 | pub fn OleInitialize(_: LPVOID) -> HRESULT; 22 | pub fn OleSetContainedObject( 23 | pUnknown: *mut IUnknown, fContained: BOOL) -> HRESULT; 24 | } 25 | 26 | #[link(name = "shlwapi")] 27 | extern "system" { 28 | pub fn SHCreateMemStream(pInit: *const BYTE, cbInit: UINT) -> *mut IStream; 29 | } 30 | 31 | // We don't use these types so we don't need exact declarations. 32 | pub type IDataObject = IUnknown; 33 | pub type IDropTarget = IUnknown; 34 | pub type IOleCommandTarget = IUnknown; 35 | pub type IOleContainer = IUnknown; 36 | pub type IOleInPlaceActiveObject = IUnknown; 37 | pub type IHTMLWindow2 = IUnknown; 38 | 39 | pub const OLEIVERB_INPLACEACTIVATE: LONG = -5; 40 | 41 | RIDL!{ 42 | #[uuid(0x00000112, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] 43 | interface IOleObject(IOleObjectVtbl) : IUnknown(IUnknownVtbl) { 44 | fn SetClientSite(pClientSite: *mut IOleClientSite,) -> HRESULT, 45 | fn Unused_GetClientSite() -> HRESULT, 46 | fn Unused_SetHostNames() -> HRESULT, 47 | fn Unused_Close() -> HRESULT, 48 | fn Unused_SetMoniker() -> HRESULT, 49 | fn Unused_GetMoniker() -> HRESULT, 50 | fn Unused_InitFromData() -> HRESULT, 51 | fn Unused_GetClipboardData() -> HRESULT, 52 | fn DoVerb( 53 | iVerb: LONG, 54 | lpmsg: LPMSG, 55 | pActiveSite: *mut IOleClientSite, 56 | lindex: LONG, 57 | hwndParent: HWND, 58 | lprcPosRect: LPCRECT,) -> HRESULT, 59 | fn Unused_EnumVerbs() -> HRESULT, 60 | fn Unused_Update() -> HRESULT, 61 | fn Unused_IsUpToDate() -> HRESULT, 62 | fn Unused_GetUserClassID() -> HRESULT, 63 | fn Unused_GetUserType() -> HRESULT, 64 | fn Unused_SetExtent() -> HRESULT, 65 | fn Unused_GetExtent() -> HRESULT, 66 | fn Unused_Advise() -> HRESULT, 67 | fn Unused_Unadvise() -> HRESULT, 68 | fn Unused_EnumAdvise() -> HRESULT, 69 | fn Unused_GetMiscStatus() -> HRESULT, 70 | fn Unused_SetColorScheme() -> HRESULT, 71 | } 72 | } 73 | 74 | RIDL!{ 75 | #[uuid(0x00000118, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] 76 | interface IOleClientSite(IOleClientSiteVtbl) : IUnknown(IUnknownVtbl) { 77 | fn SaveObject() -> HRESULT, 78 | fn GetMoniker( 79 | dwAssign: DWORD, 80 | dwWhichMoniker: DWORD, 81 | ppmk: *mut *mut IMoniker,) -> HRESULT, 82 | fn GetContainer(ppContainer: *mut *mut IOleContainer,) -> HRESULT, 83 | fn ShowObject() -> HRESULT, 84 | fn OnShowWindow(fShow: BOOL,) -> HRESULT, 85 | fn RequestNewObjectLayout() -> HRESULT, 86 | } 87 | } 88 | 89 | RIDL!{ 90 | #[uuid(0x00000114, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] 91 | interface IOleWindow(IOleWindowVtbl) : IUnknown(IUnknownVtbl) { 92 | fn GetWindow(phwnd: *mut HWND,) -> HRESULT, 93 | fn ContextSensitiveHelp(fEnterMode: BOOL,) -> HRESULT, 94 | } 95 | } 96 | 97 | RIDL!{ 98 | #[uuid(0x00000115, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] 99 | interface IOleInPlaceUIWindow(IOleInPlaceUIWindowVtbl) : 100 | IOleWindow(IOleWindowVtbl) 101 | { 102 | fn GetBorder(lprectBorder: LPRECT,) -> HRESULT, 103 | fn RequestBorderSpace( 104 | pborderwidths: LPCRECT,) -> HRESULT, 105 | fn SetBorderSpace( 106 | pborderwidths: LPCRECT,) -> HRESULT, 107 | fn SetActiveObject( 108 | pActiveObject: *mut IOleInPlaceActiveObject, 109 | pszObjName: LPCOLESTR,) -> HRESULT, 110 | } 111 | } 112 | 113 | RIDL!{ 114 | #[uuid(0x00000116, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] 115 | interface IOleInPlaceFrame(IOleInPlaceFrameVtbl) : 116 | IOleInPlaceUIWindow(IOleInPlaceUIWindowVtbl) 117 | { 118 | fn InsertMenus( 119 | hmenuShared: HMENU, 120 | lpMenuWidths: LPVOID,) -> HRESULT, 121 | fn SetMenu( 122 | hmenuShared: HMENU, 123 | holemenu: HGLOBAL, 124 | hwndActiveObject: HWND,) -> HRESULT, 125 | fn RemoveMenus( 126 | hmenuShared: HMENU,) -> HRESULT, 127 | fn SetStatusText( 128 | pszStatusText: LPCOLESTR,) -> HRESULT, 129 | fn EnableModeless( 130 | fEnable: BOOL,) -> HRESULT, 131 | fn TranslateAccelerator( 132 | lpmsg: LPMSG, 133 | wID: WORD,) -> HRESULT, 134 | } 135 | } 136 | 137 | STRUCT!{ 138 | struct OLEINPLACEFRAMEINFO { 139 | cb: UINT, 140 | fMDIApp: BOOL, 141 | hwndFrame: HWND, 142 | haccel: HACCEL, 143 | cAccelEntries: UINT, 144 | } 145 | } 146 | 147 | RIDL!{ 148 | #[uuid(0x00000119, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] 149 | interface IOleInPlaceSite(IOleInPlaceSiteVtbl) : IOleWindow(IOleWindowVtbl) { 150 | fn CanInPlaceActivate() -> HRESULT, 151 | fn OnInPlaceActivate() -> HRESULT, 152 | fn OnUIActivate() -> HRESULT, 153 | fn GetWindowContext( 154 | ppFrame: *mut *mut IOleInPlaceFrame, 155 | ppDoc: *mut *mut IOleInPlaceUIWindow, 156 | lprcPosRect: LPRECT, 157 | lprcClipRect: LPRECT, 158 | lpFrameInfo: *mut OLEINPLACEFRAMEINFO,) -> HRESULT, 159 | fn Scroll(scrollExtant: SIZE,) -> HRESULT, 160 | fn OnUIDeactivate(fUndoable: BOOL,) -> HRESULT, 161 | fn OnInPlaceDeactivate() -> HRESULT, 162 | fn DiscardUndoState() -> HRESULT, 163 | fn DeactivateAndUndo() -> HRESULT, 164 | fn OnPosRectChange(lprcPosRect: LPCRECT,) -> HRESULT, 165 | } 166 | } 167 | 168 | RIDL!{ 169 | #[uuid(0x00000113, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] 170 | interface IOleInPlaceObject(IOleInPlaceObjectVtbl) : IOleWindow(IOleWindowVtbl) { 171 | fn InPlaceDeactivate() -> HRESULT, 172 | fn UIDeactivate() -> HRESULT, 173 | fn SetObjectRects( 174 | lprcPosRect: LPCRECT, 175 | lprcClipRect: LPCRECT,) -> HRESULT, 176 | fn ReactivateAndUndo() -> HRESULT, 177 | } 178 | } 179 | 180 | RIDL!{ 181 | #[uuid(0xeab22ac1, 0x30c1, 0x11cf, 0xa7, 0xeb, 0x00, 0x00, 0xc0, 0x5b, 0xae, 0x0b)] 182 | interface IWebBrowser(IWebBrowserVtbl) : IDispatch(IDispatchVtbl) { 183 | fn Unused_GoBack() -> HRESULT, 184 | fn Unused_GoForward() -> HRESULT, 185 | fn Unused_GoHome() -> HRESULT, 186 | fn Unused_GoSearch() -> HRESULT, 187 | fn Navigate( 188 | url: BSTR, 189 | flags: *mut VARIANT, 190 | targetFrameName: *mut VARIANT, 191 | postData: *mut VARIANT, 192 | headers: *mut VARIANT,) -> HRESULT, 193 | fn Unused_Refresh() -> HRESULT, 194 | fn Unused_Refresh2() -> HRESULT, 195 | fn Unused_Stop() -> HRESULT, 196 | fn Unused_get_Application() -> HRESULT, 197 | fn Unused_get_Parent() -> HRESULT, 198 | fn Unused_get_Container() -> HRESULT, 199 | fn get_Document(ppDisp: *mut *mut IDispatch,) -> HRESULT, 200 | fn Unused_get_TopLevelContainer() -> HRESULT, 201 | fn Unused_get_Type() -> HRESULT, 202 | fn Unused_get_Left() -> HRESULT, 203 | fn Unused_put_Left() -> HRESULT, 204 | fn Unused_get_Top() -> HRESULT, 205 | fn Unused_put_Top() -> HRESULT, 206 | fn Unused_get_Width() -> HRESULT, 207 | fn put_Width(width: c_long,) -> HRESULT, 208 | fn Unused_get_Height() -> HRESULT, 209 | fn put_Height(height: c_long,) -> HRESULT, 210 | fn Unused_get_LocationName() -> HRESULT, 211 | fn Unused_get_LocationURL() -> HRESULT, 212 | fn Unused_get_Busy() -> HRESULT, 213 | } 214 | } 215 | 216 | RIDL!{ 217 | #[uuid(0x0002df05, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] 218 | interface IWebBrowserApp(IWebBrowserAppVtbl) : IWebBrowser(IWebBrowserVtbl) { 219 | fn Unused_Quit() -> HRESULT, 220 | fn Unused_ClientToWindow() -> HRESULT, 221 | fn Unused_PutProperty() -> HRESULT, 222 | fn Unused_GetProperty() -> HRESULT, 223 | fn Unused_get_Name() -> HRESULT, 224 | fn Unused_get_HWND() -> HRESULT, 225 | fn Unused_get_FullName() -> HRESULT, 226 | fn Unused_get_Path() -> HRESULT, 227 | fn Unused_get_Visible() -> HRESULT, 228 | fn put_Visible(value: VARIANT_BOOL,) -> HRESULT, 229 | fn Unused_get_StatusBar() -> HRESULT, 230 | fn Unused_put_StatusBar() -> HRESULT, 231 | fn Unused_get_StatusText() -> HRESULT, 232 | fn Unused_put_StatusText() -> HRESULT, 233 | fn Unused_get_ToolBar() -> HRESULT, 234 | fn Unused_put_ToolBar() -> HRESULT, 235 | fn Unused_get_MenuBar() -> HRESULT, 236 | fn Unused_put_MenuBar() -> HRESULT, 237 | fn Unused_get_FullScreen() -> HRESULT, 238 | fn Unused_put_FullScreen() -> HRESULT, 239 | } 240 | } 241 | 242 | RIDL!{ 243 | #[uuid(0xd30c1661, 0xcdaf, 0x11d0, 0x8a, 0x3e, 0x00, 0xc0, 0x4f, 0xc9, 0xe2, 0x6e)] 244 | interface IWebBrowser2(IWebBrowser2Vtbl) : IWebBrowserApp(IWebBrowserAppVtbl) { 245 | fn Unused_Navigate2() -> HRESULT, 246 | fn Unused_QueryStatusWB() -> HRESULT, 247 | fn Unused_ExecWB() -> HRESULT, 248 | fn Unused_ShowBrowserBar() -> HRESULT, 249 | fn Unused_get_ReadyState() -> HRESULT, 250 | fn Unused_get_Offline() -> HRESULT, 251 | fn Unused_put_Offline() -> HRESULT, 252 | fn Unused_get_Silent() -> HRESULT, 253 | fn Unused_put_Silent() -> HRESULT, 254 | fn Unused_get_RegisterAsBrowser() -> HRESULT, 255 | fn Unused_put_RegisterAsBrowser() -> HRESULT, 256 | fn Unused_get_RegisterAsDropTarget() -> HRESULT, 257 | fn Unused_put_RegisterAsDropTarget() -> HRESULT, 258 | fn Unused_get_TheaterMode() -> HRESULT, 259 | fn Unused_put_TheaterMode() -> HRESULT, 260 | fn Unused_get_AddressBar() -> HRESULT, 261 | fn Unused_put_AddressBar() -> HRESULT, 262 | fn Unused_get_Resizable() -> HRESULT, 263 | fn Unused_put_Resizable() -> HRESULT, 264 | } 265 | } 266 | 267 | DEFINE_GUID!{ 268 | CLSID_WebBrowser, 269 | 0x8856f961, 0x340a, 0x11d0, 0xa9, 0x6b, 0x00, 0xc0, 0x4f, 0xd7, 0x05, 0xa2} 270 | 271 | RIDL!{ 272 | #[uuid(0x7fd52380, 0x4e07, 0x101b, 0xae, 0x2d, 0x08, 0x00, 0x2b, 0x2e, 0xc7, 0x13)] 273 | interface IPersistStreamInit(IPersistStreamInitVtbl) : IPersist(IPersistVtbl) { 274 | fn IsDirty() -> HRESULT, 275 | fn Load(pStm: *mut IStream,) -> HRESULT, 276 | fn Save(pStm: *mut IStream, fClearDirty: BOOL,) -> HRESULT, 277 | fn GetSizeMax(pcbSize: *mut ULARGE_INTEGER,) -> HRESULT, 278 | fn InitNew() -> HRESULT, 279 | } 280 | } 281 | 282 | STRUCT!{ 283 | struct DOCHOSTUIINFO { 284 | cbSize: c_ulong, 285 | dwFlags: DWORD, 286 | dwDoubleClick: DWORD, 287 | pchHostCss: *mut OLECHAR, 288 | pchHostNS: *mut OLECHAR, 289 | } 290 | } 291 | 292 | RIDL!{ 293 | #[uuid(0xbd3f23c0, 0xd43e, 0x11cf, 0x89, 0x3b, 0x00, 0xaa, 0x00, 0xbd, 0xce, 0x1a)] 294 | interface IDocHostUIHandler(IDocHostUIHandlerVtbl) : IUnknown(IUnknownVtbl) { 295 | fn ShowContextMenu( 296 | dwID: DWORD, 297 | ppt: *mut POINT, 298 | pcmdtReserved: *mut IUnknown, 299 | pdispReserved: *mut IDispatch,) -> HRESULT, 300 | fn GetHostInfo(pInfo: *mut DOCHOSTUIINFO,) -> HRESULT, 301 | fn ShowUI( 302 | dwID: DWORD, 303 | pActiveObject: *mut IOleInPlaceActiveObject, 304 | pCommandTarget: *mut IOleCommandTarget, 305 | pFrame: *mut IOleInPlaceFrame, 306 | pDoc: *mut IOleInPlaceUIWindow,) -> HRESULT, 307 | fn HideUI() -> HRESULT, 308 | fn UpdateUI() -> HRESULT, 309 | fn EnableModeless(fEnable: BOOL,) -> HRESULT, 310 | fn OnDocWindowActivate(fActivate: BOOL,) -> HRESULT, 311 | fn OnFrameWindowActivate(fActivate: BOOL,) -> HRESULT, 312 | fn ResizeBorder( 313 | prcBorder: LPCRECT, 314 | pUIWindow: *mut IOleInPlaceUIWindow, 315 | fRameWindow: BOOL,) -> HRESULT, 316 | fn TranslateAccelerator( 317 | lpMsg: LPMSG, 318 | pguidCmdGroup: *const GUID, 319 | nCmdID: DWORD,) -> HRESULT, 320 | fn GetOptionKeyPath( 321 | pchKey: *mut LPOLESTR, 322 | dw: DWORD,) -> HRESULT, 323 | fn GetDropTarget( 324 | pDropTarget: *mut IDropTarget, 325 | ppDropTarget: *mut *mut IDropTarget,) -> HRESULT, 326 | fn GetExternal( 327 | ppDispatch: *mut *mut IDispatch,) -> HRESULT, 328 | fn TranslateUrl( 329 | dwTranslate: DWORD, 330 | pchURLIn: LPWSTR, 331 | ppchURLOut: *mut LPWSTR,) -> HRESULT, 332 | fn FilterDataObject( 333 | pDO: *mut IDataObject, 334 | ppDORet: *mut *mut IDataObject,) -> HRESULT, 335 | } 336 | } 337 | 338 | RIDL!{ 339 | #[uuid(0x626fc520, 0xa41e, 0x11cf, 0xa7, 0x31, 0x00, 0xa0, 0xc9, 0x08, 0x26, 0x37)] 340 | interface IHTMLDocument(IHTMLDocumentVtbl) : IDispatch(IDispatchVtbl) { 341 | fn Unused_get_Script() -> HRESULT, 342 | } 343 | } 344 | 345 | RIDL!{ 346 | #[uuid(0x332c4425, 0x26cb, 0x11d0, 0xb4, 0x83, 0x00, 0xc0, 0x4f, 0xd9, 0x01, 0x19)] 347 | interface IHTMLDocument2(IHTMLDocument2Vtbl) : IHTMLDocument(IHTMLDocumentVtbl) { 348 | fn Unused_get_all() -> HRESULT, 349 | fn Unused_get_body() -> HRESULT, 350 | fn Unused_get_activeElement() -> HRESULT, 351 | fn Unused_get_images() -> HRESULT, 352 | fn Unused_get_applets() -> HRESULT, 353 | fn Unused_get_links() -> HRESULT, 354 | fn Unused_get_forms() -> HRESULT, 355 | fn Unused_get_anchors() -> HRESULT, 356 | fn Unused_put_title() -> HRESULT, 357 | fn Unused_get_title() -> HRESULT, 358 | fn Unused_get_scripts() -> HRESULT, 359 | fn Unused_put_designMode() -> HRESULT, 360 | fn Unused_get_designMode() -> HRESULT, 361 | fn Unused_get_selection() -> HRESULT, 362 | fn Unused_get_readyState() -> HRESULT, 363 | fn Unused_get_frames() -> HRESULT, 364 | fn Unused_get_embeds() -> HRESULT, 365 | fn Unused_get_plugins() -> HRESULT, 366 | fn Unused_put_alinkColor() -> HRESULT, 367 | fn Unused_get_alinkColor() -> HRESULT, 368 | fn Unused_put_bgColor() -> HRESULT, 369 | fn Unused_get_bgColor() -> HRESULT, 370 | fn Unused_put_fgColor() -> HRESULT, 371 | fn Unused_get_fgColor() -> HRESULT, 372 | fn Unused_put_linkColor() -> HRESULT, 373 | fn Unused_get_linkColor() -> HRESULT, 374 | fn Unused_put_vlinkColor() -> HRESULT, 375 | fn Unused_get_vlinkColor() -> HRESULT, 376 | fn Unused_get_referrer() -> HRESULT, 377 | fn Unused_get_location() -> HRESULT, 378 | fn Unused_get_lastModified() -> HRESULT, 379 | fn Unused_put_URL() -> HRESULT, 380 | fn Unused_get_URL() -> HRESULT, 381 | fn Unused_put_domain() -> HRESULT, 382 | fn Unused_get_domain() -> HRESULT, 383 | fn Unused_put_cookie() -> HRESULT, 384 | fn Unused_get_cookie() -> HRESULT, 385 | fn Unused_put_expando() -> HRESULT, 386 | fn Unused_get_expando() -> HRESULT, 387 | fn Unused_put_charset() -> HRESULT, 388 | fn Unused_get_charset() -> HRESULT, 389 | fn Unused_put_defaultCharset() -> HRESULT, 390 | fn Unused_get_defaultCharset() -> HRESULT, 391 | fn Unused_get_mimeType() -> HRESULT, 392 | fn Unused_get_fileSize() -> HRESULT, 393 | fn Unused_get_fileCreatedDate() -> HRESULT, 394 | fn Unused_get_fileModifiedDate() -> HRESULT, 395 | fn Unused_get_fileUpdatedDate() -> HRESULT, 396 | fn Unused_get_security() -> HRESULT, 397 | fn Unused_get_protocol() -> HRESULT, 398 | fn Unused_get_nameProp() -> HRESULT, 399 | fn Unused_write() -> HRESULT, 400 | fn Unused_writeln() -> HRESULT, 401 | fn Unused_open() -> HRESULT, 402 | fn Unused_close() -> HRESULT, 403 | fn Unused_clear() -> HRESULT, 404 | fn Unused_queryCommandSupported() -> HRESULT, 405 | fn Unused_queryCommandEnabled() -> HRESULT, 406 | fn Unused_queryCommandState() -> HRESULT, 407 | fn Unused_queryCommandIndeterm() -> HRESULT, 408 | fn Unused_queryCommandText() -> HRESULT, 409 | fn Unused_queryCommandValue() -> HRESULT, 410 | fn Unused_execCommand() -> HRESULT, 411 | fn Unused_execCommandShowHelp() -> HRESULT, 412 | fn Unused_createElement() -> HRESULT, 413 | fn Unused_put_onhelp() -> HRESULT, 414 | fn Unused_get_onhelp() -> HRESULT, 415 | fn Unused_put_onclick() -> HRESULT, 416 | fn Unused_get_onclick() -> HRESULT, 417 | fn Unused_put_ondblclick() -> HRESULT, 418 | fn Unused_get_ondblclick() -> HRESULT, 419 | fn Unused_put_onkeyup() -> HRESULT, 420 | fn Unused_get_onkeyup() -> HRESULT, 421 | fn Unused_put_onkeydown() -> HRESULT, 422 | fn Unused_get_onkeydown() -> HRESULT, 423 | fn Unused_put_onkeypress() -> HRESULT, 424 | fn Unused_get_onkeypress() -> HRESULT, 425 | fn Unused_put_onmouseup() -> HRESULT, 426 | fn Unused_get_onmouseup() -> HRESULT, 427 | fn Unused_put_onmousedown() -> HRESULT, 428 | fn Unused_get_onmousedown() -> HRESULT, 429 | fn Unused_put_onmousemove() -> HRESULT, 430 | fn Unused_get_onmousemove() -> HRESULT, 431 | fn Unused_put_onmouseout() -> HRESULT, 432 | fn Unused_get_onmouseout() -> HRESULT, 433 | fn Unused_put_onmouseover() -> HRESULT, 434 | fn Unused_get_onmouseover() -> HRESULT, 435 | fn Unused_put_onreadystatechange() -> HRESULT, 436 | fn Unused_get_onreadystatechange() -> HRESULT, 437 | fn Unused_put_onafterupdate() -> HRESULT, 438 | fn Unused_get_onafterupdate() -> HRESULT, 439 | fn Unused_put_onrowexit() -> HRESULT, 440 | fn Unused_get_onrowexit() -> HRESULT, 441 | fn Unused_put_onrowenter() -> HRESULT, 442 | fn Unused_get_onrowenter() -> HRESULT, 443 | fn Unused_put_ondragstart() -> HRESULT, 444 | fn Unused_get_ondragstart() -> HRESULT, 445 | fn Unused_put_onselectstart() -> HRESULT, 446 | fn Unused_get_onselectstart() -> HRESULT, 447 | fn Unused_elementFromPoint() -> HRESULT, 448 | fn get_parentWindow(p: *mut *mut IHTMLWindow2,) -> HRESULT, 449 | fn Unused_get_styleSheets() -> HRESULT, 450 | fn Unused_put_onbeforeupdate() -> HRESULT, 451 | fn Unused_get_onbeforeupdate() -> HRESULT, 452 | fn Unused_put_onerrorupdate() -> HRESULT, 453 | fn Unused_get_onerrorupdate() -> HRESULT, 454 | fn Unused_toString() -> HRESULT, 455 | fn Unused_createStyleSheet() -> HRESULT, 456 | } 457 | } 458 | -------------------------------------------------------------------------------- /src/win32/client_site.rs: -------------------------------------------------------------------------------- 1 | use std::boxed::Box; 2 | use std::ptr::null_mut; 3 | use std::rc::Rc; 4 | 5 | // Non-asterisk imports are required to eliminate ambiguity 6 | use winapi::Interface; 7 | use winapi::ctypes::*; 8 | use winapi::shared::guiddef::*; 9 | use winapi::shared::minwindef::*; 10 | use winapi::shared::minwindef::ULONG; 11 | use winapi::shared::ntdef::LPWSTR; 12 | use winapi::shared::windef::*; 13 | use winapi::shared::windef::SIZE; 14 | use winapi::shared::winerror::*; 15 | use winapi::shared::wtypesbase::*; 16 | use winapi::shared::wtypes::VT_BSTR; 17 | use winapi::um::oaidl::*; 18 | use winapi::um::oaidl::DISPID; 19 | use winapi::um::objidl::IMoniker; 20 | use winapi::um::oleauto::*; 21 | use winapi::um::unknwnbase::*; 22 | use winapi::um::winbase::*; 23 | use winapi::um::winnt::LCID; 24 | use winapi::um::winuser::*; 25 | 26 | use lib::JavascriptCallback; 27 | use win32::com_pointer::ComPointer; 28 | use win32::ffi::*; 29 | 30 | #[repr(C, packed)] 31 | struct ClientSite { 32 | ole_client_site: IOleClientSite, 33 | ole_in_place_site: IOleInPlaceSite, 34 | doc_host_ui_handler: IDocHostUIHandler, 35 | dispatch: IDispatch, 36 | ole_in_place_frame: ComPointer, 37 | ole_in_place_object: ComPointer, 38 | reference_counter: ULONG, 39 | window: HWND, 40 | callback: Rc, 41 | } 42 | 43 | impl ClientSite { 44 | fn from_ole_in_place_site( 45 | instance: *mut IOleInPlaceSite) -> *mut ClientSite 46 | { 47 | ClientSite::from_member_and_offset( 48 | instance as *mut u8, offset_of!(ClientSite, ole_in_place_site)) 49 | } 50 | 51 | fn from_doc_host_ui_handler( 52 | instance: *mut IDocHostUIHandler) -> *mut ClientSite 53 | { 54 | ClientSite::from_member_and_offset( 55 | instance as *mut u8, offset_of!(ClientSite, doc_host_ui_handler)) 56 | } 57 | 58 | fn from_dispatch( 59 | instance: *mut IDispatch) -> *mut ClientSite 60 | { 61 | ClientSite::from_member_and_offset( 62 | instance as *mut u8, offset_of!(ClientSite, dispatch)) 63 | } 64 | 65 | fn from_member_and_offset( 66 | member: *mut u8, offset: usize) -> *mut ClientSite 67 | { 68 | unsafe { 69 | member.offset(-(offset as isize)) as *mut ClientSite 70 | } 71 | } 72 | } 73 | 74 | const OLE_CLIENT_SITE_VTABLE: IOleClientSiteVtbl = IOleClientSiteVtbl { 75 | parent: IUnknownVtbl { 76 | AddRef: IOleClientSite_AddRef, 77 | Release: IOleClientSite_Release, 78 | QueryInterface: IOleClientSite_QueryInterface, 79 | }, 80 | SaveObject: IOleClientSite_SaveObject, 81 | GetMoniker: IOleClientSite_GetMoniker, 82 | GetContainer: IOleClientSite_GetContainer, 83 | ShowObject: IOleClientSite_ShowObject, 84 | OnShowWindow: IOleClientSite_OnShowWindow, 85 | RequestNewObjectLayout: IOleClientSite_RequestNewObjectLayout, 86 | }; 87 | 88 | const OLE_IN_PLACE_SITE_VTABLE: IOleInPlaceSiteVtbl = IOleInPlaceSiteVtbl { 89 | parent: IOleWindowVtbl { 90 | parent: IUnknownVtbl { 91 | AddRef: IOleInPlaceSite_AddRef, 92 | Release: IOleInPlaceSite_Release, 93 | QueryInterface: IOleInPlaceSite_QueryInterface, 94 | }, 95 | GetWindow: IOleInPlaceSite_GetWindow, 96 | ContextSensitiveHelp: IOleInPlaceSite_ContextSensitiveHelp, 97 | }, 98 | CanInPlaceActivate: IOleInPlaceSite_CanInPlaceActivate, 99 | OnInPlaceActivate: IOleInPlaceSite_OnInPlaceActivate, 100 | OnUIActivate: IOleInPlaceSite_OnUIActivate, 101 | GetWindowContext: IOleInPlaceSite_GetWindowContext, 102 | Scroll: IOleInPlaceSite_Scroll, 103 | OnUIDeactivate: IOleInPlaceSite_OnUIDeactivate, 104 | OnInPlaceDeactivate: IOleInPlaceSite_OnInPlaceDeactivate, 105 | DiscardUndoState: IOleInPlaceSite_DiscardUndoState, 106 | DeactivateAndUndo: IOleInPlaceSite_DeactivateAndUndo, 107 | OnPosRectChange: IOleInPlaceSite_OnPosRectChange, 108 | }; 109 | 110 | const DOC_HOST_UI_HANDLER_VTABLE: IDocHostUIHandlerVtbl = 111 | IDocHostUIHandlerVtbl { 112 | parent: IUnknownVtbl { 113 | AddRef: IDocHostUIHandler_AddRef, 114 | Release: IDocHostUIHandler_Release, 115 | QueryInterface: IDocHostUIHandler_QueryInterface, 116 | }, 117 | ShowContextMenu: IDocHostUIHandler_ShowContextMenu, 118 | GetHostInfo: IDocHostUIHandler_GetHostInfo, 119 | ShowUI: IDocHostUIHandler_ShowUI, 120 | HideUI: IDocHostUIHandler_HideUI, 121 | UpdateUI: IDocHostUIHandler_UpdateUI, 122 | EnableModeless: IDocHostUIHandler_EnableModeless, 123 | OnDocWindowActivate: IDocHostUIHandler_OnDocWindowActivate, 124 | OnFrameWindowActivate: IDocHostUIHandler_OnFrameWindowActivate, 125 | ResizeBorder: IDocHostUIHandler_ResizeBorder, 126 | TranslateAccelerator: IDocHostUIHandler_TranslateAccelerator, 127 | GetOptionKeyPath: IDocHostUIHandler_GetOptionKeyPath, 128 | GetDropTarget: IDocHostUIHandler_GetDropTarget, 129 | GetExternal: IDocHostUIHandler_GetExternal, 130 | TranslateUrl: IDocHostUIHandler_TranslateUrl, 131 | FilterDataObject: IDocHostUIHandler_FilterDataObject, 132 | }; 133 | 134 | const DISPATCH_VTABLE: IDispatchVtbl = IDispatchVtbl { 135 | parent: IUnknownVtbl { 136 | AddRef: IDispatch_AddRef, 137 | Release: IDispatch_Release, 138 | QueryInterface: IDispatch_QueryInterface, 139 | }, 140 | GetTypeInfoCount: IDispatch_GetTypeInfoCount, 141 | GetTypeInfo: IDispatch_GetTypeInfo, 142 | GetIDsOfNames: IDispatch_GetIDsOfNames, 143 | Invoke: IDispatch_Invoke, 144 | }; 145 | 146 | pub fn new_client_site( 147 | window: HWND, 148 | ole_in_place_object: ComPointer, 149 | callback: Rc) -> ComPointer 150 | { 151 | let client_site = Box::new( 152 | ClientSite { 153 | ole_client_site: IOleClientSite { 154 | lpVtbl: &OLE_CLIENT_SITE_VTABLE 155 | }, 156 | ole_in_place_site: IOleInPlaceSite { 157 | lpVtbl: &OLE_IN_PLACE_SITE_VTABLE 158 | }, 159 | doc_host_ui_handler: IDocHostUIHandler { 160 | lpVtbl: &DOC_HOST_UI_HANDLER_VTABLE 161 | }, 162 | dispatch: IDispatch { 163 | lpVtbl: &DISPATCH_VTABLE, 164 | }, 165 | ole_in_place_frame: new_in_place_frame(window), 166 | ole_in_place_object: ole_in_place_object, 167 | reference_counter: 1, 168 | window: window, 169 | callback: callback, 170 | }); 171 | 172 | ComPointer::from_raw(Box::into_raw(client_site) as *mut IOleClientSite) 173 | } 174 | 175 | unsafe extern "system" fn IOleClientSite_AddRef( 176 | instance: *mut IUnknown) -> ULONG 177 | { 178 | let client_site = instance as *mut ClientSite; 179 | 180 | (*client_site).reference_counter += 1; 181 | (*client_site).reference_counter 182 | } 183 | 184 | unsafe extern "system" fn IOleClientSite_Release( 185 | instance: *mut IUnknown) -> ULONG 186 | { 187 | let client_site = instance as *mut ClientSite; 188 | 189 | let result = { 190 | (*client_site).reference_counter -= 1; 191 | (*client_site).reference_counter 192 | }; 193 | 194 | assert!(result != ULONG::max_value()); 195 | 196 | if result == 0 { 197 | Box::from_raw(client_site); 198 | } 199 | 200 | result 201 | } 202 | 203 | unsafe extern "system" fn IOleClientSite_QueryInterface( 204 | instance: *mut IUnknown, 205 | riid: REFIID, 206 | ppvObject: *mut *mut c_void) -> HRESULT 207 | { 208 | let client_site = instance as *mut ClientSite; 209 | 210 | *ppvObject = if IsEqualGUID(&*riid, &IUnknown::uuidof()) { 211 | client_site as *mut c_void 212 | } else if IsEqualGUID(&*riid, &IOleClientSite::uuidof()) { 213 | client_site as *mut c_void 214 | } else if IsEqualGUID(&*riid, &IOleInPlaceSite::uuidof()) { 215 | &mut (*client_site).ole_in_place_site 216 | as *mut IOleInPlaceSite 217 | as *mut c_void 218 | } else if IsEqualGUID(&*riid, &IOleWindow::uuidof()) { 219 | &mut (*client_site).ole_in_place_site 220 | as *mut IOleInPlaceSite 221 | as *mut c_void 222 | } else if IsEqualGUID(&*riid, &IDocHostUIHandler::uuidof()) { 223 | &mut (*client_site).doc_host_ui_handler 224 | as *mut IDocHostUIHandler 225 | as *mut c_void 226 | } else if IsEqualGUID(&*riid, &IDispatch::uuidof()) { 227 | &mut (*client_site).dispatch 228 | as *mut IDispatch 229 | as *mut c_void 230 | } else { 231 | null_mut() 232 | }; 233 | 234 | if *ppvObject != null_mut() { 235 | (*instance).AddRef(); 236 | S_OK 237 | } else { 238 | E_NOINTERFACE 239 | } 240 | } 241 | 242 | unsafe extern "system" fn IOleClientSite_SaveObject( 243 | _instance: *mut IOleClientSite) -> HRESULT 244 | { 245 | S_OK 246 | } 247 | 248 | unsafe extern "system" fn IOleClientSite_GetMoniker( 249 | _instance: *mut IOleClientSite, 250 | _dwAssign: DWORD, 251 | _dwWhichMoniker: DWORD, 252 | ppmk: *mut *mut IMoniker,) -> HRESULT 253 | { 254 | *ppmk = null_mut(); 255 | E_NOTIMPL 256 | } 257 | 258 | unsafe extern "system" fn IOleClientSite_GetContainer( 259 | _instance: *mut IOleClientSite, 260 | ppContainer: *mut *mut IOleContainer) -> HRESULT 261 | { 262 | *ppContainer = null_mut(); 263 | E_NOINTERFACE 264 | } 265 | 266 | unsafe extern "system" fn IOleClientSite_ShowObject( 267 | _instance: *mut IOleClientSite) -> HRESULT 268 | { 269 | S_OK 270 | } 271 | 272 | unsafe extern "system" fn IOleClientSite_OnShowWindow( 273 | _instance: *mut IOleClientSite, _fShow: BOOL) -> HRESULT 274 | { 275 | S_OK 276 | } 277 | 278 | unsafe extern "system" fn IOleClientSite_RequestNewObjectLayout( 279 | _instance: *mut IOleClientSite) -> HRESULT 280 | { 281 | E_NOTIMPL 282 | } 283 | 284 | unsafe extern "system" fn IOleInPlaceSite_AddRef( 285 | instance: *mut IUnknown) -> ULONG 286 | { 287 | let client_site = ClientSite::from_ole_in_place_site( 288 | instance as *mut IOleInPlaceSite); 289 | 290 | (*client_site).ole_client_site.AddRef() 291 | } 292 | 293 | unsafe extern "system" fn IOleInPlaceSite_Release( 294 | instance: *mut IUnknown) -> ULONG 295 | { 296 | let client_site = ClientSite::from_ole_in_place_site( 297 | instance as *mut IOleInPlaceSite); 298 | 299 | (*client_site).ole_client_site.Release() 300 | } 301 | 302 | unsafe extern "system" fn IOleInPlaceSite_QueryInterface( 303 | instance: *mut IUnknown, 304 | riid: REFIID, 305 | ppvObject: *mut *mut c_void) -> HRESULT 306 | { 307 | let client_site = ClientSite::from_ole_in_place_site( 308 | instance as *mut IOleInPlaceSite); 309 | 310 | (*client_site).ole_client_site.QueryInterface(riid, ppvObject) 311 | } 312 | 313 | unsafe extern "system" fn IOleInPlaceSite_GetWindow( 314 | instance: *mut IOleWindow, 315 | phwnd: *mut HWND) -> HRESULT 316 | { 317 | let client_site = ClientSite::from_ole_in_place_site( 318 | instance as *mut IOleInPlaceSite); 319 | 320 | *phwnd = (*client_site).window; 321 | S_OK 322 | } 323 | 324 | unsafe extern "system" fn IOleInPlaceSite_ContextSensitiveHelp( 325 | _instance: *mut IOleWindow, 326 | _fEnterMode: BOOL) -> HRESULT 327 | { 328 | S_OK 329 | } 330 | 331 | unsafe extern "system" fn IOleInPlaceSite_CanInPlaceActivate( 332 | _instance: *mut IOleInPlaceSite) -> HRESULT 333 | { 334 | S_OK 335 | } 336 | 337 | unsafe extern "system" fn IOleInPlaceSite_OnInPlaceActivate( 338 | _instance: *mut IOleInPlaceSite) -> HRESULT 339 | { 340 | S_OK 341 | } 342 | 343 | unsafe extern "system" fn IOleInPlaceSite_OnUIActivate( 344 | _instance: *mut IOleInPlaceSite) -> HRESULT 345 | { 346 | S_OK 347 | } 348 | 349 | unsafe extern "system" fn IOleInPlaceSite_GetWindowContext( 350 | instance: *mut IOleInPlaceSite, 351 | ppFrame: *mut *mut IOleInPlaceFrame, 352 | ppDoc: *mut *mut IOleInPlaceUIWindow, 353 | _lprcPosRect: LPRECT, 354 | _lprcClipRect: LPRECT, 355 | lpFrameInfo: *mut OLEINPLACEFRAMEINFO) -> HRESULT 356 | { 357 | let client_site = ClientSite::from_ole_in_place_site(instance); 358 | 359 | *ppFrame = (*client_site).ole_in_place_frame.as_ptr(); 360 | (**ppFrame).AddRef(); 361 | 362 | *ppDoc = null_mut(); 363 | 364 | // TODO: set rectangles 365 | 366 | (*lpFrameInfo).fMDIApp = FALSE; 367 | (*lpFrameInfo).hwndFrame = (*client_site).window; 368 | (*lpFrameInfo).haccel = null_mut(); 369 | (*lpFrameInfo).cAccelEntries = 0; 370 | 371 | S_OK 372 | } 373 | 374 | unsafe extern "system" fn IOleInPlaceSite_Scroll( 375 | _instance: *mut IOleInPlaceSite, 376 | _scrollExtant: SIZE) -> HRESULT 377 | { 378 | S_OK 379 | } 380 | 381 | unsafe extern "system" fn IOleInPlaceSite_OnUIDeactivate( 382 | _instance: *mut IOleInPlaceSite, 383 | _fUndoable: BOOL) -> HRESULT 384 | { 385 | S_OK 386 | } 387 | 388 | unsafe extern "system" fn IOleInPlaceSite_OnInPlaceDeactivate( 389 | _instance: *mut IOleInPlaceSite) -> HRESULT 390 | { 391 | S_OK 392 | } 393 | 394 | unsafe extern "system" fn IOleInPlaceSite_DiscardUndoState( 395 | _instance: *mut IOleInPlaceSite) -> HRESULT 396 | { 397 | S_OK 398 | } 399 | 400 | unsafe extern "system" fn IOleInPlaceSite_DeactivateAndUndo( 401 | _instance: *mut IOleInPlaceSite) -> HRESULT 402 | { 403 | S_OK 404 | } 405 | 406 | unsafe extern "system" fn IOleInPlaceSite_OnPosRectChange( 407 | instance: *mut IOleInPlaceSite, 408 | lprcPosRect: LPCRECT) -> HRESULT 409 | { 410 | let client_site = ClientSite::from_ole_in_place_site(instance); 411 | 412 | (*client_site) 413 | .ole_in_place_object 414 | .get() 415 | .map(|ole_in_place_object| { 416 | ole_in_place_object.SetObjectRects( 417 | lprcPosRect, 418 | lprcPosRect); 419 | }); 420 | 421 | S_OK 422 | } 423 | 424 | unsafe extern "system" fn IDocHostUIHandler_AddRef( 425 | instance: *mut IUnknown) -> ULONG 426 | { 427 | let client_site = ClientSite::from_doc_host_ui_handler( 428 | instance as *mut IDocHostUIHandler); 429 | 430 | (*client_site).ole_client_site.AddRef() 431 | } 432 | 433 | unsafe extern "system" fn IDocHostUIHandler_Release( 434 | instance: *mut IUnknown) -> ULONG 435 | { 436 | let client_site = ClientSite::from_doc_host_ui_handler( 437 | instance as *mut IDocHostUIHandler); 438 | 439 | (*client_site).ole_client_site.Release() 440 | } 441 | 442 | unsafe extern "system" fn IDocHostUIHandler_QueryInterface( 443 | instance: *mut IUnknown, 444 | riid: REFIID, 445 | ppvObject: *mut *mut c_void) -> HRESULT 446 | { 447 | let client_site = ClientSite::from_doc_host_ui_handler( 448 | instance as *mut IDocHostUIHandler); 449 | 450 | (*client_site).ole_client_site.QueryInterface(riid, ppvObject) 451 | } 452 | 453 | unsafe extern "system" fn IDocHostUIHandler_ShowContextMenu( 454 | _instance: *mut IDocHostUIHandler, 455 | dwID: DWORD, 456 | _ppt: *mut POINT, 457 | _pcmdtReserved: *mut IUnknown, 458 | _pdispReserved: *mut IDispatch) -> HRESULT 459 | { 460 | const CONTEXT_MENU_CONTROL: DWORD = 0x2; 461 | const CONTEXT_MENU_TEXTSELECT: DWORD = 0x4; 462 | const CONTEXT_MENU_VSCROLL: DWORD = 0x9; 463 | const CONTEXT_MENU_HSCROLL: DWORD = 0x10; 464 | 465 | match dwID { 466 | CONTEXT_MENU_CONTROL | 467 | CONTEXT_MENU_TEXTSELECT | 468 | CONTEXT_MENU_VSCROLL | 469 | CONTEXT_MENU_HSCROLL => S_FALSE, 470 | _ => S_OK 471 | } 472 | } 473 | 474 | unsafe extern "system" fn IDocHostUIHandler_GetHostInfo( 475 | _instance: *mut IDocHostUIHandler, 476 | pInfo: *mut DOCHOSTUIINFO) -> HRESULT 477 | { 478 | const DOCHOSTUIFLAG_NO3DBORDER: DWORD = 0x00000004; 479 | const DOCHOSTUIFLAG_ENABLE_INPLACE_NAVIGATION: DWORD = 0x00010000; 480 | const DOCHOSTUIFLAG_THEME: DWORD = 0x00040000; 481 | const DOCHOSTUIFLAG_DPI_AWARE: DWORD = 0x40000000; 482 | 483 | (*pInfo).dwFlags = 484 | DOCHOSTUIFLAG_NO3DBORDER | 485 | DOCHOSTUIFLAG_ENABLE_INPLACE_NAVIGATION | 486 | DOCHOSTUIFLAG_THEME | 487 | DOCHOSTUIFLAG_DPI_AWARE; 488 | (*pInfo).dwDoubleClick = 0; 489 | 490 | S_OK 491 | } 492 | 493 | unsafe extern "system" fn IDocHostUIHandler_ShowUI( 494 | _instance: *mut IDocHostUIHandler, 495 | _dwID: DWORD, 496 | _pActiveObject: *mut IOleInPlaceActiveObject, 497 | _pCommandTarget: *mut IOleCommandTarget, 498 | _pFrame: *mut IOleInPlaceFrame, 499 | _pDoc: *mut IOleInPlaceUIWindow) -> HRESULT 500 | { 501 | S_OK 502 | } 503 | 504 | unsafe extern "system" fn IDocHostUIHandler_HideUI( 505 | _instance: *mut IDocHostUIHandler) -> HRESULT 506 | { 507 | S_OK 508 | } 509 | 510 | unsafe extern "system" fn IDocHostUIHandler_UpdateUI( 511 | _instance: *mut IDocHostUIHandler) -> HRESULT 512 | { 513 | S_OK 514 | } 515 | 516 | unsafe extern "system" fn IDocHostUIHandler_EnableModeless( 517 | _instance: *mut IDocHostUIHandler, 518 | _fEnable: BOOL) -> HRESULT 519 | { 520 | S_OK 521 | } 522 | 523 | unsafe extern "system" fn IDocHostUIHandler_OnDocWindowActivate( 524 | _instance: *mut IDocHostUIHandler, 525 | _fActivate: BOOL) -> HRESULT 526 | { 527 | S_OK 528 | } 529 | 530 | unsafe extern "system" fn IDocHostUIHandler_OnFrameWindowActivate( 531 | _instance: *mut IDocHostUIHandler, 532 | _fActivate: BOOL) -> HRESULT 533 | { 534 | S_OK 535 | } 536 | 537 | unsafe extern "system" fn IDocHostUIHandler_ResizeBorder( 538 | _instance: *mut IDocHostUIHandler, 539 | _prcBorder: LPCRECT, 540 | _pUIWindow: *mut IOleInPlaceUIWindow, 541 | _fRameWindow: BOOL) -> HRESULT 542 | { 543 | S_OK 544 | } 545 | 546 | unsafe extern "system" fn IDocHostUIHandler_TranslateAccelerator( 547 | _instance: *mut IDocHostUIHandler, 548 | _lpMsg: LPMSG, 549 | _pguidCmdGroup: *const GUID, 550 | _nCmdID: DWORD) -> HRESULT 551 | { 552 | S_FALSE 553 | } 554 | 555 | unsafe extern "system" fn IDocHostUIHandler_GetOptionKeyPath( 556 | _instance: *mut IDocHostUIHandler, 557 | pchKey: *mut LPOLESTR, 558 | _dw: DWORD) -> HRESULT 559 | { 560 | *pchKey = null_mut(); 561 | S_FALSE 562 | } 563 | 564 | unsafe extern "system" fn IDocHostUIHandler_GetDropTarget( 565 | _instance: *mut IDocHostUIHandler, 566 | _pDropTarget: *mut IDropTarget, 567 | _ppDropTarget: *mut *mut IDropTarget) -> HRESULT 568 | { 569 | E_NOTIMPL 570 | } 571 | 572 | unsafe extern "system" fn IDocHostUIHandler_GetExternal( 573 | instance: *mut IDocHostUIHandler, 574 | ppDispatch: *mut *mut IDispatch) -> HRESULT 575 | { 576 | let client_site = ClientSite::from_doc_host_ui_handler(instance); 577 | 578 | (*client_site).ole_client_site.QueryInterface( 579 | &IDispatch::uuidof(), ppDispatch as *mut *mut c_void); 580 | S_OK 581 | } 582 | 583 | unsafe extern "system" fn IDocHostUIHandler_TranslateUrl( 584 | _instance: *mut IDocHostUIHandler, 585 | _dwTranslate: DWORD, 586 | _pchURLIn: LPWSTR, 587 | ppchURLOut: *mut LPWSTR) -> HRESULT 588 | { 589 | *ppchURLOut = null_mut(); 590 | S_FALSE 591 | } 592 | 593 | unsafe extern "system" fn IDocHostUIHandler_FilterDataObject( 594 | _instance: *mut IDocHostUIHandler, 595 | _pDO: *mut IDataObject, 596 | ppDORet: *mut *mut IDataObject) -> HRESULT 597 | { 598 | *ppDORet = null_mut(); 599 | S_FALSE 600 | } 601 | 602 | unsafe extern "system" fn IDispatch_AddRef( 603 | instance: *mut IUnknown) -> ULONG 604 | { 605 | let client_site = ClientSite::from_dispatch( 606 | instance as *mut IDispatch); 607 | 608 | (*client_site).ole_client_site.AddRef() 609 | } 610 | 611 | unsafe extern "system" fn IDispatch_Release( 612 | instance: *mut IUnknown) -> ULONG 613 | { 614 | let client_site = ClientSite::from_dispatch( 615 | instance as *mut IDispatch); 616 | 617 | (*client_site).ole_client_site.Release() 618 | } 619 | 620 | unsafe extern "system" fn IDispatch_QueryInterface( 621 | instance: *mut IUnknown, 622 | riid: REFIID, 623 | ppvObject: *mut *mut c_void) -> HRESULT 624 | { 625 | let client_site = ClientSite::from_dispatch( 626 | instance as *mut IDispatch); 627 | 628 | (*client_site).ole_client_site.QueryInterface(riid, ppvObject) 629 | } 630 | 631 | unsafe extern "system" fn IDispatch_GetTypeInfoCount( 632 | _instance: *mut IDispatch, 633 | pctinfo: *mut UINT) -> HRESULT 634 | { 635 | *pctinfo = 0; 636 | S_OK 637 | } 638 | 639 | unsafe extern "system" fn IDispatch_GetTypeInfo( 640 | _instance: *mut IDispatch, 641 | _iTInfo: UINT, 642 | _lcid: LCID, 643 | ppTInfo: *mut *mut ITypeInfo) -> HRESULT 644 | { 645 | *ppTInfo = null_mut(); 646 | S_FALSE 647 | } 648 | 649 | unsafe extern "system" fn IDispatch_GetIDsOfNames( 650 | _instance: *mut IDispatch, 651 | _riid: REFIID, 652 | rgszNames: *mut LPOLESTR, 653 | cNames: UINT, 654 | _lcid: LCID, 655 | rgDispId: *mut DISPID) -> HRESULT 656 | { 657 | for index in 0..cNames { 658 | *rgDispId.offset(index as isize) = DISPID_UNKNOWN; 659 | } 660 | 661 | // The "invoke" string encoded in utf16. 662 | const METHOD_NAME: [u16; 7] = [105, 110, 118, 111, 107, 101, 0]; 663 | 664 | if cNames != 1 || lstrcmpW(*rgszNames, METHOD_NAME.as_ptr()) != 0 { 665 | return DISP_E_UNKNOWNNAME; 666 | } 667 | 668 | *rgDispId = 1; 669 | S_OK 670 | } 671 | 672 | unsafe extern "system" fn IDispatch_Invoke( 673 | instance: *mut IDispatch, 674 | dispIdMember: DISPID, 675 | _riid: REFIID, 676 | _lcid: LCID, 677 | wFlags: WORD, 678 | pDispParams: *mut DISPPARAMS, 679 | pVarResult: *mut VARIANT, 680 | _pExcepInfo: *mut EXCEPINFO, 681 | puArgErr: *mut UINT) -> HRESULT 682 | { 683 | let client_site = ClientSite::from_dispatch(instance); 684 | 685 | if dispIdMember != 1 { 686 | return DISP_E_MEMBERNOTFOUND; 687 | } 688 | 689 | if wFlags != DISPATCH_METHOD && 690 | wFlags != DISPATCH_METHOD | DISPATCH_PROPERTYGET 691 | { 692 | return DISP_E_BADPARAMCOUNT; 693 | } 694 | 695 | if (*pDispParams).cNamedArgs != 0 { 696 | return DISP_E_NONAMEDARGS; 697 | } 698 | 699 | if (*pDispParams).cArgs != 1 { 700 | return DISP_E_BADPARAMCOUNT; 701 | } 702 | 703 | if (*(*pDispParams).rgvarg).n1.n2().vt as u32 != VT_BSTR { 704 | *puArgErr = 0; 705 | return DISP_E_TYPEMISMATCH; 706 | } 707 | 708 | // This is ridiculous 709 | let argument = *(*(*pDispParams).rgvarg).n1.n2().n3.bstrVal(); 710 | let argument_length = SysStringLen(argument); 711 | 712 | use std::ffi::{OsStr, OsString}; 713 | use std::os::windows::ffi::{OsStrExt, OsStringExt}; 714 | use std::slice; 715 | 716 | let argument_utf8 = 717 | OsString::from_wide( 718 | slice::from_raw_parts( 719 | argument, 720 | argument_length as usize)) 721 | .into_string(); 722 | 723 | if argument_utf8.is_err() { 724 | return DISP_E_OVERFLOW; 725 | } 726 | 727 | let result = ((*client_site).callback)(argument_utf8.unwrap()); 728 | 729 | if pVarResult != null_mut() { 730 | VariantInit(pVarResult); 731 | 732 | let result_utf16: Vec = 733 | OsStr::new(&result).encode_wide().collect(); 734 | 735 | (*pVarResult).n1.n2_mut().vt = VT_BSTR as u16; 736 | *(*pVarResult).n1.n2_mut().n3.bstrVal_mut() = SysAllocStringLen( 737 | result_utf16.as_ptr(), 738 | result_utf16.len() as u32); 739 | } 740 | 741 | S_OK 742 | } 743 | 744 | #[repr(C, packed)] 745 | struct InPlaceFrame { 746 | ole_in_place_frame: IOleInPlaceFrame, 747 | reference_counter: ULONG, 748 | window: HWND, 749 | } 750 | 751 | const OLE_IN_PLACE_FRAME_VTABLE: IOleInPlaceFrameVtbl = IOleInPlaceFrameVtbl { 752 | parent: IOleInPlaceUIWindowVtbl { 753 | parent: IOleWindowVtbl { 754 | parent: IUnknownVtbl { 755 | AddRef: IOleInPlaceFrame_AddRef, 756 | Release: IOleInPlaceFrame_Release, 757 | QueryInterface: IOleInPlaceFrame_QueryInterface, 758 | }, 759 | GetWindow: IOleInPlaceFrame_GetWindow, 760 | ContextSensitiveHelp: IOleInPlaceFrame_ContextSensitiveHelp, 761 | }, 762 | GetBorder: IOleInPlaceFrame_GetBorder, 763 | RequestBorderSpace: IOleInPlaceFrame_RequestBorderSpace, 764 | SetBorderSpace: IOleInPlaceFrame_SetBorderSpace, 765 | SetActiveObject: IOleInPlaceFrame_SetActiveObject, 766 | }, 767 | InsertMenus: IOleInPlaceFrame_InsertMenus, 768 | SetMenu: IOleInPlaceFrame_SetMenu, 769 | RemoveMenus: IOleInPlaceFrame_RemoveMenus, 770 | SetStatusText: IOleInPlaceFrame_SetStatusText, 771 | EnableModeless: IOleInPlaceFrame_EnableModeless, 772 | TranslateAccelerator: IOleInPlaceFrame_TranslateAccelerator, 773 | }; 774 | 775 | fn new_in_place_frame(window: HWND) -> ComPointer { 776 | let in_place_frame = Box::new( 777 | InPlaceFrame { 778 | ole_in_place_frame: IOleInPlaceFrame { 779 | lpVtbl: &OLE_IN_PLACE_FRAME_VTABLE 780 | }, 781 | reference_counter: 1, 782 | window: window, 783 | }); 784 | 785 | ComPointer::from_raw( 786 | Box::into_raw(in_place_frame) as *mut IOleInPlaceFrame) 787 | } 788 | 789 | unsafe extern "system" fn IOleInPlaceFrame_AddRef( 790 | instance: *mut IUnknown) -> ULONG 791 | { 792 | let in_place_frame = instance as *mut InPlaceFrame; 793 | 794 | (*in_place_frame).reference_counter += 1; 795 | (*in_place_frame).reference_counter 796 | } 797 | 798 | unsafe extern "system" fn IOleInPlaceFrame_Release( 799 | instance: *mut IUnknown) -> ULONG 800 | { 801 | let in_place_frame = instance as *mut InPlaceFrame; 802 | 803 | let result = { 804 | (*in_place_frame).reference_counter -= 1; 805 | (*in_place_frame).reference_counter 806 | }; 807 | 808 | assert!(result != ULONG::max_value()); 809 | 810 | if result == 0 { 811 | Box::from_raw(in_place_frame); 812 | } 813 | 814 | result 815 | } 816 | 817 | unsafe extern "system" fn IOleInPlaceFrame_QueryInterface( 818 | instance: *mut IUnknown, 819 | riid: REFIID, 820 | ppvObject: *mut *mut c_void) -> HRESULT 821 | { 822 | *ppvObject = 823 | if IsEqualGUID(&*riid, &IUnknown::uuidof()) || 824 | IsEqualGUID(&*riid, &IOleWindow::uuidof()) || 825 | IsEqualGUID(&*riid, &IOleInPlaceUIWindow::uuidof()) || 826 | IsEqualGUID(&*riid, &IOleInPlaceFrame::uuidof()) 827 | { 828 | instance as *mut c_void 829 | } else { 830 | null_mut() 831 | }; 832 | 833 | if *ppvObject != null_mut() { 834 | (*instance).AddRef(); 835 | S_OK 836 | } else { 837 | E_NOINTERFACE 838 | } 839 | } 840 | 841 | unsafe extern "system" fn IOleInPlaceFrame_GetWindow( 842 | instance: *mut IOleWindow, 843 | phwnd: *mut HWND) -> HRESULT 844 | { 845 | let in_place_frame = instance as *mut InPlaceFrame; 846 | 847 | *phwnd = (*in_place_frame).window; 848 | S_OK 849 | } 850 | 851 | unsafe extern "system" fn IOleInPlaceFrame_ContextSensitiveHelp( 852 | _instance: *mut IOleWindow, 853 | _fEnterMode: BOOL) -> HRESULT 854 | { 855 | S_OK 856 | } 857 | 858 | unsafe extern "system" fn IOleInPlaceFrame_GetBorder( 859 | _instance: *mut IOleInPlaceUIWindow, 860 | _lprectBorder: LPRECT) -> HRESULT 861 | { 862 | INPLACE_E_NOTOOLSPACE 863 | } 864 | 865 | unsafe extern "system" fn IOleInPlaceFrame_RequestBorderSpace( 866 | _instance: *mut IOleInPlaceUIWindow, 867 | _pborderwidths: LPCRECT) -> HRESULT 868 | { 869 | INPLACE_E_NOTOOLSPACE 870 | } 871 | 872 | unsafe extern "system" fn IOleInPlaceFrame_SetBorderSpace( 873 | _instance: *mut IOleInPlaceUIWindow, 874 | _pborderwidths: LPCRECT) -> HRESULT 875 | { 876 | S_OK 877 | } 878 | 879 | unsafe extern "system" fn IOleInPlaceFrame_SetActiveObject( 880 | _instance: *mut IOleInPlaceUIWindow, 881 | _pActiveObject: *mut IOleInPlaceActiveObject, 882 | _pszObjName: LPCOLESTR) -> HRESULT 883 | { 884 | S_OK 885 | } 886 | 887 | unsafe extern "system" fn IOleInPlaceFrame_InsertMenus( 888 | _instance: *mut IOleInPlaceFrame, 889 | _hmenuShared: HMENU, 890 | _lpMenuWidths: LPVOID) -> HRESULT 891 | { 892 | S_OK 893 | } 894 | 895 | unsafe extern "system" fn IOleInPlaceFrame_SetMenu( 896 | _instance: *mut IOleInPlaceFrame, 897 | _hmenuShared: HMENU, 898 | _holemenu: HGLOBAL, 899 | _hwndActiveObject: HWND) -> HRESULT 900 | { 901 | S_OK 902 | } 903 | 904 | unsafe extern "system" fn IOleInPlaceFrame_RemoveMenus( 905 | _instance: *mut IOleInPlaceFrame, 906 | _hmenuShared: HMENU) -> HRESULT 907 | { 908 | S_OK 909 | } 910 | 911 | unsafe extern "system" fn IOleInPlaceFrame_SetStatusText( 912 | _instance: *mut IOleInPlaceFrame, 913 | _pszStatusText: LPCOLESTR) -> HRESULT 914 | { 915 | S_OK 916 | } 917 | 918 | unsafe extern "system" fn IOleInPlaceFrame_EnableModeless( 919 | _instance: *mut IOleInPlaceFrame, 920 | _fEnable: BOOL) -> HRESULT 921 | { 922 | S_OK 923 | } 924 | 925 | unsafe extern "system" fn IOleInPlaceFrame_TranslateAccelerator( 926 | _instance: *mut IOleInPlaceFrame, 927 | _lpmsg: LPMSG, 928 | _wID: WORD) -> HRESULT 929 | { 930 | S_OK 931 | } 932 | --------------------------------------------------------------------------------