<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Angry Richard's WebLog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/angryrichard/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/angryrichard/feed.xml</link>
    <description>He&amp;#039;s not as angry as he looks</description>
    <lastBuildDate>Wed, 17 Apr 2019 03:15:28 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Memory Allocation Profiling is Managed Only!</title>
      <link>https://docs.microsoft.com/archive/blogs/angryrichard/memory-allocation-profiling-is-managed-only</link>
      <pubDate>Wed, 13 Dec 2006 10:24:00 GMT</pubDate>
      <dc:creator><![CDATA[AngryRichard]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/angryrichard/2006/12/13/memory-allocation-profiling-is-managed-only/</guid>
      <description><![CDATA[People have been discovering that the VS Team System profiler can collect allocation data for an...]]></description>
      <content:encoded><![CDATA[<P>People have been discovering that the VS Team System profiler can collect allocation data for an application.&nbsp; It isn't long after that they discover that it only works on <EM>managed</EM> code, not native.&nbsp; Sadly, the documentation is not clear on this.</P>
<P>The memory alloction profiling support in VSTS uses the profiler API provided by the&nbsp;CLR.&nbsp; This gives us a rich set of information that allows us to track the lifetimes of individual objects.&nbsp; There is no such off-the-shelf support in native memory management, since there are nearly as many heap implementations as there are applications in the world.</P>
<P>Memory allocation profiling is a much bigger deal for managed code, as the CLR has effectively turned what used to be a <EM>correctness</EM> issue (leaks, double frees, etc) into <EM>performance</EM> issues (excessive GCs and memory pressure)*.&nbsp; This does not mean that some kind memory allocation profiling wouldn't benefit the world, but the combination of it being less important and more difficult keeps it out of the product for now.</P>
<P>If you think you are facing memory issues in <EM>native</EM> code, there&nbsp;is at least one utility&nbsp;I&nbsp;can&nbsp;offer up: In the server resource kits, the <EM>vadump</EM> utility can give you information about your virtual address space, including memory allocated by VirtualAlloc.</P>
<P><A href="http://www.microsoft.com/downloads/details.aspx?FamilyID=9d467a69-57ff-4ae7-96ee-b18c4790cffd&amp;DisplayLang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=9d467a69-57ff-4ae7-96ee-b18c4790cffd&amp;DisplayLang=en">http://www.microsoft.com/downloads/details.aspx?FamilyID=9d467a69-57ff-4ae7-96ee-b18c4790cffd&amp;DisplayLang=en</A></P>
<P>Unfortunately, this is a pale shadow (if that) of what you can get from the managed side.</P>
<P><FONT size=1>* The idea that <EM>correctness </EM>issues become <EM>performance </EM>issues as we develop more advanced runtimes was something I heard David Detlefs mention somewhere.</FONT></P>
<P mce_keep="true">&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>How to shoot yourself in the foot with const (or the lack thereof)</title>
      <link>https://docs.microsoft.com/archive/blogs/angryrichard/how-to-shoot-yourself-in-the-foot-with-const-or-the-lack-thereof</link>
      <pubDate>Wed, 24 May 2006 14:00:00 GMT</pubDate>
      <dc:creator><![CDATA[AngryRichard]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/angryrichard/2006/05/24/how-to-shoot-yourself-in-the-foot-with-const-or-the-lack-thereof/</guid>
      <description><![CDATA[It has long puzzled me why various Win32 functions take non-const string parameters, when clearly...]]></description>
      <content:encoded><![CDATA[<P><FONT face=Tahoma size=2>It has long puzzled me why various Win32 functions take non-const string parameters, when clearly they have no business manipulating the string.&nbsp; Take, for instance, GetNamedSecurityInfo:</FONT></P><FONT face=Tahoma size=2>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"><PRE class=syntax xml:space="preserve"><B>DWORD</B> <B>GetNamedSecurityInfo(</B>
  <B>LPTSTR</B> <A class=synParam onclick=showTip(this) href=""><EM><FONT color=#000000>pObjectName</FONT></EM></A><B></B><B><EM>,</EM>
</B>  <B>SE_OBJECT_TYPE</B> <I><A class=synParam onclick=showTip(this) href=""><FONT color=#000000>ObjectType</FONT></A></I><B></B><FONT color=#000000><B>,
</B>  <B>SECURITY_INFORMATION</B> <I><A class=synParam onclick=showTip(this) href=""><FONT color=#000000>SecurityInfo</FONT></A></I><B></B></FONT><FONT color=#000000><B>,
</B>  <B>PSID*</B> <I><A class=synParam onclick=showTip(this) href=""><FONT color=#000000>ppsidOwner</FONT></A></I><B></B></FONT><FONT color=#000000><B>,
</B>  <B>PSID*</B> <I><A class=synParam onclick=showTip(this) href=""><FONT color=#000000>ppsidGroup</FONT></A></I><B></B></FONT><FONT color=#000000><B>,
</B>  <B>PACL*</B> <I><A class=synParam onclick=showTip(this) href=""><FONT color=#000000>ppDacl</FONT></A></I><B></B></FONT><FONT color=#000000><B>,
</B>  <B>PACL*</B> <I><A class=synParam onclick=showTip(this) href=""><FONT color=#000000>ppSacl</FONT></A></I><B></B></FONT><FONT color=#000000><B>,
</B>  <B>PSECURITY_DESCRIPTOR*</B> <I><A class=synParam onclick=showTip(this) href=""><FONT color=#000000>ppSecurityDescriptor</FONT></A></I><B></B></FONT><B>
</B><B>);</B></PRE></BLOCKQUOTE></FONT>
<P><FONT face=Tahoma size=2>I can't imagine why this function should ever need to write to pObjectName.&nbsp; In fact, the SDK documentation explicitly lists it as an [in] parameter.&nbsp; Also note that pObjectName is an LP<STRONG>T</STRONG>STR.&nbsp; This is important to the shooting of the foot.</FONT></P>
<P><FONT face=Tahoma size=2>A tidy, const-aware&nbsp;developer might want to do something like this:</FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><FONT face="Courier New" size=1>const LPWSTR SomeFile = L"\\somefile.txt";</FONT></P>
<P><FONT face="Courier New" size=1>[...]</FONT></P>
<P><FONT face="Courier New" size=1>GetNamedSecurityInfo(Somefile, ...)</FONT></P></BLOCKQUOTE>
<P><FONT face=Tahoma size=2>Of course, this will fail to compile, because SomeFile is const.&nbsp; But casting solves this problem, right?&nbsp; </FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><FONT face=Tahoma size=2><FONT face="Courier New" size=1>GetNamedSecurityInfo((LPTSTR)Somefile, ...)</FONT></FONT></P></BLOCKQUOTE>
<P><FONT face=Tahoma size=2>Yay, this compiles.&nbsp; Why, it even appears to return the correct data.</FONT></P>
<P><FONT face=Tahoma size=2>Fast forward a year or two, when suddenly the code stops working on Vista.&nbsp; What could be wrong?&nbsp; Why, in the process of casting away const, we've also turned an LP<STRONG>W</STRONG>STR into an LP<STRONG>T</STRONG>STR.&nbsp; In this case, TCHAR resolved to char, so the code above was actually returning a security descriptor for "\\".&nbsp; Well, that is until Vista came along.</FONT></P>
<P><FONT face=Tahoma size=2>So while I hang my head in shame for being lame enough to cast between incompatible types, I will also caution the rest of you to consider whether your string parameters really need to be non-const, and avoid making your clients play casting games to use your API.&nbsp; And yes, using <A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/express_75.asp">const_cast&lt;&gt;</A> might have prevented this issue, but I didn't know about it at the time.&nbsp; You, having read this far, have no excuse.</FONT></P>
<P>&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>DataCollection at the Global Level</title>
      <link>https://docs.microsoft.com/archive/blogs/angryrichard/datacollection-at-the-global-level</link>
      <pubDate>Mon, 10 Oct 2005 13:41:00 GMT</pubDate>
      <dc:creator><![CDATA[AngryRichard]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/angryrichard/2005/10/10/datacollection-at-the-global-level/</guid>
      <description><![CDATA[If you are using the DataCollection API (either from native, by linking agains VSPerf.lib, or from...]]></description>
      <content:encoded><![CDATA[<P><FONT face=Tahoma size=2>If you are using the <a href="http://blogs.msdn.com/angryrichard/archive/2005/01/16/354194.aspx">DataCollection API</A> (either from native, by linking agains VSPerf.lib, or from managed, by importing Microsoft.VisualStudio.Profiler.dll), and wish to enable or disable collection at the <EM>global</EM> level, you must pass CurrentId for the elementId parameter:</FONT></P>
<P><FONT face="Courier New" color=#000000 size=2><STRONG>&nbsp; using Microsoft.VisualStudio.Profiler;</STRONG></FONT></P>
<P><FONT face="Courier New" color=#000000 size=2><EM>&nbsp; [Not so interesting code here]&nbsp;&nbsp;</EM></FONT></P>
<P><FONT face="Courier New" color=#000000 size=2><STRONG>&nbsp; DataCollection.StartProfile(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ProfileLevel.Global, <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataCollection.CurrentId);</STRONG></FONT></P>
<P><FONT face="Courier New" color=#000000 size=2><EM>&nbsp; [Interesting code here]</EM></FONT></P>
<P><FONT face=Tahoma size=2>Similarly, for native code:</FONT></P>
<P><FONT face="Courier New" size=2><STRONG>&nbsp; #include "VSPerf.h"</STRONG></FONT></P>
<P><FONT face="Courier New" size=2><EM>&nbsp; [Not so interesting code here]</EM></FONT></P>
<P><FONT face="Courier New" size=2><STRONG>&nbsp; StartProfile(PROFILE_GLOBALLEVEL, PROFILE_CURRENTID);</STRONG></FONT></P>
<P><FONT face="Courier New" size=2><EM>&nbsp; [Interesting code here]</EM></FONT></P>
<P><FONT face=Tahoma size=2>Note that both the native and managed versions return zero on success, so it is possible to detect whether the call succeeded:</FONT></P>
<TABLE>
<TR>
<TD><FONT face="Courier New" size=2>C#</FONT></TD>
<TD><FONT face="Courier New" size=2>c++</FONT></TD>
<TD><FONT face="Courier New" size=2>Description</FONT></TD></TR>
<TR>
<TD><FONT face="Courier New" size=2>ProfileOperationResult.ErrorNotYetImplemented</FONT></TD>
<TD><FONT face="Courier New" size=2>PROFILE_ERROR_NOT_YET_IMPLEMENTED</FONT></TD>
<TD><FONT face="Courier New" size=2>API level, id combination not supported</FONT></TD></TR>
<TR>
<TD><FONT face="Courier New" size=2>ProfileOperationResult.ErrorModeNever</FONT></TD>
<TD><FONT face="Courier New" size=2>PROFILE_ERROR_MODE_NEVER</FONT></TD>
<TD><FONT face="Courier New" size=2>Global mode was "never" when called</FONT></TD></TR>
<TR>
<TD><FONT face="Courier New" size=2>ProfileOperationResult.ErrorLevelDoesNotExist</FONT></TD>
<TD><FONT face="Courier New" size=2>PROFILE_ERROR_LEVEL_NOEXIST</FONT></TD>
<TD><FONT face="Courier New" size=2>Profile level does not exist</FONT></TD></TR>
<TR>
<TD><FONT face="Courier New" size=2>ProfileOperationResult.ErrorIdDoesNotExist</FONT></TD>
<TD><FONT face="Courier New" size=2>PROFILE_ERROR_ID_NOEXIST</FONT></TD>
<TD><FONT face="Courier New" size=2>Element id doesn't exist</FONT></TD></TR></TABLE>]]></content:encoded>
    </item>
    <item>
      <title>Response Files</title>
      <link>https://docs.microsoft.com/archive/blogs/angryrichard/response-files</link>
      <pubDate>Sun, 07 Aug 2005 22:12:00 GMT</pubDate>
      <dc:creator><![CDATA[AngryRichard]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/angryrichard/2005/08/07/response-files/</guid>
      <description><![CDATA[On the forums, someone was using the /INCLUDE option in VsInstr.exe.&nbsp; It is possible to use...]]></description>
      <content:encoded><![CDATA[<P>On the forums, someone was using the /INCLUDE option in VsInstr.exe.&nbsp; It is possible to use multiple instances of this option to include different sets of functions.&nbsp; For a big chunk of functions, you might want to use dozens of function specifications.&nbsp; Who the heck wants to do all that typing?&nbsp; You could make a batch file, but a response file would be better.</P>
<P>Response files are text files where each line in the file is a single command line option.&nbsp; Since each line holds exactly one option, quotes are not necessary.&nbsp; They are much easier to edit than a batch file (which would have single, really long line).&nbsp; To use a response file, simply use @filename on the command line of the tool.&nbsp; For example:</P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><FONT face="Courier New" size=2>VsPerfCmd /start:sample "/output:c:\Documents and Settings\AngryRichard\foo.vsp" "/user:NETWORK SERVICE"</FONT></P></BLOCKQUOTE>
<P>can be turned into a response file like this:</P>
<P>Startup.rsp:</P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><FONT face="Courier New" size=2>/start:sample<BR>/output:c:\Documents and Settings\AngryRichard\foo.vsp<BR>/user:NETWORK SERVICE<BR></FONT></P>
<P><FONT face="Courier New" size=2>VsPerfCmd @Startup.rsp</FONT></P></BLOCKQUOTE>
<P>All of the command line tools for the profiler accept response files.&nbsp; It beats all that error prone typing, and if you run scenarios from the command line a lot, it can pay to have some response files laying about for common scenarios.&nbsp; </P>
<P>&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>Off-road Profiling Windows Services</title>
      <link>https://docs.microsoft.com/archive/blogs/angryrichard/off-road-profiling-windows-services</link>
      <pubDate>Thu, 28 Jul 2005 15:36:00 GMT</pubDate>
      <dc:creator><![CDATA[AngryRichard]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/angryrichard/2005/07/28/off-road-profiling-windows-services/</guid>
      <description><![CDATA[I've just posted an article on the pitfalls of profiling services with the Visual Studio...]]></description>
      <content:encoded><![CDATA[<P><FONT face=Garamond>I've just posted an article on the pitfalls of profiling services with the Visual Studio profiler.&nbsp; It includes a sample service with a quick walkthrough.&nbsp; Enjoy.</FONT></P>
<P><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"><a href="http://blogs.msdn.com/angryrichard/articles/Profiling_Windows_Services.aspx"><FONT face=Garamond>Profiling Windows™ Services with the Visual Studio Profiler</FONT></A></SPAN></P>]]></content:encoded>
    </item>
    <item>
      <title>Offroad Profiling: The Visual Studio Profiler and Windows™ Services</title>
      <link>https://docs.microsoft.com/archive/blogs/angryrichard/offroad-profiling-the-visual-studio-profiler-and-windows-services</link>
      <pubDate>Thu, 28 Jul 2005 15:00:00 GMT</pubDate>
      <dc:creator><![CDATA[AngryRichard]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/angryrichard/2005/07/28/offroad-profiling-the-visual-studio-profiler-and-windows-services/</guid>
      <description><![CDATA[Introduction
The Visual Studio Team System Profiler primarily addresses stand alone application...]]></description>
      <content:encoded><![CDATA[<H3>Introduction</H3>
<P><FONT face=Georgia size=2>The Visual Studio Team System Profiler primarily addresses stand alone application scenarios.&nbsp; However, more and more modern applications are built around a distributed architecture, and larger and larger portions of functionality are moving into remote services.&nbsp; Of course, this is nothing new -- multi-tier applications have been the norm for some time - but we in the tools group are increasingly asked to better support these architectures. </FONT>
<P><FONT face=Georgia size=2>What makes this difficult?&nbsp; Services are not started like normal applications.&nbsp; Services do not necessarily run under the same account as the user sitting at the console.&nbsp; Services may run in a completely different Terminal Services session than the current user (in fact, this will likely always be the case when Windows Vista hits the street).</FONT></P>
<P><FONT face=Georgia size=2>In the Visual Studio IDE, we provide some narrow support for profiling ASP.NET web applications running on the developer desktop.&nbsp; This is a very special case of service profiling, one where we know a lot about the service process (for example, w3wp.exe on Windows Server 2003) and its behavior, and one we know a majority of people will care about.&nbsp; For other services, however, IDE support is scant or nonexistent.&nbsp; In these scenarios you must go off road, using the command line utilities.</FONT></P>
<P><FONT face=Georgia size=2>In order to understand how to profile services, it will be necessary (or at least helpful) to understand how the profiler itself works.&nbsp; Over the next few days I'll describe the basics how the profiler collects data from a running application.&nbsp; With this overview you should be able to understand what contexts break the profiler, and which ones will work.&nbsp; You should also be able to troubleshoot profiling problems that emerge in your scenario.</FONT></P>
<P><FONT face=Georgia size=2>As a demonstration, I will provide a simple managed service and client application, and we'll do a walk-through with some simple profiling scenarios.</FONT></P>
<H3>Understanding Data Collection - Target&nbsp;/&nbsp;Profiler communication</H3>
<P><FONT face=Georgia size=2>The profiler collects data in a centralized monitor process, VSPerfMon.exe, allowing collection and correlation of data from multiple sources.&nbsp; Typically, various runtime libraries generate the data that the monitor consumes.&nbsp; For any type of managed profiling, we load an extension into the CLR.&nbsp; For trace profiling, instrumentation places an implicit dependency on the trace profiling runtime.&nbsp; For sample profiling, we load the runtime remotely using CreateRemoteThread.&nbsp; Additionally, for sample profiling, we also collect data from a software only kernel mode device driver.&nbsp; Here is a rough sketch of who communicates with whom:</FONT></P><IMG src="http://angryrichard.members.winisp.net/Samples/ServiceProfilingBlog1/BasicProfilerCommunication.png"> 
<P><FONT face=Georgia size=2>Each of the three user mode runtimes communicates with the monitor over various globally shared objects, such as events, mutices, and memory sections.&nbsp; These objects are created when the monitor starts, and the runtimes (loaded into the target processes) establish "connections" to the monitor via these shared objects.&nbsp; To avoid the overhead of attempting a connection on every profiler runtime call, the process typically gets only one opportunity to connect to the monitor.&nbsp; If this attempt fails, further calls into the profiler runtime are stubbed and produce no useful data.&nbsp; The implication here is that an instrumented target binary that executes before the monitor initializes will provide no data, and must be restarted.</FONT></P>
<H4>Getting the Runtimes in</H4>
<P><FONT face=Georgia size=2>When profiling managed code, we must install an inproc-server to gather various data about the state of the CLR.&nbsp; The CLR defines a pair of COM interfaces, one implemented by the profiler component by which it receives notifications, and one implemented by the CLR allowing the profiler to query information about the process.</FONT></P>
<P><FONT face=Georgia size=2>The CLR can only load a profiler component when the process starts.&nbsp; It decides to do this by checking the COR_ENABLE_PROFILING environment variable.&nbsp; When set to '1', the CLR will CoCreateClassObject on the class ID specified in the COR_PROFILER environment variable.&nbsp; In order for the Visual Studio profiler to load its profiling extensions into a process hosting the CLR, these two environment variables must be appropriately set, and the VS Profiler's COM object must be registered.</FONT></P>
<TABLE width="80%" align=center bgColor=#ccccff>
<TBODY>
<TR>
<TD><FONT face=Georgia size=2>Note: We've provided a batch file, VSPerfClrEnv.cmd, that will set up the appropriate environment variables.&nbsp; Also note that services pick up their environment variables from the system defaults.&nbsp; This batch file can set these as well.</FONT></TD></TR></TBODY></TABLE>
<P><FONT face=Georgia size=2>When running a session in sampling mode, and attaching to a process, we use CreateRemoteThread to load the sampling runtime library (appropriately named SamplingRuntime.dll).&nbsp; CreateRemoteThread has a serious limitation in that it does not work across different Terminal Services sessions.&nbsp; This means you cannot attach to a process running in another session!&nbsp; Typically services will run in session zero, and by default, TS sessions will be non-zero, unless you specify the /console flag when connecting.</FONT></P>
<TABLE width="80%" align=center bgColor=#ccccff>
<TBODY>
<TR>
<TD><FONT face=Georgia size=2>Note: Do not confuse Terminal Server Session with Logon Session.&nbsp; Logon Sessions distinguish the security token a process runs with by default.&nbsp; 80 different processes running with 80 different security tokens can all be interacting with the same desktop in the same Terminal Server Session (though this is not a good idea).&nbsp; Terminal Server Sessions provide a different kind of boundary, most notably separate desktops and distinct instances of csrss.exe. </FONT></TD></TR></TBODY></TABLE><BR>
<TABLE width="80%" align=center bgColor=#ccccff>
<TBODY>
<TR>
<TD><FONT face=Georgia size=2>Note: In Windows Vista, any interactive user session will have a non-zero Terminal Services Session ID.&nbsp; Yes, this breaks the profiler.&nbsp; Yes, we are working on a solution to the problem.</FONT></TD></TR></TBODY></TABLE>
<H3>Understanding Data Collection - Access issues</H3>
<P><FONT face=Georgia size=2>The previous discussion has some implications when profiling across two different logon sessions.</FONT></P>
<P><FONT face=Georgia size=2>First, the monitor always creates the shared objects - it will fail to start if any of its objects are already created.&nbsp; All objects are created with NULL security attributes, which means they will only be accessible from the account that launched the monitor (modulo an administrator's privilege to take ownership and modify the security descriptor).</FONT></P>
<P><FONT face=Georgia size=2>What happens when an instrumented application starting in another account attempts to connect to the monitor?&nbsp; The first profiler runtime call to OpenEvent (or OpenMutex, etc) will fail with ERROR_ACCESS_DENIED.&nbsp; This will signal that the runtime cannot connect to the monitor, and no data will be collected.&nbsp; In order to work in this scenario, the target process account must be explicitly granted access to the monitor's objects.&nbsp; When launching the monitor from the command line, the /USER option allows you to do this.&nbsp; For instance, if you need an instrumented service to connect to the monitor, and the service runs as LOCAL SERVICE, start the monitor with the following command:</FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><FONT face="Courier New" color=#000000 size=2>VSPerfCmd /start:trace /output:data.vsp /user:"LOCAL SERVICE"</FONT></P></BLOCKQUOTE>
<TABLE width="80%" align=center bgColor=#ccccff>
<TBODY>
<TR>
<TD><FONT face=Georgia size=2>Note: You may provide multiple /user options if you need to add more than one account.&nbsp; You may also supply DOMAIN\user for domain accounts. This is an example of a task that the integrated support for ASP.NET profiling in the IDE does automatically.</FONT></TD></TR></TBODY></TABLE>
<P>
<TABLE width="80%" align=center bgColor=#ccccff>
<TBODY>
<TR>
<TD><FONT face=Georgia size=2>Note: Be careful when cutting and pasting command lines from web pages. Your browser, or our publishing tool, might encode the characters in some funny manner that causes the command line parsing to go haywire. </FONT></TD></TR></TBODY></TABLE></P>
<P><FONT face=Georgia size=2>Those who have developed services for a while now will immediately ask, "But what if the first profiler runtime code that executes happens while my service is impersonating another user?"&nbsp; Sadly, the profiler does not accommodate this situation very gracefully.&nbsp; You're choices are&nbsp; either to add a /USER option for every user that the service could conceivably impersonate, or make sure your service is connecting to the monitor from a known account.</FONT></P>
<H3>Getting Started - A sample service and client</H3>
<H4>A Simple Managed Service</H4>
<P><FONT face=Georgia size=2>For the purposes of this example I'll use a simple managed service that I built from an application I've been toying with over the last few weeks.&nbsp; As an amateur (very amateur) cryptography enthusiast, it has always embarrassed me that I've never written a viable cryptogram solver, so I've set out to correct that problem.&nbsp; As part of my design, I decided that I needed some sort of dictionary to keep tabs on English words, so I built a couple classes around that task.&nbsp; </FONT></P>
<P><FONT face=Georgia size=2>Making this "dictionary" a service seemed like a reasonable sample for demonstrating how to profile a service.&nbsp; For one thing, the scenario isn't entirely fictional - many services take data, do some sort of processing on that data, and return some other data.&nbsp; This service is no different.&nbsp; Orthogonally, this process is neither CPU nor I/O bound, which in my opinion represents the real world a little more accurately than samples that just do useless work, like calculating <EM>pi</EM>.</FONT></P>
<P><FONT face=Georgia size=2>At the core of this service is the IPatternDictionary interface.&nbsp; The interface provides two methods (each with an overload).&nbsp; The first stores a pattern, and the second retrieves a list of words that match a given pattern.&nbsp; The service implements this dictionary using the fancy new System.Collections.Generic.Dictionary&lt;,&gt; generic collection class, and exposes an IPatternDictionary interface via a remoting channel.&gt;</FONT></P>
<H4>A Simple Client</H4>
<P><FONT face=Georgia size=2>On the other side of the system, we'll have a client.&nbsp; The provided client is a console application that provides two functions.&nbsp; The client can read a text file, adding each word in the file to the dictionary through IPatternDictionary.AddWord(string word).&nbsp; Once we've built a nice sized dictionary this way, the client can also query the dictionary for a given pattern using IPatternDictionary.FindPattern(string pattern).&nbsp; We'll use this client to invoke various operations in the service while profiling.</FONT></P>
<H4>Run the Example</H4>
<P><FONT face=Georgia size=2>Source code for the example is at the end of this article.&nbsp; You may also download the sample code <A href="http://angryrichard.members.winisp.net/Samples/ServiceProfilingBlog1/Cryptogram_Sample.zip">here</A>.</FONT></P>
<TABLE width="80%" align=center bgColor=#ccccff>
<TBODY>
<TR>
<TD><FONT face=Georgia size=2>Annoying Disclaimer: This sample code is for the purposes of this demonstration only. There is no guarantee that this code isn't chock full of defects. Don't use this as a base for developing anything you want to use for real -- it has design problems, performance problems, and quite probably security problems as well. </FONT></TD></TR>
<TBODY></TBODY></TABLE>
<P><FONT face=Georgia size=2>Build the service and client from the supplied solution.&nbsp; For the sake of profiling, it probably makes the most sense to build the Retail configuration, but for the purposes of this example it isn't important.&nbsp; </FONT></P>
<P><FONT face=Georgia size=2>The service itself includes a package installer, so you can use InstallUtil (in %WINDIR%\Microsoft.NET\Frameworks\&lt;version&gt;) to install it.</FONT></P>
<P><FONT face=Georgia size=2>Once installed, you can start the service from the services snap-in.&nbsp; If you wish, you may supply a filename from which to serialize / deserialize dictionary data in the "Start Parameters" field in the property page for the service.&nbsp; If you do not supply a filename, the service starts with an empty dictionary, and discards the dictionary when it shuts down.</FONT></P>
<P><FONT face=Georgia size=2>With the service started, you can now import data using the client.&nbsp; There are plenty of large bodies of text available at Project Gutenberg.&nbsp; To keep up an ironic appearance, I chose "Emma" by Jane Austen (<A href="http://www.gutenberg.org/etext/158">http://www.gutenberg.org/etext/158</A>).&nbsp; Import the text by running</FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><FONT size=2><FONT face="Courier New">&gt; <STRONG>cryptoclient import emma11.txt</STRONG></FONT></FONT></P>
<P><FONT face="Courier New" size=2>Connecting to IPatternDictionary<BR>Reading emma11.txt<BR>Added 163682 words</FONT></P></BLOCKQUOTE>
<P><FONT face=Georgia size=2>Now the service has a body of words that it knows about.&nbsp; Let's look for a pattern amongst them.</FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><FONT face="Courier New" size=2>&gt; <STRONG>cryptoclient find qgabbat</STRONG></FONT></P>
<P><FONT face="Courier New" size=2>Connecting to IPatternDictionary<BR>Looking up qgabbat<BR>blessed : 7<BR>pressed : 9<BR>guessed : 7<BR>blossom : 1<BR>swelled : 1</FONT></P></BLOCKQUOTE>
<P><FONT face=Georgia size=2>If you get this far, then you've now got a working service and client with which to continue.&nbsp; In the next installment, we'll start profiling.</P></FONT>
<H3>Profiling the Service</H3>
<H4>Sampling</H4>
<P><FONT face=Georgia size=2>First, get the service installed.&nbsp; Do not start the service; you need to have the magic environment variables set before starting.&nbsp; To do this, use vsperfclrenv /GlobalSampleOn 
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"><FONT face="Courier New" size=2>&gt; vsperfclrenv /globalsampleon<BR>Enabling VSPerf Global Profiling. Allows to 'attaching' to managed services.<BR>You need to restart the service to detect the new settings. This may require a r<BR>eboot of your machine. </FONT></BLOCKQUOTE>
<P><FONT face=Georgia size=2>This has the gross side effect of turning on this cursed environment variable for everybody.&nbsp; Most likely, you will need to reboot.&nbsp;</FONT></P>
<TABLE width="80%" align=center bgColor=#ccccff>
<TBODY>
<TR>
<TD><FONT face=Georgia size=2>Note: I don't need to tell you (and you don't need to tell me) that having to reboot is lame.&nbsp; I'll have a post about how you can work around this annoyance in the near future. </FONT></TD></TR></TBODY></TABLE>
<P><FONT face=Georgia size=2>Start up the monitor in sampling mode.&nbsp; Make sure you include the service account in the /USER option. 
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"><FONT face="Courier New" size=2>&gt; <STRONG>vsperfcmd /start:sample /output:import_sample.vsp /user:"LOCAL SERVICE"<BR></STRONG>Microsoft (R) VSPerf Command Version 8.0.50215 x86<BR>Copyright (C) Microsoft Corp. All rights reserved. 
<H3></H3></FONT></BLOCKQUOTE>
<P><FONT face=Georgia size=2>Now you can start the service.&nbsp; The environment variables will cause the CLR to load the Visual Studio runtime for managed profiling.&nbsp; The monitor is now running, and is set up to allow the LOCAL SERVICE account to connect.&nbsp; You can verify this with the /STATUS option. </FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><FONT face="Courier New" color=#000000 size=2>&gt; <STRONG>vsperfcmd /status<BR></STRONG>Microsoft (R) VSPerf Command Version 8.0.50215 x86<BR>Copyright (C) Microsoft Corp. All rights reserved. <BR>Process and Thread Status<BR>============================================================<BR>Output File Name&nbsp; : C:\import_sample.vsp<BR>Maximum Processes: 64<BR>Maximum Threads: 256<BR>Number of Buffers: 258<BR>Size of Buffers: 65536<BR>============================================================<BR>Maximum Number of Processes : 64<BR>Number of Active Processes&nbsp; : 0<BR>Global Start/Stop Count&nbsp;&nbsp;&nbsp;&nbsp; : 1<BR>Global Suspend/Resume Count : 0<BR>============================================================<BR>Users with access rights to monitor:<BR>UserName (SID)<BR><STRONG><FONT style="BACKGROUND-COLOR: #ffffff" color=#ff0000>NT AUTHORITY\LOCAL SERVICE (S-1-5-19)<BR></FONT></STRONG>SLYTHERIN\AngryRichard (S-1-5-21-1184752212-29216014-527188231-1450159)<BR>NT AUTHORITY\SYSTEM (S-1-5-18)</FONT></P></BLOCKQUOTE>
<P><FONT face=Georgia size=2>&nbsp;Start the service from the services snap-in as usual.&nbsp; If you're using the provided sample service, most likely it is just sitting there doing nothing, and now would be a good time to attach to it. </FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><FONT face="Courier New" size=2>&gt; <STRONG>vsperfcmd /attach:PatternDictionaryService.exe<BR></STRONG>Microsoft (R) VSPerf Command Version 8.0.50215 x86<BR>Copyright (C) Microsoft Corp. All rights reserved. <BR>Successfully attached to process ID:2380 </FONT></P></BLOCKQUOTE>
<P>
<TABLE width="80%" align=center bgColor=#ccccff>
<TBODY>
<TR>
<TD><FONT face=Georgia size=2>Note: Because the service is launched by the Service Control Manager, there isn't any way to use VSPerfCmd /LAUNCH to start the service.&nbsp; Or is there?&nbsp; I have an idea for how to work around this, and I hope to share it with you soon. </FONT></TD></TR>
<TBODY></TBODY></TABLE><FONT face=Georgia size=2>
<P>Now make the service do something useful. </FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><FONT face="Courier New" size=2>&gt; <STRONG>cryptoclient import emma11.txt<BR></STRONG>Connecting to IPatternDictionary<BR>Reading emma11.txt<BR>Added 163682 words </FONT></P></BLOCKQUOTE>
<P><FONT face=Georgia size=2>If this were all I wanted to profile, I could detach with VSPerfCmd /DETACH.&nbsp; However, let's pretend I care about what happens to my service all the way to the bitter end, so I'll go ahead and stop the service, then shut down the monitor. </FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><FONT face="Courier New" size=2>&gt; <STRONG>vsperfcmd /shutdown<BR></STRONG>Microsoft (R) VSPerf Command Version 8.0.50215 x86<BR>Copyright (C) Microsoft Corp. All rights reserved. </FONT></P>
<P><FONT face="Courier New" size=2>Shutting down the Profile Monitor<BR>------------------------------------------------------------ </FONT></P></BLOCKQUOTE>
<P><FONT face=Georgia size=2>Now I have a VSP file that I can load into the IDE for analysis.&nbsp; From the IDE, click File-&gt;Open-&gt;File and select the VSP file you just created.&nbsp;&nbsp; </FONT></P><IMG src="http://angryrichard.members.winisp.net/Samples/ServiceProfilingBlog1/sample_view.PNG"> 
<P><FONT face=Georgia size=2>I won't go too deeply into data analysis here; it isn't terribly different from analyzing data from an application, and there's nothing too surprising to see in this example.&nbsp; I will point out, though, that when sampling a scenario like this, you will see a lot of noise related to marshalling, remoting, serialization, and all that tasty goo the CLR gives you to make distributed application development easier.&nbsp; I've found that a good way to drill through all this gunk is to start from the Function View, right click and choose "Group By Module".&nbsp; 
<P>
<TABLE width="80%" align=center bgColor=#ccccff>
<TBODY>
<TR>
<TD><FONT face=Georgia size=2>Note: In the July CTP and later, "Group by Module" will be the default in the Function View </FONT></TD></TR></TBODY></TABLE>
<P>Now you can get started looking at your own code, rather than frameworks methods with really long names. </FONT></P>
<H4>Trace</H4>
<P><FONT face=Georgia size=2>Trace profiling a service is only slightly different from sample profiling.&nbsp; First of all, <EM>and most importantly</EM>, the Visual Studio profiler's CLR component uses a different CLSID for trace profiling, so once again it's necessary to set up the environment properly, and reboot the system: </FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><FONT face="Courier New" size=2>&gt; <STRONG>vsperfclrenv /globaltraceon<BR></STRONG>Enabling VSPerf Global Profiling. Allows trace profiling of managed services without allocation profiling. You need to restart the service to detect the new settings. This may require a reboot of your machine. <BR></FONT><FONT face=Georgia size=2></FONT></P></BLOCKQUOTE>
<P dir=ltr><FONT face=Georgia size=2>When trace profiling, you must instrument the code you wish to profile.&nbsp; The example service uses two assemblies: PatternDictionaryService.exe and CommonTypes.dll.&nbsp; For this example, I'll instrument both. </FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P dir=ltr><FONT face="Courier New" size=2>&gt; <STRONG>vsinstr PatternDictionaryService.exe </STRONG></FONT></P>
<P dir=ltr><FONT face="Courier New" size=2>Microsoft (R) VSInstr Post-Link Instrumentation 8.0.50215 x86<BR>Copyright (C) Microsoft Corp. All rights reserved. </FONT></P>
<P dir=ltr><FONT face="Courier New" size=2>File to Process:<BR>&nbsp;&nbsp; C:\PatternDictionaryService.exe --&gt; C:\PatternDictionaryService.exe<BR>Original file backed up to C:\PatternDictionaryService.orig.exe Successfully instrumented file C:\PatternDictionaryService.exe. </FONT></P>
<P dir=ltr><FONT face="Courier New" size=2>&gt; <STRONG>vsinstr commontypes.dll<BR></STRONG>Microsoft (R) VSInstr Post-Link Instrumentation 8.0.50215 x86<BR>Copyright (C) Microsoft Corp. All rights reserved. File to Process:<BR>&nbsp;&nbsp; C:\commontypes.dll --&gt; C:\commontypes.dll<BR>Original file backed up to C:\commontypes.orig.dll Successfully instrumented file C:\commontypes.dll. </FONT></P></BLOCKQUOTE>
<P dir=ltr><FONT face=Georgia size=2>Start the monitor.&nbsp; Remember, the monitor must be started before the trace runtime attempts to connect.&nbsp; The trace runtime will attempt to connect when the service is started. </FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P dir=ltr><FONT face="Courier New" size=2>&gt; <STRONG>vsperfcmd /start:trace /output:find_trace.vsp<BR></STRONG>Microsoft (R) VSPerf Command Version 8.0.50215 x86<BR>Copyright (C) Microsoft Corp. All rights reserved. <BR></FONT></P></BLOCKQUOTE>
<P><FONT face=Georgia size=2>Start the service, just like normal.&nbsp; When I ran this example, I supplied the same file name as in the Sampling example, so that I'd be profiling the work to deserialize the dictionary. You can verify that the trace runtime connected with the monitor using the STATUS option.&nbsp; When trace profiling, the monitor also tracks threads, so you'll get a bunch of output, which I've pruned a little. </FONT></P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P dir=ltr><FONT face=Georgia size=2><FONT face="Courier New">&gt; <STRONG>vsperfcmd /status<BR></STRONG>Microsoft (R) VSPerf Command Version 8.0.50215 x86<BR>Copyright (C) Microsoft Corp. All rights reserved. <BR>Process and Thread Status<BR>============================================================<BR>Output File Name&nbsp; : C:\find_trace.vsp<BR>Maximum Processes: 64<BR>Maximum Threads: 256<BR>Number of Buffers: 258<BR>Size of Buffers: 65536<BR>============================================================<BR>Maximum Number of Processes : 64<BR>Number of Active Processes&nbsp; : 1<BR>Global Start/Stop Count&nbsp;&nbsp;&nbsp;&nbsp; : 1<BR>Global Suspend/Resume Count : 0<BR>------------------------------------------------------------<BR>&nbsp;Process&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :&nbsp; C:\PatternDictionaryService.exe<BR>&nbsp;Process ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 3768<BR>&nbsp;Num Threads&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 13<BR>&nbsp;Start/Stop Count&nbsp;&nbsp;&nbsp;&nbsp; : 1<BR>&nbsp;Suspend/Resume Count : 0<BR>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<BR>&nbsp;&nbsp; Thread&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :&nbsp; T@ 04B5B450:12<BR>&nbsp;&nbsp; Thread ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 2456<BR>&nbsp;&nbsp; Start/Stop Count&nbsp;&nbsp;&nbsp;&nbsp; : 1<BR>&nbsp;&nbsp; Suspend/Resume Count : 0<BR>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<BR>&nbsp;&nbsp; Thread&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :&nbsp; T@ 04B5B768:13<BR>&nbsp;&nbsp; Thread ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 2456<BR>&nbsp;&nbsp; Start/Stop Count&nbsp;&nbsp;&nbsp;&nbsp; : 1<BR>&nbsp;&nbsp; Suspend/Resume Count : 0<BR>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<BR>[snippage]</FONT></P>
<H3><FONT face="Courier New"></FONT></H3>
<P><FONT face="Courier New">Users with access rights to monitor:<BR>UserName (SID)<BR>SLYTHERIN\AngryRichard (S-1-5-21-1847212521-1276092920-1812408775-1514059)<BR>NT AUTHORITY\SYSTEM (S-1-5-18) <BR></FONT></P></BLOCKQUOTE>
<P>
<TABLE width="80%" align=center bgColor=#ccccff>
<TBODY>
<TR>
<TD><FONT face=Georgia size=2>Note: You'll notice that I didn't add LOCAL SERVICE to the monitor.&nbsp; While working on this article, I had to move the sample project to a different machine, and somewhere in the shuffle reverted the service to running as SYSTEM.&nbsp; A service running as SYSTEM doesn't need any help from you to get at the monitor.&nbsp; It is SYSTEM, after all. </FONT></TD></TR></TBODY></TABLE></P>
<P>Invoke the service.&nbsp; This time I'll find a pattern in the dictionary. </P>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><FONT face="Courier New">&gt; <STRONG>cryptoclient find bhhnq<BR></STRONG>Connecting to IPatternDictionary<BR>Looking up bhhnq<BR>books : 9<BR>apply : 4<BR>allow : 48<BR>alloy : 3<BR>looks : 29<BR>ennui : 1<BR>weeks : 21<BR>abbey : 31<BR>apple : 8<BR>upper : 3<BR>goose : 2<BR>feels : 10<BR>doors : 12<BR>occur : 10<BR>offer : 19<BR>fools : 2<BR>affix : 1<BR>pools : 1<BR>rooms : 15<BR>issue : 2<BR>needs : 2<BR>utter : 4<BR>essay : 1<BR>arrow : 1<BR>meets : 1<BR>woods : 1 </FONT></P></BLOCKQUOTE>
<H3></H3>Stop the service, then stop the monitor.&nbsp; 
<H3></H3>
<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">
<P><FONT face="Courier New">&gt; <STRONG>vsperfcmd /shutdown<BR></STRONG>Microsoft (R) VSPerf Command Version 8.0.50215 x86<BR>Copyright (C) Microsoft Corp. All rights reserved. </FONT></P>
<H3><FONT face="Courier New"></FONT></H3>
<P><BR><FONT face="Courier New">Shutting down the Profile Monitor<BR>------------------------------------------------------------ </FONT></P></BLOCKQUOTE>
<P>Again, you'll have a VSP file that you can view in Visual Studio. </P><IMG src="http://angryrichard.members.winisp.net/Samples/ServiceProfilingBlog1/trace_view.PNG"> 
<P><FONT face=Georgia size=2>Nothing too surprising here in the call stack, although do notice that with trace, since we start collecting the moment the service starts, we can see into the OnStart method if we cared to.&nbsp; <BR></FONT></P>
<H3>Epilogue</H3>
<P><FONT face=Georgia size=2>The examples above should give you enough information to get started using the profiler on your service.&nbsp; Though admittedly inelegant to get running, you <EM>will&nbsp;</EM>get data by doing this, and I hope you get data that helps you optimize your applications. </FONT>
<P><FONT face=Georgia size=2>I've alluded to a number of future topics in this series, which I'll recap here: 
<UL>
<LI>CLR Profiling Environment Variables <BR><I>How to get those pesky environment variables into your service (and just your service) without rebooting the whole machine </I>
<P></P>
<LI>Launching a Service for Sampling<BR><I>A somewhat brutal workaround to enable the logical equivalent to VSPerfCmd /launch:foo.exe </I>
<P></P>
<LI>Cross Session Madness<BR><I>How to attach the sampler to a process in another TS session </I>
<P></P>
<LI>Controlling the Data Flood<BR><I>How to use the Profiler Control API to focus on interesting parts of your service<BR>I touched on this already in <a href="http://blogs.msdn.com/angryrichard/archive/2005/01/16/354194.aspx">this</A> post. </I>
<P></P>
<LI>Examining Client / Server Interaction<BR><I>How to profile the service and the client simultaneously, and look at the interaction between the two&nbsp;</I></LI></UL>
<P></FONT></FONT></FONT>&nbsp;</P></FONT>
<H3>Source Code for Sample</H3>
<H4>CommonTypes.dll</H4>
<H5>CommonTypes.cs</H5>
<P>
<TABLE width="90%" align=center bgColor=#cccccc>
<TBODY>
<TR>
<TD>
<P><FONT face="Courier New" size=2>/*<BR>&nbsp;* Copyright (c) 2005 Microsoft Corporation<BR>&nbsp;* All rights reserved.&nbsp; No warrantees expressed or implied.<BR>&nbsp;*/<BR>using System;<BR>using System.Collections.Generic;<BR>using System.Text;</FONT></P>
<P><FONT face="Courier New" size=2>namespace Cryptogram<BR>{<BR>&nbsp;&nbsp;&nbsp; namespace CommonTypes<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// Every word in a dictionary has data associated with it.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// For now, all we care about is relative frequency in the english<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// language, but it's conceivable that semantics could be encoded <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// here.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [System.Serializable]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public struct WordProperties<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private string Word_;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private int Frequency_;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public string Word <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get { return Word_; } <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int Frequency<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get { return Frequency_; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set { Frequency_ = value; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public WordProperties(string word, int frequency)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.Word_ = word.ToLower();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.Frequency_ = frequency;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// A Pattern is simply a canonical representation of a word by its<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// unique characters.&nbsp; Any word is a non-canonical pattern, but <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// a *canonical* pattern has special form:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ///&nbsp; * The first character is always 'A'<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ///&nbsp; * Further characters must either be a prior character, or <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ///&nbsp;&nbsp;&nbsp; the successor character to a prior character.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// For example, 'aaaa', 'abcd', 'aaba' are all valid canonical <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// patterns.&nbsp; 'baaa', 'acaa', 'acba' are *not* valid canonical<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// patterns.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// We "canonicalize" a pattern by substituting the first character<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// with 'a'.&nbsp; Other characters in the pattern that match the first<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// character are also replaced with 'a'.&nbsp; We then proceed to the <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// next unique character and replace it with 'b'.&nbsp; This continues <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// until the word is fully canonicalized.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// For example, the word 'canonical' translates to the canonical<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// pattern 'abcdceabf'.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [System.Serializable]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public struct Pattern<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private String Pattern_;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public override String ToString()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Pattern_;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public override int GetHashCode()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Pattern_.GetHashCode();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Pattern(String word)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Case insensitive<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; word.ToLower();</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Create a string with just dots, same length as the original word.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char[] pattern = new char[word.Length];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; word.Length; ++i)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pattern[i] = '.';</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // For each letter in the word<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char t = 'a';<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; word.Length; ++i)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // If the pattern already has a token, we've already taken care<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // of this one.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (pattern[i] != '.')<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Need to assign a token for this guy.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int j = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ((j = word.IndexOf(word[i], j)) != -1)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pattern[j] = t;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++j;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++t;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Pattern_ = new String(pattern);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// Objects that expose the pattern dictionary interface provide a <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// mechanism for clients to add to the corpus of word properties, <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// along with a mechanism to recover word collections matching a <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// given pattern.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public interface IPatternDictionary<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// Adds a word to the corpus.&nbsp; The word is assigned a default<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// frequency of '1'.&nbsp; If the corpus already contains the word,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// the corpus' frequency for the word is incremented by '1'.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;param name="word"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// The word to add to the corpus.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void AddWord(string word);</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// Adds given word properties to the corpus.&nbsp; If the corpus<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// already contains the word, the frequencies are combined.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;param name="wordProperties"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// Properties of the word to be added.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void AddWord(WordProperties wordProperties);</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// Retrieves a list of word properties for the given pattern.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;param name="pattern"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// A pattern to search for in the corpus.&nbsp; The pattern need<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// not be canonical.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;returns&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// A list of WordProperties matching the given pattern<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/returns&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;WordProperties&gt; Lookup(string pattern);</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// Retrieves a list of word properties for the given pattern.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;param name="canonicalPattern"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// A pattern to search for in the corpus.&nbsp; The pattern must<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// be canonical.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;returns&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// A list of WordProperties matching the given pattern<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/returns&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;WordProperties&gt; Lookup(Pattern canonicalPattern);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>}&nbsp;</FONT></P></TD></TR></TBODY></TABLE></P>
<H4>PatternDictionaryService.exe</H4>
<H5>Installer.cs</H5>
<P>
<TABLE width="90%" align=center bgColor=#cccccc>
<TBODY>
<TR>
<TD>
<P><FONT face="Courier New" size=2>/*<BR>&nbsp;* Copyright (c) 2005 Microsoft Corporation<BR>&nbsp;* All rights reserved.&nbsp; No warrantees expressed or implied.<BR>&nbsp;*/<BR>using System;<BR>using System.ComponentModel;<BR>using System.Configuration.Install;<BR>using System.ServiceProcess;</FONT></P>
<P><FONT face="Courier New" size=2>namespace PatternDictionaryService<BR>{<BR>&nbsp;&nbsp;&nbsp; [RunInstaller(true)]<BR>&nbsp;&nbsp;&nbsp; public class PatternDictionaryServiceInstaller : Installer<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private ServiceProcessInstaller ServiceProcessInstaller_;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private ServiceInstaller ServiceInstaller_;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public PatternDictionaryServiceInstaller()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ServiceInstaller_ = new ServiceInstaller();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ServiceInstaller_.ServiceName = "PatternDictionaryService";</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ServiceProcessInstaller_ = new ServiceProcessInstaller();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ServiceProcessInstaller_.Account = ServiceAccount.LocalSystem;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Installers.AddRange(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Installer[] {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ServiceProcessInstaller_,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ServiceInstaller_<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>}</FONT></P></TD></TR></TBODY></TABLE></P>
<H5>PatternDictionaryImpl.cs</H5>
<P>
<TABLE width="90%" align=center bgColor=#cccccc>
<TBODY>
<TR>
<TD>
<P><FONT face="Courier New" size=2>/*<BR>&nbsp;* Copyright (c) 2005 Microsoft Corporation<BR>&nbsp;* All rights reserved.&nbsp; No warrantees expressed or implied.<BR>&nbsp;*/<BR>using System;<BR>using System.Collections.Generic;<BR>using System.Diagnostics;<BR>using System.IO;<BR>using System.Runtime.Serialization;<BR>using System.Runtime.Serialization.Formatters.Binary;<BR>using System.Text;</FONT></P>
<P><FONT face="Courier New" size=2>using Cryptogram.CommonTypes;</FONT></P>
<P><FONT face="Courier New" size=2>namespace PatternDictionaryService<BR>{<BR>&nbsp;&nbsp;&nbsp; class PatternDictionaryImpl : MarshalByRefObject, IPatternDictionary<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private static PatternDictionary patternDictionary;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void Init(string fileName)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (fileName != null)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; patternDictionary = PatternDictionary.CreateFromDictionaryFile(fileName);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (System.IO.FileNotFoundException)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; patternDictionary = new PatternDictionary();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; patternDictionary = new PatternDictionary();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void Shutdown(string fileName)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (fileName == null)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (patternDictionary == null)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (File.Exists(fileName))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File.Delete(fileName);</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; patternDictionary.ExportToFile(fileName);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // IPatternDictionary<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void AddWord(string word) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; patternDictionary.AddWord(new WordProperties(word, 1));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void AddWord(WordProperties wordProperties) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; patternDictionary.AddWord(wordProperties);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public List&lt;WordProperties&gt; Lookup(string pattern)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return patternDictionary.Lookup(new Pattern(pattern));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public List&lt;WordProperties&gt; Lookup(Pattern canonicalPattern)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return patternDictionary.Lookup(canonicalPattern);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp; [System.Serializable]<BR>&nbsp;&nbsp;&nbsp; public class PatternDictionary : Dictionary&lt;Pattern, Dictionary&lt;string, WordProperties&gt;&gt;<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public PatternDictionary()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void AddWord(WordProperties wordProperties)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string word = wordProperties.Word;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Pattern p = new Pattern(word);</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dictionary&lt;string, WordProperties&gt; wordList;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (this.ContainsKey(p))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wordList = this[p];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wordList = new Dictionary&lt;string, WordProperties&gt;();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.Add(p, wordList);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (wordList.ContainsKey(word))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int frequency = wordList[word].Frequency + wordProperties.Frequency;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wordList[word] = new WordProperties(word, frequency);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wordList.Add(word, wordProperties);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public List&lt;WordProperties&gt; Lookup(Pattern canonicalPattern)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EventLog.WriteEntry("PatternDictionaryService", <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String.Format("IPatternDictionary.Lookup({0})", canonicalPattern.ToString()));</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;WordProperties&gt; result = new List&lt;WordProperties&gt;();</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (this.ContainsKey(canonicalPattern))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (WordProperties wordProperties in this[canonicalPattern].Values)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result.Add(wordProperties);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return result;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Writes dictionary to a file.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void ExportToFile(String fileName)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BinaryFormatter formatter = new BinaryFormatter();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; using (FileStream fileStream = new FileStream(fileName, FileMode.CreateNew))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; formatter.Serialize(fileStream, this);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // A factory to deserialize from a file.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static PatternDictionary CreateFromDictionaryFile(String fileName)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PatternDictionary patternDictionary;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BinaryFormatter formatter = new BinaryFormatter();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; using (FileStream fileStream = new FileStream(fileName, FileMode.Open))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; patternDictionary = (PatternDictionary)formatter.Deserialize(fileStream);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return patternDictionary;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Deserializing constructor<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected PatternDictionary(SerializationInfo info, StreamingContext context) </FONT><FONT face="Courier New" size=2>: base(info, context)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>}</FONT></P></TD></TR></TBODY></TABLE></P>
<H5>PatternDictionaryService.cs</H5>
<P>
<TABLE width="90%" align=center bgColor=#cccccc>
<TBODY>
<TR>
<TD>
<P><FONT face="Courier New" size=2>/*<BR>&nbsp;* Copyright (c) 2005 Microsoft Corporation<BR>&nbsp;* All rights reserved.&nbsp; No warrantees expressed or implied.<BR>&nbsp;*/<BR>using System;<BR>using System.Collections.Generic;<BR>using System.ComponentModel;<BR>using System.Data;<BR>using System.Diagnostics;<BR>using System.ServiceProcess;<BR>using System.Runtime.Remoting.Channels;<BR>using System.Runtime.Remoting.Channels.Tcp;<BR>using System.Runtime.Remoting;<BR>using System.Text;</FONT></P>
<P><FONT face="Courier New" size=2>namespace PatternDictionaryService<BR>{<BR>&nbsp;&nbsp;&nbsp; public class PatternDictionaryService : ServiceBase<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// Persist the startup file name, so that when we shut down,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// we can serialize updated data back to the file.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private string FileName_;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// Channel that exposes IPatternDictionary<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TcpChannel RemoteChannel_;</FONT></P><FONT face="Courier New" size=2>
<P><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// Initialize junk here.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public PatternDictionaryService()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileName_ = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// Called when the service starts<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;param name="args"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// The first element of this array is an optional filename for <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// recovering or storing dictionary data.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected override void OnStart(string[] args)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EventLog.WriteEntry("PatternDictionaryService", "OnStart");</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // If a file name is provided, we deserialize from that file.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (args.Length &gt; 0)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileName_ = args[0];</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EventLog.WriteEntry("PatternDictionaryService",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String.Format("Deserializing from {0}", FileName_));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PatternDictionaryImpl.Init(FileName_);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileName_ = null;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EventLog.WriteEntry("PatternDictionaryService",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Starting with empty pattern dictionary");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PatternDictionaryImpl.Init(null);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Create a channel for remoting IPatternDictionary.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RemoteChannel_ = new TcpChannel(8080);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ChannelServices.RegisterChannel(RemoteChannel_);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RemotingConfiguration.RegisterWellKnownServiceType(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typeof(PatternDictionaryImpl), <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "IPatternDictionary", <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WellKnownObjectMode.SingleCall);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// Called when the service is stopped.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected override void OnStop()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EventLog.WriteEntry("PatternDictionaryService", "OnStop");</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (RemoteChannel_ != null)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ChannelServices.UnregisterChannel(RemoteChannel_);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RemoteChannel_ = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PatternDictionaryImpl.Shutdown(FileName_);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>}</FONT></P></TD></TR></TBODY></TABLE></P>
<H5>Program.cs</H5>
<P>
<TABLE width="90%" align=center bgColor=#cccccc>
<TBODY>
<TR>
<TD>
<P><FONT face="Courier New" size=2>/*<BR>&nbsp;* Copyright (c) 2005 Microsoft Corporation<BR>&nbsp;* All rights reserved.&nbsp; No warrantees expressed or implied.<BR>&nbsp;*/<BR>using System.Collections.Generic;<BR>using System.ServiceProcess;<BR>using System.Text;</FONT></P>
<P><FONT face="Courier New" size=2>namespace PatternDictionaryService<BR>{<BR>&nbsp;&nbsp;&nbsp; static class Program<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// The main entry point for the application.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static void Main()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ServiceBase[] ServicesToRun;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // More than one user Service may run within the same process. To add<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // another service to this process, change the following line to<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // create a second service object. For example,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp; ServicesToRun = new ServiceBase[] {new Service1(), new MySecondUserService()};<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ServicesToRun = new ServiceBase[] { new PatternDictionaryService() };</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ServiceBase.Run(ServicesToRun);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>}&nbsp;</FONT></P></TD></TR></TBODY></TABLE></P>
<H4>CryptoClient.exe</H4>
<H5>Program.cs</H5>
<P>
<TABLE width="90%" align=center bgColor=#cccccc>
<TBODY>
<TR>
<TD>
<P><FONT face="Courier New" size=2>/*<BR>&nbsp;* Copyright (c) 2005 Microsoft Corporation<BR>&nbsp;* All rights reserved.&nbsp; No warrantees expressed or implied.<BR>&nbsp;*/<BR>using System;<BR>using System.Collections.Generic;<BR>using System.IO;<BR>using System.Text;</FONT></P>
<P><FONT face="Courier New" size=2>using System.Runtime.Remoting.Channels;<BR>using System.Runtime.Remoting.Channels.Tcp;<BR>using System.Runtime.Remoting;</FONT></P>
<P><FONT face="Courier New" size=2>using Cryptogram.CommonTypes;</FONT></P>
<P><FONT face="Courier New" size=2>namespace CryptoClient<BR>{<BR>&nbsp;&nbsp;&nbsp; class Program<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static void Usage()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Out.WriteLine("Usage:");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Out.WriteLine("");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Out.WriteLine("&nbsp;&nbsp;&nbsp; CryptoClient [command [args]]");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Out.WriteLine("");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Out.WriteLine("&nbsp;&nbsp;&nbsp; Where [command] is:");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Out.WriteLine("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Import (filename)");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Out.WriteLine("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Find&nbsp;&nbsp; (pattern)");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static int Find(string pattern)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Out.WriteLine("Connecting to IPatternDictionary");</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Get interface to pattern service<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IPatternDictionary a =<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (IPatternDictionary)Activator.GetObject(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typeof(IPatternDictionary),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "tcp://localhost:8080/IPatternDictionary");</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;WordProperties&gt; results;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Out.WriteLine("Looking up {0}", pattern);</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; results = a.Lookup(pattern);</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (WordProperties properties in results)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Out.WriteLine("{0} : {1}", properties.Word, properties.Frequency);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static int Import(string fileName)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Out.WriteLine("Connecting to IPatternDictionary");</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Get interface to pattern service<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IPatternDictionary a =<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (IPatternDictionary)Activator.GetObject(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typeof(IPatternDictionary),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "tcp://localhost:8080/IPatternDictionary");</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Out.WriteLine("Reading {0}", fileName);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int wordCount = 0;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Create file stream from file name.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; using (FileStream fs = File.OpenRead(fileName))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; using (StreamReader sr = new StreamReader(fs))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WordStream ws = new WordStream(sr);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String word;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Add each word in the file to the dictionary.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ((word = ws.Get()) != null)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.AddWord(word);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++wordCount;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.Out.WriteLine("Added {0} words", wordCount);</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static int Main(string[] args)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (args.Length == 0)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Usage();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TcpChannel channel = new TcpChannel();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ChannelServices.RegisterChannel(channel);</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string command = args[0];</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (command.Equals("Import", StringComparison.OrdinalIgnoreCase))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (args.Length &lt; 2)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Usage();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string fileName = args[1];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Import(fileName);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (command.Equals("Find", StringComparison.OrdinalIgnoreCase))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (args.Length &lt; 2)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Usage();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string pattern = args[1];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Find(pattern);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>}&nbsp;</FONT></P></TD></TR></TBODY></TABLE></P>
<H5>WordStream.cs</H5>
<P>
<TABLE width="90%" align=center bgColor=#cccccc>
<TBODY>
<TR>
<TD>
<P><FONT face="Courier New" size=2>/*<BR>&nbsp;* Copyright (c) 2005 Microsoft Corporation<BR>&nbsp;* All rights reserved.&nbsp; No warrantees expressed or implied.<BR>&nbsp;* <BR>&nbsp;* WordStream class library.&nbsp; Produces a stream of words from a text stream.<BR>&nbsp;*/<BR>using System;<BR>using System.Collections.Generic;<BR>using System.IO;<BR>using System.Text.RegularExpressions;</FONT></P>
<P><FONT face="Courier New" size=2>using Cryptogram.CommonTypes;</FONT></P>
<P><FONT face="Courier New" size=2>namespace CryptoClient<BR>{<BR>&nbsp;&nbsp;&nbsp; public class WordStream<BR>&nbsp;&nbsp;&nbsp; {</FONT></P>
<P><FONT face="Courier New" size=2>#region(PrivateData)</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private StreamReader Stream_;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private MatchCollection Matches_;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private int MatchIndex_;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private Regex Regex_;</FONT></P>
<P><FONT face="Courier New" size=2>#endregion</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // WordStream is constructed from an existing stream reader.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public WordStream(StreamReader stream)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Stream_ = stream;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Matches_ = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MatchIndex_ = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Regex_ = new Regex("<A href="file://w/">\\w</A>*");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Return a word from the stream.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public String Get()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (Stream_ == null)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (true)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // If no current matches, read a line and match it.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (Matches_ == null)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String line = Stream_.ReadLine();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (line == null)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Matches_ = Regex_.Matches(line);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MatchIndex_ = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (MatchIndex_ &lt; Matches_.Count)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Match m = Matches_[MatchIndex_];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++MatchIndex_;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String word = m.ToString();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (word.Length &gt; 0)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m.ToString();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Go around again.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Matches_ = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New" size=2>&nbsp;&nbsp;&nbsp; }<BR>}&nbsp;</FONT></P></TD></TR></TBODY></TABLE></P>]]></content:encoded>
    </item>
    <item>
      <title>Limiting the Data Crunch from Trace Profiling</title>
      <link>https://docs.microsoft.com/archive/blogs/angryrichard/limiting-the-data-crunch-from-trace-profiling</link>
      <pubDate>Sun, 16 Jan 2005 19:41:00 GMT</pubDate>
      <dc:creator><![CDATA[AngryRichard]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/angryrichard/2005/01/16/limiting-the-data-crunch-from-trace-profiling/</guid>
      <description><![CDATA[Typically, one can use the sampling profiler to nail down the hot spot in an application.&nbsp;...]]></description>
      <content:encoded><![CDATA[<p><font face="Arial" size="2">Typically, one can use the sampling profiler to nail down the hot spot in an application.&nbsp; Having done that, what does one do when the sampling data doesn't provide enough information?&nbsp; The trace profiler can offer up more detail, particularly if the issue revolves around thread interaction.&nbsp; However, if you profile a heavily CPU bound application, you may find that you are getting huge trace files, or that the profiler is significantly impacting the performance of your application.&nbsp; The VisualStudio profiler offers a mechanism to stem the avalanche of data.</font></p> <p><font face="Arial" size="2">I'll illustrate the general idea with an example.</font></p> <p><font face="Arial" size="2">Suppose we'd like to run trace profiling on the following highly useful piece of code.&nbsp; We've decided that we only care about profiling in the context of the function "OnlyProfileThis()"</font></p> <p><font face="Arial" size="2"> <hr id="null" /> </font> <p></p> <p><font face="Courier New" size="2">using System;</font></p> <p><font face="Courier New" size="2">public class A<br />{<br />&nbsp;private int _x;<br />&nbsp;<br />&nbsp;public A(int x)<br />&nbsp;{<br />&nbsp;&nbsp;_x = x;<br />&nbsp;}<br />&nbsp;<br />&nbsp;public int DoNotProfileThis()<br />&nbsp;{<br />&nbsp;&nbsp;return _x * _x;<br />&nbsp;}<br />&nbsp;<br />&nbsp;public int OnlyProfileThis()<br />&nbsp;{<br />&nbsp;&nbsp;return _x + _x;<br />&nbsp;}<br />&nbsp;<br />&nbsp;public static void Main()<br />&nbsp;{<br />&nbsp;&nbsp;A a;<br />&nbsp;&nbsp;a = new A(2);<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;Console.WriteLine("2 square is {0}", a.DoNotProfileThis());<br />&nbsp;&nbsp;Console.WriteLine("2 doubled is {0}", a.OnlyProfileThis());<br />&nbsp;}<br />}</font></p> <p><font face="Arial" size="2"> <hr id="null" /> </font> <p></p> <p><font face="Arial" size="2">The VisualStudio profiler provides an API for controlling data collection from within the application.&nbsp; For native code, this API lives in VSPerf.dll.&nbsp; A header (VSPerf.h) and import library (VSPerf.lib) provided in the default Team Developer install allows us to use the profiler control API from native code.&nbsp; For managed code, this API is wrapped by the DataCollection class in Microsoft.VisualStudio.Profiler.dll.&nbsp; We can update the example to the following to control the profiler during our run:</font></p> <p><font face="Arial" size="2"> <hr id="null" /> </font> <p></p> <p><font face="Courier New" size="2">using System;<br /><strong><font color="#ff0000">using Microsoft.VisualStudio.Profiler;</font></strong></font></p> <p><font face="Courier New" size="2">public class A<br />{<br />&nbsp;private int _x;<br />&nbsp;<br />&nbsp;public A(int x)<br />&nbsp;{<br />&nbsp;&nbsp;_x = x;<br />&nbsp;}<br />&nbsp;<br />&nbsp;public int DoNotProfileThis()<br />&nbsp;{<br />&nbsp;&nbsp;return _x * _x;<br />&nbsp;}<br />&nbsp;<br />&nbsp;public int OnlyProfileThis()<br />&nbsp;{<br />&nbsp;&nbsp;return _x + _x;<br />&nbsp;}<br />&nbsp;<br />&nbsp;public static void Main()<br />&nbsp;{<br />&nbsp;&nbsp;A a;<br />&nbsp;&nbsp;a = new A(2);</font></p> <p><font face="Courier New" size="2">&nbsp;&nbsp;int x;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;Console.WriteLine("2 square is {0}", a.DoNotProfileThis());</font></p> <p><font face="Courier New" color="#ff0000" size="2"><strong>&nbsp;&nbsp;DataCollection.StartProfile(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataCollection.ProfileLevel.DC_LEVEL_GLOBAL, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataCollection.PROFILE_CURRENTID);</strong></font></p> <p><font face="Courier New" size="2">&nbsp;&nbsp;x = a.OnlyProfileThis();</font></p> <p><font face="Courier New" color="#ff0000" size="2"><strong>&nbsp;&nbsp;DataCollection.StopProfile(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataCollection.ProfileLevel.DC_LEVEL_GLOBAL, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataCollection.PROFILE_CURRENTID);</strong></font></p> <p><font face="Courier New" size="2">&nbsp;&nbsp;Console.WriteLine("2 doubled is {0}", x);</font></p> <p><font face="Courier New" size="2">&nbsp;}<br />}</font></p> <p><font face="Arial" size="2"> <hr id="null" /> We still need to instrument the application as normal.&nbsp; We also have one additional step.&nbsp; When running the code above, data collection will be enabled by default, so the API won't appear to do anything beyond stopping data collection after the call to OnlyProfileThis.&nbsp; We need to disable data collection before running the application.&nbsp; The profiler control tool,<br />VSPerfCmd, has options to do this.</font> <p></p> <p><font face="Arial" size="2">To run this scenario from the command line:</font></p> <blockquote dir="ltr" style="MARGIN-RIGHT: 0px"> <p><font face="Courier New" size="2">csc /debug- /r:Microsoft.VisualStudio.Profiler.dll Sample.cs<br />VSInstr Sample.exe</font></p> <p><font face="Courier New" size="2">VSPerfCmd /start:trace /output:SampleTrace.VSP<br />VSPerfCmd /globaloff<br />Sample.exe<br />VSPerfCmd /shutdown</font></p> <p><font face="Courier New" size="2">VSPerfReport /calltrace SampleTrace.VSP</font></p></blockquote> <p> <hr id="null" /> <font face="Arial" size="2">There are several control functions in the DataCollection class.&nbsp; Here is a brief rundown.</font> <p></p> <p><font face="Courier New" size="2">StartProfile(ProfileLevel level, UInt32 id)<br />StopProfile(ProfileLevel level, UInt32 id)</font></p> <blockquote dir="ltr" style="MARGIN-RIGHT: 0px"> <p><font face="Arial" size="2">This unconditionally starts or stops profiling.&nbsp; The level parameter indicates whether profiling should be stopped for the current thread, process, or globally.&nbsp; For thread and process level changes, the id specifies thread id or process id to control (respectively), or PROFILE_CURRENTID to control the current thread or process.</font></p></blockquote> <p><font face="Courier New" size="2">SuspendProfile(ProfileLevel level, UInt32 id)<br />ResumeProfile(ProfileLevel level, UInt32 id)</font></p> <blockquote dir="ltr" style="MARGIN-RIGHT: 0px"> <p><font face="Arial" size="2">This works very much like StartProfile and StopProfile, however, calls to these functions are reference counted.&nbsp; If you call SuspendProfile twice, you must call ResumeProfile twice to enable profiling.</font></p></blockquote> <p dir="ltr"><font face="Arial" size="2"><font face="Courier New">MarkProfile(Int32 markId)<br />CommentMarkProfile(Int32 markId, String comment)<br />CommentMarkAtProfile(Int64 timeStamp, Int32 markId, String comment)</font></font></p> <blockquote dir="ltr" style="MARGIN-RIGHT: 0px"> <p dir="ltr"><font face="Arial" size="2">Inserts a 32-bit data value into the collection stream.&nbsp; Optionally, you can include a comment.&nbsp; With the last function, the mark can be inserted at a specific time stamp.&nbsp; The id value and the optional comment will appear in the CallTrace report.</font></p></blockquote> <p><font face="Arial" size="2"> <hr id="null" /> The profiler control tool provides similar functionality through a command line interface, though the notion of a "current" process or thread id is obviously not relevant.</font></p> <p><font face="Courier New" size="2">VSPerfCmd /?</font></p> <p><font face="Courier New" size="2">[...]</font></p> <p><font face="Courier New" size="2">-GLOBALON&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sets the global Start/Stop count to one (starts profiling).</font></p> <p><font face="Courier New" size="2">-GLOBALOFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sets the global Start/Stop count to zero (stops profiling).</font></p> <p><font face="Courier New" size="2">-PROCESSON:pid&nbsp; Sets the Start/Stop count to one for the given process.</font></p> <p><font face="Courier New" size="2">-PROCESSOFF:pid Sets the Start/Stop count to zero for the given process.</font></p> <p><font face="Courier New" size="2">-THREADON:tid&nbsp;&nbsp; Sets the Start/Stop count to one for the given thread.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Valid only in TRACE mode.</font></p> <p><font face="Courier New" size="2">-THREADOFF:tid&nbsp; Sets the Start/Stop count to zero for the given thread.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Valid only in TRACE mode.</font></p> <p><font face="Arial" size="2"><font face="Courier New">-MARK:marknum[,marktext]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Inserts a mark into the global event stream, with<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; optional text.<br /></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />[...]</font></p> <p><font face="Arial" size="2"> <hr id="null" /> </font> <p></p> <p><font face="Arial" size="2">If you find yourself buried under a ton of trace data, investigate the profiling API to help focus on the important parts of your application.<br /></font></p>]]></content:encoded>
    </item>
    <item>
      <title>Trying out the profiler on the VPC</title>
      <link>https://docs.microsoft.com/archive/blogs/angryrichard/trying-out-the-profiler-on-the-vpc</link>
      <pubDate>Fri, 06 Aug 2004 14:19:00 GMT</pubDate>
      <dc:creator><![CDATA[AngryRichard]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/angryrichard/2004/08/06/trying-out-the-profiler-on-the-vpc/</guid>
      <description><![CDATA[I've frequently heard the question asked, "Can I use the profiler on a Virtual PC?"&nbsp; It has...]]></description>
      <content:encoded><![CDATA[<P><FONT face=Arial size=2>I've frequently heard the question asked, "Can I use the profiler on a Virtual PC?"&nbsp; It has even come up on the blog feedback a few times.&nbsp; My answer has always been, "Theoretically, yes."&nbsp; I didn't want to post this answer externally until I'd actually gotten around to trying it myself.</FONT></P>
<P><FONT face=Arial size=2>I've finally been nagged into it.</FONT></P>
<P><FONT face=Arial size=2>In my limited experience with our VirtualPC product, it has quite impressed me with its functionality.&nbsp; However, it does not emulate the hardware performance counters upon which the profiler implicitly depends.&nbsp; For this reason, you <EM>can not</EM> run the sampling profiler using a performance counter based interrupt.&nbsp; My collegue Ishai&nbsp;pointed out<SUP>*</SUP> that you should be able to use page-fault or system-call based sampling, but the VPC has a different problem with these modes that is still under investigation.</FONT></P>
<P><FONT face=Arial size=2>Instrumentation based profiling <EM>will</EM> work on the VPC.&nbsp; However, as I've already mentioned, there is a bug check issue with the driver when it unloads.&nbsp; Fortunately, instrumentation based profiling doesn't rely on the presence of the driver.</FONT></P>
<P><FONT face=Arial size=2>By renaming the driver to prevent the profiling monitor from installing it at startup, I was able to use instrumentation based profiling on the VPC.&nbsp; This is obviously just a workaround,&nbsp; but I hope this will allow you to investigate some of our tools in the comfort of a VirtualPC environment.</FONT></P>
<P><FONT face=Arial size=2>Here is how you can prevent the driver from loading on your VPC installation.</FONT></P>
<UL>
<LI><FONT face=Arial size=2>Use regedit to delete the key HKLM\CurrentControlSet\Services\VSPerfDrv.</FONT></LI>
<LI><FONT face=Arial size=2>Find C:\Program Files\Microsoft Visual Studio\Enterprise Developer Tools\Performance Tools\VSPerfDrv.sys, and rename&nbsp;it to something silly like __VSPerfDrv.sys__, or delete it.</FONT></LI>
<LI><FONT face=Arial size=2>Reboot your VPC to ensure that the driver isn't installed</FONT></LI></UL>
<P><FONT face=Arial size=2>Happy hunting!<BR></FONT></P>
<P><FONT face=Arial size=2><SUP>*&nbsp;</SUP><FONT size=1>I'm pretty sure Ishai was hired to point out things I do wrong.&nbsp;&nbsp;Fortunately, he usually points out solutions as well.</FONT></P></FONT>]]></content:encoded>
    </item>
    <item>
      <title>VPC and the BSOD (part 2)</title>
      <link>https://docs.microsoft.com/archive/blogs/angryrichard/vpc-and-the-bsod-part-2</link>
      <pubDate>Thu, 03 Jun 2004 20:00:00 GMT</pubDate>
      <dc:creator><![CDATA[AngryRichard]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/angryrichard/2004/06/03/vpc-and-the-bsod-part-2/</guid>
      <description><![CDATA[I had a nice long email chat with members of the Virtual PC team.
The good news:&nbsp; The Virtual...]]></description>
      <content:encoded><![CDATA[<P><FONT face=Arial size=2>I had a nice long email chat with members of the Virtual PC team.</FONT></P>
<P><FONT face=Arial size=2>The good news:&nbsp; The Virtual PC emulates the host processor well enough that&nbsp;our kernel-mode&nbsp;driver can detect what features are enabled.</FONT></P>
<P><FONT face=Arial size=2>The bad news:&nbsp; The Virtual PC does not emulate an APIC or performance counters.</FONT></P>
<P><FONT face=Arial size=2>So, if you were planning on running the profiler inside a Virtual PC, the best you can hope to do is get function trace data on an instrumented app.&nbsp; Sampling will not work at all, and collecting perfomance counter data in the instrumentation will fault the application.</FONT></P>
<P><FONT face=Arial size=2>Bummer.&nbsp; I wish I had better news.</FONT></P>
<P><FONT face=Arial size=2></FONT>&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>VPC and the BSOD</title>
      <link>https://docs.microsoft.com/archive/blogs/angryrichard/vpc-and-the-bsod</link>
      <pubDate>Tue, 01 Jun 2004 20:14:00 GMT</pubDate>
      <dc:creator><![CDATA[AngryRichard]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/angryrichard/2004/06/01/vpc-and-the-bsod/</guid>
      <description><![CDATA[I'm so pleased.&nbsp; Someone did something exciting and dangerous with the profiler.&nbsp; In case...]]></description>
      <content:encoded><![CDATA[<P><FONT face=Arial size=2>I'm so pleased.&nbsp; Someone did something exciting and dangerous with the profiler.&nbsp; In case you're not reading the newsgroups, an intrepid customer tried to profile on a <A href="http://www.microsoft.com/windowsxp/virtualpc/">Virtual PC</A>, and discovered that it only leads to pain and misery via the BSOD.</FONT></P>
<P><FONT face=Arial size=2>So don't do that.</FONT></P>
<P><FONT face=Arial size=2>Seriously, is this something people want to do?&nbsp; I mean, VPC is about <EM>the coolest thing ever</EM>, but we do use hardware performance counters by default, and VPC is not exactly a real life environment for performance analysis and measurement.&nbsp; Still, maybe y'all have good reasons for this.</FONT></P>
<P><FONT face=Arial size=2>At the very least, we'll fix that BSOD thing.&nbsp; I mean, how 1990's is that?</FONT></P>
<P><FONT face=Arial size=2>This is an excellent time to point out that the profiler does in fact install a kernel-mode device driver in order to play with the hardware counters on your Intel and AMD processors.&nbsp; There are some fun implications from this:</FONT></P>
<UL>
<LI><FONT face=Arial size=2>You need to be running as a user who can <EM>install</EM> a kernel-mode device driver.&nbsp; We currently install the driver dynamically when starting the profiling monitor, and we uninstall it when the monitor shuts down.</FONT></LI>
<LI><FONT face=Arial size=2>The kernel-mode device driver is not <A href="http://www.microsoft.com/whdc/winlogo/drvsign/digitsign.mspx">signed</A>.&nbsp; If you're one of those cheeky folks who has unsigned drivers shimmed through <A href="http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q244/6/17.asp&amp;NoWebContent=1">verifier</A>, you may discover the joy of a <EM>forced</EM> BSOD if you exercise the profiler in new interesting ways we hadn't thought of.&nbsp; This is not all bad; just make sure you send us the <A href="http://oca.microsoft.com/en/dcp20.asp">error report</A> after you've rebooted.</FONT></LI>
<LI><FONT face=Arial size=2>If you're running on Intel Pentium I&nbsp;or&nbsp;AMD K6* (or anything older), expect no love from the sampling based profiler, and some uphill battles with instrumentation.&nbsp; I may post hints on this latter point if a few people speak up about legacy hardware.</FONT></LI></UL>]]></content:encoded>
    </item>
  </channel>
</rss>