156 lines
3.9 KiB
Rust
156 lines
3.9 KiB
Rust
// Copyright © 2017 winapi-rs developers
|
|
// Licensed under the Apache License, Version 2.0
|
|
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
|
|
// All files in the project carrying such notice may not be copied, modified, or distributed
|
|
// except according to those terms.
|
|
|
|
#![allow(unused)]
|
|
|
|
use crate::winapi::CoInitializeEx;
|
|
use crate::winapi::IUnknown;
|
|
use crate::winapi::Interface;
|
|
use crate::winapi::BSTR;
|
|
use crate::winapi::COINIT_MULTITHREADED;
|
|
use crate::winapi::{SysFreeString, SysStringLen};
|
|
use crate::winapi::{HRESULT, S_FALSE, S_OK};
|
|
use std::ffi::{OsStr, OsString};
|
|
use std::mem::forget;
|
|
use std::ops::Deref;
|
|
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
|
use std::ptr::null_mut;
|
|
use std::slice::from_raw_parts;
|
|
|
|
pub fn initialize() -> Result<(), HRESULT> {
|
|
let err = unsafe { CoInitializeEx(null_mut(), COINIT_MULTITHREADED) };
|
|
if err != S_OK && err != S_FALSE {
|
|
// S_FALSE just means COM is already initialized
|
|
return Err(err);
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub struct ComPtr<T>(*mut T)
|
|
where
|
|
T: Interface;
|
|
impl<T> ComPtr<T>
|
|
where
|
|
T: Interface,
|
|
{
|
|
/// Creates a `ComPtr` to wrap a raw pointer.
|
|
/// It takes ownership over the pointer which means it does __not__ call `AddRef`.
|
|
/// `T` __must__ be a COM interface that inherits from `IUnknown`.
|
|
pub unsafe fn from_raw(ptr: *mut T) -> ComPtr<T> {
|
|
assert!(!ptr.is_null());
|
|
ComPtr(ptr)
|
|
}
|
|
/// Casts up the inheritance chain
|
|
pub fn up<U>(self) -> ComPtr<U>
|
|
where
|
|
T: Deref<Target = U>,
|
|
U: Interface,
|
|
{
|
|
ComPtr(self.into_raw() as *mut U)
|
|
}
|
|
/// Extracts the raw pointer.
|
|
/// You are now responsible for releasing it yourself.
|
|
pub fn into_raw(self) -> *mut T {
|
|
let p = self.0;
|
|
forget(self);
|
|
p
|
|
}
|
|
/// For internal use only.
|
|
fn as_unknown(&self) -> &IUnknown {
|
|
unsafe { &*(self.0 as *mut IUnknown) }
|
|
}
|
|
/// Performs QueryInterface fun.
|
|
pub fn cast<U>(&self) -> Result<ComPtr<U>, i32>
|
|
where
|
|
U: Interface,
|
|
{
|
|
let mut obj = null_mut();
|
|
let err = unsafe { self.as_unknown().QueryInterface(&U::uuidof(), &mut obj) };
|
|
if err < 0 {
|
|
return Err(err);
|
|
}
|
|
Ok(unsafe { ComPtr::from_raw(obj as *mut U) })
|
|
}
|
|
}
|
|
impl<T> Deref for ComPtr<T>
|
|
where
|
|
T: Interface,
|
|
{
|
|
type Target = T;
|
|
fn deref(&self) -> &T {
|
|
unsafe { &*self.0 }
|
|
}
|
|
}
|
|
impl<T> Clone for ComPtr<T>
|
|
where
|
|
T: Interface,
|
|
{
|
|
fn clone(&self) -> Self {
|
|
unsafe {
|
|
self.as_unknown().AddRef();
|
|
ComPtr::from_raw(self.0)
|
|
}
|
|
}
|
|
}
|
|
impl<T> Drop for ComPtr<T>
|
|
where
|
|
T: Interface,
|
|
{
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
self.as_unknown().Release();
|
|
}
|
|
}
|
|
}
|
|
pub struct BStr(BSTR);
|
|
impl BStr {
|
|
pub unsafe fn from_raw(s: BSTR) -> BStr {
|
|
BStr(s)
|
|
}
|
|
pub fn to_osstring(&self) -> OsString {
|
|
let len = unsafe { SysStringLen(self.0) };
|
|
let slice = unsafe { from_raw_parts(self.0, len as usize) };
|
|
OsStringExt::from_wide(slice)
|
|
}
|
|
}
|
|
impl Drop for BStr {
|
|
fn drop(&mut self) {
|
|
unsafe { SysFreeString(self.0) };
|
|
}
|
|
}
|
|
|
|
pub trait ToWide {
|
|
fn to_wide(&self) -> Vec<u16>;
|
|
fn to_wide_null(&self) -> Vec<u16>;
|
|
}
|
|
impl<T> ToWide for T
|
|
where
|
|
T: AsRef<OsStr>,
|
|
{
|
|
fn to_wide(&self) -> Vec<u16> {
|
|
self.as_ref().encode_wide().collect()
|
|
}
|
|
fn to_wide_null(&self) -> Vec<u16> {
|
|
self.as_ref().encode_wide().chain(Some(0)).collect()
|
|
}
|
|
}
|
|
pub trait FromWide
|
|
where
|
|
Self: Sized,
|
|
{
|
|
fn from_wide(wide: &[u16]) -> Self;
|
|
fn from_wide_null(wide: &[u16]) -> Self {
|
|
let len = wide.iter().take_while(|&&c| c != 0).count();
|
|
Self::from_wide(&wide[..len])
|
|
}
|
|
}
|
|
impl FromWide for OsString {
|
|
fn from_wide(wide: &[u16]) -> OsString {
|
|
OsStringExt::from_wide(wide)
|
|
}
|
|
}
|