NetProfiles - Multiple IP Profiles Made Easy
A utility to manage multiple IP profiles (home/work/grandma's etc...)
Introduction
When I worked for a network services company a few years back, we had to visit up to ten sites per day, each having their own distinct IP schemes. It was a constant pain to reconfigure network connections every time I moved between sites or subnets. I wrote this program to handle that task and keep track of the different settings for each of our customers. In this article, I will discuss several topics including some easy ways in which you can add a little style to your basic Windows Forms.
Application Interface
For this application, I chose to use a borderless form. In my opinion, it is a quick and easy way to add an aesthetic touch to your app. The can be done programmatically in the code of your form using the following statement:
this.FormBorderStyle = FormBorderStyle.None;
More information is presented on this below.
The Application Main Window
Edit Profile Window
The Code and Concepts Behind the Application
Manipulating the Windows Registry
The Microsoft.Win32
namespace provides access to the RegistryKey
class which allows you to manipulate the Windows registry. Three methods of the RegistryKey
class are utilized in this application, OpenSubKey()
, GetValue()
and SetValue()
. The code below illustrates how each of the aforementioned methods can be used.
In the following code block, I create the object Reg
and set it to reference the HKEY_LOCAL_MACHINE
hive of the registry, then navigate to a subkey "SOFTWARE\AntiDesign\NetProfiles".
//read settings from the registry
RegistryKey Reg = Registry.LocalMachine;
Reg = Reg.OpenSubKey("Software\\AntiDesign\\NetProfiles", true);
Below, I create another RegistryKey
object from a subkey of the Reg
object using the OpenSubKey()
method. The string currProfile
is assigned to using the GetValue()
method of the RegistryKey
class.
//get current profile to see if we need to remove static routes.
RegistryKey adapter = Reg.OpenSubKey("__Adapters\\" + cboSelectAdapter.Text, true);
string currProfile = adapter.GetValue("CurrentProfile").ToString();
The SetValue()
method is called in this instance to store a string
representation of your IP address in the registry. As you can see from the example below, the Type being stored is selected using an Enum
, RegistryValueKind
.
//save a setting into the registry
Reg.SetValue("IPAddress", txtIPAddress.Text, RegistryValueKind.String);
Enumerating your Network Adapters
The System.Net
namespace provides numerous classes related to networking. This project only utilizes the NetworkInterface
class's GetAllNetworkInterfaces()
method. GetAllNetworkInterfaces()
returns an array of NetworkInterface
objects. I iterate through each of the objects in the array, checking the NetworkInterfaceType
property so that only Ethernet and 802.11 interfaces are listed.
//Enumerate current system's network adapters and store results in a ComboBox
foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
{
// Only get ethernet adapters
if (netInterface.NetworkInterfaceType == NetworkInterfaceType.Ethernet |
netInterface.NetworkInterfaceType == NetworkInterfaceType.Wireless80211)
{
cboSelectAdapter.Items.Add(netInterface.Name);
}
}
try
{
cboSelectAdapter.SelectedIndex = 0;
}
catch { }
Applying IP Settings Programmatically
Windows provides a command line tool for changing your network settings called netsh
. Rather than reinvent the wheel, it serves our purpose to call this utility transparently to accomplish this task. To do this, I am going to use the System.Diagnostics.Process
class. Configuration of the process is done through Process.StartInfo
. In the example, I define the following properties:
FileName
(string
)UseShellExecute
(bool
) - Use the shell to launch the program? This value must befalse
to redirect IO or hide the console window.CreateNoWindow
(bool
) - Should the process be run in a hidden window?Arguments
(string
) - Any command line arguments to be passed to the application
After the Start()
method is called and the process begins to execute, we also call the WaitForExit()
method to stop execution until netsh.exe has finished modifying the IP settings. The netsh
object is reused to set the DNS servers after changing the Arguments
property.
//build the argument strings for netsh.exe
string argsIP, argsDNS;
argsIP = "interface ip set address name=\"" + AdapterName + "\" static " +
ipAddress + " " + subnetMask + " " + gateway + " 1";
argsDNS = "interface ip set dns name=\"" + AdapterName + "\" static " + dnsServer;
//apply the changes
Process netsh = new Process();
netsh.StartInfo.FileName = "netsh.exe";
netsh.StartInfo.UseShellExecute = false;
netsh.StartInfo.CreateNoWindow = true;
netsh.StartInfo.Arguments = argsIP;
netsh.Start();
netsh.WaitForExit();
//Add the dns server
netsh.StartInfo.Arguments = argsDNS;
netsh.Start();
netsh.WaitForExit();
netsh.Dispose();
Using Embedded Fonts
Embedded fonts are another easy way to give your application that "customized" look without too much trouble or added code. Please note that embedding resources in your program can make the size of your application increase drastically, so if executable size is a major concern, then you may want to skip this step.
To begin embedding fonts, you must add use Interop to import gdi32.dll. A method prototype needs to be declared for AddFontMemResourceEx()
. A PrivateFontCollection
will be used to hold the fonts stored in memory.
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont,
IntPtr pdv, [System.Runtime.InteropServices.In] ref uint pcFonts);
public static PrivateFontCollection PFC = new PrivateFontCollection();
Due to the nature of the Interop method being called, you have to wrap the code in an unsafe
structure.
//
// ♠ get Ravie font from our embedded resources
//
try
{
unsafe
{
fixed (byte* pFontData = Properties.Resources.RAVIE)
{
uint nil = 0;
PFC.AddMemoryFont((IntPtr)pFontData, Properties.Resources.RAVIE.Length);
AddFontMemResourceEx((IntPtr)pFontData,
(uint)Properties.Resources.RAVIE.Length, IntPtr.Zero, ref nil);
}
}
}
catch
{
MessageBox.Show("Ravie font was not loaded.");
}
Here is an example of how to use our embedded font for the Label3
Font
property. If more than one font has been added to the PrivateFontCollection
, you will need to iterate through the Families[i].Name
properties to get the correct index. In the example below, it assumes that only one font is in the PrivateFontCollection
.
//
// ♠ Set title bar to use Ravie Font
//
label3.Font = new Font(PFC.Families[0], (float)10); //Font size is 10 pt
Borderless Forms
I will quite often use borderless forms because it gives the "customized" look to an application and requires very little effort. You will however, have to add a few lines of code to allow your application to be moved around the screen. This is accomplished by adding MouseDown
and MouseMove
event handlers to the object(s) that you wish to be able to click and drag from.
The following code is inserted in the MouseDown
events for each object that you wish to use as a drag point. The variable e
is of type MouseEventArgs
and contains two properties that are useful for us, e.X
and e.Y
, which tell us the X and Y coordinates of the mouse click. These values are stored in public int
variables, x
and y
.
//add the following code to the MouseDown events
//x and y are public int values used to track click position
if (e.Button == MouseButtons.Left)
{
x = e.X;
y = e.Y;
}
The following code needs to be inserted into the MouseMove
event handler code for the objects that will be used as drag points. It uses the current mouse position and the x
and y
variables that were populated during the MouseDown
event to relocate the form.
//add the following code to your MouseMove Events
if (e.Button == MouseButtons.Left)
{
this.Left += (e.X - x);
this.Top += (e.Y - y);
}
Conclusion
Little tweaks such as ensuring a font is available (embedding) and removing the borders from your forms can go a long way as far as user experience is concerned. The version of the program that I have uploaded does not contain the Ravie Font and isn't fully implementing embedded fonts. (I started, but ran out of time on this one...)
Note: Using netsh.exe on Vista can take a while while Windows "discovers?" your network connection. This seems to be resolved in Windows 7 and wasn't an issue in XP.
Final Thought
I still use this application on both of my laptops that I carry with me to and from work. Although I no longer spend as much time at client sites, it still saves time switching from static IP (work) and DHCP (home).
History
- 7-14-2010 - Article posted