Skip to main content

glib_win32/
functions.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2#[cfg(any(windows, docsrs))]
3use glib::translate::*;
4#[cfg(any(windows, docsrs))]
5use std::path::PathBuf;
6
7#[cfg(any(windows, docsrs))]
8use crate::ffi;
9
10#[cfg(windows)]
11use std::os::windows::raw::HANDLE;
12#[cfg(all(unix, docsrs))]
13pub type HANDLE = *mut std::os::raw::c_void;
14
15/// This function tries to determine the installation directory of a
16/// software package based on the location of a DLL of the software
17/// package.
18///
19/// @hmodule should be the handle of a loaded DLL or [`None`]. The
20/// function looks up the directory that DLL was loaded from. If
21/// @hmodule is NULL, the directory the main executable of the current
22/// process is looked up. If that directory's last component is "bin"
23/// or "lib", its parent directory is returned, otherwise the directory
24/// itself.
25///
26/// It thus makes sense to pass only the handle to a "public" DLL of a
27/// software package to this function, as such DLLs typically are known
28/// to be installed in a "bin" or occasionally "lib" subfolder of the
29/// installation folder. DLLs that are of the dynamically loaded module
30/// or plugin variety are often located in more private locations
31/// deeper down in the tree, from which it is impossible for GLib to
32/// deduce the root of the package installation.
33///
34/// The typical use case for this function is to have a DllMain() that
35/// saves the handle for the DLL. Then when code in the DLL needs to
36/// construct names of files in the installation tree it calls this
37/// function passing the DLL handle.
38/// ## `hmodule`
39/// The Win32 handle for a DLL loaded into the current process, or [`None`]
40///
41/// # Returns
42///
43/// a string containing the guessed installation directory for
44/// the software package @hmodule is from. The string is in the GLib
45/// file name encoding, i.e. UTF-8. The return value should be freed
46/// with g_free() when not needed any longer. If the function fails
47/// [`None`] is returned.
48#[doc(alias = "g_win32_get_package_installation_directory_of_module")]
49#[doc(alias = "get_package_installation_directory_of_module")]
50#[cfg(any(windows, docsrs))]
51pub fn package_installation_directory_of_module(
52    hmodule: HANDLE,
53) -> Result<PathBuf, std::io::Error> {
54    // # Safety
55    // The underlying `GetModuleFilenameW` function has three possible
56    // outcomes when a raw pointer get passed to it:
57    // - When the pointer is a valid HINSTANCE of a DLL (e.g. acquired
58    // through the `GetModuleHandleW`), it sets a file path to the
59    // assigned "out" buffer and sets the return value to be the length
60    // of said path string
61    // - When the pointer is null, it sets the full path of the process'
62    // executable binary to the assigned buffer and sets the return value
63    // to be the length of said string
64    // - Whenever the provided buffer size is too small, it will set a
65    // truncated version of the path and return the length of said string
66    // while also setting the thread-local last-error code to
67    // `ERROR_INSUFFICIENT_BUFFER` (evaluates to 0x7A)
68    // - When the pointer is not a valid HINSTANCE that isn't NULL (e.g.
69    // a pointer to some GKeyFile), it will return 0 and set the last-error
70    // code to `ERROR_MOD_NOT_FOUND` (evaluates to 0x7E)
71    //
72    // The `g_win32_get_package_installation_directory_of_module` already
73    // handles all of the outcomes gracefully by:
74    // - Preallocating a MAX_PATH-long array of wchar_t for the out buffer,
75    // so that outcome #3 can be safely assumed to never happen
76    // - Returning NULL when outcome #4 happens
77    match unsafe {
78        from_glib_full::<_, Option<PathBuf>>(
79            ffi::g_win32_get_package_installation_directory_of_module(hmodule),
80        )
81    } {
82        Some(pb) => Ok(pb),
83        None => Err(std::io::Error::last_os_error()),
84    }
85}
86
87#[doc(alias = "g_win32_get_package_installation_directory")]
88#[doc(alias = "get_package_installation_directory")]
89#[deprecated = "Use `package_installation_directory_of_module()`"]
90#[cfg(any(windows, docsrs))]
91pub fn package_installation_directory(package: &str, dll_name: &str) -> glib::GString {
92    unsafe {
93        from_glib_full(ffi::g_win32_get_package_installation_directory(
94            package.to_glib_none().0,
95            dll_name.to_glib_none().0,
96        ))
97    }
98}
99
100#[doc(alias = "g_win32_get_package_installation_subdirectory")]
101#[doc(alias = "get_package_installation_subdirectory")]
102#[deprecated = "Use `package_installation_directory_of_module()`"]
103#[cfg(any(windows, docsrs))]
104pub fn package_installation_subdirectory(
105    package: &str,
106    dll_name: &str,
107    subdir: &str,
108) -> glib::GString {
109    unsafe {
110        from_glib_full(ffi::g_win32_get_package_installation_subdirectory(
111            package.to_glib_none().0,
112            dll_name.to_glib_none().0,
113            subdir.to_glib_none().0,
114        ))
115    }
116}