microsoft / windows-rs

Rust for Windows
https://kennykerr.ca/rust-getting-started/
Apache License 2.0
10.41k stars 488 forks source link

RtmRegisterEntity Access violation #3234

Closed ibigbug closed 1 month ago

ibigbug commented 1 month ago

Summary

I try to impl this example https://learn.microsoft.com/en-us/windows/win32/rras/register-with-the-routing-table-manager

and I get

Exception has occurred: W32/0xC0000005
Unhandled exception at 0x00007FFCFACEBCE4 (rtm.dll) in clash-rs.exe: 0xC0000005: Access violation writing location 0x0000000000000000.

I also get a bit confused about windows::Win32::NetworkManagement::Rras::RTM_ENTITY_ID

https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/NetworkManagement/Rras/struct.RTM_ENTITY_ID.html

and the embedded Anonymous, RTM_ENTITY_ID_0_0 stuff.

is that due to the def is a union https://learn.microsoft.com/en-us/windows/win32/api/rtmv2/ns-rtmv2-rtm_entity_id

typedef struct _RTM_ENTITY_ID {
  union {
    struct {
      ULONG EntityProtocolId;
      ULONG EntityInstanceId;
    };
    ULONGLONG EntityId;
  };
} RTM_ENTITY_ID, *PRTM_ENTITY_ID;

and that is how it looks like mapping to Rust?

I'm not sure if it's related to the pointer issue

Crate manifest

[target.'cfg(windows)'.dependencies]
windows = { version = "0.58", features = [
    "Win32_Networking_WinSock",
    "Win32_Foundation",
    "Win32_NetworkManagement_Rras",
]}

Crate code

let address_family = match dest {
        IpNet::V4(_) => AF_INET,
        IpNet::V6(_) => AF_INET6,
    };

    let rtm_reg_handle: HANDLE = null_mut();
    let mut rtm_entity_info = RTM_ENTITY_INFO::default();
    let mut rtm_regn_profile = RTM_REGN_PROFILE::default();

    rtm_entity_info.RtmInstanceId = 0;
    rtm_entity_info.AddressFamily = address_family.0;
    rtm_entity_info
        .EntityId
        .Anonymous
        .Anonymous
        .EntityProtocolId = PROTO_IP_RIP.0.try_into().unwrap();
    rtm_entity_info
        .EntityId
        .Anonymous
        .Anonymous
        .EntityInstanceId = protocol_id(
        PROTO_TYPE_UCAST,
        PROTO_VENDOR_ID,
        PROTO_IP_RIP.0.try_into().unwrap(),
    );
    let rv = unsafe {
        RtmRegisterEntity(
            &mut rtm_entity_info,
            null_mut(),
            None,
            false,
            &mut rtm_regn_profile,
            rtm_reg_handle as *mut _,
        )
    };

    if rv != ERROR_SUCCESS.0 {
        let err = unsafe { GetLastError().to_hresult().message() };
        error!("failed to register entity: {}", err);
        return Err(new_io_error(err));
    }
kennykerr commented 1 month ago

This sounds more like an API question. Might I suggest https://stackoverflow.com/search?q=windows-rs as I'm not personally familiar with this API.

ibigbug commented 1 month ago

thanks @kennykerr I posted on so https://stackoverflow.com/questions/78929446/rtmregisterentity-access-violation

however regarding the union mapping, is the _0_0 suffix somehow by design, is this how people should pass unions to winapi, do you have examples demonstrating APIs using a union?

tysm!

kennykerr commented 1 month ago

You can have a look at the overlapped sample:

https://github.com/microsoft/windows-rs/blob/9f5ec21529ec0530ac16e9a1c5d16eb8bb290535/crates/samples/windows/overlapped/src/main.rs#L24-L34

kennykerr commented 1 month ago

The challenge is that C, unlike Rust, supports nested structs. So this is a workaround to express that in Rust.

ibigbug commented 1 month ago

i see isee .thanks for the explanation!