Search code examples
rustoutlookcomwindows-rs

Passing argument to method on COM Dispatch in Rust with windows-rs


I am trying to Invoke the method Move on an Outlook MailItem Dispatch object and need to provide a MAPIFolder as an argument.

I am able to call/get other methods/properties that do not require any arguments, but all attempts to provide arguments have resulted in various errors.

From their GUIDs I know that email is _MailItem and folder is MAPIFolder.

I am also able to retrieve the dispid of _MailItem.Move.

From the docs, Move is supposed to take a single MAPIFolder as argument.

This example results in HRESULT 0x80020009 which is "exception", and the description is "Property is read-only". I've no idea which property of which object this is referring to.

let email : IDispatch = ...;
let folder : IDispatch = ...;

let args = vec![VARIANT::from(folder)];

let dispparams = DISPPARAMS {
    rgvarg : args.as_mut_ptr() as *mut VARIANT,
    rgdispidNamedArgs : null_mut() as *mut i32,
    cArgs : 1,
    cNamedArgs : 0,
};

let mut result = EXCEPINFO::default();
let mut exception = VARIANT::new();

unsafe {
email.Invoke(
    move_dispid, // Method ID
    &GUID::zeroed(), // reserved
    LOCALE_USER_DEFAULT, // constant, 0x0400
    0x01 | 0x08, // constant, Method | ByRef
    &dispparams as *const DISPPARAMS,
    Some(&mut result as *mut VARIANT),
    Some(&mut exception as *mut EXCEPINFO),
    None,
)
};

Solution

  • The problem was adding the ByRef flag to the Invoke call. It should have only been DISPATCH_METHOD.

    Other difficulties were:

    • Retrieving the Application Dispatch object by initializing an IUnknown and then casting it to IDispatch. This caused random exceptions which did not occur when initializing as IDispatch directly.
    • Trying to use named arguments instead of positional arguments. It seems that most functions just use positional arguments.