Using modem to connect to internet WinXP

Petroclus
Petroclus used Ask the Experts™
on
C# WinXP

I'm tring to write a class that connects to the internet using a modem (3G). I am using the Win32 API function called InternetDial to make the connection. This works Ok, except that if there is a failure (no dial tone etc), Windows pops up a dialog message describing the problem. I would like this class to operate in an unattended environment and therefore I don't want it to show any dialog messages - I want it to fail with no dialog/user intervention.

There is a flag called INTERNET_AUTODIAL_FORCE_UNATTENDED which appears to offer this functionality, except that annoyingly Windows still pops up a dialog when the dial-up fails.

Here is my class (from http://bytes.com/topic/c-sharp/answers/275968-internet-dial-c-code):

	public class Dialer
	{
		private IntPtr Handle;

		public Dialer(IntPtr handle)
		{
			Handle = handle;
		}

		[System.Runtime.InteropServices.DllImport("wininet.dll",
		EntryPoint="InternetGetConnectedState", ExactSpelling=true,
		CharSet=System.Runtime.InteropServices.CharSet.Ansi,
		SetLastError=true)]
		private static extern bool InternetGetConnectedState(ref Int32
		lpdwFlags, Int32 dwReserved);

		[System.Runtime.InteropServices.DllImport("Wininet.dll",
		EntryPoint="InternetDial", ExactSpelling=true,
		CharSet=System.Runtime.InteropServices.CharSet.Ansi,
		SetLastError=true)]
		private static extern Int32 InternetDial(IntPtr hwndParent, string
		lpszConnectoid, Int32 dwFlags, ref Int32 lpdwConnection, Int32
		dwReserved);

		[System.Runtime.InteropServices.DllImport("Wininet.dll",
		EntryPoint="InternetHangUp", ExactSpelling=true,
		CharSet=System.Runtime.InteropServices.CharSet.Ansi,
		SetLastError=true)]
		private static extern Int32 InternetHangUp(Int32 lpdwConnection,
		Int32 dwReserved);

		private enum Flags: int
		{
			//Local system uses a LAN to connect to the Internet.
			INTERNET_CONNECTION_LAN = 0X2,
			//Local system uses a modem to connect to the Internet.
			INTERNET_CONNECTION_MODEM = 0X1,
			//Local system uses a proxy server to connect to the Internet.
			INTERNET_CONNECTION_PROXY = 0X4,
			//Type Visual Basic 6 code here...

			//Local system has RAS installed.
			INTERNET_RAS_INSTALLED = 0X10
		}

		//Declaration Used For InternetDialUp.
		private enum DialUpOptions: int
		{
			INTERNET_AUTODIAL_FORCE_ONLINE = 0x0001,
			INTERNET_AUTODIAL_FORCE_UNATTENDED = 0x0002,
			INTERNET_DIAL_UNATTENDED = 0x8000,
			INTERNET_DIAL_SHOW_OFFLINE = 0x4000,
			INTERNET_DIAL_FORCE_PROMPT = 0x2000
		}

		private const int ERROR_SUCCESS = 0X0;
		private const int ERROR_INVALID_PARAMETER = 0X87;


		private Int32 mlConnection;

		public string GetConnectionType()
		{
			Int32 lngFlags = 0;

			if (InternetGetConnectedState(ref lngFlags, 0))
			{
				//connected.
				if ((lngFlags & (int)Flags.INTERNET_CONNECTION_LAN)!=0)
				{
					//LAN connection.
					return "LAN connection.";
				}
				else if ((lngFlags & (int)Flags.INTERNET_CONNECTION_MODEM)!=0)
				{
					//Modem connection.
					return "Modem connection.";
				}
				else if ((lngFlags & (int)Flags.INTERNET_CONNECTION_PROXY)!=0)
				{
					//Proxy connection.
					return "Proxy connection.";
				}
				return "Not connected.";
			}
			else
			{
				//not connected.
				return "Not connected.";
			}
		}

		public void Connect()
		{
			Int32 DResult = 0;

			DResult = InternetDial(Handle, "Uk2",
			Convert.ToInt32(DialUpOptions.INTERNET_AUTODIAL_FORCE_UNATTENDED), ref mlConnection, 0);

			if (DResult == ERROR_SUCCESS)
				Console.WriteLine("Dial Up Successful");
			else
				Console.WriteLine("UnSuccessFull Error Code");
		}

		public void Disconnect()
		{
			Int32 Result = 0;

			if (! (mlConnection == 0))
			{
				Result = InternetHangUp(mlConnection, 0);

				if (Result == 0)
					Console.WriteLine("Hang up successful");
				else
					Console.WriteLine("Hang up NOT successful");
			}
			else
				Console.WriteLine("You must dial a connection first!");
		}
	}

Open in new window



Does anyone know why setting INTERNET_AUTODIAL_FORCE_UNATTENDED still pops up a dialog when it fails - is there a bug in the code above? Is there a better way of forcing internet connection via modem?

Thanks
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Commented:
use a try catch block and log the error in event viewer or wherever you want. This way popup message will not appear.

Author

Commented:
Thanks puru1981 - try/catch doesn't do anything because InternetDial doesn't throw any exception when it fails, it presents a dialog box to the user which I want to try and stop.
IT Consultant
Top Expert 2010
Commented:
I'm sorry I really have no way to test this (no dial-up connections on my system here at the office), but here's some example code that uses the Ras functions (apparently the WinINet functions you referred to in your question in turn call these functions anyway).

Ras functions (RasDial, RasHangup, etc): http://msdn.microsoft.com/en-us/library/aa446739(v=VS.85).aspx
C# Definitions of P/Invoke calls & structures: http://www.pinvoke.net/
This static class below (I think) should dial a connection for you...so you're call would look like:
InternetDialer.DialConnection("The Phonebook Entry Name");
// Do stuff...
InternetDialer.Hangup();
The way I have it coded is kinda quick'n dirty, you should include some more robust error-checking. It also doesn't include any of the extended features of RAS, and as it is now will only dial a single connection - attempting to dial a second time will hangup any already established connection (making it non-static would fix that).  You may also consider providing a call-back delegate to the RasDial function so that it will operate asynchronously and provide progress updates.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

public static class InternetDialer
{
	private static IntPtr hRasConn = IntPtr.Zero;

	private class Constants
	{
		public const int RAS_MaxAreaCode = 10;
		public const int RAS_MaxCallbackNumber = RAS_MaxPhoneNumber;
		public const int RAS_MaxDeviceName = 128;
		public const int RAS_MaxDeviceType = 16;
		public const int RAS_MaxDnsSuffix = 256;
		public const int RAS_MaxEntryName = 256;
		public const int RAS_MaxFacilities = 200;
		public const int RAS_MaxPadType = 32;
		public const int RAS_MaxPath = 260;
		public const int RAS_MaxPhoneNumber = 128;
		public const int RAS_MaxUserData = 200;
		public const int RAS_MaxX25Address = 200;
		public const int UsernameLength = 256;
		public const int PasswordLength = 256;
		public const int DomainLength = 15;
		public const int ERROR_SUCCESS = 0;
	}

	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
	private struct RASDIALPARAMS
	{
		public int dwSize;
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.RAS_MaxEntryName + 1)]
		public string szEntryName;
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.RAS_MaxPhoneNumber + 1)]
		public string szPhoneNumber;
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.RAS_MaxCallbackNumber + 1)]
		public string szCallbackNumber;
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.UsernameLength + 1)]
		public string szUserName;
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.PasswordLength + 1)]
		public string szPassword;
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Constants.DomainLength + 1)]
		public string szDomain;
		public uint dwSubEntry;
		public IntPtr dwCallbackId;
	}

	[DllImport("rasapi32.dll", SetLastError = true)]
	private static extern uint RasGetEntryDialParams(string lpszPhonebook, [In, Out] ref RASDIALPARAMS lprasdialparams, out bool lpfPassword);
	[DllImport("rasapi32.dll", CharSet = CharSet.Auto)]
	private static extern uint RasDial([In] IntPtr lpRasDialExtensions, [In]string lpszPhonebook, [In]RASDIALPARAMS lpRasDialParams, uint dwNotifierType, Delegate lpvNotifier, ref IntPtr lphRasConn);
	[DllImport("coredll.dll")]
	private static extern uint RasHangUp(IntPtr pRasConn);

	public bool Connected
	{
		get
		{
			if (hRasConn == IntPtr.Zero)
				return false;
			else
				return true;
		}
	}

	public void Hangup()
	{
		RasHangUp(hRasConn);
		hRasConn = IntPtr.Zero;
	}

	public bool DialConnection(string ConnectionName)
	{
		RASDIALPARAMS rdp = new RASDIALPARAMS();
		rdp.szEntryName = ConnectionName;
		rdp.dwSize = Marshal.SizeOf(rdp);
		bool passwordRetrieved;
		uint result;

		if (this.Connected)
			Hangup();

		result = RasGetEntryDialParams(null, ref rdp, out passwordRetrieved);
		if (result != Constants.ERROR_SUCCESS || passwordRetrieved == false)
			return false;

		result = RasDial(IntPtr.Zero, null, rdp, 0, null, ref hRasConn);
		if (result == Constants.ERROR_SUCCESS)
			return true;
		else
			return false;
	}
}

Open in new window

Author

Commented:
I did have some trouble with the RasGetEntryDialParams(0 function as it kept returning error 632 (invalid structure size). It appears there are multiple structure sizes dependent on O.S.

Many thanks for a great solution.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial