Skip to content

Commit 02df4c4

Browse files
brsonFaultyRAM
authored andcommitted
Add MSVC 2017 detection
This teaches gcc-rs to find tools installed by MSVC 2017. It's not obvious to what extent the new COM interfaces are expected to be used. This patch only uses it to find the product installation directory, then infers everything else. A lot of COM scaffolding to do very little. The toolchains seem to have a different directory structure in this release to better support cross-compilation. It looks to me like all the lib/include logic is pretty much the same as it always has been. This is tested to fix the rustup installation logic, and to fix rustc in basic use cases on x86_64. cc rust-lang#143 cc rust-lang/rustup#1003 cc rust-lang/rust#38584 cc alexcrichton/curl-rust#161
1 parent 5dbfa59 commit 02df4c4

File tree

5 files changed

+694
-7
lines changed

5 files changed

+694
-7
lines changed

src/com.rs

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright © 2017 winapi-rs developers
2+
// Licensed under the Apache License, Version 2.0
3+
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
4+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
5+
// All files in the project carrying such notice may not be copied, modified, or distributed
6+
// except according to those terms.
7+
8+
#![allow(unused)]
9+
10+
use std::ffi::{OsStr, OsString};
11+
use std::mem::forget;
12+
use std::ops::Deref;
13+
use std::os::windows::ffi::{OsStrExt, OsStringExt};
14+
use std::ptr::null_mut;
15+
use std::slice::from_raw_parts;
16+
use winapi::Interface;
17+
use winapi::BSTR;
18+
use winapi::CoInitializeEx;
19+
use winapi::COINIT_MULTITHREADED;
20+
use winapi::{SysFreeString, SysStringLen};
21+
use winapi::IUnknown;
22+
use winapi::{S_OK, S_FALSE, HRESULT};
23+
24+
pub fn initialize() -> Result<(), HRESULT> {
25+
let err = unsafe { CoInitializeEx(null_mut(), COINIT_MULTITHREADED) };
26+
if err != S_OK && err != S_FALSE {
27+
// S_FALSE just means COM is already initialized
28+
return Err(err);
29+
}
30+
Ok(())
31+
}
32+
33+
pub struct ComPtr<T>(*mut T) where T: Interface;
34+
impl<T> ComPtr<T> where T: Interface {
35+
/// Creates a `ComPtr` to wrap a raw pointer.
36+
/// It takes ownership over the pointer which means it does __not__ call `AddRef`.
37+
/// `T` __must__ be a COM interface that inherits from `IUnknown`.
38+
pub unsafe fn from_raw(ptr: *mut T) -> ComPtr<T> {
39+
assert!(!ptr.is_null());
40+
ComPtr(ptr)
41+
}
42+
/// Casts up the inheritance chain
43+
pub fn up<U>(self) -> ComPtr<U> where T: Deref<Target=U>, U: Interface {
44+
ComPtr(self.into_raw() as *mut U)
45+
}
46+
/// Extracts the raw pointer.
47+
/// You are now responsible for releasing it yourself.
48+
pub fn into_raw(self) -> *mut T {
49+
let p = self.0;
50+
forget(self);
51+
p
52+
}
53+
/// For internal use only.
54+
fn as_unknown(&self) -> &IUnknown {
55+
unsafe { &*(self.0 as *mut IUnknown) }
56+
}
57+
/// Performs QueryInterface fun.
58+
pub fn cast<U>(&self) -> Result<ComPtr<U>, i32> where U: Interface {
59+
let mut obj = null_mut();
60+
let err = unsafe { self.as_unknown().QueryInterface(&U::uuidof(), &mut obj) };
61+
if err < 0 { return Err(err); }
62+
Ok(unsafe { ComPtr::from_raw(obj as *mut U) })
63+
}
64+
}
65+
impl<T> Deref for ComPtr<T> where T: Interface {
66+
type Target = T;
67+
fn deref(&self) -> &T {
68+
unsafe { &*self.0 }
69+
}
70+
}
71+
impl<T> Clone for ComPtr<T> where T: Interface {
72+
fn clone(&self) -> Self {
73+
unsafe {
74+
self.as_unknown().AddRef();
75+
ComPtr::from_raw(self.0)
76+
}
77+
}
78+
}
79+
impl<T> Drop for ComPtr<T> where T: Interface {
80+
fn drop(&mut self) {
81+
unsafe { self.as_unknown().Release(); }
82+
}
83+
}
84+
pub struct BStr(BSTR);
85+
impl BStr {
86+
pub unsafe fn from_raw(s: BSTR) -> BStr {
87+
BStr(s)
88+
}
89+
pub fn to_osstring(&self) -> OsString {
90+
let len = unsafe { SysStringLen(self.0) };
91+
let slice = unsafe { from_raw_parts(self.0, len as usize) };
92+
OsStringExt::from_wide(slice)
93+
}
94+
}
95+
impl Drop for BStr {
96+
fn drop(&mut self) {
97+
unsafe { SysFreeString(self.0) };
98+
}
99+
}
100+
101+
pub trait ToWide {
102+
fn to_wide(&self) -> Vec<u16>;
103+
fn to_wide_null(&self) -> Vec<u16>;
104+
}
105+
impl<T> ToWide for T where T: AsRef<OsStr> {
106+
fn to_wide(&self) -> Vec<u16> {
107+
self.as_ref().encode_wide().collect()
108+
}
109+
fn to_wide_null(&self) -> Vec<u16> {
110+
self.as_ref().encode_wide().chain(Some(0)).collect()
111+
}
112+
}
113+
pub trait FromWide where Self: Sized {
114+
fn from_wide(wide: &[u16]) -> Self;
115+
fn from_wide_null(wide: &[u16]) -> Self {
116+
let len = wide.iter().take_while(|&&c| c != 0).count();
117+
Self::from_wide(&wide[..len])
118+
}
119+
}
120+
impl FromWide for OsString {
121+
fn from_wide(wide: &[u16]) -> OsString {
122+
OsStringExt::from_wide(wide)
123+
}
124+
}
125+

src/lib.rs

+10
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,18 @@ use std::process::{Command, Stdio, Child};
5757
use std::io::{self, BufReader, BufRead, Read, Write};
5858
use std::thread::{self, JoinHandle};
5959

60+
// These modules are all glue to support reading the MSVC version from
61+
// the registry and from COM interfaces
6062
#[cfg(windows)]
6163
mod registry;
64+
#[cfg(windows)]
65+
#[macro_use]
66+
mod winapi;
67+
#[cfg(windows)]
68+
mod com;
69+
#[cfg(windows)]
70+
mod setup_config;
71+
6272
pub mod windows_registry;
6373

6474
/// Extra configuration to pass to gcc.

0 commit comments

Comments
 (0)