How to create a IWICImagingFactory instance in winapi-rs - winapi

I try this way,
let mut factory: *mut IWICImagingFactory = std::ptr::null_mut();
let hr = unsafe {
CoCreateInstance(
&CLSID_WICImagingFactory,
std::ptr::null_mut(),
CLSCTX_INPROC_SERVER,
&IWICImagingFactory::uuidof(),
&mut factory as *mut *mut _ as *mut *mut _,
)
};
assert!(factory.is_null());
but the factory pointer still is null, the hr is -2147221008, I don't know what that means.

The error code -2147221008 (or 0x800401F0) translates to CO_E_NOTINITIALIZED. The documentation for CoInitializeEx explains why you'd receive this error:
You need to initialize the COM library on a thread before you call any of the library functions [...]. Otherwise, the COM function will return CO_E_NOTINITIALIZED.
To instantiate an IWICImagingFactory interface implementation you'll have to initialize COM on the calling thread first:
let hr = unsafe { CoInitialize(std::ptr::null_mut()) };
// Handle errors
As a note, unless you have a specific reason to use the winapi crate, go with the windows crate instead. It makes COM programming in Rust a lot more convenient.

Related

ReadProcessMemory returning errors

When I use the ReadProcessMemory function from the windows-rs package it returns 0. This is wrong, so I used the GetLastError() function and it returned "Only part of a ReadProcessMemory or WriteProcessMemory request was completed."
Here is the code for ReadProcessMemory:
unsafe{
let mut healthValue: i32 = 0;
ReadProcessMemory(
hProcess,
0xE6A848 as *mut c_void,
healthValue as *mut c_void,
std::mem::size_of::<i32> as usize,
&mut 0
);
println!("{}", healthValue);
match GetLastError().ok() {
Ok(_) => println!("no eror"),
Err(t) => println!("error: {}", t),
}
};
The code to get handle to the process:
let hProcess: HANDLE;
unsafe{
match OpenProcess(PROCESS_ALL_ACCESS, false, procId as u32) {
Ok(T) => hProcess = T,
Err(A) => {
hProcess = INVALID_HANDLE_VALUE;
println!("hproc is INVALID");
}
}
}
I have checked and the ProcId is right, I have used cheat engine to get the memory address, both apps are run in 32-bit, and my trainer is being run as admin. None of these have helped.
Fixed it by changing healthValue as *mut c_void to ptr::addr_of_mut!(healthValue) as *mut c_void.

How to safely wrap win32's PSTR or PWSTR in an Option type (e.g. Option<&OsStr>)?

I am trying to create a safe wrapper around some Win32 APIs using Microsoft's windows crate like so:
use windows::{Win32::Foundation::*, Win32::System::Threading::*};
fn create_process(app_name: &std::ffi::OsStr) -> bool {
let mut startup_info: STARTUPINFOW = unsafe { std::mem::zeroed() };
startup_info.cb = std::mem::size_of::<STARTUPINFOW>() as u32;
let mut process_info: PROCESS_INFORMATION = unsafe {std::mem::zeroed() };
unsafe {
let success = CreateProcessW(
app_name, // lpapplicationname
None, // lpcommandname
std::ptr::null(), // lpprocessattributes
std::ptr::null(), // lpthreadattributes
true, // binherithandles
CREATE_SUSPENDED, // dwcreationflags
std::ptr::null(), // lpenvironment
&startup_info, // lpstartupinfo
&mut process_info // lpprocessinformation
).as_bool();
success
}
}
fn main() {
let app = std::ffi::OsStr::new("C:\\Windows\\system32\\notepad.exe");
let success = create_process(app);
print!("{}", success);
}
This works as expected.
However, the documentation for CreateProcessW states that
The lpApplicationName parameter can be NULL.
Thus, I would like to wrap the &OsStr in an Option<&OsStr> so I can use None when no lpApplicationName is needed.
But I cannot find a way to convert from Option<&OsStr> to anything that satisfies IntoParam<'a, PWSTR> for lpApplicationName.
As of #1801 &OsStr should implement IntoParam<PWSTR>. Since null() also implements it, you should be able to write:
use windows::core::{IntoParam, Param};
let app_name_param: Param<'_, PWSTR> = if let Some(app_name) = app_name {
app_name.into_param()
} else {
Param::None
};
...and pass app_name_param to CreateProcessW.
(I can't test this because I run on Linux, where Foundation/mod.rs fails to compile due to requiring std::os::windows::ffi::OsStrExt.)

Using winapi in Rust to get a bitmap from a window

.. Hi, I have this code :
#[cfg(windows)] extern crate winapi;
use winapi::um::winuser::{FindWindowW, GetClientRect, GetWindowDC, GetDC, ReleaseDC};
use winapi::um::wingdi::{CreateBitmap, CreateCompatibleBitmap, CreateCompatibleDC, SelectObject, GetObjectW, SaveDC, DeleteDC, DeleteObject};
use std::ptr::null_mut;
use std::mem::zeroed;
use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
#[cfg(windows)]
fn find_window(name: &str) {
let window: Vec<u16> = OsStr::new(name).encode_wide().chain(once(0)).collect();
let hwnd = unsafe { FindWindowW(null_mut(), window.as_ptr()) };
if hwnd != null_mut() {
println!("Window found");
let mut my_rect = unsafe { zeroed::<winapi::shared::windef::RECT>() };
let _client_rect = unsafe { GetClientRect(hwnd, &mut my_rect) };
let w = my_rect.right - my_rect.left;
let h = my_rect.bottom - my_rect.top;
let hwnd_dc = unsafe { GetWindowDC(hwnd) };
let mem_dc = unsafe { CreateCompatibleDC(hwnd_dc) };
let bmp = unsafe { CreateCompatibleBitmap(mem_dc, w, h) };
//SelectObject(mem_dc, bmp); <== Problem is here
//DeleteObject(bmp); <== Same problem here
unsafe { DeleteDC(mem_dc) };
unsafe { ReleaseDC(hwnd, hwnd_dc) };
}
else {
println!("Window not found");
}
}
fn main() {
find_window("Firefox"); // just for test
}
If I cargo run this, I get :
SelectObject(mem_dc, bmp);
| ^^^ expected enum `std::ffi::c_void`, found enum `winapi::shared::windef::HBITMAP__`
So I get it, it doesn't want that bitmap pointer, but in the win32 documentation, it says that this function (SelectObject) accepts a Device Context (mem_dc) and an object created by some function like CreateCompatibleBitmap.
https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-selectobject
The binding in Rust accepts the two same arguments but it seems to want that std::ffi::c_void but looking a the Rust doc, I don't get what it is exactly.
Can you help me finding what's wrong ? Thanks.
Add:
use winapi::shared::windef::{HBITMAP, HBITMAP__, HGDIOBJ, HWND, POINT, RECT, SIZE};
...
unsafe {SelectObject(mem_dc, bmp as HGDIOBJ)};
unsafe {DeleteObject(bmp as HGDIOBJ)};

Cast a ptr::null() to a Windows handle

I'm trying to use the winapi crate to create a GUI for my VST plugin. Functions like user32::SetMenu need some handles, some of which can be NULL.
The following method is called when the plugin is loaded:
fn open(&mut self, window: *mut c_void) {
unsafe {
let menu = user32::CreateMenu();
let sub_menu = user32::CreateMenu();
let hwnd: HWND = window as HWND;
user32::SetMenu(hwnd, menu);
let mut data = OsString::from("heee");
let raw = &mut data as *mut _ as LPWSTR;
let mut menu_item = MENUITEMINFOW {
cbSize: 0,
fMask: 0o0000_0020 | 0o0000_0040,
fType: 0,
fState: 0,
wID: MENUITEM_ID,
hSubMenu: sub_menu,
hbmpChecked: ptr::null() as HBITMAP,
hbmpUnchecked: ptr::null() as HBITMAP,
dwItemData: 0,
dwTypeData: raw,
cch: 0,
hbmpItem: ptr::null() as *mut _,
};
menu_item.cbSize = mem::size_of_val(&menu_item) as u32;
user32::InsertMenuItemW(menu, MENUITEM_ID, 0, &menu_item);
}
self.open = true;
}
However, I can't pass NULL for the handles:
hbmpChecked: ptr::null() as HBITMAP,
I get the error message
hbmpChecked: ptr::null() as HBITMAP,
^^^^^^^^^ cannot infer type for `_`
I can't find a solution in the docs of winapi/user32.
Here is how HBITMAP is defined in winapi:
type HBITMAP = *mut HBITMAP__;
This makes HBITMAP a mutable raw pointer. ptr::null() returns a const raw pointer. You should use ptr::null_mut() instead, as it returns a mutable raw pointer, so the compiler will be able to infer the correct type.

shared_ptr and COM object

I have a COM object named factory (IFactory), and it has several methods like
virtual HRESULT STDMETHODCALLTYPE CreateDatabase(IDatabase** Result) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateProcessor(IProcessor** Result) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateDocument(IDocument** Result) = 0;
.....
when I need create a IDocument, I need to do this:
IDocument* doc = nullptr;
factory->CreateDocument(&doc);
// some code here;
doc.Release();
So I want to create a common function to do this and generate a shared_ptr, so taht I do not need to release it manually.
I created a function like this:
template <typename T, typename K>
shared_ptr<T> create_new(K* p, HRESULT (K::*member)(T**)) {
T* pointer = nullptr;
(void)p->*member(&pointer);
shared_ptr<T> result(pointer, [=](T* o) {
o->Release();
});
return result;
}
This way, when I need create a new IDocument I just need:
auto doc = create_new(factory, &IFactory::CreateDocument);
// do not need release it manually
but this does not work, because the compiler needs more information to instantiate the template, so I use
auto doc = create_new(factory, (HRESULT (IFactory::*)(IDocument**))&IFactory::CreateDocument);
this way seems correct, but when I compile my code, the compiler stops at
(void)p->*member(&pointer);
and says:
must use '.*' or '->*' to call pointer-to-member function in 'member (...)', e.g. '(... ->* member) (...)'
In instantiation of 'std::shared_ptr<_Tp1> create_new(K*, HRESULT (K::*)(T**)) [with T = IDocument; K = IFactory; HRESULT = long int]'
Could someone help me figure this out?
Compiler is MinGW-w64 GCC 4.8.5, but I tried GCC 5.3.0, with the same output.
First off, function calls bind tighter than member pointer dereference, so you need these parentheses:
(p->*member)(&pointer);
(Add cast to void as you prefer).
Second, you can improve your call syntax by specifying the argument for T explicitly; you should then not need the horrible cast:
auto doc = create_new<IDocument>(factory, &IFactory::CreateDocument);

Resources