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

OK, I'm trying to experiment with Win32::API to programmatically create a Dial-Up Networking "connectoid" via the RAS API calls.

For me this is a learning experience, I haven't done anything like this before - so my code isn't pretty, and I may not have all the concepts down pat - I beg your indulgence :)

I've been using Win32::RASE as a bit of a reference, but it crashes with memory errors on Windows 2000 and hasn't been updated for a couple of years, hence my experiment.

My code attempt is below; I'm running it on Windows 2000 Pro with the latest ActiveState Perl, so it enters the 3rd conditional loop in my code, which is what I've been experimenting with.

Right now, the code does not work as anticipated; it always returns an error "632", which is a RAS error meaning "The structure size is incorrect."

I'm interested in all suggestions; there are a few things I'm not sure of which may make a good starting point:

- I went through the Win32::API::Struct documentation and followed the example as best I could; it did say I should be able to simply copy and paste a C-style struct, which I pretty much did from MSDN (here); did I do that properly? I assumed the constants mentioned in the MSDN entry may not work (they're not defined elsewhere in my Perl script), so I tried hard-coding the values directly into the script (no effect)

- as well, the Win32::API::Struct docs mention variable are initialized automatically and automatically passed as NULL if not expressly defined, so I've tried explicitly setting them and also just commenting out the entries I'm not interested in - no effect

- I wasn't sure how to use the Win32::API::Struct::sizeof() call exactly - I found a sample C program using the same API call, and it seems to use the name of the #define rather than the name of the instance (for instance, the C code says "sizeof(RASENTRY)", not "sizeof(newrasentry)" where newrasentry is an instance of RASENTRY) - not sure how that's supposed to look in Perl

- I'm not sure how the $RASOPTIONS variable is supposed to be defined; in the sample C program I found, the C code looked like:

#define RAS_OPTIONS \ RASEO_UseCountryAndAreaCodes+\ RASEO_RemoteDefaultGateway+\ RASEO_ModemLights+\ RASEO_TerminalAfterDial
Again, not sure what that's supposed to look like in Perl

Code below; note that the RasSetEntryProperties call needs to have a modem installed on the system; for testing purposes I hard-coded the "dummy" modem I set up into the script. Thanks again.

#! /usr/bin/perl use Win32::API::Prototype; use Win32::API; use Win32::API::Struct; use Win32; # access RasSetEntryProperties win32 API ApiLink ( 'rasapi32.dll', 'DWORD RasSetEntryProperties( LPCTSTR lpszPhonebook, LPCTSTR lpszEntry, LPRASENTRY lpRasEntry, DWORD dwEntryInfoSize, LPBYTE lpbDeviceInfo, DWORD dwDeviceInfoSize )' ) || die "can't create API prototype"; # figure out what version of Windows this is running on - # important for contents of RASENTRY struct $winvermajor = (Win32::GetOSVersion)[1]; $winverminor = (Win32::GetOSVersion)[2]; print ("Major Windows version: ", $winvermajor, "\n"); print ("Minor windows version: ", $winverminor, "\n"); $RASOPTIONS = "RASEO_IpHeaderCompression+RASEO_RemoteDefaultGateway+RA +SEO_SwCompression"; # I'm not sure how win32::API::Struct handles conditional "if" stateme +nts inside of structs; # So I'm just going to define different structs depending on what Wind +ows version it's running on: # the 1st for Win95/WinNT, the 2nd for Win98/ME, the 3rd for Win2k, an +d the 4th for WinXP; # These correspond to the MS conventions for major/minor number OS des +ignations if (($winvermajor == 4) and ($winverminor == 0)) { print ("hit loop 1\n"); Win32::API::Struct->typedef( 'RASENTRY', qw( DWORD dwSize; DWORD dwfOptions; DWORD dwCountryID; DWORD dwCountryCode; TCHAR szAreaCode[ RAS_MaxAreaCode + 1 ]; TCHAR szLocalPhoneNumber[ RAS_MaxPhoneNumber + 1 ]; DWORD dwAlternateOffset; RASIPADDR ipaddr; RASIPADDR ipaddrDns; RASIPADDR ipaddrDnsAlt; RASIPADDR ipaddrWins; RASIPADDR ipaddrWinsAlt; DWORD dwFrameSize; DWORD dwfNetProtocols; DWORD dwFramingProtocol; TCHAR szScript[ MAX_PATH ]; TCHAR szAutodialDll[ MAX_PATH ]; TCHAR szAutodialFunc[ MAX_PATH ]; TCHAR szDeviceType[ RAS_MaxDeviceType + 1 ]; TCHAR szDeviceName[ RAS_MaxDeviceName + 1 ]; TCHAR szX25PadType[ RAS_MaxPadType + 1 ]; TCHAR szX25Address[ RAS_MaxX25Address + 1 ]; TCHAR szX25Facilities[ RAS_MaxFacilities + 1 ]; TCHAR szX25UserData[ RAS_MaxUserData + 1 ]; DWORD dwChannels; DWORD dwReserved1; DWORD dwReserved2; )) || die "Can't create RASENTRY struct"; $rasentry = Win32::API::Struct->New( 'RASENTRY' ); # Not sure if the syntax for dwSize below is correct $rasentry->{dwSize} = (Win32::API::Struct::sizeof($rasentry)); $rasentry->{dwfOptions} = $RASOPTIONS; $rasentry->{dwCountryID} = 0; $rasentry->{dwCountryCode} = 0; $rasentry->{szAreaCode} = ""; $rasentry->{szLocalPhoneNumber} = "3910895"; $rasentry->{ipaddr} = [0,0,0,0]; $rasentry->{ipaddrDns} = [0,0,0,0]; $rasentry->{ipaddrDnsAlt} = [0,0,0,0]; $rasentry->{ipaddrWins} = [0,0,0,0]; $rasentry->{ipaddrWinsAlt} = [0,0,0,0]; $rasentry->{dwFrameSize} = 0; $rasentry->{dwfNetProtocols} = RASNP_Ip; $rasentry->{dwFramingProtocol} = RASFP_Ppp; $rasentry->{szScript} = ""; $rasentry->{szAutodialDll} = ""; $rasentry->{szAutodialFunc} = ""; $rasentry->{szDeviceType} = "modem"; $rasentry->{szDeviceName} = "Standard 56000 bps V90 Modem"; $rasentry->{szX25PadType} = ""; $rasentry->{szX25Address} = ""; $rasentry->{szX25Facilities} = ""; $rasentry->{szX25UserData} = ""; $rasentry->{dwChannels} = 0; $rasentry->{dwReserved1} = 0; $rasentry->{dwReserved2} = 0; } elsif (($winvermajor == 4) and ($winverminor > 0)) { print ("hit loop 2\n"); Win32::API::Struct->typedef ('RASENTRY', qw( DWORD dwSize; DWORD dwfOptions; DWORD dwCountryID; DWORD dwCountryCode; TCHAR szAreaCode[ RAS_MaxAreaCode + 1 ]; TCHAR szLocalPhoneNumber[ RAS_MaxPhoneNumber + 1 ]; DWORD dwAlternateOffset; RASIPADDR ipaddr; RASIPADDR ipaddrDns; RASIPADDR ipaddrDnsAlt; RASIPADDR ipaddrWins; RASIPADDR ipaddrWinsAlt; DWORD dwFrameSize; DWORD dwfNetProtocols; DWORD dwFramingProtocol; TCHAR szScript[ MAX_PATH ]; TCHAR szAutodialDll[ MAX_PATH ]; TCHAR szAutodialFunc[ MAX_PATH ]; TCHAR szDeviceType[ RAS_MaxDeviceType + 1 ]; TCHAR szDeviceName[ RAS_MaxDeviceName + 1 ]; TCHAR szX25PadType[ RAS_MaxPadType + 1 ]; TCHAR szX25Address[ RAS_MaxX25Address + 1 ]; TCHAR szX25Facilities[ RAS_MaxFacilities + 1 ]; TCHAR szX25UserData[ RAS_MaxUserData + 1 ]; DWORD dwChannels; DWORD dwReserved1; DWORD dwReserved2; DWORD dwSubEntries; DWORD dwDialMode; DWORD dwDialExtraPercent; DWORD dwDialExtraSampleSeconds; DWORD dwHangUpExtraPercent; DWORD dwHangUpExtraSampleSeconds; DWORD dwIdleDisconnectSeconds; )) || die "Can't create RASENTRY struct"; $rasentry = Win32::API::Struct->New( 'RASENTRY' ); $rasentry->{dwSize} = (Win32::API::Struct::sizeof($rasentry)); $rasentry->{dwfOptions} = $RASOPTIONS; $rasentry->{dwCountryID} = 0; $rasentry->{dwCountryCode} = 0; $rasentry->{szAreaCode} = ""; $rasentry->{szLocalPhoneNumber} = "3910895"; $rasentry->{ipaddr} = [0,0,0,0]; $rasentry->{ipaddrDns} = [0,0,0,0]; $rasentry->{ipaddrDnsAlt} = [0,0,0,0]; $rasentry->{ipaddrWins} = [0,0,0,0]; $rasentry->{ipaddrWinsAlt} = [0,0,0,0]; $rasentry->{dwFrameSize} = 0; $rasentry->{dwfNetProtocols} = RASNP_Ip; $rasentry->{dwFramingProtocol} = RASFP_Ppp; $rasentry->{szScript} = ""; $rasentry->{szAutodialDll} = ""; $rasentry->{szAutodialFunc} = ""; $rasentry->{szDeviceType} = "modem"; $rasentry->{szDeviceName} = "Standard 56000 bps V90 Modem"; $rasentry->{szX25PadType} = ""; $rasentry->{szX25Address} = ""; $rasentry->{szX25Facilities} = ""; $rasentry->{szX25UserData} = ""; $rasentry->{dwChannels} = 0; $rasentry->{dwReserved1} = 0; $rasentry->{dwReserved2} = 0; $rasentry->{dwSubEntries} = 0; $rasentry->{dwDialMode} = 0; $rasentry->{dwDialExtraPercent} = 0; $rasentry->{dwDialExtraSampleSeconds}; $rasentry->{dwHangUpExtraPercent} = 0; $rasentry->{dwHangUpExtraSampleSeconds} = 0; $rasentry->{dwIdleDisconnectSeconds} = 0; } elsif (($winvermajor == 5) and ($winverminor == 0)) { print ("hit loop 3\n"); Win32::API::Struct->typedef( 'RASENTRY', qw( DWORD dwSize; DWORD dwfOptions; DWORD dwCountryID; DWORD dwCountryCode; TCHAR szAreaCode[ 10 + 1 ]; TCHAR szLocalPhoneNumber[ 128 + 1 ]; DWORD dwAlternateOffset; RASIPADDR ipaddr; RASIPADDR ipaddrDns; RASIPADDR ipaddrDnsAlt; RASIPADDR ipaddrWins; RASIPADDR ipaddrWinsAlt; DWORD dwFrameSize; DWORD dwfNetProtocols; DWORD dwFramingProtocol; TCHAR szScript[ 260 ]; TCHAR szAutodialDll[ 260 ]; TCHAR szAutodialFunc[ 260 ]; TCHAR szDeviceType[ 16 + 1 ]; TCHAR szDeviceName[ 128 + 1 ]; TCHAR szX25PadType[ 32 + 1 ]; TCHAR szX25Address[ 200 + 1 ]; TCHAR szX25Facilities[ 200 + 1 ]; TCHAR szX25UserData[ 200 + 1 ]; DWORD dwChannels; DWORD dwReserved1; DWORD dwReserved2; DWORD dwSubEntries; DWORD dwDialMode; DWORD dwDialExtraPercent; DWORD dwDialExtraSampleSeconds; DWORD dwHangUpExtraPercent; DWORD dwHangUpExtraSampleSeconds; DWORD dwIdleDisconnectSeconds; DWORD dwType; DWORD dwEncryptionType; DWORD dwCustomAuthKey; GUID guidId; TCHAR szCustomDialDll[260]; DWORD dwVpnStrategy; )) || die "can't create RASENTRY struct"; $rasentry = Win32::API::Struct->new( 'RASENTRY' ); $rasentry->{dwSize} = (Win32::API::Struct::sizeof($rasentry) +); $rasentry->{dwfOptions} = $RASOPTIONS; # $rasentry->{dwCountryID} = 0; # $rasentry->{dwCountryCode} = 0; # $rasentry->{szAreaCode} = ""; $rasentry->{szLocalPhoneNumber} = "3910895"; # $rasentry->{ipaddr} = [0,0,0,0]; # $rasentry->{ipaddrDns} = [0,0,0,0]; # $rasentry->{ipaddrDnsAlt} = [0,0,0,0]; # $rasentry->{ipaddrWins} = [0,0,0,0]; # $rasentry->{ipaddrWinsAlt} = [0,0,0,0]; # $rasentry->{dwFrameSize} = 0; $rasentry->{dwfNetProtocols} = RASNP_Ip; $rasentry->{dwFramingProtocol} = RASFP_Ppp; # $rasentry->{szScript} = ""; # $rasentry->{szAutodialDll} = ""; # $rasentry->{szAutodialFunc} = ""; $rasentry->{szDeviceType} = "RASDT_Modem"; $rasentry->{szDeviceName} = "Standard 56000 bps V90 Modem"; # $rasentry->{szX25PadType} = ""; # $rasentry->{szX25Address} = ""; # $rasentry->{szX25Facilities} = ""; # $rasentry->{szX25UserData} = ""; # $rasentry->{dwChannels} = 0; # $rasentry->{dwReserved1} = 0; # $rasentry->{dwReserved2} = 0; # $rasentry->{dwSubEntries} = 0; # $rasentry->{dwDialMode} = 0; # $rasentry->{dwDialExtraPercent} = 0; # $rasentry->{dwDialExtraSampleSeconds}; # $rasentry->{dwHangUpExtraPercent} = 0; # $rasentry->{dwHangUpExtraSampleSeconds} = 0; # $rasentry->{dwIdleDisconnectSeconds} = 0; $rasentry->{dwType} = RASET_Phone; # $rasentry->{dwEncryptionType} = 0; # $rasentry->{dwCustomAuthKey} = 0; # $rasentry->{guidID} = 0; # $rasentry->{szCustomDialDll} = ""; # $rasentry->{dwVpnStrategy} = 0; } elsif (($winvermajor == 5) and ($winverminor > 0)) { print ("hit loop 4\n"); Win32::API::Struct->typedef( 'RASENTRY', qw( DWORD dwSize; DWORD dwfOptions; DWORD dwCountryID; DWORD dwCountryCode; TCHAR szAreaCode[ RAS_MaxAreaCode + 1 ]; TCHAR szLocalPhoneNumber[ RAS_MaxPhoneNumber + 1 ]; DWORD dwAlternateOffset; RASIPADDR ipaddr; RASIPADDR ipaddrDns; RASIPADDR ipaddrDnsAlt; RASIPADDR ipaddrWins; RASIPADDR ipaddrWinsAlt; DWORD dwFrameSize; DWORD dwfNetProtocols; DWORD dwFramingProtocol; TCHAR szScript[ MAX_PATH ]; TCHAR szAutodialDll[ MAX_PATH ]; TCHAR szAutodialFunc[ MAX_PATH ]; TCHAR szDeviceType[ RAS_MaxDeviceType + 1 ]; TCHAR szDeviceName[ RAS_MaxDeviceName + 1 ]; TCHAR szX25PadType[ RAS_MaxPadType + 1 ]; TCHAR szX25Address[ RAS_MaxX25Address + 1 ]; TCHAR szX25Facilities[ RAS_MaxFacilities + 1 ]; TCHAR szX25UserData[ RAS_MaxUserData + 1 ]; DWORD dwChannels; DWORD dwReserved1; DWORD dwReserved2; DWORD dwSubEntries; DWORD dwDialMode; DWORD dwDialExtraPercent; DWORD dwDialExtraSampleSeconds; DWORD dwHangUpExtraPercent; DWORD dwHangUpExtraSampleSeconds; DWORD dwIdleDisconnectSeconds; DWORD dwType; DWORD dwEncryptionType; DWORD dwCustomAuthKey; GUID guidId; TCHAR szCustomDialDll[MAX_PATH]; DWORD dwVpnStrategy; DWORD dwfOptions2; DWORD dwfOptions3; TCHAR szDnsSuffix[RAS_MaxDnsSuffix]; DWORD dwTcpWindowSize; TCHAR szPrerequisitePbk[MAX_PATH]; TCHAR szPrerequisiteEntry[RAS_MaxEntryName + 1]; DWORD dwRedialCount; DWORD dwRedialPause; )) || die "Can't create RASENTRY struct"; $rasentry = Win32::API::Struct->New( 'RASENTRY' ); $rasentry->{dwSize} = (Win32::API::Struct::sizeof($rasent +ry)); $rasentry->{dwfOptions} = $RASOPTIONS; $rasentry->{dwCountryID} = 0; $rasentry->{dwCountryCode} = 0; $rasentry->{szAreaCode} = ""; $rasentry->{szLocalPhoneNumber} = "3910895"; $rasentry->{ipaddr} = [0,0,0,0]; $rasentry->{ipaddrDns} = [0,0,0,0]; $rasentry->{ipaddrDnsAlt} = [0,0,0,0]; $rasentry->{ipaddrWins} = [0,0,0,0]; $rasentry->{ipaddrWinsAlt} = [0,0,0,0]; $rasentry->{dwFrameSize} = 0; $rasentry->{dwfNetProtocols} = RASNP_Ip; $rasentry->{dwFramingProtocol} = RASFP_Ppp; $rasentry->{szScript} = ""; $rasentry->{szAutodialDll} = ""; $rasentry->{szAutodialFunc} = ""; $rasentry->{szDeviceType} = "modem"; $rasentry->{szDeviceName} = "Standard 56000 bps V90 Modem +"; $rasentry->{szX25PadType} = ""; $rasentry->{szX25Address} = ""; $rasentry->{szX25Facilities} = ""; $rasentry->{szX25UserData} = ""; $rasentry->{dwChannels} = 0; $rasentry->{dwReserved1} = 0; $rasentry->{dwReserved2} = 0; $rasentry->{dwSubEntries} = 0; $rasentry->{dwDialMode} = 0; $rasentry->{dwDialExtraPercent} = 0; $rasentry->{dwDialExtraSampleSeconds}; $rasentry->{dwHangUpExtraPercent} = 0; $rasentry->{dwHangUpExtraSampleSeconds} = 0; $rasentry->{dwIdleDisconnectSeconds} = 0; $rasentry->{dwType} = 0; $rasentry->{dwEncryptionType} = 0; $rasentry->{dwCustomAuthKey} = 0; $rasentry->{guidID} = 0; $rasentry->{szCustomDialDll} = ""; $rasentry->{dwVpnStrategy} = 0; $rasentry->{dwfOptions2} = 0; $rasentry->{dwfOptions3} = 0; $rasentry->{szDnsSuffix} = ""; $rasentry->{dwTcpWindowSize} = 0; $rasentry->{szPrerequisitePbk} = ""; $rasentry->{szPrerequisiteEntry} = ""; $rasentry->{dwRedialCount} = 0; $rasentry->{dwRedialPause} = 0; } else { die "Can't setup RASENTRY struct. Can't find approp +riate OS version.\n"}; $Phonebook = 0; $Entry = "testtest"; $ret = RasSetEntryProperties( $Phonebook, $Entry, $rasentry, (Win32::A +PI::Struct::sizeof($rasentry), 0, 0); print ($ret); exit;

Replies are listed 'Best First'.
Re: help with Win32::API (Struct and general)
by RMGir (Prior) on Aug 21, 2003 at 14:05 UTC
    If nothing else, this will be a nice example for Win32::API, once it works.

    Did you check the return value of sizeof? I'm guessing you should pass the name of the structure, instead of the reference.

    Please try:

    #right after $rasentry = Win32::API::Struct->New( 'RASENTRY' ); # in your code printf "Sizeof \$rasentry: %d, sizeof RASENTRY: %d\n", (Win32::API::Struct::sizeof($rasentry)), (Win32::API::Struct::sizeof('RASENTRY'));
    I think you'll get a saner value for 'RASENTRY', but I'm just guessing.
    --
    Mike
      Thanks for the suggestion. Actually, sizeof($rasentry) returns a value of 204, sizeof( 'RASENTRY' ) or sizeof(RASENTRY) return 0. Time for more playing :)
        Blargh!! That was my reply, thought I was logged in, sorry.
Re: help with Win32::API (Struct and general)
by BrowserUk (Patriarch) on Aug 21, 2003 at 16:58 UTC

    It would us to help you if the code you posted at least compiled clean of simple typos.

    1. $rasentry = Win32::API::Struct->New( 'RASENTRY' );

      The is no method New(...), it is new(...)

    2. $ret = RasSetEntryProperties( $Phonebook, $Entry, $rasentry, (Win32::API::Struct::sizeof($rasentry), 0, 0);

      There is an extraneous left paren.

    If you had enabled warnings (-w or use warnings;) then you would see that once the above typos are corrected, your code produces 938 lines of warnings.

    These two

    Useless use of hash element in void context at test.pl8 line 170. Useless use of hash element in void context at test.pl8 line 349.

    relate to these two lines where you have forgotten to add the assignment.

    $rasentry->{dwDialExtraSampleSeconds}; #170 $rasentry->{dwDialExtraSampleSeconds}; #349

    The other 936 come from Win32::API::Struct or Win32::API::Type. When a module starts producing large numbers of warnings like this, you can draw one of two conclusions: Either the module author ignored warnings and published a really crap module--which does happen, but for the most part not-- or, you are using it incorrectly.

    For my part, I usually assume the latter, and I'm rarely disappointed:)

    Picking out a few lines of your code and analysing them

    • $rasentry->{dwfOptions} = $RASOPTIONS;

      You assigning a (psuedo-constant (uppercase)) value to one element of your newly created RASENTRY structure.

      Looking up the type of the dwfOptions field I find DWORD      dwfOptions;. That means it is a 32-bit unsigned numeric value.

      Looking at your definition of $RASOPTIONS I find

      $RASOPTIONS = "RASEO_IpHeaderCompression+RASEO_RemoteDefaultGateway+RA +SEO_SwCompression";

      Which is a string!

      For Win32:API::Struct to be able to 'DWIM' this would require it to somehow know that this string is an equation that adds three values together.

      And know that those 3 values are represented by symbolic names that represent numeric values.

      And know that to translate those symbolic names to their underlying numeric values, that it much either look them up in a file (probably called ras.h) somewhere in the INCLUDE path for your C compiler--assuming you have one--or go online to MSDN and navigate to try and find the appropriate values--which is a nightmare task even with my (limited) human intelligence driving the process:)

    • TCHAR      szAreaCode[ RAS_MaxAreaCode + 1 ];

      In this line, TCHAR is a typedef which Win32::API::Type.pm knows translates to the C type char.

      And this bit szAreaCode[ RAS_MaxAreaCode + 1 ] would tell a C compiler that the field named szAreaCode is an array ([...]) of char that can contain RAS_MaxAreaCode + 1 chars.

      The problem is that RAS_MaxAreaCode is another C defined constant that needs to be looked up in a header file somewhere, and the + 1 is a C compile-time constant equation which neither perl nor Win32::API::Struct has any knowledge of nor any mechanism for resolving to the underlying numeric values.

    The upshot is that you will need to resolve these symbolic constants to their numeric values. There are several approaches to doing this, and it would be an interesting project to extend Win32::API to automate some more of this type of thing, but it would entail a great deal of work and would not be something to take on lightly.

    I hope that this post won't offend you and will clarify some of the problems that you face in re-writing Win32::RASE to work with Win2K. None of the problems are insurmountable, but there is no readily available shortcut to the process.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
    If I understand your problem, I can solve it! Of course, the same can be said for you.

      No problem, not offended :) Thanks for pointing out the "warnings" thing, I wasn't aware of that option.

      I thought I had mentioned that I was testing on Windows 2000, which means only the 3rd condition in the if..else loop was relevant for me, which has the correct case for "new" and also had the offending hash assignment commented out. It's probably bad form that I didn't change all the loops equally, but I'm more concerned with getting it to actually work for me :)

      The RASOPTIONS thing is definitely confusing for me; I'm trying to understand it conceptually. How it's defined in C is mentioned in the my original post; I'm not sure how that translates to Perl. In my mind the DWORD does not compute - each of those options is represented by a checkbox in the normal Windows configuration GUI, and therefore it seems to me each should be a simple Boolean option.

      I'll keep trying when I have some more time...

      Thanks again for taking the time to look it over.

        In my mind the DWORD does not compute - each of those options is represented by a checkbox in the normal Windows configuration GUI, and therefore it seems to me each should be a simple Boolean option.

        That's exactly what they are...simple booleans. In fact each option is represented by a single binary bit. It's just that all the bits are put together into a lump of memory that is convenient for the processor to manipulate, in this case, a 32-bit unsigned value.

        The ras.h #defines for this field are

        /* RASENTRY 'dwfOptions' bit flags. */ #define RASEO_UseCountryAndAreaCodes 0x00000001 #define RASEO_SpecificIpAddr 0x00000002 #define RASEO_SpecificNameServers 0x00000004 #define RASEO_IpHeaderCompression 0x00000008 #define RASEO_RemoteDefaultGateway 0x00000010 #define RASEO_DisableLcpExtensions 0x00000020 #define RASEO_TerminalBeforeDial 0x00000040 #define RASEO_TerminalAfterDial 0x00000080 #define RASEO_ModemLights 0x00000100 #define RASEO_SwCompression 0x00000200 #define RASEO_RequireEncryptedPw 0x00000400 #define RASEO_RequireMsEncryptedPw 0x00000800 #define RASEO_RequireDataEncryption 0x00001000 #define RASEO_NetworkLogon 0x00002000 #define RASEO_UseLogonCredentials 0x00004000 #define RASEO_PromoteAlternates 0x00008000 #if (WINVER >= 0x401) #define RASEO_SecureLocalFiles 0x00010000 #endif #if (WINVER >= 0x500) #define RASEO_RequireEAP 0x00020000 #define RASEO_RequirePAP 0x00040000 #define RASEO_RequireSPAP 0x00080000 #define RASEO_Custom 0x00100000

        As you can see, each option is a represented by a seperate bit in the 32-bit DWORD. This means that to determine the value required to set the options you were trying to set

        $RASOPTIONS = "RASEO_IpHeaderCompression+RASEO_RemoteDefaultGateway+RA +SEO_SwCompression";

        You need to combine the numeric values defined for each of the options you require. You can use +, but oring (|)them is the usual idiom with boolean values like this.

        my $RASOPTIONS = 0x00000008 | 0x00000010 | 0x00000200;

        This leaves $RASOPTIONS with a value of 0x00000218, which may not make much sense until you look at that in binary.

        0x00000008 0000 0000 0000 0000 0000 0000 0000 1000 | 0x00000010 0000 0000 0000 0000 0000 0000 0001 0000 | 0x00000200 0000 0000 0000 0000 0000 0010 0000 0000 = 0x00000218 0000 0000 0000 0000 0000 0010 0001 1000

        By representing these booleans this way, up to 32 different options can be stored in an efficient manor. Currently 21 of them are used which leaves 11 for future expansion without requiring big changes to the APIs.

        It also make it possible to set, clear and test individual or combinations of options easily and efficiently.

        # Set options # RASEO_IpHeaderCompression # RASEO_RemoteDefaultGateway # RASEO_SwCompression # without affecting any other options. $options |= 0x00000008 | 0x00000010 | 0x00000200; # Clear those same options again leaving every other option as it was $options &= ~(0x00000008 | 0x00000010 | 0x00000200); # do something if all three options are set # regardless of what other options are set. if( ($options & (0x00000008 | 0x00000010 | 0x00000200)) == (0x0000000 +8 | 0x00000010 | 0x00000200) ) { # do something } # Do something if ONLY those three options are set if( $options == (0x00000008 | 0x00000010 | 0x00000200) ) { # do it }

        Of course, it is much more readable to use symbolic names instead of binary or hex constants for this, and you can do this nicely in perl by

        use constant RASEO_IpHeaderCompression = 0x00000008;

        which makes for nice, readable and efficient code. The only downside is that you will have to define these yourself as Perl doesn't read C header files. Actually it is possible to ask perl to pre-process your script through a C pre-preocessor using the -P option, but is "highly discouraged" and perlrun lists a whole bunch of reasons why you shouldn't do this. It also gives a better solution, Filter::cpp. If you have a compiler on your system, and therefor have access to ras.h, then you could use this to save you needing to hand-code all the constant definitions.

        It is also fairly trivial matter to write a perl script to convert all the simple #defines in a header file into a set of constant definitions for inclusion into your module. If you built your own copy of perl, then there is at least one script included in sources for doing this.

        Hope that this makes some sense and will assist you when you get time to persue the matter further. Good luck.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
        If I understand your problem, I can solve it! Of course, the same can be said for you.