ScriptzRas
From 40tude Dialog Wiki
zRas.ds - Dialog include file for handling dialup connections
See Handle dialup connections for details.
// ===========================================================================
// zRas.ds
// Dialog include file for accessing Windows RAS functions
// Version 2003-08-03 (J?Haible, http://www.elbiah.de/tools/dialog/)
// ===========================================================================
// ---------------------------------------------------------------------------
// RAS constants
const
RASCS_Connected = $2000; // status: connected
RASCS_Disconnected = $2001; // status: disconnected
SizeOf_TRasDialParams = 1052; // values for missing SizeOf() function
SizeOf_TRasConnStatus = 160;
SizeOf_TRasConn = 412;
SizeOf_TRasEntryName = 264;
// ---------------------------------------------------------------------------
// RAS data structures
type
TRasDialParams = record
dwSize: LongWord;
szEntryName: array[0..256] of Char;
szPhoneNumber: array[0..128] of Char;
szCallbackNumber: array[0..128] of Char;
szUserName: array[0..256] of Char;
szPassword: array[0..256] of Char;
szDomain: array[0..15] of Char;
filler: array[1..3] of Char;
end;
TRasConnStatus = record
dwSize: LongWord;
rasconnstate: LongWord;
dwError: LongWord;
szDeviceType: array[0..16] of Char;
szDeviceName: array[0..128] of Char;
filler: array[1..2] of Char;
end;
TRasConn = record
dwSize: LongWord;
hrasconn: LongWord;
szEntryName: array[0..256] of Char;
szDeviceType: array[0..16] of Char;
szDeviceName: array[0..128] of Char;
filler: array[1..1] of Char;
end;
TRasEntryName = record
dwSize: LongWord;
szEntryName: array[0..256] of Char;
filler: array[1..3] of Char;
end;
// ---------------------------------------------------------------------------
// RAS API functions
function ApiRasDial(
lpRasDialExtensions, lpszPhoneBook: LongWord;
var lpRasDialParams: TRasDialParams;
dwNotifierType, lpvNotifier: LongWord; var lphRasConn: LongWord
): LongWord; external 'RasDialA@rasapi32.dll stdcall';
function ApiRasHangup( hrasconn: LongWord
): LongWord; external 'RasHangUpA@rasapi32.dll stdcall';
function ApiRasEnumConnections(
var rasconnArray: TRasConn; var lpcb: LongWord; var lpcConnections: LongWord
): LongWord; external 'RasEnumConnectionsA@rasapi32.dll stdcall';
function ApiRasGetConnectStatus(
hrasconn: LongWord; var status: TRasConnStatus
): LongWord; external 'RasGetConnectStatusA@rasapi32.dll stdcall';
function ApiRasGetErrorString(
errorValue: LongWord; errorString: PChar; cBufSize: LongWord
): LongWord; external 'RasGetErrorStringA@rasapi32.dll stdcall';
function ApiRasEnumEntries(
reserved: LongWord;
lpszPhoneBook: LongWord;
entrynamesArray: PChar; // var entrynamesArray: TRasEntryName;
var lpcb: LongWord;
var lpcEntries: LongWord
): LongWord; external 'RasEnumEntriesA@rasapi32.dll stdcall';
// ---------------------------------------------------------------------------
// RasLastError: Error code of last RAS-API call
var RasLastError: LongWord;
// ---------------------------------------------------------------------------
// RasErrorText: Description of RAS error code
// ErrNo: Error code (e. g. RasLastError)
// Returns: Description
function RasErrorText( ErrNo: LongWord ): String;
var s: String;
begin
SetLength( s, 256 );
RasLastError := ApiRasGetErrorString( ErrNo, s, 256 );
if RasLastError = 0 then Result := s + ' (' + inttostr(ErrNo) + ')'
else Result := 'RAS error ' + inttostr(ErrNo);
end;
// ---------------------------------------------------------------------------
// RasGetConnection: Get current connection
// Returns: Identifier of current connection, 0 if not connected.
function RasGetConnection: LongWord;
var rasConn: TRasConn;
cb, cbConnections: LongWord;
begin
Result := 0;
rasConn.dwSize := SizeOf_TRasConn;
cb := SizeOf_TRasConn;
RasLastError := ApiRasEnumConnections( rasConn, cb, cbConnections );
if RasLastError <> 0 then exit;
if cbConnections < 1 then exit;
Result := rasConn.hrasconn;
end;
// ---------------------------------------------------------------------------
// RasGetConnectionName: Get name of current connection
// Returns: Name of current connection, '' if not connected.
function RasGetConnectionName: String;
var rasConn: TRasConn;
cb, cbConnections: LongWord;
i: Integer;
begin
Result := '';
rasConn.dwSize := SizeOf_TRasConn;
cb := SizeOf_TRasConn;
RasLastError := ApiRasEnumConnections( rasConn, cb, cbConnections );
if RasLastError <> 0 then exit;
if cbConnections < 1 then exit;
for i:=0 to 255 do begin
if rasConn.szEntryName[i] = chr(0) then break;
Result := Result + rasConn.szEntryName[i];
end;
end;
// ---------------------------------------------------------------------------
// RasGetStatus: Get status of connection
// connection: Connection identifier
// Returns: Status (e.g. RASCS_Connected, RASCS_Disconnected)
function RasGetStatus( connection: LongWord ): LongWord;
var status: TRasConnStatus;
begin
Result := RASCS_Disconnected;
status.dwSize := SizeOf_TRasConnStatus;
RasLastError := ApiRasGetConnectStatus( connection, status );
if RasLastError <> 0 then exit;
Result := status.rasconnstate;
end;
// ---------------------------------------------------------------------------
// RasIsConnected: Check connection
// connection: Connection identifier
// Returns: True if connected
function RasIsConnected( connection: LongWord ): Boolean;
// Returns True, if given connection is (still) connected.
begin
Result := ( RasGetStatus(connection) = RASCS_Connected );
end;
// ---------------------------------------------------------------------------
// RasAnyConnected: Check if any connection is established
// Returns: True if connected
function RasAnyConnected(): Boolean;
// Returns True, if given connection is (still) connected.
var connection: LongWord;
begin
Result := False;
connection := RasGetConnection();
if connection = 0 then exit;
Result := ( RasGetStatus(connection) = RASCS_Connected );
end;
// ---------------------------------------------------------------------------
// RasDial: Dial phonebook entry
// EntryName: Name of phonebook entry to dial
// Username: Username to login
// Password: Password to login
// Returns: Connection identifier on success, 0 on failure.
(*
// Example:
var connection: LongWord;
Begin
connection := RasDial( 'myProvider', 'myName', 'myPassword' );
if connection = 0 then begin
writeln( 'Dialing failed: ' + RasErrorText(RasLastError) );
end else begin
// [[transfer data here]]
RasHangup( connection );
end;
End.
*)
function RasDial( EntryName, Username, Password: String ): LongWord;
var params: TRasDialParams;
connection: LongWord;
i: Integer;
begin
Result := 0;
params.dwSize := SizeOf_TRasDialParams;
params.szPhoneNumber[0] := chr(0);
params.szCallbackNumber[0] := chr(0);
params.szDomain[0] := chr(0);
for i:= 1 to length(EntryName) do params.szEntryName[i-1] := EntryName[i];
params.szEntryName[length(EntryName)] := chr(0);
for i:= 1 to length(Username) do params.szUserName[i-1] := Username[i];
params.szUserName[length(Username)] := chr(0);
for i:= 1 to length(Password) do params.szPassword[i-1] := Password[i];
params.szPassword[length(Password)] := chr(0);
RasLastError := ApiRasDial( 0, 0, params, 0, 0, connection );
if RasLastError <> 0 then exit;
Result := connection;
end;
// ---------------------------------------------------------------------------
// RasHangup: Hangup specific connection
// connection: connection identifier
// Returns: True if not connected or disconnected successfully
function RasHangup( connection: LongWord ): Boolean;
var i: Integer;
begin
Result := True;
RasLastError := ApiRasHangup( connection );
Result := ( RasLastError = 0 );
if not Result then exit;
for i := 1 to 30 do begin // wait until terminated
Sleep( 100 );
RasGetStatus( connection );
if RasLastError = 6 then begin // 6=ERROR_INVALID_HANDLE
RasLastError := 0;
break;
end;
end;
end;
// ---------------------------------------------------------------------------
// RasHangup: Hangup all active connections
// Returns: True if not connected or all disconnected successfully
function RasHangupAll(): Boolean;
var connection: LongWord;
begin
Result := False;
repeat
connection := RasGetConnection();
if connection <> 0 then begin
if not RasHangup( connection ) then exit;
end;
until connection = 0;
Result := True;
end;
// ---------------------------------------------------------------------------
// RasEnumEntries: Get list of available phonebook entries
// RasList: TStringList that is filled with names
// Returns: True if list could be filled.
(*
// Example:
var RasList: TStringList;
i: Integer;
Begin
RasList := TStringList.Create();
RasEnumEntries( RasList );
for i := 0 to RasList.Count - 1 do writeln( RasList.Strings[i] );
RasList.Free;
End.
*)
function RasEnumEntries( RasList: TStringList ): Boolean;
var RasEntries : String;
RasEntriesSize: LongWord;
RasEntryCount : LongWord;
e, i, p: Integer;
s: String;
begin
Result := False;
RasList.Clear;
RasEntriesSize := SizeOf_TRasEntryName * 1;
SetLength( RasEntries, RasEntriesSize );
RasEntries[1] := chr(8); // .dwSize := 264/SizeOf_TRasEntryName;
RasEntries[2] := chr(1);
RasEntries[3] := chr(0);
RasEntries[4] := chr(0);
RasLastError := ApiRasEnumEntries( 0, 0, PChar(RasEntries),
RasEntriesSize, RasEntryCount );
if RasLastError <> 0 then begin
if RasEntriesSize = 0 then exit;
SetLength( RasEntries, RasEntriesSize );
RasEntries[1] := chr(8);
RasEntries[2] := chr(1);
RasEntries[3] := chr(0);
RasEntries[4] := chr(0);
RasLastError := ApiRasEnumEntries( 0, 0, PChar(RasEntries),
RasEntriesSize, RasEntryCount );
end;
if RasLastError = 0 then begin
Result := True;
for e := 0 to RasEntryCount - 1 do begin
p := SizeOf_TRasEntryName * e + 5;
s := '';
for i:=0 to 255 do begin
if RasEntries[p] = chr(0) then break;
s := s + RasEntries[p];
p := p + 1;
end;
RasList.Add( s );
end;
end;
end;
// ===========================================================================
JuergenHaible
==================================================================
The following code should do away with the need to provide a username and password in cleartext in a script, by reading them out of the connection name you specify.
To do this one additional external function declaration is needed under RasAPI Functions:
function ApiRasGetEntryDialParams(lpszPhoneBook: PAnsiChar; var lpDialParams: TRasDialParams; var lpfPassword: LongBool): Longint; external 'RasGetEntryDialParamsA@rasapi32.dll stdcall';
and one local function as follows:
function RasGetEntryDialParams(EntryName : string; var DialParams : TRasDialParams; var lpfPassword : Boolean) : Longint;
var i : integer;
begin
DialParams.dwSize := SizeOf_TRasDialParams;
for i:= 1 to length(EntryName) do begin
DialParams.szEntryName[i-1] := EntryName[i];
end;
DialParams.szEntryName[length(EntryName)] := chr(0);
Result := ApiRasGetEntryDialParams(0,DialParams,lpfPassword);
end;
Note that in accordance with most Win32 API function calls, the result of this function call is zero if the call succeeded or nonzero if the call failed. There are some predefined error codes, which I have not made use of here.
After making the call, the DialParams record should contain the information needed to dial the connection with a RasDial call. I have used this function in Delphi programming for this particular purpose and verified it, but haven't yet tested it in Dialog so I can't be quite sure that it works as expected.
It is also assumed that the phonebook entry need not be provided. If the null parameter is passed as here, the system uses the default phonebook. RAS services under older versions of NT would allow a phonebook file to be specified as an alternative to the default.
The value lpfPassword will be set to true if a password was found and false otherwise. I have not ascertained the circumstances in which the password will not be returned, but assume it occurs if one is not actually stored in the connectoid. In this case, having to provide one in the script reduces the benefit of using this function call.