tomsell has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to automate connecting to a WiFi network by adding WlanConnect() to the splendid Win32::Wlan::API. System is a Win XP SP3 box and Win32::Wlan::API works flawlessly.

Here's what I've got so far, modeled after the existing code:

sub WlanConnect { croak "Wlan functions are not available" unless $wlan_available; my ($handle, $guuid, $profilename, $ssid) = @_; # possibly overkill, a pDot11Ssid = 0 should suffice 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"; };

$profilename is an UTF-16LE encoded string while $ssid is just a perl string. The profile named by $profilename was freshly created and WlanSetProfile()'d properly (I can connect manually; WlanSetProfile() added by me).

WLAN_CONNECTION_PARAMETERS ist typedef'd as:

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; ));

while DOT11_SSID (possibly unnecessarily) typedef'd as

Win32::API::Struct->typedef ('DOT11_SSID', qw( ULONG uSSIDLength; UCHAR ucSSID; ));

Well, the code does not connect and referencing the Call line, $^E contains:

An attempt was made to reference a token that does not exist at...
Any idea what is missing or where things go wrong?

Replies are listed 'Best First'.
Re: Adding WlanConnect() to Win32::Wlan::API
by Corion (Patriarch) on Jun 26, 2012 at 17:52 UTC

    I never got success when using the fancier ways that Win32::API provides for encoding the structs. I've always had to manually use pack and specify integers and pointers when importing functions. Maybe the numerical value of $^E is documented somewhere in the MSDN? A cursory search turns up error 1008, which seems to just mean that you used an unknown GUID...

    The signature for WlanConnect() seems to be

    ['WlanConnect' => 'IPPI' => 'I'],

    and I think it should be possible to construct the appropriate structure without involving that dark Win32::API magic that I try to avoid. You "just" have to pack the two DOT11 structs and put pointers to them (using the P pack template) into a string, and pass that string to WlanConnect. In principle it should be easy, but I currently don't have the time to investigate this, sorry.

      @corion Hey, thanks for the reply and suggesting pack(). Dunno about the "easy" bit but failing me getting a solution in perl, as at last resort one could outsource this to a native implementation and start an external process. Pure perl would be nicer though.

      The IPPI signature is correct as is my GUID. However, the return value of the $API{ WlanConnect }->Call() is 87. Would this be need to be massaged into something meaningful?

        How are you sure your GUID is correct? Win32::API doesn't have any built in understanding of GUIDs. If you got your GUIDs by dropping the '-'s, you did it wrong. Also there might be a bug in your using of Encode. Encode won't put a wide null unless you explicitly have a "\x00" in the scalar that you can see. Encode WONT see the secret null that perl keeps after the end of the visible string. Win32::API uses the letter S, not P for structs. P is for a scalar string (or self packed integer "\x01\x02\x03\x04" or self packed struct). An API::Struct is a object, if you print it, you'll probably get the reference in hex. So whoever is using the the IPPI prototype is very wrong.

        Post the code where you created the API object and the prototype you used. Your code isn't runnable currently.

        update, I just noticed the part where you mentioned "Win32::Wlan::API", the previous 2 paragraphs were written without me realizing your using a CPAN mod. After looking at Wlan::API, I see Wlan::API never uses API::Struct. Using P instead of S is probably your error.
Re: Adding WlanConnect() to Win32::Wlan::API ($^E)
by tye (Sage) on Jun 26, 2012 at 17:58 UTC

    WlanConnect() doesn't set the Windows "last error" that is what $^E returns. It returns an error code. So you want:

    $^E = ...->Call( ... );

    - tye