0

Question

I want to rewrite my project from C# to rust. But I stuck in Segmentation Fault situation. I think I misunderstood something, or meet crate limitation, hope for some help.

Rust Code

use windows::core::{GUID, HRESULT, IUnknown, IUnknown_Vtbl, interface};
use windows::Win32::System::Com::{
    COINIT_APARTMENTTHREADED, 
    CLSCTX_ALL,
    CoInitializeEx,
    CoCreateInstance};

// define interface
#[interface("288EFDEC-3CF0-4F6C-8473-4E4CD47A93C7")]
unsafe trait Inhicshisx: IUnknown {
    fn VPNGetRandomX(&self) -> HRESULT;
}

fn run() -> Result<(), anyhow::Error> {
    unsafe {
        // 2F5AECD5-B5CD-41E1-8265-E2F6AA4548CB
        const CLSID: GUID = GUID {
            data1: 0x2F5AECD5,
            data2: 0xB5CD,
            data3: 0x41E1,
            data4: [0x82, 0x65, 0xE2, 0xF6, 0xAA, 0x45, 0x48, 0xCB],
        };
        
        // initialize runtime
        CoInitializeEx(Some(ptr::null_mut() as *mut c_void), COINIT_APARTMENTTHREADED)?;
        
        // create COM object
        let hisx: Inhicshisx = CoCreateInstance(&CLSID, None, CLSCTX_ALL)?;
        
        // call object function
        let value = hisx.VPNGetRandomX();
    }
    
    Ok(())
}

C# Part

using CSHISXLib;
string MyStr0;
CSHISXLib.Inhicshisx CSHISXLibObj = new CSHISXLib.nhicshisx();
MyStr0 = CSHISXLibObj.VPNGetRandomX();
Console.WriteLine(MyStr0);
  • It works.

Update information

According to @IInspectable help, I can generate interface by oleview.exe tool.

  • generated interface
[
  odl,
  uuid(288EFDEC-3CF0-4F6C-8473-4E4CD47A93C7),
  helpstring("Inhicshisx Interface"),
  dual,
  oleautomation
]
interface Inhicshisx : IDispatch {
    [id(0x00000001), helpstring("method VPNGetRandomX")]
    HRESULT VPNGetRandomX([out, retval] BSTR* strRandom);
    [id(0x00000002), helpstring("method VPNH_SignX")]
    HRESULT VPNH_SignX(
                    [in] BSTR strRandom, 
                    [in, optional, defaultvalue("")] BSTR strCardType, 
                    [in, optional, defaultvalue("")] BSTR strServiceType, 
                    [out, retval] BSTR* strRet);
}
  • Rust code change
use windows::core::BSTR;

#[interface("288EFDEC-3CF0-4F6C-8473-4E4CD47A93C7")]
unsafe trait Inhicshisx: IDispatch {
    fn VPNGetRandomX(&self) -> BSTR;
    fn VPNH_SignX(&self, *mut BSTR, *mut BSTR, *mut BSTR) -> BSTR;
}

But it still cause Segmentation Fault, hope some advice

G.Jim
  • 1
  • 2
  • 1
    The signature for `VPNGetRandomX` looks wrong. In the C# code it appears to be returning a string (of some kind), whereas the Rust version is declared as returning an `HRESULT` only. Please show the IDL description of the `Inhicshisx` interface. – IInspectable Feb 14 '23 at 05:25
  • @IInspectable: My (limited) understanding of COM interfaces is that they generally returns `HRESULT` for all functions, and the actual return value is returned with an output parameter, something like a `BSTR*`. The C# marshall will convert that to an actual return type plus an exception, but I don't think the Rust one will do that. – rodrigo Feb 14 '23 at 09:25
  • @IInspectable Actually, this com library dll file is come from third party team. I'm new to windows programming, is there tool can I extract IDL from dll file? Thank you for your suggestion. – G.Jim Feb 14 '23 at 15:30
  • To my knowledge, there's no way to discover the shape of interfaces given just a COM server DLL. However, you appear to have a type library (.tlb) as well. A TLB is a machine-readable description of interfaces. You can load it into [oleview.exe](https://learn.microsoft.com/en-us/windows/win32/com/ole-com-object-viewer) and have it display the interface descriptions. Or, let MSVC generate C++ header files using an [`#import`](https://learn.microsoft.com/en-us/cpp/preprocessor/hash-import-directive-cpp) directive. – IInspectable Feb 15 '23 at 08:33
  • @IInspectable Thank you very much! oleview.exe helped me take a big step forward. Now, I can generate COM library interface. – G.Jim Feb 16 '23 at 10:36
  • There is no automatic parameter translation happening here. You'll have to faithfully represent the ABI contract. The signature for `VPNGetRandomX` would probably need to look something like `fn VPNGetRandomX(&self, *mut BSTR) -> HRESULT`. – IInspectable Feb 18 '23 at 14:35
  • @IInspectable Thank a lot! It work! I misunderstand the interface. Really thank you for help! – G.Jim Feb 20 '23 at 08:09

1 Answers1

0

Thank for @IInspectable advice.

Segmentation Fault caused by wrong interface.

Find the COM interface

you can use oleview to display for COM library interface. In my case, the interface like this.

interface Inhicshisx : IDispatch {
    [id(0x00000001), helpstring("method VPNGetRandomX")]
    HRESULT VPNGetRandomX([out, retval] BSTR* strRandom);
    [id(0x00000002), helpstring("method VPNH_SignX")]
    HRESULT VPNH_SignX(
                    [in] BSTR strRandom, 
                    [in, optional, defaultvalue("")] BSTR strCardType, 
                    [in, optional, defaultvalue("")] BSTR strServiceType, 
                    [out, retval] BSTR* strRet);
}

Declare interface in Rust

#[interface("288EFDEC-3CF0-4F6C-8473-4E4CD47A93C7")]
unsafe trait Inhicshisx: IDispatch {
    fn VPNGetRandomX(&self, random: *mut BSTR) -> HRESULT;
    fn VPNH_SignX(&self, random: BSTR, card_type: BSTR, service_type: BSTR, sign: *mut BSTR) -> HRESULT;
}
G.Jim
  • 1
  • 2