Introduction
One of the features of the Visual Studio IDE I miss the most when developing Pocket PC applications is the ability to see in the Output pane, the trace messages I usually spread throughout my code. If you have developed code for a while, you know the second best option is to have a console window where you can see these messages.
Not having the knowledge, nor the time to build a solution integrated with the IDE, in this article I show a console application that displays in a host PC, the strings passed to System.Diagnostics.Debug.Write
or System.Diagnostics.Debug.WriteLine
calls in Compact Framework code running on a Pocket PC.
Background
-
Sockets
Sockets are amongst the simplest ways of communicating two apps in almost every system. But in the .NET framework you can find a pair of complementary classes that simplify even further the sockets API: System.Net.Sockets.TcpClient
and System.Net.Sockets.TcpListener
. Of course, their underlying implementation utilizes sockets and their use patterns shouldn't come as a surprise for anyone who has ever programmed against the sockets API.
TcpListener
and TcpClient
synchronous blocking communications doesn't provide all the flexibility sockets do, but in this case, they fulfill my modest requirements.
See the MSDN Library for more information on sockets and the System.Net.Sockets namespace
-
Trace listeners
The Systems.Diagnostics
namespace provides a mechanism that allows multiple output for the trace messages. When you call the Debug
or Trace
classes' Write
and WriteLine
family of methods, they invoke the corresponding methods on every listener that has been registered for that purpose. The system provides some implementations of the TraceListener
abstract class that direct messages to the output window of a debugger, an output stream or the event log. If your needs differ from the system provided options, you need to write your own implementation of System.Diagnostic.TraceListener
and add it to the listeners collection.
You can find the documentation about trace listeners here.
Using the code
The debug console
TcpTraceConsole is a console application that acts as the server. It waits for connections to arrive to the IP address and port specified in its command line. When a connection is made, it just uses System.Console.WriteLine
to display each message received.
Obviously, it must be launched in the host PC before running the Pocket PC app. For example, if the IP address of your PC is 192.168.1.1 and its port 14001 is not used yet:
C:>TcpTraceConsole 192.160.1.1 14001
The trace listener
I derived TcpTrace.TcpTraceListener
directly from TraceListener
and overrode the Write
and WriteLine
methods to redirect their output to the console app via a TcpClient
instance. This class is packaged in its own assembly, so it can be used in any application:
- Add a reference to TcpTrace.dll in your project
- Before any call to
Debug.Trace
in your code, call the static method TcpTrace.InstallTcpTraceListener
. If you use the version with parameters, you need to supply the same address and port you used to launch the TcpTrace console app. If you use the parameter-less version, your working directory must contain an application configuration file specifying the address and port in the following way:
<configuration>
<appSettings>
<add key="TcpTraceServer" value="<SERVER_NAME>" />
<add key="TcpTracePort" value= "<PORT_NUMBER>" />
</appSettings>
</configuration>
Included in the source code and in the demo .zip files, there is a Pocket PC WinForms app that shows the use of TcpTrace.TcpTraceListener
.
To run the PpcTraceClient.exe app, you must:
- Copy the PpcTraceClient.exe, PpcTraceClient.exe.config, TcpTrace.dll and NetTech.Configuration.dll files into a folder on your device
- Edit the PpcTraceClient.exe.config and update the
TcpTraceServer
and TcpTracePort
entries to match the IP address and port that TcpTraceConsole is listening to.
A little annoyance I've found when using the listener is that in my actual device, when connected to my desktop PC through the USB connection, I have to pass the PC's DNS name instead of its IP address, while in the emulator I have to pass the IP address. You may find a different behavior in your configuration.