Confusing error asking for type that doesn't seem to exist


#1

I am trying to port the function enable_visual_styles() from the native windows GUI to enable it to work for my own code so I don’t need to embed a manifest file. Unfortunately, I get this error message when compiling it in my code:

R:\rs\checksum>cargo build --release --
   Compiling wui v1.0.0 (file:///R:/rs/wui)
error[E0308]: mismatched types
  --> R:\rs\wui\src\api.rs:89:32
   |
89 |     let handle = CreateActCtxW(&mut act_ctx);
   |                                ^^^^^^^^^^^^ expected struct `winapi::winbase::ACTCTXW`, found struct `winapi::um::winbase::ACTCTXW`
   |
   = note: expected type `*const winapi::winbase::ACTCTXW`
              found type `&mut winapi::um::winbase::ACTCTXW`

error: aborting due to previous error

However, there is no such type as winapi::winbase::ACTCTXW since when I try to use it I get this error:

R:\rs\checksum>cargo build --release --
   Compiling wui v1.0.0 (file:///R:/rs/wui)
error[E0432]: unresolved import `winapi::winbase`
  --> R:\rs\wui\src\api.rs:24:13
   |
24 | use winapi::winbase::ACTCTXW;
   |             ^^^^^^^ Could not find `winbase` in `winapi`

error: aborting due to previous error

In case it is helpful, here’s an extract from my Cargo.toml:

kernel32-sys = "0.2"
winapi = { version = "0.3.5", features = ["winuser", "libloaderapi",
            "winbase", "commctrl"] }

And here are my use statements:

use errors::*;
use kernel32::{ActivateActCtx, CreateActCtxW, GetSystemDirectoryW,
               GetLastError, FormatMessageW};
use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::ptr;
use std::ffi::OsString;
use std::mem;
use std::os::windows::ffi::OsStringExt;
use super::util;
use winapi::shared::basetsd::{ULONG_PTR};
use winapi::shared::minwindef::{
    DWORD, UINT, ULONG, WPARAM, LPARAM, LRESULT, MAX_PATH};
use winapi::shared::ntdef::{LANG_NEUTRAL, MAKELANGID, SUBLANG_DEFAULT};
use winapi::shared::windef::HWND;
use winapi::um::commctrl::{
    ICC_STANDARD_CLASSES, ICC_DATE_CLASSES, ICC_PROGRESS_CLASS,
    ICC_WIN95_CLASSES, INITCOMMONCONTROLSEX, ICC_TREEVIEW_CLASSES,
    ICC_TAB_CLASSES, ICC_LISTVIEW_CLASSES, InitCommonControlsEx};
use winapi::um::winbase::{ACTCTXW, FORMAT_MESSAGE_FROM_SYSTEM}; 

And here’s the function itself:

pub unsafe fn enable_visual_styles() {
    const ACTCTX_FLAG_RESOURCE_NAME_VALID: u32 = 0x008;
    const ACTCTX_FLAG_SET_PROCESS_DEFAULT: u32 = 0x010;
    const ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID: u32 = 0x004;
    let mut sys_dir: Vec<u16> = Vec::with_capacity(MAX_PATH);
    sys_dir.set_len(MAX_PATH);
    GetSystemDirectoryW(sys_dir.as_mut_ptr(), MAX_PATH as u32);
    let mut source = as_ws("shell32.dll");
    let mut activation_cookie: ULONG_PTR = 0;
    let mut act_ctx = ACTCTXW {
        cbSize: mem::size_of::<ACTCTXW> as ULONG,
        dwFlags: ACTCTX_FLAG_RESOURCE_NAME_VALID |
                 ACTCTX_FLAG_SET_PROCESS_DEFAULT |
                 ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID,
        lpSource: source.as_mut_ptr(),
        wProcessorArchitecture: 0,
        wLangId: 0,
        lpAssemblyDirectory: sys_dir.as_mut_ptr(),
        lpResourceName: mem::transmute(124usize), // ID_MANIFEST
        lpApplicationName: ptr::null_mut(),
        hModule: ptr::null_mut()
    };
    let handle = CreateActCtxW(&mut act_ctx);
    let mut activation_cookie = activation_cookie as u64;
    ActivateActCtx(handle, &mut activation_cookie);
    let controls_classes = INITCOMMONCONTROLSEX {
        dwSize: mem::size_of::<INITCOMMONCONTROLSEX> as DWORD,
        dwICC: ICC_DATE_CLASSES | ICC_STANDARD_CLASSES |
               ICC_PROGRESS_CLASS | ICC_WIN95_CLASSES |
               ICC_TREEVIEW_CLASSES | ICC_TAB_CLASSES | ICC_LISTVIEW_CLASSES
    };
    InitCommonControlsEx(&controls_classes);
}

#2

It’s because you’re mixing 0.2.x and 0.3.x winapi. Specifically, kernel32-sys in incompatible with winapi 0.3.x. Don’t use it; use the function defined in winapi 0.3.x.


#3

Thank you! That solved the problem.

For anyone who is interested here’re the revised dependencies:

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.5", features = ["winuser", "libloaderapi",
            "winbase", "commctrl", "sysinfoapi", "errhandlingapi"] }

Here’re the revised use statements:

use errors::*;
use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::ptr;
use std::ffi::OsString;
use std::mem;
use std::os::windows::ffi::OsStringExt;
use winapi::shared::basetsd::{ULONG_PTR};
use winapi::shared::minwindef::{
    DWORD, UINT, ULONG, WPARAM, LPARAM, LRESULT, MAX_PATH};
use winapi::shared::ntdef::{LANG_NEUTRAL, MAKELANGID, SUBLANG_DEFAULT};
use winapi::shared::windef::HWND;
use winapi::um::commctrl::{
    ICC_STANDARD_CLASSES, ICC_DATE_CLASSES, ICC_PROGRESS_CLASS,
    ICC_WIN95_CLASSES, INITCOMMONCONTROLSEX, ICC_TREEVIEW_CLASSES,
    ICC_TAB_CLASSES, ICC_LISTVIEW_CLASSES, InitCommonControlsEx};
use winapi::um::winbase::{ACTCTXW, ActivateActCtx, CreateActCtxW,
                          FormatMessageW, FORMAT_MESSAGE_FROM_SYSTEM}; 
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::sysinfoapi::GetSystemDirectoryW;

And here’s the function:

pub unsafe fn enable_visual_styles() {
    const ACTCTX_FLAG_RESOURCE_NAME_VALID: u32 = 0x008;
    const ACTCTX_FLAG_SET_PROCESS_DEFAULT: u32 = 0x010;
    const ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID: u32 = 0x004;
    let mut sys_dir: Vec<u16> = Vec::with_capacity(MAX_PATH);
    sys_dir.set_len(MAX_PATH);
    GetSystemDirectoryW(sys_dir.as_mut_ptr(), MAX_PATH as u32);
    let mut source = as_ws("shell32.dll");
    let mut activation_cookie: ULONG_PTR = 0;
    let mut act_ctx = ACTCTXW {
        cbSize: mem::size_of::<ACTCTXW> as ULONG,
        dwFlags: ACTCTX_FLAG_RESOURCE_NAME_VALID |
                 ACTCTX_FLAG_SET_PROCESS_DEFAULT |
                 ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID,
        lpSource: source.as_mut_ptr(),
        wProcessorArchitecture: 0,
        wLangId: 0,
        lpAssemblyDirectory: sys_dir.as_mut_ptr(),
        lpResourceName: mem::transmute(124usize), // ID_MANIFEST
        lpApplicationName: ptr::null_mut(),
        hModule: ptr::null_mut()
    };
    let handle = CreateActCtxW(&mut act_ctx);
    ActivateActCtx(handle, &mut activation_cookie);
    let controls_classes = INITCOMMONCONTROLSEX {
        dwSize: mem::size_of::<INITCOMMONCONTROLSEX> as DWORD,
        dwICC: ICC_DATE_CLASSES | ICC_STANDARD_CLASSES |
               ICC_PROGRESS_CLASS | ICC_WIN95_CLASSES |
               ICC_TREEVIEW_CLASSES | ICC_TAB_CLASSES | ICC_LISTVIEW_CLASSES
    };
    InitCommonControlsEx(&controls_classes);
}