Skip to content

Commit

Permalink
COM scope fix.
Browse files Browse the repository at this point in the history
As stated on the MSDN, A thread must call CoUninitialize once for each
successful call it has made to the CoInitialize or CoInitializeEx
function, including any call that returns S_FALSE. We were not calling
it previously, so the fix is to make a scope guard, which handles this.
  • Loading branch information
den-mentiei committed Jun 23, 2023
1 parent 525f3f8 commit 49fbf4b
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 7 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "thound"
version = "0.1.0"
version = "0.1.1"
authors = ["Denys Mentiei <[email protected]>"]
description = "Finds the folders with VC toolchain and Windows SDK"
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Add `thound` to your `Cargo.toml`:

``` toml
[dependencies]
thound = "0.1.0"
thound = "0.1"
```

## Usage
Expand Down
6 changes: 1 addition & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,7 @@ pub fn find_vc_and_windows_sdk() -> Option<Info> {
}

fn find_vc_toolchain() -> Option<ToolchainInfo> {
let hr = unsafe { CoInitializeEx(null_mut(), COINIT_MULTITHREADED) };
// S_FALSE means COM has been already initialized.
if hr != S_OK && hr != S_FALSE {
return None;
}
let _com = ComScope::start()?;

let mut config = null_mut();
let status = unsafe {
Expand Down
27 changes: 27 additions & 0 deletions src/winapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ extern "stdcall" {
#[link(name = "Ole32")]
extern "stdcall" {
pub fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) -> HRESULT;
pub fn CoUninitialize();
pub fn CoCreateInstance(
rclsid: REFCLSID,
pUnkOuter: LPUNKNOWN,
Expand Down Expand Up @@ -400,3 +401,29 @@ pub(crate) fn reg_query_string_value(key: &RegKey, sub_key: &str) -> Option<Path
let root = OsString::from_wide(&value[..]);
Some(root.into())
}

// COM initialization seems to be a ref-count of some kind under the
// hood, so we need to make sure we play by the rules and uninit it.
pub(crate) struct ComScope;

impl ComScope {
#[must_use]
pub fn start() -> Option<Self> {
let hr = unsafe { CoInitializeEx(null_mut(), COINIT_MULTITHREADED) };
// S_FALSE means COM has been already initialized.
if hr != S_OK && hr != S_FALSE {
return None;
}

Some(ComScope)
}
}

impl Drop for ComScope {
fn drop(&mut self) {
// A thread must call CoUninitialize once for each successful
// call it has made to the CoInitialize or CoInitializeEx
// function, including any call that returns S_FALSE.
unsafe { CoUninitialize() };
}
}

0 comments on commit 49fbf4b

Please sign in to comment.