Friday, April 18, 2008

Ever since learning how to use function pointers in C, I've always been a fan of using them to help make code a bit more usable, especially when you've got a state machine.  Today, as I'm working on a Wizard UI for a desktop application I came across a typical scenario for using a function pointer.  Depending on the stage of the Wizard you're in, a button will have to do separate things.

That got me to thinking that most managed developers simply don't understand the power and utility of delegates, but instead simply consider them a necessity when using Control.Invoke or creating custom events. Sure, in my case I could have a switch statement in the click handler and do logic there, or I could unhook the click handler from one method and hook it to another, but those all seem ugly and a pain in the ass to me.  A simple function pointer change is all you need.  So I decided I'd throw together a really simple example of how you would use a delegate to change the behavior of a Button click.

Let's assume that we have a button that we want to click, and when it's clicked it will do one of 4 things, depending on the state of our application.  We'll just use a messagebox here to give you the idea - what it does is up to you- it's a function after all.

public void FunctionA()
{
  MessageBox.Show("FunctionA");
}

public void FunctionB()
{
  MessageBox.Show("FunctionB");
}

public void FunctionC()
{
  MessageBox.Show("FunctionC");
}

public void FunctionD()
{
  MessageBox.Show("FunctionD");
}

To simulate the different "states" I simply added a ListBox (called functionList) to the Form and manually added the function names to it in the Form's constructor.  Sure, I could have used Reflection to be clever and populate the list, but I'm tryiong to keep it simple and show delegates.

functionList.Items.Add("FunctionA");
functionList.Items.Add("FunctionB");
functionList.Items.Add("FunctionC");
functionList.Items.Add("FunctionD");

Alright, so now we know that depending on which item is selected, we want to call one of our four functions.  Since they all have the same interface (and they have to to use a delegate) we simply define a delegate that matches them.  This delegate can be privately scoped inside your class.

delegate void FunctionDelegate();

And then we create an instance variable to hold the current function pointer we want to use:

private FunctionDelegate m_functionPointer = null;

We add an event handler for the SelectedIndexChanged event of the ListBox (in the Form constructor)

functionList.SelectedIndexChanged += new EventHandler(functionList_SelectedIndexChanged);

And implement the event handler.  It simply looks at the newly selected index in the list and changes the value stored in m_functionPointer appropriately.

void functionList_SelectedIndexChanged(object sender, EventArgs e)
{
  // determine which function pointer to store based on selection
  switch (functionList.SelectedIndex)
  {
    case 0:
      m_functionPointer = FunctionA;
      break;
    case 1:
      m_functionPointer = FunctionB;
      break;
    case 2:
      m_functionPointer = FunctionC;
      break;
    case 3:
      m_functionPointer = FunctionD;
      break;
    default:
      m_functionPointer = null;
      break;
  }
}

Next we wire up an event handler for our button (again the the Form constructor):

callButton.Click += new EventHandler(callButton_Click);

And finally the magic and simplicity of the state-dependent call

void callButton_Click(object sender, EventArgs e)
{
  // call our function (as long as it's not null)
  if (m_functionPointer != null)
  {
    m_functionPointer();
  }
}

That's all there is to it.  Run the application, select a function and click the button.

Get the full source here.

4/18/2008 6:07:46 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [3]  | 
 Saturday, April 12, 2008

In a recent project we decided to migrate the application's data engine from SQL CE 3.1 to SQL CE 3.5.  The challenge with this is that the file formats themselves are not compatible and trying to connect to a 3.1 database usign the 3.5 objects will cause an Exception.  3.5 provides a method to upgrade 3.1 database files, but to use it you really need to know that the file is in 3.1 format to begin with.

Of course you could always put in logic to connect and catch the exception and then upgrade, but let's face it - using exceptions for flow control is a bad practice and any ime it can be avoided it should be. 

Surprisingly, the SQL CE team didn't give us any mechanism otherwise to determine a database file's version, so I put together the following (which should work on the desktop as well as the device):

internal enum SSCEVersion
{
    Unknown,
    v3_1,
    v3_5
}

internal static SSCEVersion GetDatabaseVersion(string path)
{
    uint signature = 0;

    using (FileStream stream = new FileStream(path, FileMode.Open))
    {
        using (BinaryReader reader = new BinaryReader(stream))
        {
            stream.Seek(16, SeekOrigin.Begin);

            signature = reader.ReadUInt32();
        }
    }

    switch (signature)
    {
        case 0x00357b9d: // 3.5
            return SSCEVersion.v3_5;
        case 0x002dd714: // 3.1
            return SSCEVersion.v3_1;
        default:
            return SSCEVersion.Unknown;
    }
}

4/12/2008 3:11:20 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0]  | 
 Thursday, March 06, 2008
If you use Visual Studio 2008, do yourself a huge favor and install the PowerCommands.

3/6/2008 10:32:55 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  | 
 Friday, February 15, 2008

So, you want network statistics for your Windows CE or Windows Mobile device?  I think the new Smart Device Framework 2.2's NetworkInformation namespace might just give you what you're after.  It's got almost everything the desktop gives, plus we even provide access to the ARP and routing tables (something you *don't* get on the desktop).  Here's a complete sample on getting the supported statistics:

IPGlobalProperties globalProps = IPGlobalProperties.GetIPGlobalProperties();
Debug.WriteLine("\r\nGlobal IP Properties\r\n====================");
Debug.WriteLine(string.Format(" Host Name: {0}", globalProps.HostName));
Debug.WriteLine(string.Format(" Domain Name: {0}", globalProps.DomainName));
Debug.WriteLine(string.Format(" DHCP Scope Name: {0}", globalProps.DhcpScopeName));

IPGlobalStatistics globalStatsv4 = globalProps.GetIPv4GlobalStatistics();
Debug.WriteLine("\r\nGlobal IPv4 Statistics\r\n====================");
Debug.WriteLine(string.Format(" Packets Received: {0}", globalStatsv4.ReceivedPackets));
Debug.WriteLine(string.Format(" Packets Delivered: {0}", globalStatsv4.ReceivedPacketsDelivered));
Debug.WriteLine(string.Format(" Packets Discarded: {0}", globalStatsv4.ReceivedPacketsDiscarded));
Debug.WriteLine(string.Format(" Packets Forwarded: {0}", globalStatsv4.ReceivedPacketsForwarded));
Debug.WriteLine(string.Format(" Packets Received w/ Address Errors: {0}", globalStatsv4.ReceivedPacketsWithAddressErrors));
Debug.WriteLine(string.Format(" Packets Received w/ Header Errors: {0}", globalStatsv4.ReceivedPacketsWithHeadersErrors));
Debug.WriteLine(string.Format(" Packets Received w/ Protocol Errors: {0}", globalStatsv4.ReceivedPacketsWithUnknownProtocol));
Debug.WriteLine(string.Format(" Default TTL: {0}", globalStatsv4.DefaultTtl));
Debug.WriteLine(string.Format(" Forwarding {0} Enabled", globalStatsv4.ForwardingEnabled ? "IS" : "IS NOT"));
Debug.WriteLine(string.Format(" Interfaces: {0}", globalStatsv4.NumberOfInterfaces));
Debug.WriteLine(string.Format(" IP Addresses: {0}", globalStatsv4.NumberOfIPAddresses));
Debug.WriteLine(string.Format(" Routes: {0}", globalStatsv4.NumberOfRoutes));
Debug.WriteLine(string.Format(" Output Packet Requests: {0}", globalStatsv4.OutputPacketRequests));
Debug.WriteLine(string.Format(" Output Routing Discards: {0}", globalStatsv4.OutputPacketRoutingDiscards));
Debug.WriteLine(string.Format(" Output Packet Discards: {0}", globalStatsv4.OutputPacketsDiscarded));
Debug.WriteLine(string.Format(" Output Packets w/o Route: {0}", globalStatsv4.OutputPacketsWithNoRoute));
Debug.WriteLine(string.Format(" Fragmented Packets: {0}", globalStatsv4.PacketsFragmented));
Debug.WriteLine(string.Format(" Fragment Failures: {0}", globalStatsv4.PacketFragmentFailures));
Debug.WriteLine(string.Format(" Reassemblies Required: {0}", globalStatsv4.PacketReassembliesRequired));
Debug.WriteLine(string.Format(" Reassemblies Succeeded: {0}", globalStatsv4.PacketsReassembled));
Debug.WriteLine(string.Format(" Reassembly Failures: {0}", globalStatsv4.PacketReassemblyFailures));
Debug.WriteLine(string.Format(" Reassembly Timeouts: {0}", globalStatsv4.PacketReassemblyTimeout));

#region --- IPv6 stats ---
try
{
    Debug.WriteLine("\r\nGlobal IPv6 Statistics\r\n====================");
    IPGlobalStatistics globalStatsv6 = globalProps.GetIPv6GlobalStatistics();
    Debug.WriteLine(string.Format(" Packets Received: {0}", globalStatsv6.ReceivedPackets));
    Debug.WriteLine(string.Format(" Packets Delivered: {0}", globalStatsv6.ReceivedPacketsDelivered));
    Debug.WriteLine(string.Format(" Packets Discarded: {0}", globalStatsv6.ReceivedPacketsDiscarded));
    Debug.WriteLine(string.Format(" Packets Forwarded: {0}", globalStatsv6.ReceivedPacketsForwarded));
    Debug.WriteLine(string.Format(" Packets Received w/ Address Errors: {0}", globalStatsv6.ReceivedPacketsWithAddressErrors));
    Debug.WriteLine(string.Format(" Packets Received w/ Header Errors: {0}", globalStatsv6.ReceivedPacketsWithHeadersErrors));
    Debug.WriteLine(string.Format(" Packets Received w/ Protocol Errors: {0}", globalStatsv6.ReceivedPacketsWithUnknownProtocol));
    Debug.WriteLine(string.Format(" Default TTL: {0}", globalStatsv6.DefaultTtl));
    Debug.WriteLine(string.Format(" Forwarding {0} Enabled", globalStatsv6.ForwardingEnabled ? "IS" : "IS NOT"));
    Debug.WriteLine(string.Format(" Interfaces: {0}", globalStatsv6.NumberOfInterfaces));
    Debug.WriteLine(string.Format(" IP Addresses: {0}", globalStatsv6.NumberOfIPAddresses));
    Debug.WriteLine(string.Format(" Routes: {0}", globalStatsv6.NumberOfRoutes));
    Debug.WriteLine(string.Format(" Output Packet Requests: {0}", globalStatsv6.OutputPacketRequests));
    Debug.WriteLine(string.Format(" Output Routing Discards: {0}", globalStatsv6.OutputPacketRoutingDiscards));
    Debug.WriteLine(string.Format(" Output Packet Discards: {0}", globalStatsv6.OutputPacketsDiscarded));
    Debug.WriteLine(string.Format(" Output Packets w/o Route: {0}", globalStatsv6.OutputPacketsWithNoRoute));
    Debug.WriteLine(string.Format(" Fragmented Packets: {0}", globalStatsv6.PacketsFragmented));
    Debug.WriteLine(string.Format(" Fragment Failures: {0}", globalStatsv6.PacketFragmentFailures));
    Debug.WriteLine(string.Format(" Reassemblies Required: {0}", globalStatsv6.PacketReassembliesRequired));
    Debug.WriteLine(string.Format(" Reassemblies Succeeded: {0}", globalStatsv6.PacketsReassembled));
    Debug.WriteLine(string.Format(" Reassembly Failures: {0}", globalStatsv6.PacketReassemblyFailures));
    Debug.WriteLine(string.Format(" Reassembly Timeouts: {0}", globalStatsv6.PacketReassemblyTimeout));
    Debug.WriteLine(string.Format(" Packets Received: {0}", globalStatsv6.ReceivedPackets));
}
catch (PlatformNotSupportedException)
{
    Debug.WriteLine(" IPv6 Not supported");
}
#endregion

#region --- Icmpv4 stats ---
IcmpV4Statistics icmpstats = globalProps.GetIcmpV4Statistics();
Debug.WriteLine("\r\nICMPv4 Statistics\r\n====================");
Debug.WriteLine(string.Format(" Address Mask Requests Received: {0}", icmpstats.AddressMaskRequestsReceived));
Debug.WriteLine(string.Format(" Address Mask Requests Sent: {0}", icmpstats.AddressMaskRequestsSent));
Debug.WriteLine(string.Format(" Address Mask Replies Received: {0}", icmpstats.AddressMaskRepliesReceived));
Debug.WriteLine(string.Format(" Address Mask Replies Sent: {0}", icmpstats.AddressMaskRepliesSent));
Debug.WriteLine(string.Format(" Dest Unreachable Messages Received: {0}", icmpstats.DestinationUnreachableMessagesReceived));
Debug.WriteLine(string.Format(" Dest Unreachable Messages Sent: {0}", icmpstats.DestinationUnreachableMessagesSent));
Debug.WriteLine(string.Format(" Echo Replies Received: {0}", icmpstats.EchoRepliesReceived));
Debug.WriteLine(string.Format(" Echo Replies Sent: {0}", icmpstats.EchoRepliesSent));
Debug.WriteLine(string.Format(" Echo Requests Received: {0}", icmpstats.EchoRequestsReceived));
Debug.WriteLine(string.Format(" Echo Requests Sent: {0}", icmpstats.EchoRequestsSent));
Debug.WriteLine(string.Format(" Errors Received: {0}", icmpstats.ErrorsReceived));
Debug.WriteLine(string.Format(" Errors Sent: {0}", icmpstats.ErrorsSent));
Debug.WriteLine(string.Format(" Messages Received: {0}", icmpstats.MessagesReceived));
Debug.WriteLine(string.Format(" Messages Sent: {0}", icmpstats.MessagesSent));
Debug.WriteLine(string.Format(" Parameter Problems Received: {0}", icmpstats.ParameterProblemsReceived));
Debug.WriteLine(string.Format(" Parameter Problems Sent: {0}", icmpstats.ParameterProblemsSent));
Debug.WriteLine(string.Format(" Redirects Received: {0}", icmpstats.RedirectsReceived));
Debug.WriteLine(string.Format(" Redirects Sent: {0}", icmpstats.RedirectsSent));
Debug.WriteLine(string.Format(" Source Quenches Received: {0}", icmpstats.SourceQuenchesReceived));
Debug.WriteLine(string.Format(" Source Quenches Sent: {0}", icmpstats.SourceQuenchesSent));
Debug.WriteLine(string.Format(" Time Exceeded Messages Received: {0}", icmpstats.TimeExceededMessagesReceived));
Debug.WriteLine(string.Format(" Time Exceeded Messages Sent: {0}", icmpstats.TimeExceededMessagesSent));
Debug.WriteLine(string.Format(" Timestamp Replies Received: {0}", icmpstats.TimestampRepliesReceived));
Debug.WriteLine(string.Format(" Timestamp Replies Sent: {0}", icmpstats.TimestampRepliesSent));
Debug.WriteLine(string.Format(" Timestamp Requests Received: {0}", icmpstats.TimestampRequestsReceived));
Debug.WriteLine(string.Format(" Timestamp Requests Sent: {0}", icmpstats.TimestampRequestsSent));
#endregion

#region --- TCPIPv4 stats ---
TcpStatistics tcpstats = globalProps.GetTcpIPv4Statistics();
Debug.WriteLine("\r\nTCP/IP v4 Statistics\r\n====================");
Debug.WriteLine(string.Format(" Connections Accepted: {0}", tcpstats.ConnectionsAccepted));
Debug.WriteLine(string.Format(" Connections Initiated: {0}", tcpstats.ConnectionsInitiated));
Debug.WriteLine(string.Format(" Cumulative Connections: {0}", tcpstats.CumulativeConnections));
Debug.WriteLine(string.Format(" Current Connections: {0}", tcpstats.CurrentConnections));
Debug.WriteLine(string.Format(" Errors Received: {0}", tcpstats.ErrorsReceived));
Debug.WriteLine(string.Format(" Failed Connection Attempts: {0}", tcpstats.FailedConnectionAttempts));
Debug.WriteLine(string.Format(" Maximum Connections: {0}", tcpstats.MaximumConnections));
Debug.WriteLine(string.Format(" Max Transmission Timeout: {0}", tcpstats.MaximumTransmissionTimeout));
Debug.WriteLine(string.Format(" Min Transmission Timeout: {0}", tcpstats.MinimumTransmissionTimeout));
Debug.WriteLine(string.Format(" Reset Connections: {0}", tcpstats.ResetConnections));
Debug.WriteLine(string.Format(" Resets Sent: {0}", tcpstats.ResetsSent));
Debug.WriteLine(string.Format(" Segments Received: {0}", tcpstats.SegmentsReceived));
Debug.WriteLine(string.Format(" Segments Resent: {0}", tcpstats.SegmentsResent));
Debug.WriteLine(string.Format(" Connections Sent: {0}", tcpstats.SegmentsSent));
#endregion

#region --- TCPIPv6 stats ---
Debug.WriteLine("\r\nTCP/IP v6 Statistics\r\n====================");
try
{
    tcpstats = globalProps.GetTcpIPv6Statistics();
    Debug.WriteLine(string.Format(" Connections Accepted: {0}", tcpstats.ConnectionsAccepted));
    Debug.WriteLine(string.Format(" Connections Initiated: {0}", tcpstats.ConnectionsInitiated));
    Debug.WriteLine(string.Format(" Cumulative Connections: {0}", tcpstats.CumulativeConnections));
    Debug.WriteLine(string.Format(" Current Connections: {0}", tcpstats.CurrentConnections));
    Debug.WriteLine(string.Format(" Errors Received: {0}", tcpstats.ErrorsReceived));
    Debug.WriteLine(string.Format(" Failed Connection Attempts: {0}", tcpstats.FailedConnectionAttempts));
    Debug.WriteLine(string.Format(" Maximum Connections: {0}", tcpstats.MaximumConnections));
    Debug.WriteLine(string.Format(" Max Transmission Timeout: {0}", tcpstats.MaximumTransmissionTimeout));
    Debug.WriteLine(string.Format(" Min Transmission Timeout: {0}", tcpstats.MinimumTransmissionTimeout));
    Debug.WriteLine(string.Format(" Reset Connections: {0}", tcpstats.ResetConnections));
    Debug.WriteLine(string.Format(" Resets Sent: {0}", tcpstats.ResetsSent));
    Debug.WriteLine(string.Format(" Segments Received: {0}", tcpstats.SegmentsReceived));
    Debug.WriteLine(string.Format(" Segments Resent: {0}", tcpstats.SegmentsResent));
    Debug.WriteLine(string.Format(" Connections Sent: {0}", tcpstats.SegmentsSent));
}
catch (PlatformNotSupportedException)
{
    Debug.WriteLine(" IPv6 Not supported");
}
#endregion

#region --- UDPv4 stats ---
UdpStatistics udpstats = globalProps.GetUdpIPv4Statistics();
Debug.WriteLine("\r\nUDP v4 Statistics\r\n====================");
Debug.WriteLine(string.Format(" UDP Listeners: {0}", udpstats.UdpListeners));
Debug.WriteLine(string.Format(" Datagrams Received: {0}", udpstats.DatagramsReceived));
Debug.WriteLine(string.Format(" Datagrams Sent: {0}", udpstats.DatagramsSent));
Debug.WriteLine(string.Format(" Datagrams Discarded: {0}", udpstats.IncomingDatagramsDiscarded));
Debug.WriteLine(string.Format(" Datagrams with Errors: {0}", udpstats.IncomingDatagramsWithErrors));
#endregion

#region --- UDPv6 stats ---
Debug.WriteLine("\r\nUDP v6 Statistics\r\n====================");
try
{
    udpstats = globalProps.GetUdpIPv6Statistics();
    Debug.WriteLine(string.Format(" UDP Listeners: {0}", udpstats.UdpListeners));
    Debug.WriteLine(string.Format(" Datagrams Received: {0}", udpstats.DatagramsReceived));
    Debug.WriteLine(string.Format(" Datagrams Sent: {0}", udpstats.DatagramsSent));
    Debug.WriteLine(string.Format(" Datagrams Discarded: {0}", udpstats.IncomingDatagramsDiscarded));
    Debug.WriteLine(string.Format(" Datagrams with Errors: {0}", udpstats.IncomingDatagramsWithErrors));
}
catch (PlatformNotSupportedException)
{
    Debug.WriteLine(" IPv6 Not supported");
}
#endregion

ArpTable table = ArpTable.GetArpTable();
if (table.Count > 0)
{
    Debug.WriteLine("\r\n*ARP Table\r\n====================");
    Debug.WriteLine(string.Format("{0}{1}{2}{3}",
   
"[Interface]".PadRight(16),
    "[Type]".PadLeft(10),
    "[IP Address]".PadLeft(17),
    "[MAC Address]".PadLeft(22)));
    foreach (ArpEntry entry in table)
    {
        Debug.WriteLine(string.Format("{0}{1}{2}{3}"
            entry.NetworkInterface.Name.PadRight(16), 
            entry.ArpEntryType.ToString().PadLeft(10), 
            entry.IPAddress.ToString().PadLeft(17), 
            entry.PhysicalAddress.ToString().PadLeft(22)));
    }
}
else
{
    Debug.WriteLine(" No ARP table entries");
}

IPRoutingTable routingTable = IPRoutingTable.GetRoutingTable();
if(routingTable.Count > 0)
{
    Debug.WriteLine("\r\n*IP Routing Table\r\n====================");
    Debug.WriteLine(string.Format("{0}{1}{2}{3}{4}",
        "[Interface]".PadRight(16),
        "[Type]".PadRight(12),
        "[Destination]".PadLeft(17),
        "[NetMask]".PadLeft(17),
        "[Next Hop]".PadLeft(17)));
    foreach (IPForwardEntry entry in routingTable)
    {
        string intfname = entry.NetworkInterface == null ? intfname = "{Loopback}" : entry.NetworkInterface.Name;
        Debug.WriteLine(string.Format("{0}{1}{2}{3}{4}",
        intfname.PadRight(16),
        entry.RouteType.ToString().PadRight(12),
        entry.Destination.ToString().PadLeft(17),
        entry.SubnetMask.ToString().PadLeft(17),
        entry.NextHop.ToString().PadLeft(17))); 
    }
}
else
{
    Debug.WriteLine(" No IP Routing table entries");
}

TcpConnectionInformation[] connections = globalProps.GetActiveTcpConnections();
if (connections.Length > 0)
{
    Debug.WriteLine("\r\nActive TCP Connections\r\n====================");
    Debug.WriteLine(string.Format("{0}:{1}<---->{2}{3}[{4}]",
        "[local IP]".PadLeft(16),
        "[port]".PadRight(6),
        "[remote IP]".PadLeft(16),
        "[port]".PadRight(6),
        "[state]"));
    foreach (TcpConnectionInformation info in connections)
    {
        Debug.WriteLine(string.Format("{0}:{1}<---->{2}:{3}[{4}]",
        info.LocalEndPoint.Address.ToString().PadLeft(16),
        info.LocalEndPoint.Port.ToString().PadRight(6),
        info.RemoteEndPoint.Address.ToString().PadLeft(16),
        info.RemoteEndPoint.Port.ToString().PadRight(6),
        info.State.ToString()));
    }
}
else
{
    Debug.WriteLine(" No active TCP connections");
}

2/15/2008 11:57:23 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  | 

Smart Device Framework 2.2 refactored a lot of our network interface classes.  Yes, it's likely to casue some angst with people that used the older stuff, but it really is for the best.  I never liked the older mechanism that exposed things like SSID for network interfaces that weren't even wireless.  The new model is much friendlier and object-oriented.  Here's a quick (and very thorough) example of how to use the new classes.  As you can see, there's *nothing* to be known about the interface that isn't exposed.

NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
WirelessZeroConfigNetworkInterface wzcInterface = null;

foreach (NetworkInterface ni in interfaces)
{
    Debug.WriteLine(string.Format("===========\r\nInterface {0}\r\n===========", ni.Id));
    Debug.WriteLine(string.Format(" Type: {0}", ni.GetType().Name));
    Debug.WriteLine(string.Format(" Name: {0}", ni.Name));
    Debug.WriteLine(string.Format(" Description: {0}", ni.Description));
    Debug.WriteLine(string.Format(" Network Interface Type: {0}", ni.NetworkInterfaceType.ToString()));
    PhysicalAddress address = ni.GetPhysicalAddress();
    Debug.WriteLine(string.Format(" MAC: {0}", address == null ? "{none}" : address.ToString()));
    Debug.WriteLine(string.Format(" Operational Status: {0}", ni.OperationalStatus.ToString()));
    Debug.WriteLine(string.Format(" Speed: {0}bps", ni.Speed));
    Debug.WriteLine(string.Format(" *Interface Operational Status: {0}", ni.InterfaceOperationalStatus.ToString()));
    Debug.WriteLine(string.Format(" *Current IP: {0}", ni.CurrentIpAddress.ToString()));
    Debug.WriteLine(string.Format(" *Current Subnet: {0}", ni.CurrentSubnetMask.ToString()));

    IPInterfaceProperties ipProps = ni.GetIPProperties();
    Debug.WriteLine("\r\n IP Properties\r\n -------------");

#region
--- Server Lists ---
    if (ipProps.DhcpServerAddresses.Count > 0)
    {
        for (int i = 0; i < ipProps.DhcpServerAddresses.Count; i++)
        {
            Debug.WriteLine(string.Format(" DHCP Server {0}: {1}", i, ipProps.DhcpServerAddresses[i].ToString()));
        }
    }
    else
    {
        Debug.WriteLine(" No DHCP Servers");
    }

    if (ipProps.DnsAddresses.Count > 0)
    {
        for (int i = 0; i < ipProps.DnsAddresses.Count; i++)
        {
            Debug.WriteLine(string.Format(" DNS Server {0}: {1}", i, ipProps.DnsAddresses[i].ToString()));
        }
    }
    else
    {
        Debug.WriteLine(" No DNS Servers");
    }

    if (ipProps.GatewayAddresses.Count > 0)
    {
        for (int i = 0; i < ipProps.GatewayAddresses.Count; i++)
        {
            Debug.WriteLine(string.Format(" Gateway {0}: {1}", i, ipProps.GatewayAddresses[i].Address.ToString()));
        }
    }
    else
    {
        Debug.WriteLine(" No Gateways");
    }
    
    if (ipProps.WinsServersAddresses.Count > 0)
    {
        for (int i = 0; i < ipProps.WinsServersAddresses.Count; i++)
        {
            Debug.WriteLine(string.Format(" WINS Server {0}: {1}", i, ipProps.WinsServersAddresses[i].ToString()));
        }
    }
    else
    {
        Debug.WriteLine(" No WINS Servers");
    }
#endregion

#region --- Unicast Addresses ---
    if (ipProps.UnicastAddresses.Count > 0)
    {
        for (int i = 0; i < ipProps.UnicastAddresses.Count; i++)
        {
            Debug.WriteLine(string.Format(" Unicast address {0}: {1}", i, ipProps.UnicastAddresses[i].Address.ToString()));
            Debug.WriteLine(string.Format(" Address Family: {0}", ipProps.UnicastAddresses[i].Address.AddressFamily));
            if (ipProps.UnicastAddresses[i].Address.AddressFamily == AddressFamily.InterNetworkV6)
            {
                Debug.WriteLine(string.Format(" Scope ID: {0}", ipProps.UnicastAddresses[i].Address.ScopeId));
            }
            else // ipv4
            {
                Debug.WriteLine(string.Format(" IPv4 Mask: {0}", ipProps.UnicastAddresses[i].IPv4Mask == null 
                        ? "{none}" : ipProps.UnicastAddresses[i].IPv4Mask.ToString()));
            }
            Debug.WriteLine(string.Format(" Preferred Limetime: {0}", ipProps.UnicastAddresses[i].AddressPreferredLifetime));
            Debug.WriteLine(string.Format(" Valid Limetime: {0}", ipProps.UnicastAddresses[i].AddressValidLifetime));
            Debug.WriteLine(string.Format(" DHCP Lease Limetime: {0}", ipProps.UnicastAddresses[i].DhcpLeaseLifetime));
            Debug.WriteLine(string.Format(" DAD State: {0}", ipProps.UnicastAddresses[i].DuplicateAddressDetectionState));
            Debug.WriteLine(string.Format(" {0} DNS Eligible", ipProps.UnicastAddresses[i].IsDnsEligible ? "IS" : "IS NOT"));
            Debug.WriteLine(string.Format(" {0} Transient", ipProps.UnicastAddresses[i].IsTransient ? "IS" : "IS NOT"));
            Debug.WriteLine(string.Format(" Prefix Origin: {0}", ipProps.UnicastAddresses[i].PrefixOrigin.ToString()));
            Debug.WriteLine(string.Format(" Suffix Origin: {0}", ipProps.UnicastAddresses[i].SuffixOrigin.ToString()));
        }
    }
    else
    {
        Debug.WriteLine(" No Unicast addresses");
    }
#endregion

#region
--- Anycast Addresses ---
    if (ipProps.AnycastAddresses.Count > 0)
    {
        for (int i = 0; i < ipProps.AnycastAddresses.Count; i++)
        {
            Debug.WriteLine(string.Format(" Anycast address {0}: {1}", i, ipProps.AnycastAddresses[i].Address.ToString()));
            Debug.WriteLine(string.Format(" Address Family: {0}", ipProps.AnycastAddresses[i].Address.AddressFamily));
            if (ipProps.AnycastAddresses[i].Address.AddressFamily == AddressFamily.InterNetworkV6)
            {
                Debug.WriteLine(string.Format(" Scope ID: {0}", ipProps.AnycastAddresses[i].Address.ScopeId));
            }
            Debug.WriteLine(string.Format(" {0} DNS Eligible", ipProps.UnicastAddresses[i].IsDnsEligible ? "IS" : "IS NOT"));
            Debug.WriteLine(string.Format(" {0} Transient", ipProps.UnicastAddresses[i].IsTransient ? "IS" : "IS NOT"));
        }
    }
    else
    {
        Debug.WriteLine(" No Anycast addresses");
    }
#endregion

#region --- Multicast Addresses ---
    if (ipProps.MulticastAddresses.Count > 0)
    {
        for (int i = 0; i < ipProps.MulticastAddresses.Count; i++)
        {
            Debug.WriteLine(string.Format(" Anycast address {0}: {1}", i, ipProps.MulticastAddresses[i].Address.ToString()));
            Debug.WriteLine(string.Format(" Address Family: {0}", ipProps.MulticastAddresses[i].Address.AddressFamily));
            if (ipProps.MulticastAddresses[i].Address.AddressFamily == AddressFamily.InterNetworkV6)
            {
                Debug.WriteLine(string.Format(" Scope ID: {0}", ipProps.MulticastAddresses[i].Address.ScopeId));
            }
            Debug.WriteLine(string.Format(" {0} DNS Eligible", ipProps.MulticastAddresses[i].IsDnsEligible ? "IS" : "IS NOT"));
            Debug.WriteLine(string.Format(" {0} Transient", ipProps.MulticastAddresses[i].IsTransient ? "IS" : "IS NOT"));
        }
    }
    else
    {
        Debug.WriteLine(" No Multicast addresses");
    }
#endregion

#region --- IPv4 Stats ---
    IPv4InterfaceStatistics ipstats = ni.GetIPv4Statistics();
    Debug.WriteLine("\r\n IPv4 Statistics\r\n -------------");
    Debug.WriteLine(string.Format(" Bytes Received: {0}", ipstats.BytesReceived));
    Debug.WriteLine(string.Format(" Bytes Sent: {0}", ipstats.BytesSent));
    Debug.WriteLine(string.Format(" Incoming Packets Discarded: {0}", ipstats.IncomingPacketsDiscarded));
    Debug.WriteLine(string.Format(" Incoming Packets with errors: {0}", ipstats.IncomingPacketsWithErrors));
    Debug.WriteLine(string.Format(" Incoming Packets Unk. Protocol: {0}", ipstats.IncomingUnknownProtocolPackets));
    Debug.WriteLine(string.Format(" Non Unicast Packets Received: {0}", ipstats.NonUnicastPacketsReceived));
    Debug.WriteLine(string.Format(" Non Unicast Packets Sent: {0}", ipstats.NonUnicastPacketsSent));
    Debug.WriteLine(string.Format(" Outgoing Packets Discarded: {0}", ipstats.OutgoingPacketsDiscarded));
    Debug.WriteLine(string.Format(" Outgoing Packets With Errors: {0}", ipstats.OutgoingPacketsWithErrors));
    Debug.WriteLine(string.Format(" Output Queue Length: {0}", ipstats.OutputQueueLength));
    Debug.WriteLine(string.Format(" Unicast Packets Received: {0}", ipstats.UnicastPacketsReceived));
    Debug.WriteLine(string.Format(" Unicast Packets Sent: {0}", ipstats.UnicastPacketsSent));
#endregion

#region --- IPv4 Properties ---
    IPv4InterfaceProperties ipv4props = ipProps.GetIPv4Properties();
    Debug.WriteLine("\r\n IPv4 Properties\r\n -------------");
    Debug.WriteLine(string.Format(" Index: {0}", ipv4props.Index));
    Debug.WriteLine(string.Format(" Auto Addressing {0}", ipv4props.IsAutomaticPrivateAddressingActive 
        ? "ACTIVE" : "INACTIVE"));
    Debug.WriteLine(string.Format(" Auto Addressing {0}", ipv4props.IsAutomaticPrivateAddressingEnabled 
        ? "ENABLED" : "DISABLED"));
    Debug.WriteLine(string.Format(" DHCP {0}", ipv4props.IsDhcpEnabled ? "ENABLED" : "DISABLED"));
    Debug.WriteLine(string.Format(" MTU: {0}", ipv4props.Mtu));
    Debug.WriteLine(string.Format(" {0} use WINS", ipv4props.UsesWins ? "DOES" : "DOES NOT"));
#endregion

    if (ni is WirelessZeroConfigNetworkInterface)
    {
        WirelessZeroConfigNetworkInterface wzc = (WirelessZeroConfigNetworkInterface)ni;

        // save for later operations
        wzcInterface = wzc;

        Debug.WriteLine("\r\n *WZC Properties\r\n -------------");
        Debug.WriteLine(string.Format(" *Associated AP: {0}", wzc.AssociatedAccessPoint));
        Debug.WriteLine(string.Format(" *Associated AP MAC: {0}", wzc.AssociatedAccessPointMAC));
        Debug.WriteLine(string.Format(" *Authentication Mode: {0}", wzc.AuthenticationMode.ToString()));
        Debug.WriteLine(string.Format(" *WZC Fallback Enabled: {0}", wzc.FallbackEnabled));
        Debug.WriteLine(string.Format(" *WEP Status: {0}", wzc.WEPStatus));
        Debug.WriteLine(string.Format(" *Signal Strength: {0}db ({1})", wzc.SignalStrength.Decibels, 
                wzc.SignalStrength.Strength.ToString()));
        Debug.WriteLine(string.Format(" *Authentication Mode: {0}", wzc.AuthenticationMode.ToString()));
        Debug.WriteLine(string.Format(" *Infrastructure Mode: {0}", wzc.InfrastructureMode.ToString()));
        Debug.WriteLine(string.Format(" *WEP Status: {0}", wzc.WEPStatus.ToString()));
        foreach (int rate in wzc.SupportedRates)
        {
            Debug.WriteLine(string.Format(" *Supports {0}kbps", rate));
        }
        Debug.WriteLine(string.Format(" *Radio ATIM Window: {0}Kµsec", wzc.RadioConfiguration.ATIMWindow));
        Debug.WriteLine(string.Format(" *Radio beacon Period: {0}Kµsec", wzc.RadioConfiguration.BeaconPeriod));
        Debug.WriteLine(string.Format(" *Radio Frequency: {0}kHz", wzc.RadioConfiguration.Frequency));
        Debug.WriteLine(string.Format(" *Radio Frequency Hop Dwell Time: {0}Kµsec",         
                wzc.RadioConfiguration.FrequencyHopDwellTime));
        Debug.WriteLine(string.Format(" *Radio Frequency Hop Pattern: {0}", wzc.RadioConfiguration.FrequencyHopPattern));
        Debug.WriteLine(string.Format(" *Radio Frequency Hop Set: {0}", wzc.RadioConfiguration.FrequencyHopSet));

#region --- Preferred APs ---
        if (wzc.PreferredAccessPoints.Count > 0)
        {
            Debug.WriteLine("\r\n *Preferred APs\r\n -------------");
            foreach (AccessPoint ap in wzc.PreferredAccessPoints)
            {
                Debug.WriteLine(string.Format(" *SSID: {0}", ap.Name));
                Debug.WriteLine(string.Format(" *MAC {0}", ap.PhysicalAddress.ToString()));
                Debug.WriteLine(string.Format(" *Mode {0}", ap.InfrastructureMode.ToString()));
                Debug.WriteLine(string.Format(" *Network Type {0}", ap.NetworkTypeInUse.ToString()));
                Debug.WriteLine(string.Format(" *Privacy {0}", ap.Privacy));
                Debug.WriteLine(string.Format(" *Signal Strength: {0}db ({1})", ap.SignalStrength.Decibels,                 
                        ap.SignalStrength.Strength.ToString()));
                // supported rates
                foreach (int rate in ap.SupportedRates)
                {
                    Debug.WriteLine(string.Format(" *Supports {0}kbps", rate));
                }
            }
        }
        else
        {
            Debug.WriteLine("\r\n *No Preferred APs");
        }
#endregion
#region --- Nearby APs ---
        if (wzc.NearbyAccessPoints.Count > 0)
        {
            Debug.WriteLine("\r\n *Nearby APs\r\n -------------");
            foreach (AccessPoint ap in wzc.NearbyAccessPoints)
            {
                Debug.WriteLine(string.Format(" *SSID: {0}", ap.Name));
                Debug.WriteLine(string.Format(" *MAC {0}", ap.PhysicalAddress.ToString()));
                Debug.WriteLine(string.Format(" *Mode {0}", ap.InfrastructureMode.ToString()));
                Debug.WriteLine(string.Format(" *Network Type {0}", ap.NetworkTypeInUse.ToString()));
                Debug.WriteLine(string.Format(" *Privacy {0}", ap.Privacy));
                Debug.WriteLine(string.Format(" *Signal Strength: {0}db ({1})", ap.SignalStrength.Decibels, 
                        ap.SignalStrength.Strength.ToString()));
                // supported rates
                foreach (int rate in ap.SupportedRates)
                {
                    Debug.WriteLine(string.Format(" *Supports {0}kbps", rate));
                }
            }
        }
        else
        {
            Debug.WriteLine("\r\n *No Nearby APs");
        }
#endregion
#region --- Preferred APs ---
        if (wzc.NearbyPreferredAccessPoints.Count > 0)
        {
            Debug.WriteLine("\r\n *Preferred Nearby APs\r\n -------------");
            foreach (AccessPoint ap in wzc.NearbyPreferredAccessPoints)
            {
                Debug.WriteLine(string.Format(" *SSID: {0}", ap.Name));
                Debug.WriteLine(string.Format(" *MAC {0}", ap.PhysicalAddress.ToString()));
                Debug.WriteLine(string.Format(" *Mode {0}", ap.InfrastructureMode.ToString()));
                Debug.WriteLine(string.Format(" *Network Type {0}", ap.NetworkTypeInUse.ToString()));
                Debug.WriteLine(string.Format(" *Privacy {0}", ap.Privacy));
                Debug.WriteLine(string.Format(" *Signal Strength: {0}db ({1})", ap.SignalStrength.Decibels,
                        ap.SignalStrength.Strength.ToString()));
                // supported rates
                foreach (int rate in ap.SupportedRates)
                {
                    Debug.WriteLine(string.Format(" *Supports {0}kbps", rate));
                }
            }
        }
        else
        {
            Debug.WriteLine("\r\n *No Nearby Preferred APs");
        }
#endregion
    }
    else if (ni is WirelessNetworkInterface)
    {
        WirelessNetworkInterface wni = (WirelessNetworkInterface)ni;

        Debug.WriteLine("\r\n *Wireless Properties\r\n -------------");
        Debug.WriteLine(string.Format(" *Associated AP: {0}", wni.AssociatedAccessPoint));
        Debug.WriteLine(string.Format(" *Associated AP MAC: {0}", wni.AssociatedAccessPointMAC));
        Debug.WriteLine(string.Format(" *Signal Strength: {0}db ({1})", wni.SignalStrength.Decibels,         
            wni.SignalStrength.Strength.ToString()));
        Debug.WriteLine(string.Format(" *Authentication Mode: {0}", wni.AuthenticationMode.ToString()));
        Debug.WriteLine(string.Format(" *Infrastructure Mode: {0}", wni.InfrastructureMode.ToString()));
        Debug.WriteLine(string.Format(" *WEP Status: {0}", wni.WEPStatus.ToString()));
        foreach (int rate in wni.SupportedRates)
        {
            Debug.WriteLine(string.Format(" *Supports {0}kbps", rate));
        }
        Debug.WriteLine(string.Format(" *Radio ATIM Window: {0}Kµsec", wni.RadioConfiguration.ATIMWindow));
        Debug.WriteLine(string.Format(" *Radio beacon Period: {0}Kµsec", wni.RadioConfiguration.BeaconPeriod));
        Debug.WriteLine(string.Format(" *Radio Frequency: {0}kHz", wni.RadioConfiguration.Frequency));
        Debug.WriteLine(string.Format(" *Radio Frequency Hop Dwell Time: {0}Kµsec"
                wni.RadioConfiguration.FrequencyHopDwellTime));
        Debug.WriteLine(string.Format(" *Radio Frequency Hop Pattern: {0}", wni.RadioConfiguration.FrequencyHopPattern));
        Debug.WriteLine(string.Format(" *Radio Frequency Hop Set: {0}", wni.RadioConfiguration.FrequencyHopSet));
    }
} // foreach (NetworkInterface ni in interfaces)

if (wzcInterface != null)
{
        byte[] key = null;
        bool b = wzcInterface.AddPreferredNetwork("MyOpenNetwork1", true, key, 1, AuthenticationMode.Open, 
                WEPStatus.WEPDisabled, null);
        b = wzcInterface.AddPreferredNetwork("MyOpenNetwork2", true, key, 1, AuthenticationMode.Open, 
                WEPStatus.WEPDisabled, null);
        b = wzcInterface.AddPreferredNetwork("MyOpenNetwork3", true, key, 1, AuthenticationMode.Open, 
                WEPStatus.WEPDisabled, null);
}

2/15/2008 11:48:52 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  | 

Need to view or update the Netowrk Routing  Table on your CE/ WinMo device?  Smart Device Framework 2.2's updated NetworkInformation namespace adds a whole lot of new classes, including a full set of classes for routing table access.  Here's a quick example of displaying the current routes:

IPRoutingTable table = IPRoutingTable.GetRoutingTable();

Debug.WriteLine("\r\n*IP Routing Table\r\n====================");
Debug.WriteLine(string.Format("{0}{1}{2}{3}{4}",
    "[Interface]".PadRight(16),
    "[Type]".PadRight(12),
    "[Destination]".PadLeft(17),
    "[NetMask]".PadLeft(17),
    "[Next Hop]".PadLeft(17)));

foreach (IPForwardEntry entry in table)
{
    string intfname = entry.NetworkInterface == null ? intfname = "{Loopback}" : entry.NetworkInterface.Name;
    Debug.WriteLine(string.Format("{0}{1}{2}{3}{4}",
    intfname.PadRight(16),
    entry.RouteType.ToString().PadRight(12),
    entry.Destination.ToString().PadLeft(17),
    entry.SubnetMask.ToString().PadLeft(17),
    entry.NextHop.ToString().PadLeft(17)));
}

Can't be much simpler than that.

2/15/2008 11:31:31 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  | 
SDF 2.2 has a new namespace called OpenNETCF.AppSettings.  We created this group of classes for those times when you'd like to be able to retrieve and store values in an XML settings file.  Here's a quick peek at how it might be used:

AppSettings settings = new AppSettings("\\MyApp\\ApplicationSettings.xml");

if (!settings.Groups.Contains("MyGroup"))
{
    settings.Groups.Add("MyGroup");
    SettingGroup group = settings.Groups["MyGroup"];
    group.Settings.Add("BoolSetting", true);
    group.Settings.Add("IntSetting", 21);
    group.Settings.Add("StringSetting", "hello");

    settings.Save();
}

// update a setting
settings.Groups["MyGroup"].Settings["IntSetting"].Value = 42;

// save back to the file
settings.Save();

string myValue = settings.Groups["MyGroup"].Settings["StringSetting"].Value
bool myOtherValue = settings.Groups["MyGroup"].Settings["BoolSetting"].Value

2/15/2008 11:21:07 AM (Eastern Standard Time, UTC-05:00)  #    Comments [1]  | 
 Thursday, February 14, 2008
Today we released version 2.2 of our Smart Device Framework.  Below is a quick list of changes (this list might not be 100% complete).

Fixes/changes

  • Bug fix in CRC class
  • Bug fixes in audio classes
  • ConnMgr EnumDestinations fix
  • ConnMgr RequestDisconnect fix
  • Adapter fixes for setting IPAddress, DNSServer, Gateway
  • StreamInterfaceDriver fixes for IOCTL calls with null data
  • TextDataAdapter fixes
  • AccesPoint and AccessPointCollection moved to NetworkInformation namespace
  • Many OpenNETCF.Net enums moved to OpenNETCF.Net.NetworkInformation to align with FFx model
  • NetworkInterfaceWatcher reworked for new networking classes
  • ConfigurationSettings.GetConfig added overload to allow passing context to ConfigSectionHandlers
  • See our Buzilla Database for possibly more fixes

 

Additions

  • GraphicsEx.CopyFromScreen
  • Drawing.CopyPixelOperation
  • MemoryMappedFile class
  • StreamInterfaceDriver Activate/DeactivateDevice methods
  • ToolHelp.ModuleEntry class
  • EventWaitHandle.GetData / Set(int) methods
  • EventWaitHandle.Pulse method
  • Application2.Run allows main form to remain hidden on startup
  • DelimitedTextWriter class
  • FileSystemMonitor class (works in console apps)
  • Toolhelp namespace is now desktop compatible
  • Messaging namespace refactored to allow stand-alone use
  • OpenNETCF.WindowsCE.Services namespace
  • NetworkInformation namespace additions
    • ArpEntry
    • ArpTable
    • GatewayIPAddressInformation
    • GatewayIPAddressInformationCollection
    • IcmpV4Statistics
    • IcmpV6Statistics
    • IPAddressInformation
    • IPAddressInformationCllection
    • IPAddressCollection
    • IPForwardEntry
    • IPGlobalProperties
    • IPGlobalStatistics
    • IPInterfaceProperties
    • IPProtocol
    • IPRoutingTable 
    • IPStatus
    • IPv4InterfaceProperties
    • IPv4InterfaceStatistics
    • IPv6InterfaceProperties
    • MulticastIPAddressInformation
    • MulticastIPAddressInformationCollection
    • NetworkInterface
    • OperationalStatus
    • PhysicalAddress
    • TcpConnectionInformation
    • TcpState
    • TcpStatistics
    • UdpStatistics
    • UnicastIPAddressInformation
    • UnicastIPAddressInformationCollection
    • WEPStatus
    • WirelessNetworkInterface
    • WirelessZeroConfigNetworkInterface
  • OpenNETCF.AppSettings namespace (desktop compatible code)
    • SettingsFile
    • Setting
    • Settings
    • SettingGroup
    • SettingGroups

2/14/2008 1:48:22 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1]  |