Jump to content

Using Wlanapi.dll in autoit


Recommended Posts

Hi, i'm trying to make gui application to use windows netsh.exe. But there is problem because netsh.exe console output is in several languages. So i can't do that by this way. I found on msdn site library called wlanapi.dll. I want to use wlan hostednetwork functions from it but i don't know how to use dll's that much in autoit. Can anyone help me write those functions in autoit? :

Spoiler



DWORD WINAPI WlanHostedNetworkStartUsing(
  _In_       HANDLE                      hClientHandle,
  _Out_opt_  PWLAN_HOSTED_NETWORK_REASON pFailReason,
  _Reserved_ PVOID                       pvReserved
);

DWORD WINAPI WlanOpenHandle(
   _In_        DWORD dwClientVersion,
   _Reserved_  PVOID pReserved,
   _Out_       PDWORD pdwNegotiatedVersion,
   _Out_       PHANDLE phClientHandle
 );

DWORD WINAPI WlanHostedNetworkSetProperty(
   _In_        HANDLE hClientHandle,
   _In_        WLAN_HOSTED_NETWORK_OPCODE OpCode,
   _In_        DWORD dwDataSize,
   _In_        PVOID pvData,
   _Out_opt_   PWLAN_HOSTED_NETWORK_REASON pFailReason,
   _Reserved_  PVOID pvReserved
 );


 

And other functions that i don't know to view hostednetwork status, turn off.

Link to comment
Share on other sites

I made an example for one of your functions, you can read in help file all documentation about how you can call function from dll.

ConsoleWrite('Handle: ' & WlanOpenHandle(2) & @CRLF)

Func WlanOpenHandle($dwClientVersion)
    Local $aRet = DllCall('Wlanapi.dll','dword','WlanOpenHandle', 'dword', $dwClientVersion, 'ptr', Null, 'dword*', 0, 'handle*', 0)
    If IsArray($aRet) Then
        If $aRet[0] = 0 Then
            Return $aRet[4]
        Else
            Return SetError(1)
        EndIf
    Else
        Return SetError(2)
    EndIf
EndFunc

 

Link to comment
Share on other sites

Thanks but i see that function returns handle in "_Out_      PHANDLE phClientHandle" and you write here null. And in documentatnion "_Out_      PDWORD  pdwNegotiatedVersion" can't be null

Edited by MrKris1224
Link to comment
Share on other sites

That's not true, I passed a NULL for pReserved whici should be NULL and for pdwNegotiatedVersion and phClientHandle I let AutoIt to create the variables. DllCall will return an array as follow:

$aRet[0] = function return value

$aRet[1] = dwClientVersion (first param)

$aRet[2] = pReserved (second param)

$aRet[3] = pdwNegotiatedVersion (third param)

$aRet[4] = phClientHandle (fourth param)

Link to comment
Share on other sites

Ohh sorry I didn't know that working this way. So now i will write next functions and tell you if taht works.

@Update
I write next function but seems not work :/
This will set hostednetwork mode to allow/deny:
 

$wlanHandle = WlanOpenHandle(2)
WlanSetMode($wlanHandle, True)

Func WlanOpenHandle($dwClientVersion)
    Local $aRet = DllCall('Wlanapi.dll','dword','WlanOpenHandle', 'dword', $dwClientVersion, 'ptr', Null, 'dword*', 0, 'handle*', 0)
    If IsArray($aRet) Then
        If $aRet[0] = 0 Then
            Return $aRet[4] ;phClientHandle
        Else
            Return SetError(1)
        EndIf
    Else
        Return SetError(2)
    EndIf
EndFunc

Func WlanSetMode($hHandle, $bAllow)
    Local $aRet = DllCall("Wlanapi.dll", "dword", "WlanHostedNetworkSetProperty", "handle", $hHandle, "dword", 3, "dword", 1, "bool", $bAllow, "dword", 0, "ptr", Null)
    If IsArray($aRet) Then
        If $aRet[0] = 0 Then
            Return $aRet[6] ;pFailReason
        Else
            Return SetError(1)
        EndIf
    Else
        Return SetError(2)
    EndIf
EndFunc

What's wrong in this dll call?

From msdn:

DWORD WINAPI WlanHostedNetworkSetProperty(
  _In_       HANDLE                      hClientHandle,
  _In_       WLAN_HOSTED_NETWORK_OPCODE  OpCode,
  _In_       DWORD                       dwDataSize,
  _In_       PVOID                       pvData,
  _Out_opt_  PWLAN_HOSTED_NETWORK_REASON pFailReason,
  _Reserved_ PVOID                       pvReserved
);

So first parameter type "handle" and handle given by previous function, then OpCode enum. From msdn:

typedef enum _WLAN_HOSTED_NETWORK_OPCODE { 
  wlan_hosted_network_opcode_connection_settings,
  wlan_hosted_network_opcode_security_settings,
  wlan_hosted_network_opcode_station_profile,
  wlan_hosted_network_opcode_enable
} WLAN_HOSTED_NETWORK_OPCODE, *PWLAN_HOSTED_NETWORK_OPCODE;

So enable OpCode is number 3 in this case. Second parameter type "dword" and 3 value, third parameter type "dword" and value 1 (boolean bytes size), fourth parameter "bool"? and True/False, fifth "dword*"?, value 0 and that will return in array enum of fail reason, and six parameter null.

And fail reason from msdn:

Spoiler

typedef enum _WLAN_HOSTED_NETWORK_REASON { 
  wlan_hosted_network_reason_success                               = 0,
  wlan_hosted_network_reason_unspecified,
  wlan_hosted_network_reason_bad_parameters,
  wlan_hosted_network_reason_service_shutting_down,
  wlan_hosted_network_reason_insufficient_resources,
  wlan_hosted_network_reason_elevation_required,
  wlan_hosted_network_reason_read_only,
  wlan_hosted_network_reason_persistence_failed,
  wlan_hosted_network_reason_crypt_error,
  wlan_hosted_network_reason_impersonation,
  wlan_hosted_network_reason_stop_before_start,
  wlan_hosted_network_reason_interface_available,
  wlan_hosted_network_reason_interface_unavailable,
  wlan_hosted_network_reason_miniport_stopped,
  wlan_hosted_network_reason_miniport_started,
  wlan_hosted_network_reason_incompatible_connection_started,
  wlan_hosted_network_reason_incompatible_connection_stopped,
  wlan_hosted_network_reason_user_action,
  wlan_hosted_network_reason_client_abort,
  wlan_hosted_network_reason_ap_start_failed,
  wlan_hosted_network_reason_peer_arrived,
  wlan_hosted_network_reason_peer_departed,
  wlan_hosted_network_reason_peer_timeout,
  wlan_hosted_network_reason_gp_denied,
  wlan_hosted_network_reason_service_unavailable,
  wlan_hosted_network_reason_device_change,
  wlan_hosted_network_reason_properties_change,
  wlan_hosted_network_reason_virtual_station_blocking_use,
  wlan_hosted_network_reason_service_available_on_virtual_station
} WLAN_HOSTED_NETWORK_REASON, *PWLAN_HOSTED_NETWORK_REASON;

 

DllCall returns fifth parameter = 2 so "wlan_hosted_network_reason_bad_parameters"?

Edited by MrKris1224
Link to comment
Share on other sites

The function needs admin privileges to enable Wlan so either run scite as admin or use #RequireAdmin..

 

;;#RequireAdmin

Global Enum $wlan_hosted_network_opcode_connection_settings = 0, _
        $wlan_hosted_network_opcode_security_settings, _
        $wlan_hosted_network_opcode_station_profile, _
        $wlan_hosted_network_opcode_enable


$hWlan = WlanOpenHandle(2)
Msgbox(0, "WlanOpenHandle", "handle: " & $hWlan)

WlanSetMode($hWlan, False)
If @error Then Msgbox(0,"WlanSetMode Error", "error: " & @error & " , extended: " & @extended)

Func WlanOpenHandle($dwClientVersion)
    Local $aRet = DllCall('Wlanapi.dll', 'dword', 'WlanOpenHandle', 'dword', $dwClientVersion, 'ptr', Null, 'dword*', 0, 'handle*', 0)
    If IsArray($aRet) Then
        If $aRet[0] = 0 Then
            Return $aRet[4] ;phClientHandle
        Else
            Return SetError(1, $aRet[0])
        EndIf
    Else
        Return SetError(2)
    EndIf
EndFunc   ;==>WlanOpenHandle

Func WlanSetMode($hHandle, $bAllow)
    ;Any user can call this function to set the Hosted Network properties.
    ;However, to set the wlan_hosted_network_opcode_enable flag requires elevated privileges
    Local $tEnable = DllStructCreate("bool bEnabled")
    DllStructSetData($tEnable, "bEnabled", $bAllow)

    Local $aRet = DllCall("Wlanapi.dll", "dword", "WlanHostedNetworkSetProperty", _
            "handle", $hHandle, _
            "dword", $wlan_hosted_network_opcode_enable, _
            "dword", DllStructGetSize($tEnable), _ ;Let AutoIt supply the size
            "ptr", DllStructGetPtr($tEnable), _    ;Pointer to the struct
            "dword", 0, _
            "ptr", Null)

    If IsArray($aRet) Then
        If $aRet[0] = 0 Then ;0 Means success
            Return SetError(0)
        Else
            ;https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
            ;https://msdn.microsoft.com/en-us/library/windows/desktop/dd439506(v=vs.85).aspx
            Return SetError($aRet[0], $aRet[5])
        EndIf
    Else
        Return SetError(2)
    EndIf
EndFunc   ;==>WlanSetMode

you also had your $aRet parameter off by 1

it goes

$aRet = DllCall(dllname/handle, returntype($aRet0), FunctionName, Param1Type, $aRet[1], Param2Type, $aRet[2]............)

 

Edited by Bilgus
Link to comment
Share on other sites

IIRC Bool is 4 Bytes So this would probably work as well but rather than guessing I'd prefer the way above...

Func WlanSetMode($hHandle, $bAllow)
    ;Any user can call this function to set the Hosted Network properties.
    ;However, to set the wlan_hosted_network_opcode_enable flag requires elevated privileges

    Local $aRet = DllCall("Wlanapi.dll", "dword", "WlanHostedNetworkSetProperty", _
            "handle", $hHandle, _
            "dword", $wlan_hosted_network_opcode_enable, _
            "dword", 4, _
            "bool*", $bAllow, _
            "dword", 0, _
            "ptr", Null)

    If IsArray($aRet) Then
        If $aRet[0] = 0 Then ;0 Means success
            Return SetError(0)
        Else
            ;https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
            ;https://msdn.microsoft.com/en-us/library/windows/desktop/dd439506(v=vs.85).aspx
            Return SetError($aRet[0], $aRet[5])
        EndIf
    Else
        Return SetError(2)
    EndIf
EndFunc   ;==>WlanSetMode

 

Link to comment
Share on other sites

The Wlan functions require you to hold an open handle to the dll when you use dllcall like above it opens the dll and then closes it

Instead you need to use dllopen like so..

#RequireAdmin

Global Enum $wlan_hosted_network_opcode_connection_settings = 0, _
        $wlan_hosted_network_opcode_security_settings, _
        $wlan_hosted_network_opcode_station_profile, _
        $wlan_hosted_network_opcode_enable

Global $hDll_Wlanapi
Global $hWlan = WlanOpenHandle(2, $hDll_Wlanapi)
MsgBox(0, "WlanOpenHandle", "handle: " & $hWlan)

WlanSetMode($hWlan, False, $hDll_Wlanapi)
If @error Then MsgBox(0, "WlanSetMode Error", "error: " & @error & " , extended: " & @extended)

WlanCloseHandle($hWlan, $hDll_Wlanapi)

Func WlanCloseHandle($hHandle, ByRef $hDll_Wlanapi)
    Local $aRet = DllCall($hDll_Wlanapi, 'dword', 'WlanCloseHandle', 'handle', $hHandle, 'ptr', Null)
    DllClose($hDll_Wlanapi)
    $hDll_Wlanapi = 0
    If IsArray($aRet) Then
        If $aRet[0] = 0 Then
            Return True
        Else
            Return SetError(1, $aRet[0], False)
        EndIf
    Else
        Return SetError(2, 0, False)
    EndIf
EndFunc   ;==>WlanCloseHandle

Func WlanOpenHandle($dwClientVersion, ByRef $hDll_Wlanapi)
    If Not $hDll_Wlanapi Then $hDll_Wlanapi = DllOpen("Wlanapi.dll")
    Local $aRet = DllCall($hDll_Wlanapi, 'dword', 'WlanOpenHandle', 'dword', $dwClientVersion, 'ptr', Null, 'dword*', 0, 'handle*', 0)
    If IsArray($aRet) Then
        If $aRet[0] = 0 Then
            Return $aRet[4] ;phClientHandle
        Else
            Return SetError(1, $aRet[0])
        EndIf
    Else
        Return SetError(2)
    EndIf
EndFunc   ;==>WlanOpenHandle

Func WlanSetMode($hHandle, $bAllow, $hDll_Wlanapi)
    ;Any user can call this function to set the Hosted Network properties.
    ;However, to set the wlan_hosted_network_opcode_enable flag requires elevated privileges
    Local $tEnable = DllStructCreate("bool bEnabled")
    DllStructSetData($tEnable, "bEnabled", $bAllow)

    Local $aRet = DllCall($hDll_Wlanapi, "dword", "WlanHostedNetworkSetProperty", _
            "handle", $hHandle, _
            "dword", $wlan_hosted_network_opcode_enable, _
            "dword", DllStructGetSize($tEnable), _
            "ptr", DllStructGetPtr($tEnable), _
            "dword", 0, _
            "ptr", Null)

    If IsArray($aRet) Then
        If $aRet[0] = 0 Then ;0 Means success
            Return SetError(0)
        Else
            ;https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
            ;https://msdn.microsoft.com/en-us/library/windows/desktop/dd439506(v=vs.85).aspx
            Return SetError($aRet[0], $aRet[5])
        EndIf
    Else
        Return SetError(2)
    EndIf
EndFunc   ;==>WlanSetMode

Also this has been done already

 

Link to comment
Share on other sites

  • 2 weeks later...

Thanks everyone for help. Now i'am trying to make function:

 

DWORD WINAPI WlanHostedNetworkQueryStatus(
  _In_       HANDLE                      hClientHandle,
  _Out_      PWLAN_HOSTED_NETWORK_STATUS *ppWlanHostedNetworkStatus,
  _Reserved_ PVOID                       pvReserved
);

But i don't know how to make that output structure in autoit:

 


typedef struct _WLAN_HOSTED_NETWORK_STATUS {
  WLAN_HOSTED_NETWORK_STATE      HostedNetworkState;
  GUID                           IPDeviceID;
  DOT11_MAC_ADDRESS              wlanHostedNetworkBSSID;
  DOT11_PHY_TYPE                 dot11PhyType;
  ULONG                          ulChannelFrequency;
  DWORD                          dwNumberOfPeers;
  WLAN_HOSTED_NETWORK_PEER_STATE PeerList[1];
} WLAN_HOSTED_NETWORK_STATUS, *PWLAN_HOSTED_NETWORK_STATUS;

 

Link to comment
Share on other sites

you'll have to look up what each of those underlying types are for instance..

WLAN_HOSTED_NETWORK_STATE

msdn shows this to be an enumeration, enums are typically INT

Guid is alrady defined in autoit as $tagGUID
$tag_WLAN_HOSTED_NETWORK_STATUS = "INT HostedNetworkState;" & $tag_GUID

next is DOT11_MAC_ADDRESS, https://msdn.microsoft.com/en-us/library/windows/desktop/bb427397(v=vs.85).aspx

typedef UCHAR DOT11_MAC_ADDRESS[6];
typedef DOT11_MAC_ADDRESS* PDOT11_MAC_ADDRESS;

so this one is an array of 6 UCHAR and a pointer we have to spread it out in an autoit tag struct unfortunately

$tag_WLAN_HOSTED_NETWORK_STATUS = "INT HostedNetworkState;" & $tag_GUID & ";byte Mac_Address[6];ptr pMacAddress;"

note the first ';' after guid I needed to add that to mark the end of the guid structure

next note 'byte' instead of 'uchar', I looked in the help file to find the matching autoit data type to 'uchar'

and finally note the names have meaning only to YOU the function you pass this struc to cares only for the data types for instance

$tag_WLAN_HOSTED_NETWORK_STATUS = "INT;" & $tag_GUID & ";byte[6];ptr;"

would work just the same as far as the API is concerned

 

This should get you started...

 

 

 

PS. if I'm not completely sure what a data type is  I look for the include file on the page.. Windot11.h (include Windot11.h)

I find this https://github.com/tpn/winsdk-10/blob/master/Include/10.0.10240.0/shared/windot11.h

and look at the C defines and search from there

 

 

 

Link to comment
Share on other sites

Thanks, for reply.

Now im stuck on last structure element:

"DWORD                          dwNumberOfPeers;"
 

that's array of structure:
 

typedef struct _WLAN_HOSTED_NETWORK_PEER_STATE {
  DOT11_MAC_ADDRESS                   PeerMacAddress;
  WLAN_HOSTED_NETWORK_PEER_AUTH_STATE PeerAuthState;
} WLAN_HOSTED_NETWORK_PEER_STATE, *PWLAN_HOSTED_NETWORK_PEER_STATE;

now mine struct looks:

 

Global $tag_WLAN_HOSTED_NETWORK_STATUS = "INT HostedNetworkState;" & $tag_GUID & ";byte Mac_Address[6];ptr pMacAddress;ulong ulChannelFrequency;dword dwNumberOfPeers;"

how will i do that?

Edited by MrKris1224
Link to comment
Share on other sites

Your best bet is probably to just make it byte[] and grab it after 

DOT11_MAC_ADDRESS                   PeerMacAddress; <- uchar[6]
  WLAN_HOSTED_NETWORK_PEER_AUTH_STATE PeerAuthState; <-Int(ENUM)
Global $tag_WLAN_HOSTED_NETWORK_STATUS = "INT HostedNetworkState;" & $tag_GUID & ";byte Mac_Address[6];ptr pMacAddress;ulong ulChannelFrequency;dword dwNumberOfPeers;byte PeerState[6 + 4];"

So after you know the size of dwNumberOfPeers you can do like this

;~~~$tag_WLAN_HOSTED_NETWORK_STATUS => $tNetworkStatus
Local $iPeers = DllStructGet($tNetworkStatus, "dwNumberOfPeers")
;
Local Const $tag_WLAN_HOSTED_NETWORK_PEER_STATE = "byte PeerMacAddress[6];int PeerAuthState;"

Local $tag_WLAN_HPSA = ""

For $i = 0 to $iPeers

;Lets Build Our Struct
$tag_WLAN_HPSA &= $tag_WLAN_HPSA & $tag_WLAN_HOSTED_NETWORK_PEER_STATE
Next

Now we can use the appropriately sized struct with the pointer to the data 'PeerState'

Local $pPeerState = DllStructGetPtr($tNetworkStatus, "PeerState")

If Not $pPeerState Then consoleWrite("ERROR..")

$tPeerState = DllStructCreate($tag_WLAN_HPSA, $pPeerState)

Now to read each item in tPeerState you need to access it by position or you can get fancy with the declaration and add an integer to each name as you build it..

Like Using string replace with... Local Const $tag_WLAN_HOSTED_NETWORK_PEER_STATE = "byte PeerMacAddressX[6];int PeerAuthStateX;"

DllStructGetData($tPeerState, 1) ; PeerMacAddress(1)
DllStructGetData($tPeerState, 2) ; PeerAuthState(1)
DllStructGetData($tPeerState, 3) ; PeerMacAddress(2)
DllStructGetData($tPeerState, 4) ; PeerAuthState(2)
;;;;;;;;;;;;;;;
DllStructGetData($tPeerState, 13) ; PeerMacAddress(7)
DllStructGetData($tPeerState, 14) ; PeerAuthState(7)

 

 

There may be other ways to interface with a struct like this but, I've found this way to be pretty straight forward

Edit: Ps This is all pseudo code so don't be surprised if it doesn't run out of the box 

Edited by Bilgus
Link to comment
Share on other sites

I think it's too hard for me :/ can i just write here void or something? i don't need list of peers

 

@edit

It's mine code excluding functions from last posts:

 

Global $tag_WLAN_HOSTED_NETWORK_STATUS = "INT HostedNetworkState;int IPDeviceID;byte Mac_Address[6];ptr pMacAddress;ulong ulChannelFrequency;dword dwNumberOfPeers;byte nothing[1]"
Global $hDll_Wlanapi = DllOpen("Wlanapi.dll")
Global $hWlan = WlanOpenHandle(2)

MsgBox(0,"",WlanHostedNetworkQueryStatus($hWlan).HostedNetworkState)

WlanCloseHandle($hWlan)

Func WlanHostedNetworkQueryStatus($hHandle)
    Local $tWlan_hosted_network_status = DllStructCreate($tag_WLAN_HOSTED_NETWORK_STATUS)
    Local $aRet = DllCall($hDll_Wlanapi, 'dword', 'WlanHostedNetworkQueryStatus', 'handle', $hHandle, 'ptr', DllStructGetPtr($tWlan_hosted_network_status), 'ptr', null)
    If IsArray($aRet) Then
        If $aRet[0] = 0 Then
            Return $tWlan_hosted_network_status
        Else
            Return SetError(1, $aRet[0], False)
        EndIf
    Else
        return SetError(2, 0, False)
    EndIf
EndFunc

Every run it's returning random digit. What's wrong? I just need query hostednetwork state and NUMBER of peers, hostednetwork bssid, not peer list.

Edited by MrKris1224
Link to comment
Share on other sites

Yes you should be able to just leave it off completely if you don't need the information but its probably alignment that is your problem

Global $tag_WLAN_HOSTED_NETWORK_STATUS = "STRUCT;INT HostedNetworkState;int IPDeviceID;byte Mac_Address[6];ptr pMacAddress;ulong ulChannelFrequency;dword dwNumberOfPeers;ENDSTRUCT;"

There are some API that you have to pass the pre-allocated structure usually you have to pass a size parameter with the struct for those APIs this particular API isn't one of them it just gives you a pointer for the data and you use that to fill the proper structure so if you leave off the last half of the struct (assuming you don't need it) no harm no foul

Link to comment
Share on other sites

Looking at the MSDN Page for this function it has a particular requirement for calls

Quote
ppWlanHostedNetworkStatus [out]

On input, this parameter must be NULL.

On output, this parameter receives a pointer to the current status of the wireless Hosted Network, if the call to the WlanHostedNetworkQueryStatusfunction succeeds. The current status is returned in a WLAN_HOSTED_NETWORK_STATUS structure.

so it should probably be:

Global $tag_WLAN_HOSTED_NETWORK_STATUS = "STRUCT;INT HostedNetworkState;int IPDeviceID;byte Mac_Address[6];ptr pMacAddress;ulong ulChannelFrequency;dword dwNumberOfPeers;ENDSTRUCT"
Global $hDll_Wlanapi = DllOpen("Wlanapi.dll")
Global $hWlan = WlanOpenHandle(2)

MsgBox(0,"",WlanHostedNetworkQueryStatus($hWlan).HostedNetworkState)

WlanCloseHandle($hWlan)

Func WlanHostedNetworkQueryStatus($hHandle)
    Local $tWlan_hosted_network_status
    Local $aRet = DllCall($hDll_Wlanapi, 'dword', 'WlanHostedNetworkQueryStatus', 'handle', $hHandle, 'ptr*', 0, 'ptr', null)
    If IsArray($aRet) Then
        If $aRet[0] = 0 Then
            $tWlan_hosted_network_status = DllStructCreate($tag_WLAN_HOSTED_NETWORK_STATUS, $aRet[2])
            Return $tWlan_hosted_network_status
        Else
            Return SetError(1, $aRet[0], False)
        EndIf
    Else
        return SetError(2, 0, False)
    EndIf
EndFunc

Note the *ppWlanHostedNetworkStatus *pp denotes pointer to a pointer in Windows API speak

 

Also, Don't forget.. WlanFreeMemory when you are done with the info its important to free the memory when the API allocates it for you...

Quote

If the function succeeds, the ppWlanHostedNetworkStatus parameter points to a WLAN_HOSTED_NETWORK_STATUS structure with the current status. The memory used for the WLAN_HOSTED_NETWORK_STATUS structure that is returned should be freed after use by calling the WlanFreeMemory function.

 

Edited by Bilgus
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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...