Thanks. I only modified Win32::Wlan::API by adding wrappers for these native functions:
['WlanScan' => 'IPPPI' => 'I'], ['WlanGetProfileList' => 'IPIP' => 'I'], ['WlanDeleteProfile' => 'IPPI' => 'I'], ['WlanSetProfile' => 'IPIPPIIP' => 'I'], ['WlanConnect' => 'IPSI' => 'I']
To test WlanConnect() using an existing profile on XP or Win7, run wlanconnect.pl PROFILENAME SSID. A list of UTF16 profile names can be obtained thusly: my @profilenames = WlanGetProfileList($handle, $guid).
# wlanconnect.pl -- connect to a WLAN network on Windows XP SP3 and ab +ove. # Args: PROFILENAME to use and SSID to connect to use strict; use warnings; use Encode qw(encode); use Win32::Wlan::API qw< WlanOpenHandle WlanCloseHandle WlanQueryCurrentConnection WlanEnumInterfaces WlanGetAvailableNetworkList $wlan_available WlanDeleteProfile WlanSetProfile WlanScan WlanConnect WlanGetProfileList >; main(); sub main { die "USAGE: $0 PROFILENAME SSID\n" unless($ARGV[1]); my $profilename = shift; my $ssid = shift; my $wlan_handle = WlanOpenHandle(); my @interfaces = WlanEnumInterfaces($wlan_handle); my $wlan_guuid = $interfaces[0]->{guuid}; $profilename = encode('UTF-16LE', $profilename); WlanConnect($wlan_handle, $wlan_guuid, $profilename, $ssid); }
modified Wlan::API.pm follows
###################################################################### # modified Wlan::API.pm follows # added: # ['WlanScan' => 'IPPPI' => 'I'], # ['WlanGetProfileList' => 'IPIP' => 'I'], # ['WlanDeleteProfile' => 'IPPI' => 'I'], # ['WlanSetProfile' => 'IPIPPIIP' => 'I'], # ['WlanConnect' => 'IPSI' => 'I'] ###################################################################### package Win32::Wlan::API; use strict; use Carp qw(croak); use Encode qw(decode); use Exporter 'import'; use vars qw($VERSION $wlan_available %API @signatures @EXPORT_OK); $VERSION = '0.06'; sub Zero() { "\0\0\0\0" }; # just in case we ever get a 64bit Win32::API # Zero will have to return 8 bytes of zeroes BEGIN { @signatures = ( ['WlanOpenHandle' => 'IIPP' => 'I'], ['WlanCloseHandle' => 'II' => 'I'], ['WlanFreeMemory' => 'I' => 'I'], ['WlanEnumInterfaces' => 'IIP' => 'I'], ['WlanQueryInterface' => 'IPIIPPI' => 'I'], ['WlanGetAvailableNetworkList' => 'IPIIP' => 'I'], ['WlanScan' => 'IPPPI' => 'I'], ['WlanGetProfileList' => 'IPIP' => 'I'], ['WlanDeleteProfile' => 'IPPI' => 'I'], ['WlanSetProfile' => 'IPIPPIIP' => 'I'], ['WlanConnect' => 'IPSI' => 'I'] ); @EXPORT_OK = (qw<$wlan_available WlanQueryCurrentConnection>, map +{ $_->[0] } @signatures); }; use constant { not_ready => 0, connected => 1, ad_hoc_network_formed => 2, disconnecting => 3, disconnected => 4, associating => 5, discovering => 6, authenticating => 7 }; if (! load_functions()) { # Wlan functions are not available $wlan_available = 0; } else { $wlan_available = 1; }; sub unpack_struct { # Unpacks a string into a hash # according to a key/unpack template structure my $desc = shift; my @keys; my $template = ''; for (0..$#{$desc}) { if ($_ % 2) { $template .= $desc->[ $_ ] } elsif ($desc->[ $_ ] ne '') { push @keys, $desc->[ $_ ] }; }; my %res; @res{ @keys } = unpack $template, shift; %res } sub WlanOpenHandle { croak "Wlan functions are not available" unless $wlan_available; my $version = Zero; my $handle = Zero; $API{ WlanOpenHandle }->Call(2,0,$version,$handle) == 0 or croak $^E; my $h = unpack "V", $handle; $h }; sub WlanCloseHandle { croak "Wlan functions are not available" unless $wlan_available; my ($handle) = @_; $API{ WlanCloseHandle }->Call($handle,0) == 0 or croak $^E; }; sub WlanFreeMemory { croak "Wlan functions are not available" unless $wlan_available; my ($block) = @_; $API{ WlanFreeMemory }->Call($block); }; sub _unpack_counted_array { my ($pointer,$template,$size) = @_; my $info = unpack 'P8', $pointer; my ($count,$curr) = unpack 'VV', $info; my $data = unpack "P" . (8+$count*$size), $pointer; my @items = unpack "x8 ($template)$count", $data; my @res; if ($count) { my $elements_per_item = @items / $count; while (@items) { push @res, [splice @items, 0, $elements_per_item ] }; }; @res }; sub WlanEnumInterfaces { croak "Wlan functions are not available" unless $wlan_available; my ($handle) = @_; my $interfaces = Zero; $API{ WlanEnumInterfaces }->Call($handle,0,$interfaces) == 0 or croak $^E; my @items = _unpack_counted_array($interfaces,'a16 a512 V',16+512+ +4); @items = map { # First element is the GUUID of the interface # Name is in 16bit UTF $_->[1] = decode('UTF-16LE' => $_->[1]); $_->[1] =~ s/\0+$//; # The third element is the status of the interface +{ guuid => $_->[0], name => $_->[1], status => $_->[2], }; } @items; $interfaces = unpack 'V', $interfaces; WlanFreeMemory($interfaces); @items }; sub WlanQueryInterface { croak "Wlan functions are not available" unless $wlan_available; my ($handle,$interface,$op) = @_; my $size = Zero; my $data = Zero; $API{ WlanQueryInterface }->Call($handle, $interface, $op, 0, $siz +e, $data, 0) == 0 or return; $size = unpack 'V', $size; my $payload = unpack "P$size", $data; $data = unpack 'V', $data; WlanFreeMemory($data); $payload }; =head2 C<< WlanCurrentConnection( $handle, $interface ) >> Returns a hashref containing the following keys =over 4 =item * C<< state >> - state of the interface One of the following Win32::Wlan::API::not_ready => 0, Win32::Wlan::API::connected => 1, Win32::Wlan::API::ad_hoc_network_formed => 2, Win32::Wlan::API::disconnecting => 3, Win32::Wlan::API::disconnected => 4, Win32::Wlan::API::associating => 5, Win32::Wlan::API::discovering => 6, Win32::Wlan::API::authenticating => 7 =item * C<< mode >> =item * C<< profile_name >> C<< bss_type >> infrastructure = 1, independent = 2, any = 3 =item * auth_algorithm DOT11_AUTH_ALGO_80211_OPEN = 1, DOT11_AUTH_ALGO_80211_SHARED_KEY = 2, DOT11_AUTH_ALGO_WPA = 3, DOT11_AUTH_ALGO_WPA_PSK = 4, DOT11_AUTH_ALGO_WPA_NONE = 5, DOT11_AUTH_ALGO_RSNA = 6, # wpa2 DOT11_AUTH_ALGO_RSNA_PSK = 7, # wpa2 DOT11_AUTH_ALGO_IHV_START = 0x80000000, DOT11_AUTH_ALGO_IHV_END = 0xffffffff =item * cipher_algorithm DOT11_CIPHER_ALGO_NONE = 0x00, DOT11_CIPHER_ALGO_WEP40 = 0x01, DOT11_CIPHER_ALGO_TKIP = 0x02, DOT11_CIPHER_ALGO_CCMP = 0x04, DOT11_CIPHER_ALGO_WEP104 = 0x05, DOT11_CIPHER_ALGO_WPA_USE_GROUP = 0x100, DOT11_CIPHER_ALGO_RSN_USE_GROUP = 0x100, DOT11_CIPHER_ALGO_WEP = 0x101, DOT11_CIPHER_ALGO_IHV_START = 0x80000000, DOT11_CIPHER_ALGO_IHV_END = 0xffffffff =back =cut sub WlanQueryCurrentConnection { my ($handle,$interface) = @_; my $info = WlanQueryInterface($handle,$interface,7) || ''; my @WLAN_CONNECTION_ATTRIBUTES = ( state => 'V', mode => 'V', profile_name => 'a512', # WLAN_ASSOCIATION_ATTRIBUTES ssid_len => 'V', ssid => 'a32', bss_type => 'V', mac_address => 'a6', dummy => 'a2', # ??? phy_type => 'V', phy_index => 'V', signal_quality => 'V', rx_rate => 'V', tx_rate => 'V', security_enabled => 'V', # BOOL onex_enabled => 'V', # BOOL auth_algorithm => 'V', cipher_algorithm => 'V', ); my %res = unpack_struct(\@WLAN_CONNECTION_ATTRIBUTES, $info); $res{ profile_name } = decode('UTF-16LE', $res{ profile_name }) || + ''; $res{ profile_name } =~ s/\0+$//; $res{ ssid } = substr $res{ ssid }, 0, $res{ ssid_len }; $res{ mac_address } = sprintf "%02x:%02x:%02x:%02x:%02x:%02x", unp +ack 'C*', $res{ mac_address }; %res } sub WlanGetAvailableNetworkList { my ($handle,$interface,$flags) = @_; $flags ||= 0; my $list = Zero; $API{ WlanGetAvailableNetworkList }->Call($handle,$interface,$flag +s,0,$list) == 0 or croak $^E; # name ssid_len ssid b +ss bssids connectable my @items = _unpack_counted_array($list, join( '', 'a512', # name 'V', # ssid_len 'a32', # ssid 'V', # bss 'V', # bssids 'V', # connectable 'V', # notConnectableReason, 'V', # PhysTypes 'V8', # PhysType elements 'V', # More PhysTypes 'V', # wlanSignalQuality from 0=-100dbm to 100=-50dbm, line +ar 'V', # bSecurityEnabled; 'V', # dot11DefaultAuthAlgorithm; 'V', # dot11DefaultCipherAlgorithm; 'V', # dwFlags 'V', # dwReserved; ), 512+4+32+20*4); for (@items) { my %info; @info{qw( name ssid_len ssid bss bssids connectable notConnect +ableReason phystype_count )} = splice @$_, 0, 8; $info{ phystypes }= [splice @$_, 0, 8]; @info{qw( has_more_phystypes signal_quality security_enabled default_auth_algorithm default_cipher_algorithm flags reserved )} = @$_; # Decode the elements $info{ ssid } = substr( $info{ ssid }, 0, $info{ ssid_len }); $info{ name } = decode('UTF-16LE', $info{ name }); $info{ name } =~ s/\0+$//; splice @{$info{ phystypes }}, $info{ phystype_count }; $_ = \%info; }; $list = unpack 'V', $list; WlanFreeMemory($list); @items } sub WlanScan { croak "Wlan functions are not available" unless $wlan_available; my ($handle, $guuid) = @_; $API{ WlanScan }->Call($handle, $guuid, 0, 0, 0) == 0 or die "$^E"; }; sub WlanDeleteProfile { croak "Wlan functions are not available" unless $wlan_available; my ($handle, $guuid, $profilename) = @_; $API{ WlanDeleteProfile }->Call($handle, $guuid, $profilename, 0) +== 0 or die "$^E"; }; Win32::API::Struct->typedef('WLAN_CONNECTION_PARAMETERS', qw( WLAN_CONNECTION_MODE wlanConnectionMode; LPCWSTR strProfile; PDOT11_SSID pDot11Ssid; PDOT11_BSSID_LIST pDesiredBssidList; DOT11_BSS_TYPE dot11BssType; DWORD dwFlags; )); Win32::API::Struct->typedef ('DOT11_SSID', qw( ULONG uSSIDLength; UCHAR ucSSID; )); # unused Win32::API::Struct->typedef('WLAN_CONNECTION_MODE', qw( wlan_connection_mode_profile = 0, wlan_connection_mode_temporary_profile, wlan_connection_mode_discovery_secure, wlan_connection_mode_discovery_unsecure, wlan_connection_mode_auto, wlan_connection_mode_invalid )); sub WlanConnect { croak "Wlan functions are not available" unless $wlan_available; my ($handle, $guuid, $profilename, $ssid) = @_; my $pDot11Ssid = Win32::API::Struct->new('DOT11_SSID'); $pDot11Ssid->{uSSIDLength} = length $ssid; $pDot11Ssid->{ucSSID} = $ssid; my $Wlan_connection_parameters = Win32::API::Struct->new('WLAN_CON +NECTION_PARAMETERS'); $Wlan_connection_parameters->{wlanConnectionMode} = 0; $Wlan_connection_parameters->{strProfile} = $profilename; $Wlan_connection_parameters->{pDot11Ssid} = $pDot11Ssid; $Wlan_connection_parameters->{pDesiredBssidList} = 0; $Wlan_connection_parameters->{dot11BssType} = 3; $Wlan_connection_parameters->{dwFlags} = 0; $API{ WlanConnect }->Call($handle, $guuid, $Wlan_connection_parame +ters, 0) == 0 or die "$^E"; }; sub WlanSetProfile { croak "Wlan functions are not available" unless $wlan_available; my ($handle, $guuid, $xmlref) = @_; my $reason = Zero; $API{ WlanSetProfile }->Call($handle, $guuid, 0, $$xmlref, 0, 1, 0 +, $reason) == 0 or die "$^E"; }; sub WlanGetProfileList { croak "Wlan functions are not available" unless $wlan_available; my ($handle, $guuid) = @_; my $profilelist = Zero; $API{ WlanGetProfileList }->Call($handle, $guuid, 0, $profilelist) + == 0 or die "$^E"; my @items = _unpack_counted_array($profilelist, join( '', 'a512', # profile name 'V' # dwFlags ), 512+4); my @profilenames = map { @$_[0] } @items; WlanFreeMemory($profilelist); @profilenames; }; sub load_functions { my $ok = eval { require Win32::API; 1 }; return if ! $ok; for my $sig (@signatures) { $API{ $sig->[0] } = eval { Win32::API->new( 'wlanapi.dll', @$sig ); }; if (! $API{ $sig->[0] }) { return }; }; 1 }; 1; __END__ =head1 NAME Win32::Wlan::API - Access to the Win32 WLAN API =head1 SYNOPSIS use Win32::Wlan::API qw(WlanOpenHandle WlanEnumInterfaces WlanQuer +yCurrentConnection); if ($Win32::Wlan::available) { my $handle = WlanOpenHandle(); my @interfaces = WlanEnumInterfaces($handle); my $ih = $interfaces[0]->{guuid}; # Network adapters are identified by guuid print $interfaces[0]->{name}; my $info = WlanQueryCurrentConnection($handle,$ih); print "Connected to $info{ profile_name }\n"; } else { print "No Wlan detected (or switched off)\n"; }; =head1 SEE ALSO Windows Native Wifi Reference L<http://msdn.microsoft.com/en-us/library/ms706274%28v=VS.85%29.aspx> =head1 REPOSITORY The public repository of this module is L<http://github.com/Corion/Win32-Wlan>. =head1 SUPPORT The public support forum of this module is L<http://perlmonks.org/>. =head1 BUG TRACKER Please report bugs in this module via the RT CPAN bug queue at L<https://rt.cpan.org/Public/Dist/Display.html?Name=Win32-Wlan> or via mail to L<win32-wlan-Bugs@rt.cpan.org>. =head1 AUTHOR Max Maischein C<corion@cpan.org> =head1 COPYRIGHT (c) Copyright 2011-2011 by Max Maischein C<corion@cpan.org>. =head1 LICENSE This module is released under the same terms as Perl itself. =cut
In reply to Re^6: Adding WlanConnect() to Win32::Wlan::API (modded Wlan::API.pm)
by tomsell
in thread Adding WlanConnect() to Win32::Wlan::API
by tomsell
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |