Jump to content

Need help creating RASCONNSTATUS structure


VAN0
 Share

Go to solution Solved by TheXman,

Recommended Posts

Hello.

I'm trying create a RASCONNSTATUS structure

So far I've got this much:

Global Const $RAS_MaxDeviceType = 16
Global Const $RAS_MaxDeviceName = 128
Global Const $RAS_MaxPhoneNumber = 128
#cs 
typedef struct _RASCONNSTATUS {
  DWORD             dwSize;
  RASCONNSTATE      rasconnstate;
  DWORD             dwError;
  TCHAR             szDeviceType[RAS_MaxDeviceType + 1];
  TCHAR             szDeviceName[RAS_MaxDeviceName + 1];
  TCHAR             szPhoneNumber[RAS_MaxPhoneNumber + 1];
  RASTUNNELENDPOINT  localEndPoint;
  RASTUNNELENDPOINT  remoteEndPoint;
  RASCONNSUBSTATE    rasconnsubstate;
} RASCONNSTATUS;
#ce
Global Const $tagRASCONNSTATUS = "struct;align 4;" & _
  "dword dwSize;" & _
  "int rasconnstate;" & _
  "dword dwSize;" & _
  "wchar szDeviceType[" & $RAS_MaxDeviceType + 1 & "];" & _
  "wchar szDeviceName[" & $RAS_MaxDeviceName + 1 & "];" & _
  "wchar szPhoneNumber[" & $RAS_MaxPhoneNumber + 1 & "];" & _
  "RASTUNNELENDPOINT localEndPoint;" & _
  "RASTUNNELENDPOINT remoteEndPoint;" & _
  "int rasconnsubstate;" & _
  "endstruct;"

Specifically I'm stuck with RASTUNNELENDPOINT how do I define these?

P.S.

RASCONNSTATE and RASCONNSUBSTATE are int, correct?

Link to comment
Share on other sites

  • Solution

As to your question about the Enums, by default, Enums are 32-bit integers.  To know for sure, you would need to look at how they are defined in their source files.

I don't have any RAS VPNs defined on my PC so I can't test the structs with the actual APIs.  However, I think my translation is correct.

Below is an example of how I would probably define the RASCONNSTATUS & RASTUNNELENDPOINT structures and how I would use them.  The RASIPV4ADDR struct is an alias for in_addr.  The RASIPV6ADDR struct is an alias for in6_addr.  I only gave an example of setting values, in order for you to see the struct with data in it.  Reading values would pretty much be the same, except you would be getting the values instead of setting them.

Example:

#include <Constants.au3>
#include <WinAPIDiag.au3>


Const $RAS_MaxDeviceType  = 16,  _
      $RAS_MaxDeviceName  = 128, _
      $RAS_MaxPhoneNumber = 128

Enum  $RASTUNNELENDPOINT_UNKNOWN, _  ;0
      $RASTUNNELENDPOINT_IPV4,    _  ;1
      $RASTUNNELENDPOINT_IPV6        ;2

#cs
    typedef struct RASTUNNELENDPOINT
    {
        DWORD dwType;
        union {
            RASIPV4ADDR ipv4;
            RASIPV6ADDR ipv6;
        };
    };
#ce
Global $tagRASTUNNELENDPOINT = _
    "struct;"          & _
    "dword dwType;"    & _
    "byte  bytes[16];" & _
    "endstruct;"

Global $tagRASTUNNELENDPOINT_UNION_IPV4 = _
    "struct;"             & _
    "dword dwType;"       & _
    "byte  bytes[4];"     & _
    "endstruct;"

Global $tagRASTUNNELENDPOINT_UNION_IPV6 = _
    "struct;"            & _
    "dword  dwType;"     & _
    "word   words[8];"   & _
    "endstruct;"

#cs
    typedef struct RASCONNSTATUS {
      DWORD             dwSize;
      RASCONNSTATE      rasconnstate;
      DWORD             dwError;
      TCHAR             szDeviceType[RAS_MaxDeviceType + 1];
      TCHAR             szDeviceName[RAS_MaxDeviceName + 1];
      TCHAR             szPhoneNumber[RAS_MaxPhoneNumber + 1];
      RASTUNNELENDPOINT  localEndPoint;
      RASTUNNELENDPOINT  remoteEndPoint;
      RASCONNSUBSTATE    rasconnsubstate;
    } RASCONNSTATUS;
#ce
Global $tagRASCONNSTATUS = _
    "struct;"                                               & _
    "dword dwSize;"                                         & _
    "int   rasconnstate;"                                   & _
    "dword dwError;"                                        & _
    "wchar szDeviceType["  & $RAS_MaxDeviceType  + 1 & "];" & _
    "wchar szDeviceName["  & $RAS_MaxDeviceName  + 1 & "];" & _
    "wchar szPhoneNumber[" & $RAS_MaxPhoneNumber + 1 & "];" & _
    $tagRASTUNNELENDPOINT                                   & _ ;local endpoint
    $tagRASTUNNELENDPOINT                                   & _ ;remote endpoint
    "int   rasconnsubstate;"                                & _
    "endstruct;"


example()

Func example()

    Local $tRASCONNSTATUS, _
          $tENDPOINT

    ;Create RASCONNSTATUS structure
    $tRASCONNSTATUS = DllStructCreate($tagRASCONNSTATUS)

    ;Set RASCONNSTATUS dwSize field
    $tRASCONNSTATUS.dwSize = DllStructGetSize($tRASCONNSTATUS)

    $tRASCONNSTATUS.szDeviceType  = "Some device type"
    $tRASCONNSTATUS.szDeviceName  = "Some device name"
    $tRASCONNSTATUS.szPhoneNumber = "8005551212"

    ;Set local ipv4 tunnel endpoint
    $tENDPOINT        = DllStructCreate($tagRASTUNNELENDPOINT_UNION_IPV4, DllStructGetPtr($tRASCONNSTATUS, 7))
    $tENDPOINT.dwType = $RASTUNNELENDPOINT_IPV4
    $tENDPOINT.bytes(1) = 127 ;127.0.0.1
    $tENDPOINT.bytes(2) = 0
    $tENDPOINT.bytes(3) = 0
    $tENDPOINT.bytes(4) = 1

    ;Set remote ipv6 tunnel endpoint
    $tENDPOINT          = DllStructCreate($tagRASTUNNELENDPOINT_UNION_IPV6, DllStructGetPtr($tRASCONNSTATUS, 9))
    $tENDPOINT.dwType   = $RASTUNNELENDPOINT_IPV6
    $tENDPOINT.words(1) = Binary("0x2001") ;2001:0db8:85a3:0000:0000:8a2e:0370:7334
    $tENDPOINT.words(2) = Binary("0x0db8")
    $tENDPOINT.words(3) = Binary("0x85a3")
    $tENDPOINT.words(4) = Binary("0x0000")
    $tENDPOINT.words(5) = Binary("0x0000")
    $tENDPOINT.words(6) = Binary("0x8a2e")
    $tENDPOINT.words(7) = Binary("0x0370")
    $tENDPOINT.words(8) = Binary("0x7334")

    ;Display example struct
    _WinAPI_DisplayStruct($tRASCONNSTATUS, $tagRASCONNSTATUS, "RASCONNSTATUS")
EndFunc

image.png.f2448128b328ec246edba6b4eeaceda3.png

 

Edited by TheXman
Link to comment
Share on other sites

You're welcome!

The size of the $tagRASTUNNELENDPOINT struct is 20 bytes.  As I showed in the example, the RASTUNNELENDPOINT struct is defined as:

typedef struct RASTUNNELENDPOINT
{
    DWORD dwType;
    union {
        RASIPV4ADDR ipv4;
        RASIPV6ADDR ipv6;
    };
};

That's a DWORD (4 bytes) followed by a union containing 2 members, a RASIPV4ADDR struct and a RASIPV6ADDR struct.  The RASIPV4ADDR struct is 4 bytes and the RASIPV6ADDR struct is 16 bytes (8 WORDs).  The size of a union in memory is the size of the largest member within the union.  Therefore, the size of the RASTUNNELENDPOINT struct is: DWORD (4 btyes) + the size of the largest member within the union (16 bytes).  So the total size is 20 bytes.

If you need a high-level explanation of C Unions, the provided link is a good start.

 

The RASCONNSTATUS and RASTUNNELENDPOINT structs can be defined in AutoIt in multiple ways that can produce the same result.  Since AutoIt does not have an intrinsic data type similar to a C union, I choose to define unions by defining the physical (memory) representation and also the logical representations.  The physical representations are used to read/write the whole struct to/from memory.  The logical representations are used to correctly get and set members within a union.

That is why you see in my example:

  • $tagRASTUNNELENDPOINT (the physical representation; how the data is stored in memory)
  • $tagRASTUNNELENDPOINT_UNION_IPV4 (logical definition of an IPV4 endpoint struct)
  • $tagRASTUNNELENDPOINT_UNION_IPV6 (logical definition of an IPV6 endpoint struct)

If you look at my previous example, the logical structs are used to set the values.  Basically, the pointer of the logical struct is set to the physical memory location of the endpoint struct that I want to set.  In memory, the endpoint's IP address takes up 16 bytes whether it is IPV4 or IPV6,  The logical structs define how I reference the memory location, which can be as an IPV4 endpoint (4 bytes) or an IPV6 endpoint (8, 2-byte WORDs; 16 bytes).

Edited by TheXman
Added a more detailed explanation
Link to comment
Share on other sites

Sure.  The example below is a different way to define the structs.  Note that the way the endpoints are set is a little different.  This allows for the use of member names, instead of indexes, when using the DllStructGetPtr() functions.  There are reasons why I prefer to use the original way, but this way works too.  It produces the exact same result as the original example.

#include <Constants.au3>
#include <WinAPIDiag.au3>


Const $RAS_MaxDeviceType  = 16,  _
      $RAS_MaxDeviceName  = 128, _
      $RAS_MaxPhoneNumber = 128

Enum  $RASTUNNELENDPOINT_UNKNOWN, _  ;0
      $RASTUNNELENDPOINT_IPV4,    _  ;1
      $RASTUNNELENDPOINT_IPV6        ;2

#cs
    typedef struct RASTUNNELENDPOINT
    {
        DWORD dwType;
        union {
            RASIPV4ADDR ipv4;
            RASIPV6ADDR ipv6;
        };
    };
#ce
Global $tagRASIPV4ADDR = "byte bytes[4];"
Global $tagRASIPV6ADDR = "word words[8];"

#cs
    typedef struct RASCONNSTATUS {
      DWORD             dwSize;
      RASCONNSTATE      rasconnstate;
      DWORD             dwError;
      TCHAR             szDeviceType[RAS_MaxDeviceType + 1];
      TCHAR             szDeviceName[RAS_MaxDeviceName + 1];
      TCHAR             szPhoneNumber[RAS_MaxPhoneNumber + 1];
      RASTUNNELENDPOINT  localEndPoint;
      RASTUNNELENDPOINT  remoteEndPoint;
      RASCONNSUBSTATE    rasconnsubstate;
    } RASCONNSTATUS;
#ce
Global $tagRASCONNSTATUS = _
    "struct;"                                                 & _
    "  dword dwSize;"                                         & _
    "  int   rasconnstate;"                                   & _
    "  dword dwError;"                                        & _
    "  wchar szDeviceType["  & $RAS_MaxDeviceType  + 1 & "];" & _
    "  wchar szDeviceName["  & $RAS_MaxDeviceName  + 1 & "];" & _
    "  wchar szPhoneNumber[" & $RAS_MaxPhoneNumber + 1 & "];" & _
    "  struct;"                                               & _
    "    dword dwLocalEndpointType;"                          & _
    "    byte  localEndpoint[16];"                            & _
    "  endstruct;"                                            & _
    "  struct;"                                               & _
    "    dword dwRemoteEndpointType;"                         & _
    "    byte  remoteEndpoint[16];"                           & _
    "  endstruct;"                                            & _
    "  int   rasconnsubstate;"                                & _
    "endstruct;"


example()

Func example()

    Local $tRASCONNSTATUS, _
          $tENDPOINT

    ;Create RASCONNSTATUS structure
    $tRASCONNSTATUS = DllStructCreate($tagRASCONNSTATUS)

    ;Set RASCONNSTATUS dwSize field
    $tRASCONNSTATUS.dwSize = DllStructGetSize($tRASCONNSTATUS)

    $tRASCONNSTATUS.szDeviceType  = "Some device type"
    $tRASCONNSTATUS.szDeviceName  = "Some device name"
    $tRASCONNSTATUS.szPhoneNumber = "8005551212"

    ;Set local ipv4 tunnel endpoint
    $tRASCONNSTATUS.dwLocalEndpointType = $RASTUNNELENDPOINT_IPV4

    $tENDPOINT = DllStructCreate($tagRASIPV4ADDR, DllStructGetPtr($tRASCONNSTATUS, "localEndpoint"))
    $tENDPOINT.bytes(1) = 127 ;127.0.0.1
    $tENDPOINT.bytes(2) = 0
    $tENDPOINT.bytes(3) = 0
    $tENDPOINT.bytes(4) = 1

    ;Set remote ipv6 tunnel endpoint
    $tRASCONNSTATUS.dwRemoteEndpointType = $RASTUNNELENDPOINT_IPV6

    $tENDPOINT = DllStructCreate($tagRASIPV6ADDR, DllStructGetPtr($tRASCONNSTATUS, "remoteEndpoint"))
    $tENDPOINT.words(1) = Binary("0x2001") ;2001:0db8:85a3:0000:0000:8a2e:0370:7334
    $tENDPOINT.words(2) = Binary("0x0db8")
    $tENDPOINT.words(3) = Binary("0x85a3")
    $tENDPOINT.words(4) = Binary("0x0000")
    $tENDPOINT.words(5) = Binary("0x0000")
    $tENDPOINT.words(6) = Binary("0x8a2e")
    $tENDPOINT.words(7) = Binary("0x0370")
    $tENDPOINT.words(8) = Binary("0x7334")

    ;Display example struct
    _WinAPI_DisplayStruct($tRASCONNSTATUS, $tagRASCONNSTATUS, "RASCONNSTATUS")
EndFunc

image.png.6c9e17402b947554dc0745098bf8677e.png

Edited by TheXman
Link to comment
Share on other sites

Awesome!

But why doesn't this work?:

Global $tagRASTUNNELENDPOINT_UNION_IPV4 = _
    "struct;"             & _
    "dword dwType;"       & _
    "byte  localEndpoint[4];"     & _
    "endstruct;"

I thought the structure of a struct field is: `<type> <name>;` so basically `<name>` can be anything?, but in this particular case replacing `bytes` with anything else results in no data assigned to that field.

Link to comment
Share on other sites

2 minutes ago, VAN0 said:

But why doesn't this work?:

I have no way to know without seeing the script that uses your struct.

Link to comment
Share on other sites

Ops, my bad. I was referring to your original example, where I replaced keyword "bytes":

Global $tagRASTUNNELENDPOINT_UNION_IPV4 = _
    "struct;"             & _
    "dword dwType;"       & _
    "byte  bytes[4];"     & _
    "endstruct;"

with "localEndpoint":

 

Global $tagRASTUNNELENDPOINT_UNION_IPV4 = _
    "struct;"             & _
    "dword dwType;"       & _
    "byte  localEndpoint[4];"     & _
    "endstruct;"
Link to comment
Share on other sites

I'm not going to make assumptions on why it may not have worked.  So again, without seeing the relevant part of the script that implements your changes, I have no way to know why it may not have worked. 

Edited by TheXman
Link to comment
Share on other sites

I am an idiot...I totally missed the part that the data is explicitly assigned to `bytes` by:

$tENDPOINT.bytes(1) = 127 ;127.0.0.1
    $tENDPOINT.bytes(2) = 0
    $tENDPOINT.bytes(3) = 0
    $tENDPOINT.bytes(4) = 1

I thought it was some sort of internal function call...

 
Link to comment
Share on other sites

Yes, the name I used for the byte array was "bytes" and the name for the word array was "words".  I can see how that may have been a little hard to decipher at first.  :)  It does look like some sort of internal function when using dot-notation instead of DllStructSetData() with member names.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...