<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Simply Does Not Work</title>
	
	<link>http://nicholas.piasecki.name/blog</link>
	<description>Confessions of a small business software developer</description>
	<lastBuildDate>Wed, 03 Feb 2010 14:34:34 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/SimplyDoesNotWork" /><feedburner:info uri="simplydoesnotwork" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>37.754254</geo:lat><geo:long>-77.474659</geo:long><item>
		<title>Buying Software Sucks</title>
		<link>http://feedproxy.google.com/~r/SimplyDoesNotWork/~3/17xt49SGLOw/</link>
		<comments>http://nicholas.piasecki.name/blog/2010/01/buying-software-sucks/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 22:50:35 +0000</pubDate>
		<dc:creator>Nicholas Piasecki</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Rants]]></category>
		<category><![CDATA[consulting]]></category>
		<category><![CDATA[cots]]></category>
		<category><![CDATA[marketing]]></category>
		<category><![CDATA[purchasing]]></category>
		<category><![CDATA[requirements]]></category>
		<category><![CDATA[salespeople]]></category>

		<guid isPermaLink="false">http://nicholas.piasecki.name/blog/?p=522</guid>
		<description><![CDATA[What follows is a rant about the state of marketing in the software industry.

We happen to like our system

So we&#8217;ve branched out and offered fulfillment services to other merchants, as I&#8217;ve mentioned before. Essentially, other e-commerce stores or merchants can store their items in our warehouse and then transmit orders as &#8220;fulfillment requests&#8221; to us. [...]]]></description>
			<content:encoded><![CDATA[<p>What follows is a rant about the state of marketing in the software industry.</p>

<h2>We happen to like our system</h2>

<p>So we&#8217;ve branched out and offered <a href="http://www.warehousefulfillmentservices.com/">fulfillment services to other merchants</a>, as I&#8217;ve mentioned before. Essentially, other e-commerce stores or merchants can store their items in our warehouse and then transmit orders as &#8220;fulfillment requests&#8221; to us. We either ship the request or mark it as invalid with a little message (&#8220;item has insufficient stock, delivery point validation failed, tax identification number required, etc.&#8221;). If they want to re-attempt, then they re-submit an entirely new fulfillment request.</p>

<p>This simple model has worked surprisingly well: the system doesn&#8217;t track &#8220;orders&#8221; (since each merchant handles backordering and cancellations differently), and while it does maintain an inventory log, it doesn&#8217;t track the cost of goods in inventory or anything like that, since that is not necessary for us to do our job. (Instead, it tracks a whole boatload of other information that people don&#8217;t normally think about, like HS codes or unit weight.)</p>

<h2>Some of our merchants need some hand-holding</h2>

<p>We have an API so merchants can integrate with our system. And so I&#8217;ve written a few plug-ins for Magento and osCommerce that auto-transmit their orders as fulfillment requests, sync outbound shipments back, and deduct inventory from their systems (since we are the authoritative inventory count). This works great for their retail businesses.</p>

<p>We have a merchant that we&#8217;ve been doing retail business with for some time who now wants to do wholesale stuff with us. He wants a sales order/invoicing/inventory management solution, and it needs to be able to track multiple inventories across multiple warehouses (our integration, if any, would only be adjusting inventory for a particular warehouse). He wants to enter sales orders remotely, press a button that shows him how much is ordered so he knows how much to make, have that manufactured and sent to us, click another button to transmit the sales order as a fulfillment request to us once it&#8217;s in stock, and then have us sync back with the shipment info, creating an invoice.</p>

<p>&#8220;Shouldn&#8217;t they have had these features prior to switching to you guys?&#8221; you ask. Well, yes. In this case, all of these features were provided in an all-in-one system provided by their previous fulfillment warehouse. They have since learned their lesson about keeping all of their data in the hands of a third party because when that relationship went south, so did their access to their own data.</p>

<p>We would rather not add these features to our system. Since all merchants have different ways of handling backorders, pre-orders, cancellations, cost of goods sold (FIFO, LIFO, average, priority), we&#8217;ve been maintaining the position that&#8211;unlike our competitors&#8211;our system is essentially feature complete, since it&#8217;s <em>ours</em> and does what <em>we</em> need it to do to ship things out. The features that I&#8217;ve mentioned <em>should</em> be things that the merchants are keeping track of themselves&#8211;since that&#8217;s their business&#8211;and integrate with our system via the programming API. While an argument could be made that our system would be abso-freaking-fantastic for merchants who need an all-in-one software and data solution (yes, it certainly would), the reality is that our competitors have an outsourced team of software developers, and we are a small business working in an area that is tangential to our core business as a result of the &#8220;new economy&#8221; that has a software development team of just one person (me) and can&#8217;t even begin to dream of hiring any more until we start seeing some serious cash flow.</p>

<p>In any case, to land this deal, we need to find a system for this merchant, and fast, because there are some important trade shows coming up.</p>

<h2>Welcome to marketing Hell</h2>

<p>Now for the rant, because you would think that these requirements are not exotic:</p>

<ul>
<li>Let salespeople enter sales orders remotely.</li>
<li>Keep track of inventory in multiple locations, and track the cost of inventory.</li>
<li>Provide integration hooks so the user can send orders to the warehouse and so the warehouse can send shipment data back.</li>
<li>Keep track of sales-order-to-invoice conversions and payments.</li>
<li>Provide reporting features.</li>
</ul>

<h3>QuickBooks 2010: Same as last year! Now with more shininess!</h3>

<p>You might take a look at integrating with QuickBooks, but you&#8217;d realize that once you&#8217;ve penetrated the marketing speak that the software in 2010 is essentially no different in terms of fundamental feature set as it was in 2006, and that it doesn&#8217;t support inventory in multiple locations and doesn&#8217;t scale well. In fact, QuickBooks performance once you start approaching 10,000 SKUs is so bad that they sell an &#8220;enterprise&#8221; version that essentially&#8211;aside from some fine-grained access permissions&#8211;has no added features other than the feature of not crashing when dealing with large lists of information.</p>

<p>We could pay another couple of thousand dollars for <a href="http://www.fishbowlinventory.com/products/pricing/">Fishbowl inventory</a>, which would add multiple location support to Quickbooks, but then we&#8217;d have created a Rube Goldberg machine straight out of the gate, with me synchronizing with Fishbowl which is then synchronizing with Quickbooks. I&#8217;m sure nothing would go wrong there. That would be insane; we might as well just stick a few fax machines into the sync process and call it an insurance company.</p>

<h3>A gap in the market</h3>

<p>The reality is that there is a huge gap in the marketplace between merchants who are moving $200k or less per year&#8211;just use commercial off-the-shelf (COTS) QuickBooks, you can do most things manually and use your e-commerce system&#8217;s native order management functions&#8211;and merchants who are moving $5m or more&#8211;just use SAP or some other enterprisey software. If you&#8217;re in between, like we are and like the merchant that I&#8217;m researching for is, the options available to you are not pretty.</p>

<p>I&#8217;m not sure why this is. All I can think of is that perhaps companies historically did not spend much time in this space&#8211;they either stayed small or had venture capital to acquire the big boy systems and grow quickly. People aren&#8217;t exactly lending money anymore, so I suspect that this is a segment that is only going to grow.</p>

<p>If you try to look for COTS software in this segment, you&#8217;ll never find the feature matrix that you need:</p>

<ul>
<li><a href="http://www.inflowinventory.com/">inFlow Inventory</a> is pretty, but offers no integration features, as if an entire business could be run out of one app, and doesn&#8217;t offer Web access.</li>
<li><a href="http://www.workingpoint.com/">WorkingPoint</a> is Web-based but doesn&#8217;t offer inventory tracking in multiple locations or an integration API.</li>
<li><a href="http://quickbooks.intuit.com/">QuickBooks</a> has a <a href="http://www.vi4qb.com/">Web-based</a> extension that lets QuickBooks understand multiple inventories but costs thousands of dollars, assumes that the company owns its own warehouse (that is, needing picking/packing/shipping capabilities), and still does the same style of synchronization as Fishbowl does. You&#8217;d think Intuit would just add the @#$#@ feature to QuickBooks itself!</li>
</ul>

<h3>No COTS to sleep in</h3>

<p>The market seems to have determined that people in this segment have outgrown COTS software and need some consulting help. So any Web sites that advertise products will be full of pages and pages of <a href="http://www.netsuite.com/portal/home.shtml">impenetrable marketing bullshit</a> that use obnoxious acronyms like ERP, CRM, MRP, and WMS, promise the moon, and coyly make no reference to pricing or contract requirements so you can&#8217;t even tell if you&#8217;re dealing with the right league of product, when the reality is at the end of the day you could look at two or three screenshots and the SDK&#8217;s API and immediately tell if the product fit your needs.</p>

<p>Instead, I notice a disturbing trend of &#8220;pretty Web site, crap product,&#8221; such as <a href="http://www.simplyaccounting.com/productsServices/compare_products/?WT.mc_id=hp_comp">Sage&#8217;s Simply Accounting</a>, which certainly appears to have an impressive array of features but in reality doesn&#8217;t even know the difference between a <a href="http://en.wikipedia.org/wiki/Sales_order">sales order</a> and an <a href="http://en.wikipedia.org/wiki/Invoice">invoice</a>. You can try going to <a href="http://www.microsoft.com/dynamics/en/us/default.aspx">Microsoft&#8217;s Dynamics site</a>, but good luck figuring out what the difference between Dynamics AX, Dynamics CRM, Dynamics NAV, and Dynamics GP are: you&#8217;ll be told to contact your &#8220;Microsoft Dynamics solutions representative&#8221; for help. At that point, you&#8217;re thinking &#8220;Microsoft solutions representative? Who said I committed to Microsoft?! I&#8217;m just trying to figure out <em>what in the blue hell your product even <strong>does</strong></em>.&#8221;</p>

<p>If you do find a vendor that maybe sorta-kinda-hard-to-tell meets your solutions, then you can expect days of scheduling WebEx teleconferences and meetings and run-around with your &#8220;account rep&#8221; so that they can determine how much you&#8217;re worth and willing to pay so that <a href="http://www.endicia.com/Developers/">they can charge you a completely different amount</a> than what they charged Bob next door for the same services and bits. Trying to extract &#8220;$X/user&#8221; and &#8220;the login starts working on MM/DD/YYYY&#8221; and &#8220;the developer get a demo account so if you can know if this is feasible&#8221; answers from these people seems to require a hammer in one hand and their genitals in the other. We both know that to add a new account, they&#8217;re pressing a button that says &#8220;they really bought into that &#8216;enterprise&#8217; crap&#8221; and poof! a new account is created. Let&#8217;s quit pretending that the world&#8217;s carbon footprint has increased ten-fold by us merely asking to be on the platform.</p>

<p>Trying to extract technical capabilities from these salespeople is nigh-impossible either. I think part of the problem is that they seem to actually believe that the features that they are promising really exist, when in reality I just need them to show me what the data dictionary looks like and how the session needs to be handled and then I can tell for myself whether or not my scenario is actually supported. Instead? I&#8217;m waiting on a &#8220;discovery session&#8221; teleconference with an &#8220;engineer&#8221; tomorrow.</p>

<h2>Conclusions and Delusions</h2>

<p>It has to be easier than this. No wonder there are so many not-invented-here software solutions in the world today&#8211;custom crap that barely works at home may yet indeed be better than generic crap that you have to waste hundreds of dollars on in productivity time and research before you even get it in your hands and realize that it is also crap, just with a maintenance contract.</p>

<p>If it takes a consultant to help people decide what software to buy, or which of your products is right for them, or whether or not your product <em>even applies to their problem domain</em>, then your marketing <em>simply does not work.</em></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=17xt49SGLOw:TgYJNGFq2m8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=17xt49SGLOw:TgYJNGFq2m8:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SimplyDoesNotWork/~4/17xt49SGLOw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://nicholas.piasecki.name/blog/2010/01/buying-software-sucks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://nicholas.piasecki.name/blog/2010/01/buying-software-sucks/</feedburner:origLink></item>
		<item>
		<title>Integration Testing with SQL Server Express 2008, NHibernate, and MSTEST</title>
		<link>http://feedproxy.google.com/~r/SimplyDoesNotWork/~3/dadJ7Iy81Jo/</link>
		<comments>http://nicholas.piasecki.name/blog/2010/01/integration-testing-with-sql-server-express-2008-nhibernate-and-mstest/#comments</comments>
		<pubDate>Tue, 05 Jan 2010 03:14:21 +0000</pubDate>
		<dc:creator>Nicholas Piasecki</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[nhibernate]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://nicholas.piasecki.name/blog/?p=508</guid>
		<description><![CDATA[When dealing with NHibernate, I find that it&#8217;s important to write tests to make sure that I&#8217;ve created my mapping files correctly&#8211;that is, that properties actually are mapped correctly, that I remembered to specify an IUserType where appropriate, that I remembered to make my properties virtual, that I remembered to add a parameterless constructor, that [...]]]></description>
			<content:encoded><![CDATA[<p>When dealing with NHibernate, I find that it&#8217;s important to write tests to make sure that I&#8217;ve created my mapping files correctly&#8211;that is, that properties actually are mapped correctly, that I remembered to specify an <code>IUserType</code> where appropriate, that I remembered to make my properties <code>virtual</code>, that I remembered to add a parameterless constructor, that I set the right <code>cascade</code> option on an association, and so on.</p>

<p>It would be nice if I could run an automated test that would &#8220;exercise&#8221; my NHibernate mapping file against an actual database to see if it all worked. It&#8217;s not really a unit test&#8211;I&#8217;m not testing NHibernate itself, I&#8217;m testing my <em>configuration</em> of NHIbernate&#8211;but it&#8217;s still appropriate as an integration test.</p>

<p><a href="http://ayende.com/Blog/archive/2009/04/28/nhibernate-unit-testing.aspx">Ayende Rahien has a spiffy implementation</a> of an in-memory database test that uses NHibernate&#8217;s <code>SchemaExport</code> to build up an empty, in-memory SQLite database at the start of each NUnit test. His implementation serves as the inspiration for my example.</p>

<p>In my case, I&#8217;m working on a little moonlighting project that uses some database-specific features of SQL Server Express 2008, in particular the <code>GEOGRAPHY</code> type and <code>SPATIAL</code> indexes. SQLite wouldn&#8217;t help me here&#8211;unless I just didn&#8217;t want to use it for those particular tests&#8211;but I figure that if I&#8217;m bothering to write an integration test, then it should actually test the integration against the database that I&#8217;m actually using. Additionally, unlike Ayende&#8217;s example, I&#8217;m using MSTest instead of nUnit because it&#8217;s built into Visual Studio and I am a masochist.</p>

<h2>Understanding SQL Server Express User Instances</h2>

<p>SQL Server Express has the concept of a &#8220;user instance&#8221; that allows a non-administrator user to attach and detach an *.mdf file to the local SQL Server Express instance. I thought this was what I needed. But there are some things to understand about user instances that confused me and probably confuse other people as well:</p>

<ul>
<li>They&#8217;re not the same thing as an in-memory database or even a &#8220;file-based&#8221; database like SQLite. It&#8217;s a regular SQL Server database file.</li>
<li>The file has to exist. Unlike SQLite, if you tell SQL Server Express to attach to an *.mdf that isn&#8217;t there, you&#8217;ll get an error instead of having the database created for you just in time.</li>
<li>To access the database, it has to be attached to a SQL Server instance. This means downloading SQL Server Express and installing the service on the machine. It&#8217;s not as if your application can just directly access the *.mdf file through some special DLL or anything like that. It really is still client/server.</li>
<li>Permissions can still be an issue. The SQL Server instance will need to be able to read the *.mdf file, so the NTFS permissions need to be set appropriately; in most cases, this means that <code>NETWORK SERVICE</code> will need to be able to read and write to it.</li>
</ul>

<p>After spending a few hours learning such things the hard way, I realized that user instances were not necessary for me (VS already runs as administrator, can&#8217;t debug in IIS without it). Instead I&#8217;ll just use <a href="http://msdn.microsoft.com/en-us/library/ms162169.aspx">SQL Server Management Objects</a> (SMO) to programmatically set up the database at the start of each test. (More on this later.)</p>

<h2>Understanding MSTest Execution Order</h2>

<p>On my first attempt, I put my database and NHibernate set-up and tear-down code in methods decorated with the MSTest <code>[TestInitialize]</code> and <code>[TestCleanup]</code> attributes. And this does indeed work well when a single <code>[TestMethod]</code> is executed in isolation. But if I executed more than one test in a single test run, all hell would break loose because the <code>[TestInitialize]</code> for a test that is scheduled to execute might get executed before the <code>[TestCleanup]</code> from a test that has already run.</p>

<p>This seemed like astonishing behavior to me and seems to be just a quirk of Microsoft&#8217;s design of MSTest. In nUnit and pretty much any other xUnit framework I&#8217;ve tried, the initialize/test/cleanup triumvirate is guaranteed to execute &#8220;atomically&#8221; before any part of any other test triumvirate is executed. In other words, if you&#8217;re running a test run with two tests A and B, then you <em>might</em> see this behavior in the two testing frameworks:</p>

<ul>
<li>nUnit: Initialize A > Test A > Cleanup A > Initialize B > Test B > Cleanup B</li>
<li>MSTest: Initialize A > Test A > Initialize B > Cleanup A > Test B > Cleanup B</li>
</ul>

<p>That&#8217;s because MSTest executes tests in multiple threads, and while for a particular test method you&#8217;re guaranteed that its <code>[TestInitialize]</code> and <code>[TestCleanup]</code> methods will be called before and after the test itself executes, respectively, <a href="http://blogs.msdn.com/nnaderi/archive/2007/02/17/explaining-execution-order.aspx">there is no guarantee about its relationship with the other simultaneously executing test methods</a>.</p>

<p>This causes a problem when the test method is assuming exclusive access to a shared system resource, like a test SQL Server Express database that has just been set up for that test method&#8217;s exclusive use. My brute force workaround is to use <code>Monitor.Enter()</code> and <code>Monitor.Exit()</code> in the <code>[TestInitialize]</code> and <code>[TestCleanup]</code> methods to force MSTest to execute them in the correct order:</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">private</span> <span style="color: #0600FF;">static</span> <span style="color: #0600FF;">readonly</span> <span style="color: #FF0000;">object</span> lockObject <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> <span style="color: #FF0000;">object</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
<span style="color: #000000;">&#91;</span>TestInitialize<span style="color: #000000;">&#93;</span>
<span style="color: #0600FF;">public</span> <span style="color: #0600FF;">void</span> TestInitialize<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	Monitor.<span style="color: #0000FF;">Enter</span><span style="color: #000000;">&#40;</span>lockObject<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #0600FF;">try</span>
	<span style="color: #000000;">&#123;</span>
		<span style="color: #008080; font-style: italic;">// TODO: Delete any pre-existing SQL Server Express Instance</span>
		<span style="color: #008080; font-style: italic;">// TODO: Set up the SQL Server Express Instance</span>
		<span style="color: #008080; font-style: italic;">// TODO: Set up NHibernate</span>
	<span style="color: #000000;">&#125;</span>
	<span style="color: #0600FF;">catch</span>
	<span style="color: #000000;">&#123;</span>
		<span style="color: #008080; font-style: italic;">// If something went horribly wrong, release the lock</span>
		<span style="color: #008080; font-style: italic;">// or else MSTest will never finish the test run!</span>
		Monitor.<span style="color: #0000FF;">Exit</span><span style="color: #000000;">&#40;</span>lockObject<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
		throw<span style="color: #008000;">;</span>
	<span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span>
&nbsp;
<span style="color: #000000;">&#91;</span>TestCleanup<span style="color: #000000;">&#93;</span>
<span style="color: #0600FF;">public</span> <span style="color: #0600FF;">void</span> TestCleanup<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	<span style="color: #008080; font-style: italic;">// TODO: Delete the SQL Server Express instance</span>
	Monitor.<span style="color: #0000FF;">Exit</span><span style="color: #000000;">&#40;</span>lockObject<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>


<h2>Using SMO to Bind It All Together</h2>

<p>All that was left was to fill in those TODOs.</p>

<h3>Deleting an Existing Database</h3>

<p>First up is deleting an existing instance, which is pretty trivial with SMO (just add a reference to <code>Microsoft.SqlServer.Smo.dll</code>, which is available after you installing SQL Server Express, and you&#8217;re set):</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">private</span> <span style="color: #0600FF;">static</span> <span style="color: #0600FF;">readonly</span> <span style="color: #FF0000;">string</span> serverInstance <span style="color: #008000;">=</span> <span style="color: #666666;">@&quot;(local)\SQLEXPRESS&quot;</span><span style="color: #008000;">;</span>
&nbsp;
<span style="color: #0600FF;">private</span> <span style="color: #0600FF;">static</span> <span style="color: #0600FF;">readonly</span> <span style="color: #FF0000;">string</span> databaseName <span style="color: #008000;">=</span> <span style="color: #666666;">&quot;EquineTest&quot;</span><span style="color: #008000;">;</span>
&nbsp;
<span style="color: #0600FF;">private</span> <span style="color: #FF0000;">string</span> dataFilePath<span style="color: #008000;">;</span>
&nbsp;
<span style="color: #0600FF;">private</span> <span style="color: #FF0000;">string</span> logFilePath<span style="color: #008000;">;</span>
&nbsp;
<span style="color: #0600FF;">private</span> <span style="color: #0600FF;">void</span> DeleteDatabaseIfExists<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	var server <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> Server<span style="color: #000000;">&#40;</span>serverInstance<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>server.<span style="color: #0000FF;">Databases</span>.<span style="color: #0000FF;">Contains</span><span style="color: #000000;">&#40;</span>databaseName<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
	<span style="color: #000000;">&#123;</span>
		<span style="color: #008080; font-style: italic;">// Something might be caching an open connection, so tell everyone</span>
		<span style="color: #008080; font-style: italic;">// to screw off by forcing their connections shut. If we don't do this,</span>
		<span style="color: #008080; font-style: italic;">// the DetachDatabase() call could faile.</span>
		var sql <span style="color: #008000;">=</span> <span style="color: #FF0000;">string</span>.<span style="color: #0000FF;">Format</span><span style="color: #000000;">&#40;</span>
			CultureInfo.<span style="color: #0000FF;">InvariantCulture</span>,
			<span style="color: #666666;">&quot;ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE&quot;</span>,
			databaseName<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
		server.<span style="color: #0000FF;">Databases</span><span style="color: #000000;">&#91;</span>databaseName<span style="color: #000000;">&#93;</span>.<span style="color: #0000FF;">ExecuteNonQuery</span><span style="color: #000000;">&#40;</span>sql<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
		server.<span style="color: #0000FF;">DetachDatabase</span><span style="color: #000000;">&#40;</span>databaseName, <span style="color: #0600FF;">true</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
		File.<span style="color: #0000FF;">Delete</span><span style="color: #000000;">&#40;</span><span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">dataFilePath</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
		File.<span style="color: #0000FF;">Delete</span><span style="color: #000000;">&#40;</span><span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">logFilePath</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	<span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>


<p>Why check for an delete an existing database at the start of a test? In case a previous test failed. Shockingly, MSTest won&#8217;t call <code>[TestCleanup]</code> if a test method explodes with an exception. I know, I&#8217;m in total agreement with you, what were they thinking?</p>

<h3>Figuring Out Where to Put the Files</h3>

<p>Simple enough, but you&#8217;ll notice that my <code>dataFilePath</code> and <code>logFilePath</code> variables, which should be pointing to my *.mdf and *.ldf database files, respectively, aren&#8217;t initialized in my above example. Prior to calling this function, I make sure that my <code>InitializePaths()</code> method is called:</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">private</span> <span style="color: #FF0000;">string</span> GetExecutingDirectory<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	var path <span style="color: #008000;">=</span> Assembly.<span style="color: #0000FF;">GetExecutingAssembly</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">GetName</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">CodeBase</span><span style="color: #008000;">;</span>
	<span style="color: #0600FF;">return</span> Path.<span style="color: #0000FF;">GetDirectoryName</span><span style="color: #000000;">&#40;</span><span style="color: #008000;">new</span> Uri<span style="color: #000000;">&#40;</span>path<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">LocalPath</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span>
&nbsp;
<span style="color: #0600FF;">private</span> <span style="color: #0600FF;">void</span> InitializePaths<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	var directoryPath <span style="color: #008000;">=</span> <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">GetExecutingDirectory</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">dataFilePath</span> <span style="color: #008000;">=</span> Path.<span style="color: #0000FF;">Combine</span><span style="color: #000000;">&#40;</span>directoryPath, databaseName <span style="color: #008000;">+</span> <span style="color: #666666;">&quot;.mdf&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	<span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">logFilePath</span> <span style="color: #008000;">=</span> Path.<span style="color: #0000FF;">Combine</span><span style="color: #000000;">&#40;</span>directoryPath, databaseName <span style="color: #008000;">+</span> <span style="color: #666666;">&quot;_log.ldf&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>


<p>This is convoluted way of determining the directory that MSTest created for the current test run. (MSTest sets the working directory to some nonsense in Program Files, so no help there. And <code>[DeploymentItem()]</code> is an absolute nightmare!)</p>

<h3>Creating the Test Database</h3>

<p>The code for creating the database via SMO is similarly straightforward:</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">private</span> <span style="color: #0600FF;">void</span> CreateDatabase<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	var server <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> Server<span style="color: #000000;">&#40;</span>serverInstance<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	var database <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> Database<span style="color: #000000;">&#40;</span>server, databaseName<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
	var fileGroup <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> FileGroup<span style="color: #000000;">&#40;</span>database, <span style="color: #666666;">&quot;PRIMARY&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	database.<span style="color: #0000FF;">FileGroups</span>.<span style="color: #0000FF;">Add</span><span style="color: #000000;">&#40;</span>fileGroup<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
	var dataFile <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> DataFile<span style="color: #000000;">&#40;</span>fileGroup, databaseName, <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">dataFilePath</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	dataFile.<span style="color: #0000FF;">Growth</span> <span style="color: #008000;">=</span> <span style="color: #FF0000;">10</span><span style="color: #008000;">;</span>
	dataFile.<span style="color: #0000FF;">GrowthType</span> <span style="color: #008000;">=</span> FileGrowthType.<span style="color: #0000FF;">Percent</span><span style="color: #008000;">;</span>
	fileGroup.<span style="color: #0000FF;">Files</span>.<span style="color: #0000FF;">Add</span><span style="color: #000000;">&#40;</span>dataFile<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
	var logFile <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> LogFile<span style="color: #000000;">&#40;</span>database, databaseName <span style="color: #008000;">+</span> <span style="color: #666666;">&quot;_log&quot;</span>, <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">logFilePath</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	logFile.<span style="color: #0000FF;">Growth</span> <span style="color: #008000;">=</span> <span style="color: #FF0000;">10</span><span style="color: #008000;">;</span>
	logFile.<span style="color: #0000FF;">GrowthType</span> <span style="color: #008000;">=</span> FileGrowthType.<span style="color: #0000FF;">Percent</span><span style="color: #008000;">;</span>
	database.<span style="color: #0000FF;">LogFiles</span>.<span style="color: #0000FF;">Add</span><span style="color: #000000;">&#40;</span>logFile<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
	database.<span style="color: #0000FF;">Create</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>


<p>The only quirk is that I explicitly set the <code>Growth</code> and <code>GrowthType</code> because on some machines it was defaulting to <code>None</code> causing the integration tests to fail when lots of data is inserted under some circumstances. It seems to be a per-server default setting, but I haven&#8217;t bothered to figure out why the default behavior is different among the multiple machines that I own; setting it here guarantees the tests will work consistently.</p>

<h3>Initializing the Database and Configuring NHibernate</h3>

<p>The last piece of the puzzle is to configure NHibernate and set up the freshly-minted database&#8217;s schema. I use the NHibernate&#8217;s <code>SchemaExport</code> tool to create the schema for me based on my mapping files. The only caveat is that when using SQL <code>SCHEMA</code>s, the <code>SchemaExport</code> tool won&#8217;t create those for you, so they have to be handled explicitly:</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #000000;">&#91;</span>TestInitialize<span style="color: #000000;">&#93;</span>
<span style="color: #0600FF;">public</span> <span style="color: #0600FF;">void</span> TestInitialize<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	Monitor.<span style="color: #0000FF;">Enter</span><span style="color: #000000;">&#40;</span>lockObject<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #0600FF;">try</span>
	<span style="color: #000000;">&#123;</span>
		<span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">InitializePaths</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
		<span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">DeleteDatabaseIfExists</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
		<span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">CreateDatabase</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
		<span style="color: #008080; font-style: italic;">// The configuration is a static variable, I don't care if the</span>
		<span style="color: #008080; font-style: italic;">// configuration is shared among test methods</span>
		<span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>configuration <span style="color: #008000;">==</span> <span style="color: #0600FF;">null</span><span style="color: #000000;">&#41;</span>
		<span style="color: #000000;">&#123;</span>
			<span style="color: #008080; font-style: italic;">// Disabling connection pooling is important</span>
			var connectionString <span style="color: #008000;">=</span> <span style="color: #FF0000;">string</span>.<span style="color: #0000FF;">Format</span><span style="color: #000000;">&#40;</span>
				CultureInfo.<span style="color: #0000FF;">InvariantCulture</span>,
				<span style="color: #666666;">@&quot;Data Source={0}; Integrated Security=true; Initial Catalog={1}; Connection Timeout=120; Pooling=false;&quot;</span>,
				serverInstance,
				databaseName<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
			configuration <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> Configuration<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>
				.<span style="color: #0000FF;">SetProperty</span><span style="color: #000000;">&#40;</span>Environment.<span style="color: #0000FF;">ReleaseConnections</span>, <span style="color: #666666;">&quot;on_close&quot;</span><span style="color: #000000;">&#41;</span>
				.<span style="color: #0000FF;">SetProperty</span><span style="color: #000000;">&#40;</span>Environment.<span style="color: #0000FF;">Dialect</span>, <span style="color: #008000;">typeof</span><span style="color: #000000;">&#40;</span>MsSql2008Dialect<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">AssemblyQualifiedName</span><span style="color: #000000;">&#41;</span>
				.<span style="color: #0000FF;">SetProperty</span><span style="color: #000000;">&#40;</span>Environment.<span style="color: #0000FF;">ConnectionDriver</span>, <span style="color: #008000;">typeof</span><span style="color: #000000;">&#40;</span>SqlClientDriver<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">AssemblyQualifiedName</span><span style="color: #000000;">&#41;</span>
				.<span style="color: #0000FF;">SetProperty</span><span style="color: #000000;">&#40;</span>Environment.<span style="color: #0000FF;">ConnectionString</span>, connectionString<span style="color: #000000;">&#41;</span>
				.<span style="color: #0000FF;">SetProperty</span><span style="color: #000000;">&#40;</span>Environment.<span style="color: #0000FF;">ProxyFactoryFactoryClass</span>, <span style="color: #008000;">typeof</span><span style="color: #000000;">&#40;</span>ProxyFactoryFactory<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">AssemblyQualifiedName</span><span style="color: #000000;">&#41;</span>
				.<span style="color: #0000FF;">AddAssembly</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;EquineBusinessBureau.Model&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
			sessionFactory <span style="color: #008000;">=</span> configuration.<span style="color: #0000FF;">BuildSessionFactory</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
		<span style="color: #000000;">&#125;</span>
&nbsp;
		<span style="color: #008080; font-style: italic;">// We definitely need a new session for each test method, though		</span>
		<span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">session</span> <span style="color: #008000;">=</span> sessionFactory.<span style="color: #0000FF;">OpenSession</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
		<span style="color: #008080; font-style: italic;">// SchemaExport won't create the database schemas for us</span>
		<span style="color: #0600FF;">foreach</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span> schema <span style="color: #0600FF;">in</span> schemas<span style="color: #000000;">&#41;</span>
		<span style="color: #000000;">&#123;</span>
			var sql <span style="color: #008000;">=</span> <span style="color: #FF0000;">string</span>.<span style="color: #0000FF;">Format</span><span style="color: #000000;">&#40;</span>CultureInfo.<span style="color: #0000FF;">InvariantCulture</span>, <span style="color: #666666;">&quot;CREATE SCHEMA {0}&quot;</span>, schema<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
			<span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">session</span>.<span style="color: #0000FF;">CreateSQLQuery</span><span style="color: #000000;">&#40;</span>sql<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">ExecuteUpdate</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
		<span style="color: #000000;">&#125;</span>
&nbsp;
		<span style="color: #008000;">new</span> SchemaExport<span style="color: #000000;">&#40;</span>configuration<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">Execute</span><span style="color: #000000;">&#40;</span>
			<span style="color: #0600FF;">true</span>,
			<span style="color: #0600FF;">true</span>,
			<span style="color: #0600FF;">false</span>,
			session.<span style="color: #0000FF;">Connection</span>,
			Console.<span style="color: #0600FF;">Out</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	<span style="color: #000000;">&#125;</span>
	<span style="color: #0600FF;">catch</span>
	<span style="color: #000000;">&#123;</span>
&nbsp;
		Monitor.<span style="color: #0000FF;">Exit</span><span style="color: #000000;">&#40;</span>lockObject<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
		throw<span style="color: #008000;">;</span>
	<span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>


<h2>Conclusions and Delusions</h2>

<p>Wrap all of this up in an abstract class called <code>IntegrationTestBase</code>, and you&#8217;ve got an easy way to write integration tests in a style that&#8217;s similar to what Ayende originally posted:</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #000000;">&#91;</span>TestClass<span style="color: #000000;">&#93;</span>
<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">class</span> RoleTest <span style="color: #008000;">:</span> InMemoryDatabaseTestBase
<span style="color: #000000;">&#123;</span>
    <span style="color: #000000;">&#91;</span>TestMethod<span style="color: #000000;">&#93;</span>
    <span style="color: #0600FF;">public</span> <span style="color: #0600FF;">void</span> CanSaveAndLoadRole<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>
    <span style="color: #000000;">&#123;</span>
        <span style="color: #FF0000;">object</span> identity<span style="color: #008000;">;</span>
&nbsp;
        <span style="color: #0600FF;">using</span> <span style="color: #000000;">&#40;</span>var tx <span style="color: #008000;">=</span> <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">session</span>.<span style="color: #0000FF;">BeginTransaction</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
        <span style="color: #000000;">&#123;</span>
            identity <span style="color: #008000;">=</span> session.<span style="color: #0000FF;">Save</span><span style="color: #000000;">&#40;</span><span style="color: #008000;">new</span> Role<span style="color: #000000;">&#40;</span>EquineRoles.<span style="color: #0000FF;">Administrator</span>, <span style="color: #666666;">&quot;Administrator&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
            tx.<span style="color: #0000FF;">Commit</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #000000;">&#125;</span>
&nbsp;
        session.<span style="color: #0000FF;">Clear</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
        <span style="color: #0600FF;">using</span> <span style="color: #000000;">&#40;</span>var tx <span style="color: #008000;">=</span> <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">session</span>.<span style="color: #0000FF;">BeginTransaction</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
        <span style="color: #000000;">&#123;</span>
            var role <span style="color: #008000;">=</span> session.<span style="color: #0000FF;">Get</span><span style="color: #008000;">&lt;</span>Role<span style="color: #008000;">&gt;</span><span style="color: #000000;">&#40;</span>identity<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
            Assert.<span style="color: #0000FF;">AreEqual</span><span style="color: #008000;">&lt;</span><span style="color: #FF0000;">string</span><span style="color: #008000;">&gt;</span><span style="color: #000000;">&#40;</span>EquineRoles.<span style="color: #0000FF;">Administrator</span>, role.<span style="color: #0000FF;">RoleEnum</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
            Assert.<span style="color: #0000FF;">AreEqual</span><span style="color: #008000;">&lt;</span><span style="color: #FF0000;">string</span><span style="color: #008000;">&gt;</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;Administrator&quot;</span>, role.<span style="color: #0000FF;">RoleName</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
            tx.<span style="color: #0000FF;">Commit</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #000000;">&#125;</span>
    <span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>


<p>The first test in a test run takes a while to run, on the order of 6 &#8211; 8 seconds. Painful, but this is also an integration test, so it&#8217;s not like I&#8217;m running them every five minutes, and it&#8217;s faster than spinning up the Web site and seeing if it crashed. Subsequent tests, since the NHibernate configuration is already initialized in the static variable, execute much more quickly, about one second per test.</p>

<p>Hope this saves someone a few hours of putting the puzzle pieces together.</p>

<p><a href='http://nicholas.piasecki.name/blog/wp-content/uploads/2010/01/IntegrationTestBase.cs_.txt'>Download the IntegrationTestBase example source file.</a></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=dadJ7Iy81Jo:TlFGkp5St5s:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=dadJ7Iy81Jo:TlFGkp5St5s:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SimplyDoesNotWork/~4/dadJ7Iy81Jo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://nicholas.piasecki.name/blog/2010/01/integration-testing-with-sql-server-express-2008-nhibernate-and-mstest/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://nicholas.piasecki.name/blog/2010/01/integration-testing-with-sql-server-express-2008-nhibernate-and-mstest/</feedburner:origLink></item>
		<item>
		<title>Quick Tip: BinaryWriter’s Write(string) overload prepends the binary data with the length of the string</title>
		<link>http://feedproxy.google.com/~r/SimplyDoesNotWork/~3/6_FhNiMMCwo/</link>
		<comments>http://nicholas.piasecki.name/blog/2009/12/quick-tip-binarywriters-writestring-overload-prepends-the-binary-data-with-the-length-of-the-string/#comments</comments>
		<pubDate>Tue, 22 Dec 2009 18:28:58 +0000</pubDate>
		<dc:creator>Nicholas Piasecki</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[interop]]></category>
		<category><![CDATA[printing]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://nicholas.piasecki.name/blog/?p=497</guid>
		<description><![CDATA[If you&#8217;re like me and you&#8217;re using the .NET Framework&#8217;s BinaryWriter class to write bytes to a stream, you might call the overload that takes a string as its parameter and expect to get the sequence of characters that is that string written to the stream as a series of bytes according to the encoding [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re like me and you&#8217;re using the .NET Framework&#8217;s <a href="http://msdn.microsoft.com/en-us/library/system.io.binarywriter.aspx"><code>BinaryWriter</code></a> class to write bytes to a stream, you might call the overload that takes a string as its parameter and expect to get the sequence of characters that is that string written to the stream as a series of bytes according to the encoding set in the <code>BinaryWriter</code> instance.</p>

<p>In other words, I was expecting the <code>BinaryWriter</code>&#8217;s <code>Write(string)</code> implementation to look something like this pseudocode:</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">public</span> <span style="color: #0600FF;">void</span> Write<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span> text<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
     <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">buffer</span>.<span style="color: #0000FF;">Append</span><span style="color: #000000;">&#40;</span><span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">encoding</span>.<span style="color: #0000FF;">GetBytes</span><span style="color: #000000;">&#40;</span>text<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>


<p>After all, when you call <code>Write()</code> with an <code>int</code>, you get four bytes written. If I call <code>Write()</code> with the string &#8220;TEST&#8221; and the <code>BinaryWriter</code> is using the ASCII encoding, I&#8217;d expect four bytes to be written. But instead it writes five.</p>

<p>That&#8217;s because the <code>BinaryWriter</code> writes the length of the string in one byte and <em>then</em> calls <code>GetBytes()</code> to output the string data.</p>

<p>Now that I think about it, this makes perfect sense: strings in the .NET framework are typically not thought of as being null-terminated, they&#8217;ve got a length, and in order for the <code>BinaryReader</code>&#8217;s <code>Read(string)</code> method to work, it&#8217;ll need to be able to know the length of the string to determine how many bytes to read.</p>

<p>In my case, I was writing data to an Epson TM-T88III receipt printer, and given the structure of the commands that the printer expects, it doesn&#8217;t need or want the length of the string in this way. Because I didn&#8217;t read the MSDN documentation closely, I was left scratching my head as to why weird characters were showing up or characters were being omitted in my output.</p>

<p>The workaround is to just call <code>GetBytes()</code> myself and pass the byte buffer to the <code>BinaryWriter</code>&#8217;s <code>Write(byte[])</code> overload:</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #008080; font-style: italic;">// &quot;bw&quot; is an instance of a BinaryWriter</span>
<span style="color: #008080; font-style: italic;">// &quot;barcode&quot; is a string</span>
&nbsp;
bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span>AsciiControlChars.<span style="color: #0000FF;">GroupSeparator</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">'k'</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">byte</span><span style="color: #000000;">&#41;</span><span style="color: #FF0000;">4</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">'*'</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span>Encoding.<span style="color: #0000FF;">ASCII</span>.<span style="color: #0000FF;">GetBytes</span><span style="color: #000000;">&#40;</span>barcode<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span> <span style="color: #008080; font-style: italic;">// NOT bw.Write(barcode);</span>
bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">'*'</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span>AsciiControlChars.<span style="color: #0600FF;">Null</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span></pre></div></div>


<p>Hope this saves someone from a forehead-slapping moment.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=6_FhNiMMCwo:FoJ7d6qIp4Y:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=6_FhNiMMCwo:FoJ7d6qIp4Y:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SimplyDoesNotWork/~4/6_FhNiMMCwo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://nicholas.piasecki.name/blog/2009/12/quick-tip-binarywriters-writestring-overload-prepends-the-binary-data-with-the-length-of-the-string/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://nicholas.piasecki.name/blog/2009/12/quick-tip-binarywriters-writestring-overload-prepends-the-binary-data-with-the-length-of-the-string/</feedburner:origLink></item>
		<item>
		<title>Dear FedEx</title>
		<link>http://feedproxy.google.com/~r/SimplyDoesNotWork/~3/CGBSo0mcQf8/</link>
		<comments>http://nicholas.piasecki.name/blog/2009/12/dear-fedex/#comments</comments>
		<pubDate>Tue, 15 Dec 2009 21:36:03 +0000</pubDate>
		<dc:creator>Nicholas Piasecki</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[fedex]]></category>
		<category><![CDATA[Rants]]></category>

		<guid isPermaLink="false">http://nicholas.piasecki.name/blog/2009/12/dear-fedex/</guid>
		<description><![CDATA[Puerto Rico is not a country.
]]></description>
			<content:encoded><![CDATA[<p>Puerto Rico is not a country.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=CGBSo0mcQf8:5Oz3uI_21jk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=CGBSo0mcQf8:5Oz3uI_21jk:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SimplyDoesNotWork/~4/CGBSo0mcQf8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://nicholas.piasecki.name/blog/2009/12/dear-fedex/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://nicholas.piasecki.name/blog/2009/12/dear-fedex/</feedburner:origLink></item>
		<item>
		<title>Sending a bit image to an Epson TM-T88III receipt printer using C# and ESC/POS</title>
		<link>http://feedproxy.google.com/~r/SimplyDoesNotWork/~3/FHKr8rYybOI/</link>
		<comments>http://nicholas.piasecki.name/blog/2009/12/sending-a-bit-image-to-an-epson-tm-t88iii-receipt-printer-using-c-and-escpos/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 01:10:40 +0000</pubDate>
		<dc:creator>Nicholas Piasecki</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[epson]]></category>
		<category><![CDATA[esc/pos]]></category>
		<category><![CDATA[interop]]></category>
		<category><![CDATA[printing]]></category>

		<guid isPermaLink="false">http://nicholas.piasecki.name/blog/?p=442</guid>
		<description><![CDATA[At Skiviez/WFS, our &#8220;low-volume fulfillment requests&#8221; (which usually simply means &#8220;retail orders&#8221;) get a simple receipt printed out via an Epson TM-T88III receipt printer.

You&#8217;ve probably seen the TM-T88III before, though the current model is the TM-T88IV&#8211;they&#8217;re ubiquitous and especially common in restaurants. We chose it because the receipt prints quickly (which reduces the probability that [...]]]></description>
			<content:encoded><![CDATA[<p>At <a href="http://www.skiviez.com/">Skiviez</a>/<a href="http://www.warehousefulfillmentservices.com/">WFS</a>, our &#8220;low-volume fulfillment requests&#8221; (which usually simply means &#8220;retail orders&#8221;) get a simple receipt printed out via an Epson TM-T88III receipt printer.</p>

<div id="attachment_456" class="wp-caption aligncenter" style="width: 187px"><a href="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/28251914.JPG"><img src="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/28251914.JPG" alt="TM-T88III Receipt Printer" title="TM-T88III Receipt Printer" width="177" height="150" class="size-full wp-image-456" /></a><p class="wp-caption-text">TM-T88III Receipt Printer</p></div>

<p>You&#8217;ve probably seen the TM-T88III before, though the current model is the TM-T88IV&#8211;they&#8217;re ubiquitous and especially common in restaurants. We chose it because the receipt prints quickly (which reduces the probability that a stack of order receipts gets missorted such that an employee puts the wrong receipt in the wrong parcel), is thermal so there is no ink to replace (which reduces the cost of consumables), uses standard thermal receipt paper (which is cheap, and we can always run out to Staples if we run out), and, perhaps most importantly, we found one in a box in the back of the warehouse.</p>

<p>At the top of the retail receipt, I print out the Skiviez logo. This is stored in a non-volatile area of memory in the printer (called NV RAM in EPSON parlance), and I dole out a command that essentially says &#8220;print out the image stored in slot #1,&#8221; having previously uploaded the bitmap via the printer driver&#8217;s flash utility. This worked great for as long as we only shipped Skiviez orders and only had one TM-T88III printer. But
with the advent of WFS, however, Skiviez now ships orders (we call them &#8220;fulfillment requests&#8221;) for multiple e-commerce stores, each requiring a different logo to appear at the top of the receipt. So I now had two options:</p>

<ul>
<li>I could manually upload the logos for all of the merchants that we ship for into all of the receipt printers that we use, making sure to upload each merchant image into the same NV memory slot for each printer.</li>
<li>I could store the merchant&#8217;s logo in our database, figure out how to use the &#8220;select bit image mode&#8221; receipt printer command, and just send the image data just-in-time whenever I generated a receipt.</li>
</ul>

<p>The second option has obvious maintenance benefits, so that&#8217;s the path I started hacking my way down.</p>

<h2>A brief primer on ESC/POS and data</h2>

<p>Like the Zebra LP2844 and its brethren, the TM-T88III comes with a Windows printer driver that allows Windows and applications to see it as any other GDI-based printer. You can print a Word document to the TM-T88III and it will print, albeit slowly, and it&#8217;ll look like crap. That&#8217;s because, as with any other GDI printer, the Word document gets rendered as a bitmap and the entire big-ass bitmap gets sent to the poor little receipt printer which then prints it 24 dots at a time. A better method is to use the printer for its intended purpose and use the native printer language to generate the receipt. This allows us to select printer fonts that are specifically designed for the printer&#8217;s resolution and speed characteristics and use other advanced features of the printer such as the paper cutter.</p>

<p>That printer language is called ESC/POS, which is entirely unpronounceable and a stupid name. The &#8220;POS&#8221; stands for &#8220;Point of Sale&#8221; since this printer belongs to a class of devices commonly known as point of sale devices&#8211;cash drawers, VFDs, barcode scanners, and the like. The &#8220;ESC&#8221; stands for &#8220;escape&#8221; because the printer treats any data that is sent to it as text&#8211;passed straight through&#8211;unless it is escaped with a special character to indicate that a command instruction follows in the input stream. The most common escape character used is the ASCII <code>ESC</code> character, and so we have &#8220;ESC/POS&#8221; as our language name.</p>

<p>If you&#8217;ve just picked up one of these printers on eBay, you may find that getting documentation on this language is hard to come by because you need to get a copy of the &#8220;ESC/POS Application Programming Guide&#8221; from your &#8220;EPSON Authorized Dealer,&#8221; whoever the hell that is. (Again, we found ours in a box in the back of the warehouse, so my &#8220;authorized dealer&#8221; is long gone.) Still, some Googling will give you more or less complete and current copies of these guides, which I&#8217;ve mirrored here. Go ahead and download them:</p>

<ul>
<li><a href='http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/ESC-POS-Command-Guide.pdf'>ESC POS Command Guide</a></li>
<li><a href='http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/ESC-POS-Programming-Guide.pdf'>ESC POS Programming Guide</a></li>
</ul>

<p>(I particularly like how the programming guide has &#8220;proprietary&#8221; and &#8220;confidential&#8221; stamped all over it and then proceeds to describe how great EPSON is for &#8220;taking initiative&#8221; for &#8220;expandability&#8221; and &#8220;universal applicability&#8221; on page 7 of the same document. You can&#8217;t make this crap up&#8211;it&#8217;s full of oxymorons.)</p>

<p>Having just come from writing in the EPL2 printer language for our Zebra LP2844 and Zebra ZP 500 Plus thermal label printers, I found the ESC/POS language to be confusing. My confusion mostly stemmed partly from the way the documentation was written and partly because I was used to the way EPL2 worked. Let&#8217;s take a look at the documentation for the bit image command that I&#8217;m trying to use:</p>

<p><a href="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/esc8.PNG"><img src="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/esc8.PNG" alt="Documentation Snipped" title="Documentation Snipped" width="345" height="90" class="aligncenter size-full wp-image-461" /></a></p>

<p>If this were EPL2, I would actually send the document as a <em>string</em> to the printer, so if a command needed the integer 33 as a parameter, I would send the string &#8220;33&#8243; (two bytes of data). In ESC/POS, each parameter is a single byte, so if I want to send 33 as a parameter for <code>m</code> in the bit image command above, then I need to send 33 in a single byte: that is, <code>0b100001</code>, which is 2<sup>5</sup> + 2<sup>0</sup> = 32 + 1 = 33.</p>

<p>The reason that this is super confusing is that other parameters in the documentation are specified to be ASCII characters, such as the &#8216;*&#8217; parameter in the bit image command above. This is because low-level programmers, such as those who designed the ESC/POS language, tend to blur the lines between data types: it&#8217;s all bytes at the end of the day. As a result, if you&#8217;re using C#, you might be tempted to use a <code>StringBuilder</code> to build up your document to send to the printer. Don&#8217;t do it! You&#8217;ll inevitably get confused by its overloads. Let&#8217;s take that <code>m = 33</code> parameter as an example:</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;">var sb <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> StringBuilder<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
<span style="color: #008080; font-style: italic;">// ASCII escape</span>
sb.<span style="color: #0000FF;">Append</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">char</span><span style="color: #000000;">&#41;</span><span style="color: #FF0000;">27</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span> 
&nbsp;
<span style="color: #008080; font-style: italic;">// ASCII '*' for the bit image command</span>
sb.<span style="color: #0000FF;">Append</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">'*'</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span> 
&nbsp;
<span style="color: #008080; font-style: italic;">// oops! this appends the string &quot;33&quot; in two bytes, doesn't work</span>
sb.<span style="color: #0000FF;">Append</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">33</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span> 
&nbsp;
<span style="color: #008080; font-style: italic;">// this is what I want, but semantically weird</span>
sb.<span style="color: #0000FF;">Append</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">char</span><span style="color: #000000;">&#41;</span><span style="color: #FF0000;">33</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span></pre></div></div>


<p>A much better and less confusing in the long run solution is to eschew any notion that we are dealing with text. Instead, let&#8217;s use the semantics that we are sending bytes of raw binary data directly to the printer:</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">using</span> <span style="color: #000000;">&#40;</span>var ms <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> MemoryStream<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
<span style="color: #0600FF;">using</span> <span style="color: #000000;">&#40;</span>var bw <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> BinaryWriter<span style="color: #000000;">&#40;</span>bw<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
     bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span>AsciiControlChars.<span style="color: #0000FF;">Escape</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
     bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">'*'</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>         <span style="color: #008080; font-style: italic;">// bit-image mode</span>
     bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">byte</span><span style="color: #000000;">&#41;</span><span style="color: #FF0000;">33</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>    <span style="color: #008080; font-style: italic;">// 24-dot double-density</span>
<span style="color: #000000;">&#125;</span></pre></div></div>


<p>But remember that cast to <code>byte</code>! Otherwise, you&#8217;ll get a C# <code>int</code>, which is <em>four</em> bytes, written to the stream, when we only wanted one. Yes, that means that any parameter that an ESC/POS command takes has a maximum value of 255.</p>

<p>You could get by on the <code>StringBuilder</code> method for a while and not have it burn you until you try the bit image command because all the characters that you&#8217;re appending happen to be less than 128&#8211;greater than that and you start getting into bytes that don&#8217;t map to a Unicode character for quirky historical reasons, such as the range 128 to 159, and you&#8217;ll be pulling your hair out as to why some of your data is getting &#8220;lost.&#8221; Just use the <code>BinaryWriter</code> method.  You can thank me later.</p>

<h2>Why is the bit image command designed this way?</h2>

<p>The <code>m</code> parameter in the bit image command as defined in the previous section has 4 values, and each value changes the way we construct the image data bytes and the way the printer interprets them. The first three values are of dubious value, so let&#8217;s throw them out for now. We&#8217;ll focus on <code>m = 33</code>, which means &#8220;24-dot double density mode.&#8221; So keep this in mind and set this aside.</p>

<p>When we think of drawing a bitmap in high level software, we usually think of drawing it pixel by pixel, left to right, top to bottom. So the order that the dots get printed as indicated by the programming guide seems strange:</p>

<p><a href="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/Capture.PNG"><img src="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/Capture.PNG" alt="Relationship between image data and the print result" title="Relationship between image data and the print result" width="200" height="226" class="aligncenter size-full wp-image-472" /></a></p>

<p>That is, the dots are rendered from top to bottom, <em>then</em> left to right.</p>

<p>Why in the blue hell do I need to rearrange my nice and neat array of bitmap data into this Connect Four scheme of dots? It all comes down to the size of the print head.</p>

<p>For our mental model, the thermal print head in the receipt printer is physically 1 dot wide by 24 dots high where there are 203 dots per inch (square pixels). It moves left to right across the receipt paper, burning up to 24 dots in the vertical (y) direction for each dot in the horizontal (x) direction.</p>

<p>Since we&#8217;re talking about a thermal printer here, there&#8217;s no concept of gray scale tones&#8211;we&#8217;ve either burned a dot into the paper (black) or we haven&#8217;t. So if we&#8217;re sending image data to the printer in bytes, it would make sense to say that a bit set to 1 means &#8220;burn a dot&#8221; and a bit set to &#8220;0&#8243; means do nothing.</p>

<p>But a byte is only 8 bits wide, and we have 24 dots to burn in each &#8220;slice&#8221; of the image. 24 just happens to be divisible by 8, so we can send 3 bytes of data for each slice to represent our 24 dots. (If the bitmap I want to draw is taller than 24 dots/pixels, then I need to send multiple bit image commands, effectively doing multiple stripes of the image that are 24 dots high; more on this later.)</p>

<p>So, now, the diagram in the programming guide makes sense: we&#8217;re not burning 1 dot at time, we&#8217;re burning a vertical stripe that is 1 dot wide and 24 dots high at a time, and then moving to the right. So our printer reads our first 3 bytes of image data, burns the dots specified by those 24 bits, then reads the next 3 bytes, and so on.</p>

<h2>Aside: Converting the bitmap to monochrome</h2>

<p>Right. So a merchant has given me a *.bmp file, and I need to convert that into array of bits that I can send to the receipt printer. It&#8217;s a good bet that the bitmap that the merchant sent me for the logo is not monochrome (that is, every pixel is either 100% black or 100% white).</p>

<p>So what we can do is look at each pixel in the bitmap, determine its <a href="http://en.wikipedia.org/wiki/Luma_%28video%29">luma</a>, and if that&#8217;s below a certain threshold, count that pixel as black. How did I write the code to do this? <a href="http://stackoverflow.com/questions/601963/reading-monochrome-bitmap-pixel-colors">I looked the formula up via the intertubes</a> and modified it to fit my needs:</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">private</span> <span style="color: #0600FF;">static</span> BitmapData GetBitmapData<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span> bmpFileName<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
    <span style="color: #0600FF;">using</span> <span style="color: #000000;">&#40;</span>var bitmap <span style="color: #008000;">=</span> <span style="color: #000000;">&#40;</span>Bitmap<span style="color: #000000;">&#41;</span>Bitmap.<span style="color: #0000FF;">FromFile</span><span style="color: #000000;">&#40;</span>bmpFileName<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
    <span style="color: #000000;">&#123;</span>
        var threshold <span style="color: #008000;">=</span> <span style="color: #FF0000;">127</span><span style="color: #008000;">;</span>
        var index <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span>
        var dimensions <span style="color: #008000;">=</span> bitmap.<span style="color: #0000FF;">Width</span> <span style="color: #008000;">*</span> bitmap.<span style="color: #0000FF;">Height</span><span style="color: #008000;">;</span>
        var dots <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> BitArray<span style="color: #000000;">&#40;</span>dimensions<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
        <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span>var y <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> y <span style="color: #008000;">&lt;</span> bitmap.<span style="color: #0000FF;">Height</span><span style="color: #008000;">;</span> y<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
        <span style="color: #000000;">&#123;</span>
            <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span>var x <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> x <span style="color: #008000;">&lt;</span> bitmap.<span style="color: #0000FF;">Width</span><span style="color: #008000;">;</span> x<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
            <span style="color: #000000;">&#123;</span>
                var color <span style="color: #008000;">=</span> bitmap.<span style="color: #0000FF;">GetPixel</span><span style="color: #000000;">&#40;</span>x, y<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
                var luminance <span style="color: #008000;">=</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#40;</span>color.<span style="color: #0000FF;">R</span> <span style="color: #008000;">*</span> <span style="color: #FF0000;">0.3</span> <span style="color: #008000;">+</span> color.<span style="color: #0000FF;">G</span> <span style="color: #008000;">*</span> <span style="color: #FF0000;">0.59</span> <span style="color: #008000;">+</span> color.<span style="color: #0000FF;">B</span> <span style="color: #008000;">*</span> <span style="color: #FF0000;">0.11</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
                dots<span style="color: #000000;">&#91;</span>index<span style="color: #000000;">&#93;</span> <span style="color: #008000;">=</span> <span style="color: #000000;">&#40;</span>luminance <span style="color: #008000;">&lt;</span> threshold<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
                index<span style="color: #008000;">++;</span>
            <span style="color: #000000;">&#125;</span>
        <span style="color: #000000;">&#125;</span>
&nbsp;
        <span style="color: #0600FF;">return</span> <span style="color: #008000;">new</span> BitmapData<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>
            <span style="color: #000000;">&#123;</span>
                Dots <span style="color: #008000;">=</span> dots,
                Height <span style="color: #008000;">=</span> bitmap.<span style="color: #0000FF;">Height</span>,
                Width <span style="color: #008000;">=</span> bitmap.<span style="color: #0000FF;">Width</span>
            <span style="color: #000000;">&#125;</span><span style="color: #008000;">;</span>
    <span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>


<p><code>BitmapData</code> is just a little struct that contains the three properties that you see here. After all, once I have my <code>BitArray</code> with <code>1</code> indicating black dots and <code>0</code> indicating white dots, I don&#8217;t need the original <code>Bitmap</code> instance anymore.</p>

<p>Just to clarify, this means that we&#8217;re holding onto a <code>BitArray</code> of monochrome data in the <code>Dots</code> property that conceptually looks something like this:</p>

<p><a href="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/Capture1.PNG"><img src="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/Capture1.PNG" alt="Conceptual Overview" title="Conceptual Overview" width="517" height="188" class="aligncenter size-full wp-image-483" /></a></p>

<h2>Marshalling the monochrome data</h2>

<p>Now for the trickiest part of all. We need to take our <code>BitArray</code> of monochrome data, divide it up into 8-dot chunks, represent those 8-dot chunks as bytes, and send them to the printer in the order required by the bit image command, discussed above. That is, I&#8217;ll need to send the data as bytes in this order:</p>

<p><a href="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/Capture2.PNG"><img src="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/Capture2.PNG" alt="Capture" title="Capture" width="394" height="509" class="aligncenter size-full wp-image-488" /></a></p>

<p>So the printer will draw them one vertical stripe of three bytes each at a time. (If you don&#8217;t get it, print out that image, cut up the bytes, and then arrange them in the order shown in the diagram from the EPSON documentation. It&#8217;ll instantly make sense once you see it.) The X&#8217;s in the diagram correspond to bits that aren&#8217;t in our original image that we have to send anyway as padding. Remember, since we selected the 24-dot double density mode, the printer is going to draw a 1 x 24 dot slice as it moves the print head. My example bitmap is only 4 pixels tall, so I have to send 20 zero bits as padding.</p>

<p>And thus we would end up with our pretty image.</p>

<p>Unfortunately, there is some math involved in translating the bits in our <code>BitArray</code> into these bytes that we need to send. Assuming <code>bw</code> is our reference to a <code>BinaryWriter</code>, here&#8217;s the code that does just that:</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #008080; font-style: italic;">// So we have our bitmap data sitting in a bit array called &quot;dots.&quot;</span>
<span style="color: #008080; font-style: italic;">// This is one long array of 1s (black) and 0s (white) pixels arranged</span>
<span style="color: #008080; font-style: italic;">// as if we had scanned the bitmap from top to bottom, left to right.</span>
<span style="color: #008080; font-style: italic;">// The printer wants to see these arranged in bytes stacked three high.</span>
<span style="color: #008080; font-style: italic;">// So, essentially, we need to read 24 bits for x = 0, generate those</span>
<span style="color: #008080; font-style: italic;">// bytes, and send them to the printer, then keep increasing x. If our</span>
<span style="color: #008080; font-style: italic;">// image is more than 24 dots high, we have to send a second bit image</span>
<span style="color: #008080; font-style: italic;">// command to draw the next slice of 24 dots in the image.</span>
&nbsp;
<span style="color: #008080; font-style: italic;">// Set the line spacing to 24 dots, the height of each &quot;stripe&quot; of the</span>
<span style="color: #008080; font-style: italic;">// image that we're drawing. If we don't do this, and we need to</span>
<span style="color: #008080; font-style: italic;">// draw the bitmap in multiple passes, then we'll end up with some</span>
<span style="color: #008080; font-style: italic;">// whitespace between slices of the image since the default line</span>
<span style="color: #008080; font-style: italic;">// height--how much the printer moves on a newline--is 30 dots.</span>
bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span>AsciiControlChars.<span style="color: #0000FF;">Escape</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">'3'</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span> <span style="color: #008080; font-style: italic;">// '3' just means 'change line height command'</span>
bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">byte</span><span style="color: #000000;">&#41;</span><span style="color: #FF0000;">24</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
<span style="color: #008080; font-style: italic;">// OK. So, starting from x = 0, read 24 bits down and send that data</span>
<span style="color: #008080; font-style: italic;">// to the printer. The offset variable keeps track of our global 'y'</span>
<span style="color: #008080; font-style: italic;">// position in the image. For example, if we were drawing a bitmap</span>
<span style="color: #008080; font-style: italic;">// that is 48 pixels high, then this while loop will execute twice,</span>
<span style="color: #008080; font-style: italic;">// once for each pass of 24 dots. On the first pass, the offset is</span>
<span style="color: #008080; font-style: italic;">// 0, and on the second pass, the offset is 24. We keep making</span>
<span style="color: #008080; font-style: italic;">// these 24-dot stripes until we've run past the height of the</span>
<span style="color: #008080; font-style: italic;">// bitmap.</span>
<span style="color: #FF0000;">int</span> offset <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span>
&nbsp;
<span style="color: #0600FF;">while</span> <span style="color: #000000;">&#40;</span>offset <span style="color: #008000;">&lt;</span> data.<span style="color: #0000FF;">Height</span><span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
    <span style="color: #008080; font-style: italic;">// The third and fourth parameters to the bit image command are</span>
    <span style="color: #008080; font-style: italic;">// 'nL' and 'nH'. The 'L' and the 'H' refer to 'low' and 'high', respectively.</span>
    <span style="color: #008080; font-style: italic;">// All 'n' really is is the width of the image that we're about to draw.</span>
    <span style="color: #008080; font-style: italic;">// Since the width can be greater than 255 dots, the parameter has to</span>
    <span style="color: #008080; font-style: italic;">// be split across two bytes, which is why the documentation says the</span>
    <span style="color: #008080; font-style: italic;">// width is 'nL' + ('nH' * 256).</span>
    bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span>AsciiControlChars.<span style="color: #0000FF;">Escape</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
    bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">'*'</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>         <span style="color: #008080; font-style: italic;">// bit-image mode</span>
    bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">byte</span><span style="color: #000000;">&#41;</span><span style="color: #FF0000;">33</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>    <span style="color: #008080; font-style: italic;">// 24-dot double-density</span>
    bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span>width<span style="color: #000000;">&#91;</span><span style="color: #FF0000;">0</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>  <span style="color: #008080; font-style: italic;">// width low byte</span>
    bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span>width<span style="color: #000000;">&#91;</span><span style="color: #FF0000;">1</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>  <span style="color: #008080; font-style: italic;">// width high byte</span>
&nbsp;
    <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> x <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> x <span style="color: #008000;">&lt;</span> data.<span style="color: #0000FF;">Width</span><span style="color: #008000;">;</span> <span style="color: #008000;">++</span>x<span style="color: #000000;">&#41;</span>
    <span style="color: #000000;">&#123;</span>
        <span style="color: #008080; font-style: italic;">// Remember, 24 dots = 24 bits = 3 bytes. </span>
        <span style="color: #008080; font-style: italic;">// The 'k' variable keeps track of which of those</span>
        <span style="color: #008080; font-style: italic;">// three bytes that we're currently scribbling into.</span>
        <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> k <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> k <span style="color: #008000;">&lt;</span> <span style="color: #FF0000;">3</span><span style="color: #008000;">;</span> <span style="color: #008000;">++</span>k<span style="color: #000000;">&#41;</span>
        <span style="color: #000000;">&#123;</span>
            <span style="color: #FF0000;">byte</span> slice <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span>
&nbsp;
            <span style="color: #008080; font-style: italic;">// A byte is 8 bits. The 'b' variable keeps track</span>
            <span style="color: #008080; font-style: italic;">// of which bit in the byte we're recording.                 </span>
            <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> b <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> b <span style="color: #008000;">&lt;</span> <span style="color: #FF0000;">8</span><span style="color: #008000;">;</span> <span style="color: #008000;">++</span>b<span style="color: #000000;">&#41;</span>
            <span style="color: #000000;">&#123;</span>
                <span style="color: #008080; font-style: italic;">// Calculate the y position that we're currently</span>
                <span style="color: #008080; font-style: italic;">// trying to draw. We take our offset, divide it</span>
                <span style="color: #008080; font-style: italic;">// by 8 so we're talking about the y offset in</span>
                <span style="color: #008080; font-style: italic;">// terms of bytes, add our current 'k' byte</span>
                <span style="color: #008080; font-style: italic;">// offset to that, multiple by 8 to get it in terms</span>
                <span style="color: #008080; font-style: italic;">// of bits again, and add our bit offset to it.</span>
                <span style="color: #FF0000;">int</span> y <span style="color: #008000;">=</span> <span style="color: #000000;">&#40;</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#40;</span>offset <span style="color: #008000;">/</span> <span style="color: #FF0000;">8</span><span style="color: #000000;">&#41;</span> <span style="color: #008000;">+</span> k<span style="color: #000000;">&#41;</span> <span style="color: #008000;">*</span> <span style="color: #FF0000;">8</span><span style="color: #000000;">&#41;</span> <span style="color: #008000;">+</span> b<span style="color: #008000;">;</span>
&nbsp;
                <span style="color: #008080; font-style: italic;">// Calculate the location of the pixel we want in the bit array.</span>
                <span style="color: #008080; font-style: italic;">// It'll be at (y * width) + x.</span>
                <span style="color: #FF0000;">int</span> i <span style="color: #008000;">=</span> <span style="color: #000000;">&#40;</span>y <span style="color: #008000;">*</span> data.<span style="color: #0000FF;">Width</span><span style="color: #000000;">&#41;</span> <span style="color: #008000;">+</span> x<span style="color: #008000;">;</span>
&nbsp;
                <span style="color: #008080; font-style: italic;">// If the image (or this stripe of the image)</span>
                <span style="color: #008080; font-style: italic;">// is shorter than 24 dots, pad with zero.</span>
                <span style="color: #FF0000;">bool</span> v <span style="color: #008000;">=</span> false<span style="color: #008000;">;</span>
                <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>i <span style="color: #008000;">&lt;</span> dots.<span style="color: #0000FF;">Length</span><span style="color: #000000;">&#41;</span>
                <span style="color: #000000;">&#123;</span>
                    v <span style="color: #008000;">=</span> dots<span style="color: #000000;">&#91;</span>i<span style="color: #000000;">&#93;</span><span style="color: #008000;">;</span>
                <span style="color: #000000;">&#125;</span>
&nbsp;
                <span style="color: #008080; font-style: italic;">// Finally, store our bit in the byte that we're currently</span>
                <span style="color: #008080; font-style: italic;">// scribbling to. Our current 'b' is actually the exact</span>
                <span style="color: #008080; font-style: italic;">// opposite of where we want it to be in the byte, so</span>
                <span style="color: #008080; font-style: italic;">// subtract it from 7, shift our bit into place in a temp</span>
                <span style="color: #008080; font-style: italic;">// byte, and OR it with the target byte to get it into there.</span>
                slice <span style="color: #008000;">|=</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">byte</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#40;</span>v <span style="color: #008000;">?</span> <span style="color: #FF0000;">1</span> <span style="color: #008000;">:</span> <span style="color: #FF0000;">0</span><span style="color: #000000;">&#41;</span> <span style="color: #008000;">&lt;&lt;</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">7</span> <span style="color: #008000;">-</span> b<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
            <span style="color: #000000;">&#125;</span>
&nbsp;
            <span style="color: #008080; font-style: italic;">// Phew! Write the damn byte to the buffer</span>
            bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span>slice<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #000000;">&#125;</span>
    <span style="color: #000000;">&#125;</span>
&nbsp;
    <span style="color: #008080; font-style: italic;">// We're done with this 24-dot high pass. Render a newline</span>
    <span style="color: #008080; font-style: italic;">// to bump the print head down to the next line</span>
    <span style="color: #008080; font-style: italic;">// and keep on trucking.</span>
    offset <span style="color: #008000;">+=</span> <span style="color: #FF0000;">24</span><span style="color: #008000;">;</span>
    bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span>AsciiControlChars.<span style="color: #0000FF;">Newline</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span>
&nbsp;
<span style="color: #008080; font-style: italic;">// Restore the line spacing to the default of 30 dots.</span>
bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span>AsciiControlChars.<span style="color: #0000FF;">Escape</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">'3'</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
bw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">byte</span><span style="color: #000000;">&#41;</span><span style="color: #FF0000;">30</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span></pre></div></div>


<p>This code looks confusing, and is, but I&#8217;ve tried to document it with explanatory comments in line.</p>

<h2>Sending the document to the printer</h2>

<p>Finally, there is the task of sending this array of bytes directly to the printer. I&#8217;ve talked about this before and the code is uninteresting, requiring some P/Invokes into native APIs. Essentially, you pass in the name of the printer as it appears in the Control Panel, the array of bytes from our <code>BinaryWriter</code>, and you&#8217;re all set:</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">private</span> <span style="color: #0600FF;">static</span> <span style="color: #0600FF;">void</span> Print<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span> printerName, <span style="color: #FF0000;">byte</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> document<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
    NativeMethods.<span style="color: #0000FF;">DOC_INFO_1</span> documentInfo<span style="color: #008000;">;</span>
    IntPtr printerHandle<span style="color: #008000;">;</span>
&nbsp;
    documentInfo <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> NativeMethods.<span style="color: #0000FF;">DOC_INFO_1</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
    documentInfo.<span style="color: #0000FF;">pDataType</span> <span style="color: #008000;">=</span> <span style="color: #666666;">&quot;RAW&quot;</span><span style="color: #008000;">;</span>
    documentInfo.<span style="color: #0000FF;">pDocName</span> <span style="color: #008000;">=</span> <span style="color: #666666;">&quot;Bit Image Test&quot;</span><span style="color: #008000;">;</span>
&nbsp;
    printerHandle <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> IntPtr<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">0</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
    <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>NativeMethods.<span style="color: #0000FF;">OpenPrinter</span><span style="color: #000000;">&#40;</span>printerName.<span style="color: #0000FF;">Normalize</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>, <span style="color: #0600FF;">out</span> printerHandle, IntPtr.<span style="color: #0000FF;">Zero</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
    <span style="color: #000000;">&#123;</span>
        <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>NativeMethods.<span style="color: #0000FF;">StartDocPrinter</span><span style="color: #000000;">&#40;</span>printerHandle, <span style="color: #FF0000;">1</span>, documentInfo<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
        <span style="color: #000000;">&#123;</span>
            <span style="color: #FF0000;">int</span> bytesWritten<span style="color: #008000;">;</span>
            <span style="color: #FF0000;">byte</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> managedData<span style="color: #008000;">;</span>
            IntPtr unmanagedData<span style="color: #008000;">;</span>
&nbsp;
            managedData <span style="color: #008000;">=</span> document<span style="color: #008000;">;</span>
            unmanagedData <span style="color: #008000;">=</span> Marshal.<span style="color: #0000FF;">AllocCoTaskMem</span><span style="color: #000000;">&#40;</span>managedData.<span style="color: #0000FF;">Length</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
            Marshal.<span style="color: #0000FF;">Copy</span><span style="color: #000000;">&#40;</span>managedData, <span style="color: #FF0000;">0</span>, unmanagedData, managedData.<span style="color: #0000FF;">Length</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
            <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>NativeMethods.<span style="color: #0000FF;">StartPagePrinter</span><span style="color: #000000;">&#40;</span>printerHandle<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
            <span style="color: #000000;">&#123;</span>
                NativeMethods.<span style="color: #0000FF;">WritePrinter</span><span style="color: #000000;">&#40;</span>
                    printerHandle,
                    unmanagedData,
                    managedData.<span style="color: #0000FF;">Length</span>,
                    <span style="color: #0600FF;">out</span> bytesWritten<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
                NativeMethods.<span style="color: #0000FF;">EndPagePrinter</span><span style="color: #000000;">&#40;</span>printerHandle<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
            <span style="color: #000000;">&#125;</span>
            <span style="color: #0600FF;">else</span>
            <span style="color: #000000;">&#123;</span>
                <span style="color: #0600FF;">throw</span> <span style="color: #008000;">new</span> Win32Exception<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
            <span style="color: #000000;">&#125;</span>
&nbsp;
            Marshal.<span style="color: #0000FF;">FreeCoTaskMem</span><span style="color: #000000;">&#40;</span>unmanagedData<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
            NativeMethods.<span style="color: #0000FF;">EndDocPrinter</span><span style="color: #000000;">&#40;</span>printerHandle<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #000000;">&#125;</span>
        <span style="color: #0600FF;">else</span>
        <span style="color: #000000;">&#123;</span>
            <span style="color: #0600FF;">throw</span> <span style="color: #008000;">new</span> Win32Exception<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #000000;">&#125;</span>
&nbsp;
        NativeMethods.<span style="color: #0000FF;">ClosePrinter</span><span style="color: #000000;">&#40;</span>printerHandle<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
    <span style="color: #000000;">&#125;</span>
    <span style="color: #0600FF;">else</span>
    <span style="color: #000000;">&#123;</span>
        <span style="color: #0600FF;">throw</span> <span style="color: #008000;">new</span> Win32Exception<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
    <span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>


<p>The P/Invoke declarations can be found in the sample code at the end of the article, and the documentation is available on MSDN. But, again, there&#8217;s nothing sexy going on here.</p>

<h2>Conclusions and delusions</h2>

<p>And that&#8217;s a wrap. I always find it interesting when I encounter a problem at work&#8211;which is a small business by any definition of the phrase&#8211;and the Google indicates that no one has ever encountered or documented this problem before. And it&#8217;s these types of integration problems that I find fascinating; after years of playing in castles in the sky, dealing with databases and exceptions and HTML forms, it&#8217;s nice to know that I can dust off the corners of my brain and my college degree and deal with bits and bytes when I need to. Writing software that makes hardware do stuff is always fun, too.</p>

<p>And after hours of watching the receipt printer spew out lines and lines of gibberish, there&#8217;s nothing like the feeling of seeing the bitmap print out and knowing that, finally, things have simply started to work.</p>

<p>Good luck!</p>

<p><a href='http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/BitImageTest.zip'>Download the code used in this article.</a></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=FHKr8rYybOI:w6zIIW3u6yQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=FHKr8rYybOI:w6zIIW3u6yQ:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SimplyDoesNotWork/~4/FHKr8rYybOI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://nicholas.piasecki.name/blog/2009/12/sending-a-bit-image-to-an-epson-tm-t88iii-receipt-printer-using-c-and-escpos/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://nicholas.piasecki.name/blog/2009/12/sending-a-bit-image-to-an-epson-tm-t88iii-receipt-printer-using-c-and-escpos/</feedburner:origLink></item>
		<item>
		<title>Thank You, Comcast</title>
		<link>http://feedproxy.google.com/~r/SimplyDoesNotWork/~3/7pXCshKY4QI/</link>
		<comments>http://nicholas.piasecki.name/blog/2009/11/thank-you-comcast/#comments</comments>
		<pubDate>Tue, 10 Nov 2009 04:00:37 +0000</pubDate>
		<dc:creator>Nicholas Piasecki</dc:creator>
				<category><![CDATA[Rants]]></category>
		<category><![CDATA[comcast-sucks]]></category>
		<category><![CDATA[it-stuff]]></category>

		<guid isPermaLink="false">http://nicholas.piasecki.name/blog/?p=427</guid>
		<description><![CDATA[There is nothing quite like dashing to work at night to restart the &#8220;SMC Comcast Business IP Gateway&#8221; because it stopped routing packets for one of our static IP addresses.

The reason? Oh, it just does that sort of thing every 25 days or so.
]]></description>
			<content:encoded><![CDATA[<p>There is nothing quite like dashing to work at night to restart the &#8220;SMC Comcast Business IP Gateway&#8221; because it stopped routing packets for one of our static IP addresses.</p>

<p>The reason? Oh, it just does that sort of thing every 25 days or so.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=7pXCshKY4QI:NKv50Gs6qpg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=7pXCshKY4QI:NKv50Gs6qpg:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SimplyDoesNotWork/~4/7pXCshKY4QI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://nicholas.piasecki.name/blog/2009/11/thank-you-comcast/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://nicholas.piasecki.name/blog/2009/11/thank-you-comcast/</feedburner:origLink></item>
		<item>
		<title>Programmatically updating software deployed via Group Policy</title>
		<link>http://feedproxy.google.com/~r/SimplyDoesNotWork/~3/HmhoQ-ASYlw/</link>
		<comments>http://nicholas.piasecki.name/blog/2009/11/programmatically-updating-software-deployed-via-group-policy/#comments</comments>
		<pubDate>Sat, 07 Nov 2009 17:38:40 +0000</pubDate>
		<dc:creator>Nicholas Piasecki</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[installation]]></category>
		<category><![CDATA[it-stuff]]></category>
		<category><![CDATA[windows installer]]></category>
		<category><![CDATA[wix]]></category>

		<guid isPermaLink="false">http://nicholas.piasecki.name/blog/?p=399</guid>
		<description><![CDATA[At work, I&#8217;ve written a small application called the &#8220;Fulfillment Manager.&#8221; From a user&#8217;s perspective, it&#8217;s an extremely simple application. It shows the current order counts for all of the stores that we ship for, and if you scan a barcode, it figures out what store that barcode belongs to, determines if the order the [...]]]></description>
			<content:encoded><![CDATA[<p>At work, I&#8217;ve written a small application called the &#8220;Fulfillment Manager.&#8221; From a user&#8217;s perspective, it&#8217;s an extremely simple application. It shows the current order counts for all of the stores that we ship for, and if you scan a barcode, it figures out what store that barcode belongs to, determines if the order the barcode corresponds to needs to be packed or shipped, and prints out a receipt/packing slip or USPS/FedEx shipping label and supporting shipping documentation automatically. Most operations involve just scanning the barcode and pressing enter.</p>

<div id="attachment_400" class="wp-caption aligncenter" style="width: 310px"><a href="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/11/fm.png"><img src="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/11/fm-300x225.png" alt="Yes, it epitomizes &quot;Battleship Grey.&quot; You love it." title="Fulfillment Manager" width="300" height="225" class="size-medium wp-image-400" /></a><p class="wp-caption-text">Yes, it epitomizes Battleship Grey. You love it.</p></div>

<p>But, behind the scenes, it&#8217;s not quite as simple as all of that. It&#8217;s aggregating order data from heterogeneous data sources&#8211;some in our legacy database, some in our new fulfillment system, some in a custom integration with a third party. It has to figure out which postage account to pay for postage with or which FedEx account number to use to ship a package. For orders that aren&#8217;t coming from <a href="http://www.warehousefulfillmentservices.com/">our new fulfillment system</a>, it has to &#8220;cleanse&#8221; the address against the current USPS address database. It has to figure out the cheapest way to ship a package, compute customs values correctly, generate certificates of origin and commercial invoices for international shipments, and determine what box types an order is allowed to be packed in. And it has to write shipment information back to one of those three disparate data sources.</p>

<p>What this means is that I&#8217;m frequently making adjustments and bug fixes to the application. And managing the deployment and installation of those bug fixes had been, up until now, a pain.</p>

<h2>A brief interlude on ClickOnce</h2>

<p>The other internal application that we use (&#8220;Undies Client&#8221;) for our <a href="http://www.skiviez.com/">long-time running e-commerce store</a> is deployed via <a href="http://en.wikipedia.org/wiki/ClickOnce">ClickOnce</a>, which is essentially the Java Web Start of the .NET world.</p>

<p>While ClickOnce is a neat technology and has its applications, to be sure, I probably wouldn&#8217;t use it again on Undies Client if I were starting that application over today, just as I decided not to use it for the Fulfillment Manager (which is an effort to divorce the processing and shipping features from Undies Client and make them simpler and applicable to multiple e-commerce stores).</p>

<p>First, there&#8217;s user confusion. If I deploy a Windows Installer MSI via Group Policy, then the application is magically there on all computers in the office. But for Undies Client, you have to go to a special Web page and click on a link. With ClickOnce, the installation happens per user, so employees can get confused if they go to another computer one day, log into their account, and see that the app isn&#8217;t there (&#8220;but Jennifer runs it on this computer so I thought it was already installed&#8221;).</p>

<p>Second, there&#8217;s deployment headaches. Like Java Web Start, you get a retarded warning if the deployment manifest wasn&#8217;t signed with an expensive code signing certificate. To mitigate that, you either buy one or start diddling with the self-signing certificate capability within the context of your own Active Directory domain. Not a show-stopper, and it makes sense, I guess, but it&#8217;s One More Thing that you have to deal with.</p>

<p>Third, when that certificate expires and needs to be renewed, <a href="http://stackoverflow.com/questions/149718/pitfalls-gotchas-of-click-once-smart-client-deployment-in-net/293503#293503">you&#8217;re in for a world of hurt</a>, because essentially all users will need to uninstall and re-visit the Web site download link and reinstall. Otherwise, the application simply stops seeing the newer updated versions and doesn&#8217;t update itself.</p>

<p>Fourth, the distribution of your app now has a dependency on an IIS installation somewhere, so that&#8217;s something else to maintain&#8211;both the configuration of that virtual directory in IIS as well as the shared drive to which Visual Studio dumps its files when clicking the &#8220;Publish&#8221; button.</p>

<p>Fifth, the installation can&#8217;t do much. Until recently, you couldn&#8217;t even create an icon on the desktop as part of the installation process. Nor can you do anything that would require elevated permissions for actions that you might typically do when running an installer, such as registering a COM DLL, or installing some third-party dependency. So the Web page at which you download the app usually contains things like &#8220;ooh be sure to install this that and the other first,&#8221; defeating the deployment simplicity of ClickOnce. And if you need to update one of those third party dependencies and your app because dependent on one of those updates, you have no way to update that dependency with ClickOnce, unless you take it upon yourself to have your application manage the upgrade during its next run. That&#8217;s just more work than you shouldn&#8217;t have to do.</p>

<p>After writing all of this, it may seem like I am saying that ClickOnce is a half-baked load of crap; it&#8217;s not half-baked. I&#8217;m saying it&#8217;s a fully-baked, complete load of crap. (Kidding. ClickOnce has its applications for applications that can be completely self-contained, but if at any point you become dependent on anything COM, it&#8217;s time to move on to real deployment technology.)</p>

<h2>Using WiX to create a Windows Installer MSI file</h2>

<p>I&#8217;ve blogged about <a href="http://wix.sourceforge.net/">WiX</a> before. It&#8217;s a great open source tool put together by some guys who decided to write a reasonable mechanism for generating Windows installers because, for some reason, the Windows installer team has seemed to think that editing database tables in a cheeseball editor called <a href="http://msdn.microsoft.com/en-us/library/aa370557%28VS.85%29.aspx">Orca</a> was sufficient. This would be like saying that our warehouse workers could ship orders by updating data in a Microsoft Excel spreadsheet.</p>

<p>You could also pay lots of money for InstallShield or something similar, which would create MSI installers for you, but installation is a convenience for <em>me</em>&#8211;as a small business whose primary focus is not end-user software, paying for that doesn&#8217;t make much sense. There&#8217;s also <a href="http://nsis.sourceforge.net/Main_Page">NSIS</a>, but, oh&#8211;I just threw up all over myself. We&#8217;ll save NSIS for another post.</p>

<p>Additionally, the WiX guys have realized that installers usually need to do useful things, like install certificates, set up Web sites in IIS, and run database scripts, whereas the Windows Installer team seems to have been trying to make writing custom actions harder, not easier, with their subsequent releases, because that&#8217;s where most of the crashes and problems in setup packages happen. With WiX, we now have a suite of well-tested custom actions that lots of people are using; this should have been the Installer team&#8217;s original response instead of depending on the community and third parties to fill in this gap for them, but it is what it is.</p>

<p>The point is that WiX enables a whole class of small business developers like me to build first-class deployment methods into their applications. With a 300-odd line XML file, the Fulfillment Manager now builds to an MSI file. And since WiX integrates with Visual Studio, I can generate that XML file as part of my build process.</p>

<p>Indeed, I&#8217;ve set up <a href="http://www.jetbrains.com/teamcity/index.html">TeamCity</a> and use this as a continuous integration server. Whenever I commit a change to Subversion, TeamCity picks up the change, compiles the solution, runs the tests, and if they pass, copies the newly generated MSI file to a network share for potential deployment. It&#8217;s pretty sweet.</p>

<p>The missing piece of the puzzle, then, is actually getting this freshly baked MSI file onto all of the client machines in the office.</p>

<h2>Deploying via the Group Policy Software Installation Extension</h2>

<p>My first instinct was to use the Group Policy Software Installation Extension. This is the thingie where when you open up a group policy in the Group Policy Management Editor, you can drill down to the Software Installation thing under Computer Configuration, specify an MSI file for deployment, and (presto!) any computers linked to that GPO will install the MSI on next boot.</p>

<p>This worked swimmingly well for the first release of Fulfillment Manager.</p>

<h3>We pause for another brief interlude on update strategies</h3>

<p>Let me explain the design of the installation for a moment. I&#8217;ve written my WiX file such that each new MSI file that it generates is a &#8220;major upgrade&#8221; in the Windows Installer parlance&#8211;it has a different product code, a different package code, and a different version number (since my version numbers are a combination of an incrementing build number and the Subversion revision number). But they all have the same upgrade code and I schedule <code>RemoveExistingProducts</code> during the install.</p>

<p>This means that if you have an older version of the Fulfillment Manager on your machine and double-click the MSI file for a newer, updated version, you don&#8217;t have to do anything&#8211;the existing version is completely uninstalled and the new version is installed on top of it.</p>

<p>The Windows Installer has support for <a href="http://msdn.microsoft.com/en-us/library/aa370037%28VS.85%29.aspx">&#8220;minor upgrades&#8221;</a> and <a href="http://msdn.microsoft.com/en-us/library/aa370037%28VS.85%29.aspx">&#8220;small updates&#8221;</a>, but I can never keep the damn things straight. Can I add a new component? Can I change a file? Can I reorganize a feature? Do I really want to be thinking about this every time I press Build in Visual Studio? My application is small, so I think it&#8217;s far easier and more reassuring to just blow away the whole thing and install again during an update, starting with a clean slate each time. In fact, I think this is a reasonable approach for many reasonably-sized applications (Paint.NET, for example, does this) and only becomes a problem when you start getting really large (such as Visual Studio or Microsoft Word).</p>

<h3>Getting the update out there</h3>

<p>OK. So all I really need to do is get all of the client computers to run <code>msiexec /i FulfillmentManager.msi</code> on the MSI and I&#8217;ll be good to go.</p>

<p>You might think that I could just overwrite the old MSI file on the network share with the new one, and the computers would notice the change at the next boot. But you would be, as I was, a fool&#8211;machines that already had the install would not notice the change and machines that did not have the install would freak out because they could not find the correct MSI file. <a href="http://serverfault.com/questions/81492/touching-software-deployment-group-policy-programmatically-or-via-script">After positing my question on ServerFault</a>, I discovered the way the Group Policy Software Installation Extension works is by creating an advertisement script (*.aas file) and referencing that script via an object sitting in the Active Directory. That LDAP entry and the script file both do annoying things like reference a specific package code and product code, both of which I change with every new build of my software. So this method is out for the count.</p>

<p>Similarly, lugging out the Group Policy Editor and trudging down to the package entry and clicking &#8220;Redeploy application&#8230;&#8221; won&#8217;t work for the reasons described above&#8211;except that it&#8217;ll break the machines that already have the software installed, too.</p>

<p>What works is lugging out the Group Policy Editor, trudging down to the package entry, clicking &#8220;Remove&#8221; and &#8220;Immediately remove&#8221;, and then adding the package right back. This creates an updated *.aas file and correspondingly updated LDAP entries, and the old LDAP entry is flagged with a &#8220;remove me now please&#8221; flag. This works, but there are three things that I don&#8217;t like about it:</p>

<ul>
<li>It&#8217;s a manual process, so I have to remember to do it every time I create a new deployable build.</li>
<li>References to all of the old versions hang around by necessity, since it&#8217;s recording the fact that &#8220;hey, if I see this particular product code then I need to uninstall it.&#8221; Indeed, upon inspecting the SYSVOL share, I saw that there about 45 of such files sitting in there since development of this app started in early July.</li>
<li>There is no way to perform this process programmatically. (Well, there is, it&#8217;s <a href="http://download.microsoft.com/download/a/e/6/ae6e4142-aa58-45c6-8dcf-a657e5900cd3/%5BMS-GPSI%5D.pdf">documented as part of the EU anti-trust settlement</a>, but let&#8217;s get real now: if it has LDAP in the spec then <a href="http://stackoverflow.com/questions/552130/what-obscure-syntax-ruined-your-day/552197#552197">I&#8217;m not touching it with a ten-foot pole</a>. Plus, this would be work that is totally tangential to my problem, which is automating a 1-minute task that ignores the crap out of me. At several days&#8217; worth of work, it&#8217;d take me a long time to climb out of that time deficit to realize any savings.)</li>
</ul>

<h2>Nirvana: Automatic updating</h2>

<p>The Software Installation extension for Group Policy can do a lot of things that I don&#8217;t need, like using patches or transforms, or shifting installed software by just moving a computer to a different OU, when at the end of the day all I really wanted was something that looked like this:</p>

<div id="attachment_404" class="wp-caption aligncenter" style="width: 282px"><a href="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/11/Install.png"><img src="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/11/Install-272x300.png" alt="Must this be so difficult?" title="Ideal Install Process" width="272" height="300" class="size-medium wp-image-404" /></a><p class="wp-caption-text">Must this be so difficult?</p></div>

<p>Since my installer will uninstall any previous versions, all I need to do is run the installation package via <code>msiexec</code>. This is easy enough to do via batch script that I&#8217;ve configured to run at startup via group policy, since those batch scripts run as SYSTEM and will have the necessary privileges to complete successfully.</p>

<p>You would think that in addition to <code>/i</code> and <code>/x</code> (and the idiotic <code>/vomus</code>), <code>msiexec</code> would have a somewhat useful parameter called, oh, I don&#8217;t know, <code>/install-it-only-if-the-damn-thing-isn't-already-installed</code>, but that would be a useful feature, so of course the Windows Installer team didn&#8217;t actually implement it.</p>

<p>Now, granted, there is actually no harm in running my installer when my app is already installed. It just would check that all the components are indeed installed and exit. But this still leaves a bad taste in my mouth. Not all MSI&#8217;s that I want to use in this way might behave like this. And, if I have any custom actions, that means that they&#8217;ll also get run on every boot, which seems like a waste.</p>

<p>While I could spelunk through the registry to try and see if I can find my current product code in the list, I&#8217;d rather not do that, because (1) that might not work consistently on all versions of Windows and (2) really, I&#8217;m just not that comfortable with batch scripts to begin with.</p>

<p>What ended up doing is writing a little command-line program called <code>msicheck</code>. The <a href="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/11/msicheck.c.txt">source file</a> is boring and decently commented. Because all of the Windows Installer APIs are in C, my utility is in C. I briefly thought about writing it in C# with some interop, because I hate C just that much, but that did seem awfully overkill for such a simple application.</p>

<p>Ah, C in Windows. I had long forgotten the days of Hungarian variable names that sound like Yosemite Sam cussing (&#8220;<code>lpszPackageVer</code>&#8220;) and the land of <code>if ("swizzle" == "swizzle")</code> returning false. Heck, I had forgotten the days of not evening having <code>false</code>! I digress; the code is probably awful, but seems to work well enough for my purposes.</p>


<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">&gt; msicheck.exe /?
&nbsp;
Determines if a given Windows Installer package is installed.
&nbsp;
msicheck package
&nbsp;
Exit Codes:
        0       Exact version installed
        1       General failure
        2       Path to MSI package not found or not accessible
        3       Error determining package status
        4       Newer version installed
        5       No version installed
        6       Older version installed</pre></div></div>


<p>All <code>msicheck</code> does is take the full path to an MSI file as an argument and returns an exit code that indicates the status of that particular package by looking at the product code and the version. (That is, if the product code is not installed, it returns 5; if the same product code is found, it compares the version and returns 0, 4, or 6.) I call it in my batch script (which, I don&#8217;t do this for a living, it&#8217;s probably retarded) like so:</p>


<div class="wp_syntax"><div class="code"><pre class="batch" style="font-family:monospace;">@ECHO OFF
&nbsp;
REM ---------------------------------------------------------------------
REM VARIABLES
REM ---------------------------------------------------------------------
&nbsp;
SET path=\\SKIVIEZSBS2008\Group Policy Installations\Fulfillment Manager\
SET package=%path%Skiviez.FulfillmentManager.Installer.WinForms.msi
SET msicheck=%path%msicheck.exe
&nbsp;
ECHO Checking installed version of Fulfillment Manager...
&nbsp;
&quot;%msicheck%&quot; &quot;%package%&quot;
&nbsp;
IF ERRORLEVEL 0 IF NOT ERRORLEVEL 1 (
	echo Fulfillment Manager is up to date.
) ELSE (
	IF ERRORLEVEL 5 (
		echo Installing latest version...
		%SYSTEMROOT%\system32\msiexec /qn /i &quot;%package%&quot;
		IF ERRORLEVEL 0 (
			echo Fulfillment Manager successfully updated.
		) ELSE (
			echo Errors may have occurred during installation.
		)
	) ELSE (
		echo Newer version installed or error occurred.
	)
)</pre></div></div>


<p>Keeping in mind that <code>IF ERRORLEVEL 5</code> evaluates to true for error levels of 5 <em>or greater</em>, this means that I call <code>msiexec</code> only if the product isn&#8217;t installed or if an older version is installed.</p>

<h2>Conclusions and Delusions</h2>

<p>So, by using a batch script and my <code>msicheck</code> utility, I have things the way I want them. I commit a change; TeamCity builds it, runs the tests, and copies the resulting MSI to the network share that is referenced in my batch script; and the batch script runs at the next boot, uses <code>msicheck</code> to note that that package is not installed, and so runs <code>msiexec</code> to install the update (which removes the old version as part of the install process).</p>

<p>It&#8217;s certainly not applicable to every software deployment scenario, much like ClickOnce, but hopefully it&#8217;ll help someone out there who wanted to do something similar.</p>

<p><a href='http://nicholas.piasecki.name/blog/wp-content/uploads/2009/11/MsiCheck.zip'>Download MsiCheck, which requires Windows Installer 4.5 to run.</a> Complete with the &#8220;works on my machine!&#8221; guarantee of absolutely no warranties.</p>

<p>Good luck!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=HmhoQ-ASYlw:zpChSUqFIWw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=HmhoQ-ASYlw:zpChSUqFIWw:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SimplyDoesNotWork/~4/HmhoQ-ASYlw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://nicholas.piasecki.name/blog/2009/11/programmatically-updating-software-deployed-via-group-policy/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://nicholas.piasecki.name/blog/2009/11/programmatically-updating-software-deployed-via-group-policy/</feedburner:origLink></item>
		<item>
		<title>Quick Tip: Fixing “Cannot reintegrate into a working copy not entirely at infinite depth” in Subversion</title>
		<link>http://feedproxy.google.com/~r/SimplyDoesNotWork/~3/O9lABdaYw5A/</link>
		<comments>http://nicholas.piasecki.name/blog/2009/10/quick-tip-fixing-cannot-reintegrate-into-a-working-copy-not-entirely-at-infinite-depth-in-subversion/#comments</comments>
		<pubDate>Wed, 28 Oct 2009 17:19:44 +0000</pubDate>
		<dc:creator>Nicholas Piasecki</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[subversion source control quick-tip]]></category>

		<guid isPermaLink="false">http://nicholas.piasecki.name/blog/?p=397</guid>
		<description><![CDATA[When attempting to re-integrate a feature branch into a trunk in my Subversion repository, I was getting a weird &#8220;Cannot reintegrate into a working copy not entirely at infinite depth&#8221; error.

To fix this, I had to fix two problems.

First, my working copy was very &#8220;old.&#8221; Like, two years of sitting on my desktop old. And [...]]]></description>
			<content:encoded><![CDATA[<p>When attempting to re-integrate a feature branch into a trunk in my Subversion repository, I was getting a weird &#8220;Cannot reintegrate into a working copy not entirely at infinite depth&#8221; error.</p>

<p>To fix this, I had to fix two problems.</p>

<p>First, my working copy was very &#8220;old.&#8221; Like, two years of sitting on my desktop old. And I had upgraded Subversion since that time. Apparently, something was not happy with this, particularly related to some new checkout option not being set. So I created a new directory and made a fresh checkout, specifying the &#8220;Fully recursive&#8221; option in TortoiseSVN.</p>

<p>When I did this, I got a new message: &#8220;Retrieval of mergeinfo unsupported.&#8221; Still an error, but different!</p>

<p>I had upgraded my Subversion server to 1.6, but I never actually upgraded my repositories to the latest version, which was created way back in 1.4. So I had been operating in a kind of backwards-compatibility mode for two years. Whoops.</p>

<p>Running <code>svnadmin upgrade c:\path\to\my\repo</code> on the server fixed this right up. I also ran the recommended <code>svn-populate-node-origins-index.exe</code> program, which I&#8217;m sure did something magical.</p>

<p>Now I can complete the merge successfully in TortoiseSVN. Hope this helps someone.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=O9lABdaYw5A:qYY9x2OkRQY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=O9lABdaYw5A:qYY9x2OkRQY:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SimplyDoesNotWork/~4/O9lABdaYw5A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://nicholas.piasecki.name/blog/2009/10/quick-tip-fixing-cannot-reintegrate-into-a-working-copy-not-entirely-at-infinite-depth-in-subversion/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://nicholas.piasecki.name/blog/2009/10/quick-tip-fixing-cannot-reintegrate-into-a-working-copy-not-entirely-at-infinite-depth-in-subversion/</feedburner:origLink></item>
		<item>
		<title>Creating sane plain text sales transactional e-mails in Magento</title>
		<link>http://feedproxy.google.com/~r/SimplyDoesNotWork/~3/kUc44C75rSY/</link>
		<comments>http://nicholas.piasecki.name/blog/2009/10/creating-sane-plain-text-sales-transactional-e-mails-in-magento/#comments</comments>
		<pubDate>Fri, 16 Oct 2009 18:30:23 +0000</pubDate>
		<dc:creator>Nicholas Piasecki</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[magento]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[templates]]></category>

		<guid isPermaLink="false">http://nicholas.piasecki.name/blog/?p=387</guid>
		<description><![CDATA[So, as I&#8217;ve described previously, we&#8217;ve set up a Magento store to clear out some of the older inventory at the company I work for: consider Men&#8217;s Underwear Discounters to be the bargain bin, Sunday! Sunday! Sunday! closeout section for Skiviez. Using a free, open source platform like Magento has saved us a lot of [...]]]></description>
			<content:encoded><![CDATA[<p>So, as <a href="http://nicholas.piasecki.name/blog/2009/10/add-avs-and-cvn-to-magentos-admin-screen-in-just-637-easy-steps/">I&#8217;ve described previously</a>, we&#8217;ve set up a Magento store to clear out some of the older inventory at the company I work for: consider <a href="http://www.mensunderweardiscounters.com/">Men&#8217;s Underwear Discounters</a> to be the bargain bin, Sunday! Sunday! Sunday! closeout section for <a href="http://www.skiviez.com">Skiviez</a>. Using a free, open source platform like Magento has saved us a lot of time and money, especially for a store that we&#8217;re not really making huge amounts of money off of anyway (it&#8217;s there to recoup the costs of products that didn&#8217;t sell well, sort of like damage control).</p>

<h2>Aside: You probably have configured your sales e-mails incorrectly</h2>

<p>I have seen three live Magento installations. I have also seen three Magento installations where sales e-mails have been customized improperly. Since it has happened three times, by the engineer&#8217;s first law of truth, it must be true that many people have been configuring the sales e-mails in their Magento stores improperly.</p>

<p>By default, all of the sales e-mails are written in less-than-stellar English and contain references to things like &#8220;Magento Demo Store&#8221; and &#8220;(555) 555-5555.&#8221; And these sales e-mail templates live by default in the <code>/app/design/frontend/default/default/template/email</code> directory.</p>

<p>If you&#8217;re like us, you made the mistake of editing these files directly, replacing the references to &#8220;Magento Demo Store&#8221; with references to your own store, like &#8220;Men&#8217;s Underwear Discounters.&#8221; And this would work fine until you, like us, apply the next security update or upgrade via Magento Connect. If they&#8217;ve updated the default template, then you can be slightly bemused that, like us, all of your sales e-mails have reverted to the defaults, and you are now thanking customers for shopping at the &#8220;Magento Demo Store.&#8221; The result? You, like us, look like an idiot.</p>

<p>What we need is a way to make sure that our e-mail customizations persist across security updates and upgrades.</p>

<p>The way to do that is to set up new copies of each and every e-mail. From the Magento Admin screen, you need to</p>

<ol>
<li>Choose System > Transactional E-mails from the menu.</li>
<li>Click &#8220;Add New Template.&#8221;</li>
<li>Under &#8220;Load default template&#8221;, select the template you would like to customize, then hit &#8220;Load Template&#8221;. The &#8220;Template Subject&#8221; and &#8220;Template Content&#8221; fields are populated with a <em>copy</em> of the template you selected.</li>
<li>Edit that template to your heart&#8217;s content, give it a name, and hit &#8220;Save Template&#8221;.</li>
<li>Under System > Configuration > Sales E-mails, be sure to select your new template instead of &#8220;Default from locale&#8221;.</li>
</ol>

<p>Hooray! Now the changes that we make will stick around.</p>

<h2>Formatting those e-mails as plain text</h2>

<p>For Skiviez proper, we send multipart e-mails, where both HTML- and text-formatted messages are sent within the same e-mail. This works great because, depending on the customer&#8217;s preference and e-mail capabilities, they can view the e-mail in the format that they prefer.</p>

<p>Unfortunately, Magento doesn&#8217;t (at the time of this writing) have the capability for these multipart e-mails. Instead, you get to choose between HTML (the default) and plain text. I decided to go with plain text because</p>

<ul>
<li>I had seen issues on the forums where the HTML e-mails have problems displaying in some Web-based e-mail clients; and</li>
<li>Nothing pisses me off more than HTML e-mail. I don&#8217;t know why. I just hate it.</li>
</ul>

<p>Converting most of the e-mails to plain text is straight-forward; you just hit the &#8220;Convert to Plain Text&#8221; button and then reformat the template content so that it is not hideous. But when you get to the order e-mail, you&#8217;ll discover that some of the variables and references are returning the content in HTML; particularly, the address, payment, and item summary fields.</p>

<p>You could do something like changing the reference from</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#123;</span> <span style="color: #000000; font-weight: bold;">var</span> order<span style="color: #339933;">.</span>getBillingAddress<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span>format<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'html'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#125;</span></pre></div></div>


<p>to</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#123;</span> <span style="color: #000000; font-weight: bold;">var</span> order<span style="color: #339933;">.</span>getBillingAddress<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span>format<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'text'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#125;</span></pre></div></div>


<p>and that would work, but the output would not be what you expect:</p>


<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">&nbsp;
Nicholas Piasecki
&nbsp;
3005 Some Street
&nbsp;
&nbsp;
&nbsp;
Sillytown,  California, 92683
United States
T: 5555555555</pre></div></div>


<p>That is, if an element in the address is empty, it still receives a blank space, so you end up with the odd address formatting that you see in the above example.</p>

<p>You could then spend an hour and a half just trying to figure out what that magic <code>-&gt;format('html')</code> or <code>-&gt;format('text')</code> call actually does and where it&#8217;s coming from. That is an adventure in and of itself, but to make a long story short, there is a <code>config.xml</code> file in the <code>/app/code/core/Mage/Customer/etc/</code> directory that contains entries like the following:</p>


<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">                    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;text</span> <span style="color: #000066;">translate</span>=<span style="color: #ff0000;">&quot;title&quot;</span> <span style="color: #000066;">module</span>=<span style="color: #ff0000;">&quot;customer&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Text<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;defaultFormat<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><span style="color: #339933;">&lt;![CDATA[</span>
<span style="color: #339933;">{{depend prefix}}{{var prefix}} {{/depend}}{{var firstname}} {{depend middlename}}{{var middlename}} {{/depend}}{{var lastname}}{{depend suffix}} {{var suffix}}{{/depend}}</span>
<span style="color: #339933;">{{depend company}}{{var company}}{{/depend}}</span>
<span style="color: #339933;">{{var street1}}</span>
<span style="color: #339933;">{{depend street2}}{{var street2}}{{/depend}}</span>
<span style="color: #339933;">{{depend street3}}{{var street3}}{{/depend}}</span>
<span style="color: #339933;">{{depend street4}}{{var street4}}{{/depend}}</span>
<span style="color: #339933;">{{depend city}}{{var city}},  {{/depend}}{{depend region}}{{var region}}, {{/depend}}{{var postcode}}</span>
<span style="color: #339933;">{{var country}}</span>
<span style="color: #339933;">T: {{var telephone}}</span>
<span style="color: #339933;">{{depend fax}}F: {{var fax}}{{/depend}}</span>
<span style="color: #339933;">                        ]]&gt;</span><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/defaultFormat<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/text<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;oneline</span> <span style="color: #000066;">translate</span>=<span style="color: #ff0000;">&quot;title&quot;</span> <span style="color: #000066;">module</span>=<span style="color: #ff0000;">&quot;customer&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Text One Line<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;htmlEscape<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>true<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/htmlEscape<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;defaultFormat<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #339933;">&lt;![CDATA[{{depend prefix}}{{var prefix}} {{/depend}}{{var firstname}} {{depend middlename}}{{var middlename}} {{/depend}}{{var lastname}}{{depend suffix}} {{var suffix}}{{/depend}}, {{var street}}, {{var city}}, {{var region}} {{var postcode}}, {{var country}}]]&gt;</span>
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/defaultFormat<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/oneline<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;html</span> <span style="color: #000066;">translate</span>=<span style="color: #ff0000;">&quot;title&quot;</span> <span style="color: #000066;">module</span>=<span style="color: #ff0000;">&quot;customer&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>HTML<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;htmlEscape<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>true<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/htmlEscape<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;defaultFormat<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><span style="color: #339933;">&lt;![CDATA[</span>
<span style="color: #339933;">{{depend prefix}}{{var prefix}} {{/depend}}{{var firstname}} {{depend middlename}}{{var middlename}} {{/depend}}{{var lastname}}{{depend suffix}} {{var suffix}}{{/depend}}&lt;br/&gt;</span>
<span style="color: #339933;">{{depend company}}{{var company}}&lt;br /&gt;{{/depend}}</span>
<span style="color: #339933;">{{var street1}}&lt;br /&gt;</span>
<span style="color: #339933;">{{depend street2}}{{var street2}}&lt;br /&gt;{{/depend}}</span>
<span style="color: #339933;">{{depend street3}}{{var street3}}&lt;br /&gt;{{/depend}}</span>
<span style="color: #339933;">{{depend street4}}{{var street4}}&lt;br /&gt;{{/depend}}</span>
<span style="color: #339933;">{{depend city}}{{var city}},  {{/depend}}{{depend region}}{{var region}}, {{/depend}}{{var postcode}}&lt;br/&gt;</span>
<span style="color: #339933;">{{var country}}&lt;br/&gt;</span>
<span style="color: #339933;">{{depend telephone}}T: {{var telephone}}{{/depend}}</span>
<span style="color: #339933;">{{depend fax}}&lt;br/&gt;F: {{var fax}}{{/depend}}</span>
<span style="color: #339933;">            ]]&gt;</span><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/defaultFormat<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>


<p>Once you stumble across that, it&#8217;s not so difficult to figure out what is going on. The Magento address object returns a <code>Varien_Filter_Template</code> object that takes one of the above <code>defaultFormat</code> entries as its template based on the parameter that you pass into the <code>format()</code> function. So you can see that valid parameters are &#8216;html&#8217;, &#8216;text&#8217;, &#8216;oneline&#8217;, and so on.</p>

<p>The <code>{{depend}}</code> syntax means that if the enclosed variable is empty, then that output won&#8217;t appear. For HTML, this works fine, since newlines aren&#8217;t signficant. But for the <code>text</code> template, this doesn&#8217;t work, because even though things like <code>{{street2}}</code> get omitted, the newline is still sitting there in the template. This is why we get the fugly output in our plain text e-mails.</p>

<p>My solution is to define my own block that I just reference in my e-mails. Here&#8217;s the e-mail template for Men&#8217;s Underwear Discounters, for example:</p>


<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">Dear {{var order.getCustomerName()}},
&nbsp;
Thank you for your order from Men's Underwear Discounters.
Once your package ships, we will send an email with a link 
to track your order. You can check the status of your order
by logging into your account.
&nbsp;
If you have any questions about your order please contact
us at support@mensunderweardiscounters.com.
&nbsp;
Your order confirmation is below. Thank you again for your 
business.
&nbsp;
ORDER {{var order.increment_id}} 
&nbsp;
Placed on {{var order.getCreatedAtFormated('long')}}
&nbsp;
BILLING INFORMATION
&nbsp;
{{block type='core/template' area='frontend' template='email/order/addresstext.phtml' address=$order.getBillingAddress()}}
&nbsp;
SHIPPING INFORMATION
&nbsp;
{{block type='core/template' area='frontend' template='email/order/addresstext.phtml' address=$order.getShippingAddress()}}
&nbsp;
via {{var order.getShippingDescription()}}
&nbsp;
ORDER DETAILS
&nbsp;
{{block type='core/template' area='frontend' template='email/order/itemstext.phtml' order=$order}} 
&nbsp;
Thanks for shopping at Men's Underwear Discounters.
&nbsp;
Sincerely,
The Men's Underwear Discounters Team
support@mensunderweardiscounters.com</pre></div></div>


<p>If you compare this with the default e-mails, you can see that I&#8217;ve added these new <code>{{block}}</code> entries in several places. All they are saying is &#8220;hey, create a new static block with the file at <code>/app/design/frontend/default/default/template/email/order/itemstext.phtml</code> (or <code>addresstext.phtml</code>) and pass a variable into it. Whatever variable I pass in here will be accessible in the .phtml file by referencing <code>$this-&gt;getWhatever()</code>, where &#8220;Whatever&#8221; is the name of the parameter. For example, my <code>itemstext.phtml</code> file could reference <code>$this-&gt;getOrder()</code> and my <code>addresstext.phtml</code> file could reference <code>$this-&gt;getAddress()</code>.</p>

<p>These &#8220;itemstext.phtml&#8221; and &#8220;addresstext.phtml&#8221; files don&#8217;t exist in the default installation. I had to create them and FTP them to that appropriate directory. The contents aren&#8217;t exotic; they&#8217;re just PHP files that emit output that&#8217;s suitable for dropping into a plain text e-mail.</p>

<p>Here&#8217;s the <code>itemstext.phtml</code> file:</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
	<span style="color: #000088;">$order</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getOrder</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$order</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$order</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getAllItems</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$item</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getParentItem</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#123;</span>
				<span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
&nbsp;
			<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'('</span><span style="color: #339933;">;</span>
			<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getQtyOrdered</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
			<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">')'</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">' '</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">' @ '</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #b1b100;">echo</span> <span style="color: #990000;">number_format</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getPrice</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">' ea = '</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #b1b100;">echo</span> <span style="color: #990000;">number_format</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRowTotal</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'Subtotal: $'</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">echo</span> <span style="color: #990000;">number_format</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$order</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getSubtotal</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'Discount: $'</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">echo</span> <span style="color: #990000;">number_format</span><span style="color: #009900;">&#40;</span><span style="color:#800080;">0.00</span> <span style="color: #339933;">-</span> <span style="color: #000088;">$order</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getDiscountAmount</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'Shipping &amp; Handling: $'</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">echo</span> <span style="color: #990000;">number_format</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$order</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getShippingAmount</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'Tax: $'</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">echo</span> <span style="color: #990000;">number_format</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$order</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getTaxAmount</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'Grand Total: $'</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">echo</span> <span style="color: #990000;">number_format</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$order</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getGrandTotal</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>


<p>And here&#8217;s the <code>addresstext.html</code> file:</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
	<span style="color: #000088;">$address</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getAddress</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$address</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getPrefix</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getPrefix</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">' '</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getFirstname</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getMiddlename</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">' '</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getMiddlename</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">' '</span><span style="color: #339933;">.</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getLastname</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getSuffix</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">' '</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getSuffix</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCompany</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCompany</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStreet1</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStreet2</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStreet2</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStreet3</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStreet3</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStreet4</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStreet4</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCity</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCity</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">', '</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRegion</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRegion</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">' '</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getPostcode</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCountry</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getTelephone</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'T: '</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$address</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getTelephone</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>


<h2>Conclusions and delusions</h2>

<p>This story has been typical of my experiences with Magento. I eventually end up finding something that was thoughtfully designed (if slightly overarchitected), but poor documentation and difficulty testing impede progress more than necessary. Let&#8217;s hope that this gets better in future versions of the framework.</p>

<p>Good luck.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=kUc44C75rSY:xsFmgQHajj0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=kUc44C75rSY:xsFmgQHajj0:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SimplyDoesNotWork/~4/kUc44C75rSY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://nicholas.piasecki.name/blog/2009/10/creating-sane-plain-text-sales-transactional-e-mails-in-magento/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://nicholas.piasecki.name/blog/2009/10/creating-sane-plain-text-sales-transactional-e-mails-in-magento/</feedburner:origLink></item>
		<item>
		<title>Controlling the location of the soft input panel in NETCF</title>
		<link>http://feedproxy.google.com/~r/SimplyDoesNotWork/~3/KXKlu7zCyh0/</link>
		<comments>http://nicholas.piasecki.name/blog/2009/10/controlling-the-location-of-the-soft-input-panel-in-netcf/#comments</comments>
		<pubDate>Mon, 12 Oct 2009 20:27:16 +0000</pubDate>
		<dc:creator>Nicholas Piasecki</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[honeywell]]></category>
		<category><![CDATA[interop]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[netcf]]></category>

		<guid isPermaLink="false">http://nicholas.piasecki.name/blog/?p=378</guid>
		<description><![CDATA[One of the pieces of WFS is an application that I&#8217;ve written that runs on our Honeywell Dolphin 7600. The Dolphin is a little mobile device than runs Windows CE 5.0, has 802.11g access, and has a barcode scanner. The application that I&#8217;ve written allows a warehouse employee to pick fulfillment requests, scan in inbound [...]]]></description>
			<content:encoded><![CDATA[<p>One of the pieces of <a href="http://www.warehousefulfillmentservices.com/">WFS</a> is an application that I&#8217;ve written that runs on our <a href="http://www.honeywellaidc.com/Site.aspx/na/en/product_center/hardware/?product=246">Honeywell Dolphin 7600</a>. The Dolphin is a little mobile device than runs Windows CE 5.0, has 802.11g access, and has a barcode scanner. The application that I&#8217;ve written allows a warehouse employee to pick fulfillment requests, scan in inbound shipments against a previously recorded manifest, and process any returns that customers have sent back. Pretty neat stuff.</p>

<p><a href="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/10/CAPT0001.BMP"><img src="http://nicholas.piasecki.name/blog/wp-content/uploads/2009/10/CAPT0001.BMP" alt="Big text, big buttons, and easy keyboard navigation." title="User Interface" class="aligncenter size-full wp-image-379" /></a></p>

<p>I&#8217;ve designed most of the interface so that it can be used with just the big green &#8220;SCAN&#8221; button and the numeric keypad, since it&#8217;s cumbersome to bust out a stylus and use two hands while using it in the warehouse. There are, however, a few cases where the user does need to type something in, typically via the soft input panel, which is the stupid Microsoft name for the on-screen keyboard. Examples where the on-screen keyboard are necessary include typing in a merchant&#8217;s identifier for an inbound shipment manifest or typing in a user name and password to sign into the application.</p>

<p>By default, the soft input panel displays &#8220;whereever it feels like,&#8221; typically at the bottom of the screen or whatever random location the user last left it in, and while the user can drag it out of the way with the stylus if it obstructs UI elements, I thought it would be nice if I showed, hid, and positioned the soft input panel automatically when necessary. For example, if the user focuses a textbox where I expect they&#8217;ll need to type in some text, I&#8217;ll pop up the soft input panel and position it automatically just underneath that textbox.</p>

<p>If you load up Visual Studio, you&#8217;ll see the <code>Microsoft.WindowsCE.Forms.InputPanel</code> available in the toolbox. But it doesn&#8217;t provide any way to position the input panel once it is displayed. For that, I had to P/Invoke into a native method.</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
<span style="color: #008080; font-style: italic;">/// Shows the input panel relative to the given control.</span>
<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
<span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;control&quot;&gt;The control.&lt;/param&gt;</span>
<span style="color: #0600FF;">private</span> <span style="color: #0600FF;">void</span> ShowInputPanel<span style="color: #000000;">&#40;</span>Control control<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	NativeMethods.<span style="color: #0000FF;">SIPINFO</span> sipInfo<span style="color: #008000;">;</span>
	var x <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span>
	var y <span style="color: #008000;">=</span> control.<span style="color: #0000FF;">PointToScreen</span><span style="color: #000000;">&#40;</span><span style="color: #008000;">new</span> Point<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">0</span>, control.<span style="color: #0000FF;">Height</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">Y</span><span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">inputPanel</span>.<span style="color: #0000FF;">Enabled</span> <span style="color: #008000;">=</span> true<span style="color: #008000;">;</span>
&nbsp;
	sipInfo <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> NativeMethods.<span style="color: #0000FF;">SIPINFO</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	sipInfo.<span style="color: #0000FF;">cbSize</span> <span style="color: #008000;">=</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">uint</span><span style="color: #000000;">&#41;</span>Marshal.<span style="color: #008000;">SizeOf</span><span style="color: #000000;">&#40;</span>sipInfo<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	<span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>NativeMethods.<span style="color: #0000FF;">SipGetInfo</span><span style="color: #000000;">&#40;</span><span style="color: #0600FF;">ref</span> sipInfo<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
	<span style="color: #000000;">&#123;</span>
		sipInfo.<span style="color: #0000FF;">rcSipRect</span>.<span style="color: #0000FF;">left</span> <span style="color: #008000;">=</span> x<span style="color: #008000;">;</span>
		sipInfo.<span style="color: #0000FF;">rcSipRect</span>.<span style="color: #0000FF;">top</span> <span style="color: #008000;">=</span> y<span style="color: #008000;">;</span>
&nbsp;
		NativeMethods.<span style="color: #0000FF;">SipSetInfo</span><span style="color: #000000;">&#40;</span><span style="color: #0600FF;">ref</span> sipInfo<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	<span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>


<p>The above method simply takes an instance of a <code>Control</code> on the form and shows the soft input panel right underneath it. The input panel is shown by setting <code>Enabled</code> to <code>true</code>; it&#8217;s the <code>SipSetInfo()</code> call that actually positions it. Since our screen is super tiny, I only worry about the <code>y</code> coordinate; no sense in positioning in the horizontal direction because otherwise I&#8217;d crop off part of the input panel from view. The <code>NativeMethods</code> class is where I dump all of my P/Invoke declarations:</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
<span style="color: #008080; font-style: italic;">/// This structure contains information about the current state of the </span>
<span style="color: #008080; font-style: italic;">/// software-based input panel, such as the software-based input panel </span>
<span style="color: #008080; font-style: italic;">/// size, screen location, docked status, and visibility status.</span>
<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
<span style="color: #000000;">&#91;</span>StructLayout<span style="color: #000000;">&#40;</span>LayoutKind.<span style="color: #0000FF;">Sequential</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span>
<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">struct</span> SIPINFO
<span style="color: #000000;">&#123;</span>
	<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
	<span style="color: #008080; font-style: italic;">/// Size, in bytes, of the SIPINFO structure. This member must be </span>
	<span style="color: #008080; font-style: italic;">/// filled in by the application with the size of operator. Because</span>
	<span style="color: #008080; font-style: italic;">/// the system can check the size of the structure to determine </span>
	<span style="color: #008080; font-style: italic;">/// the operating system version number, this member allows for</span>
	<span style="color: #008080; font-style: italic;">/// future enhancements to the SIPINFO structure while maintaining </span>
	<span style="color: #008080; font-style: italic;">/// backward compatibility.</span>
	<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
	<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">uint</span> cbSize<span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
	<span style="color: #008080; font-style: italic;">/// Specifies flags representing state information of the </span>
	<span style="color: #008080; font-style: italic;">/// software-based input panel. The following table shows the</span>
	<span style="color: #008080; font-style: italic;">/// possible bit flags. These flags can be used in combination. </span>
	<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
	<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">uint</span> fdwFlags<span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
	<span style="color: #008080; font-style: italic;">/// Rectangle, in screen coordinates, that represents the area of </span>
	<span style="color: #008080; font-style: italic;">/// the desktop not obscured by the software-based input panel. </span>
	<span style="color: #008080; font-style: italic;">/// If the software-based input panel is floating, this rectangle </span>
	<span style="color: #008080; font-style: italic;">/// is equivalent to the working area. Full-screen applications </span>
	<span style="color: #008080; font-style: italic;">/// that respond to software-based input panel size changes can </span>
	<span style="color: #008080; font-style: italic;">/// set their window rectangle to this rectangle. If the</span>
	<span style="color: #008080; font-style: italic;">/// software-based input panel is docked but does not occupy </span>
	<span style="color: #008080; font-style: italic;">/// an entire edge, then this rectangle represents the largest </span>
	<span style="color: #008080; font-style: italic;">/// rectangle not obscured by the software-based input panel. </span>
	<span style="color: #008080; font-style: italic;">/// If an application wants to use the screen space around the</span>
	<span style="color: #008080; font-style: italic;">/// software-based input panel, it needs to reference rcSipRect.</span>
	<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
	<span style="color: #0600FF;">public</span> RECT rcVisibleDesktop<span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
	<span style="color: #008080; font-style: italic;">/// Rectangle, in screen coordinates of the window rectangle and </span>
	<span style="color: #008080; font-style: italic;">/// not the client area, the represents the size and location of </span>
	<span style="color: #008080; font-style: italic;">/// the software-based input panel. An application does not</span>
	<span style="color: #008080; font-style: italic;">/// generally use this information unless it needs to wrap</span>
	<span style="color: #008080; font-style: italic;">/// around a floating or a docked software-based input panel </span>
	<span style="color: #008080; font-style: italic;">/// that does not occupy an entire edge.</span>
	<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
	<span style="color: #0600FF;">public</span> RECT rcSipRect<span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
	<span style="color: #008080; font-style: italic;">/// Specifies the size of the data pointed to by the pvImData member.</span>
	<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
	<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">uint</span> dwImDataSize<span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
	<span style="color: #008080; font-style: italic;">/// Void pointer to IM-defined data. The IM calls the</span>
	<span style="color: #008080; font-style: italic;">/// IInputMethod::GetImData and IInputMethod::SetImData methods to</span>
	<span style="color: #008080; font-style: italic;">/// send and receive information from this structure.</span>
	<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
	<span style="color: #0600FF;">public</span> IntPtr pvImData<span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span>
&nbsp;
<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
<span style="color: #008080; font-style: italic;">/// This structure defines the coordinates of the upper-left and</span>
<span style="color: #008080; font-style: italic;">/// lower-right corners of a rectangle. </span>
<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
<span style="color: #000000;">&#91;</span>StructLayout<span style="color: #000000;">&#40;</span>LayoutKind.<span style="color: #0000FF;">Sequential</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span>
<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">struct</span> RECT
<span style="color: #000000;">&#123;</span>
	<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
	<span style="color: #008080; font-style: italic;">/// Specifies the x-coordinate of the upper-left corner of the rectangle. </span>
	<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
	<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">int</span> left<span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
	<span style="color: #008080; font-style: italic;">/// Specifies the y-coordinate of the upper-left corner of the rectangle. </span>
	<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
	<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">int</span> top<span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
	<span style="color: #008080; font-style: italic;">/// Specifies the x-coordinate of the lower-right corner of the rectangle. </span>
	<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
	<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">int</span> right<span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
	<span style="color: #008080; font-style: italic;">/// Specifies the y-coordinate of the lower-right corner of the rectangle. </span>
	<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
	<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">int</span> bottom<span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span>
&nbsp;
<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
<span style="color: #008080; font-style: italic;">/// This function receives information including the state of the</span>
<span style="color: #008080; font-style: italic;">/// software-based input panel, the area of the desktop that is not </span>
<span style="color: #008080; font-style: italic;">/// obscured by the software-based input panel, the screen coordinates</span>
<span style="color: #008080; font-style: italic;">/// of the software-based input panel, and information about the input </span>
<span style="color: #008080; font-style: italic;">/// method (IM) that the software-based input panel is currently using.</span>
<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
<span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;sipInfo&quot;&gt;[out] Pointer to the SIPINFO structure that</span>
<span style="color: #008080; font-style: italic;">/// contains information about the current software-based input panel.&lt;/param&gt;</span>
<span style="color: #008080; font-style: italic;">/// &lt;returns&gt;TRUE indicates success. FALSE indicates failure. To get </span>
<span style="color: #008080; font-style: italic;">/// extended error information, call GetLastError. &lt;/returns&gt;</span>
<span style="color: #000000;">&#91;</span>DllImport<span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;coredll.dll&quot;</span>, SetLastError <span style="color: #008000;">=</span> <span style="color: #0600FF;">true</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span>
<span style="color: #000000;">&#91;</span><span style="color: #0600FF;">return</span><span style="color: #008000;">:</span> MarshalAs<span style="color: #000000;">&#40;</span>UnmanagedType.<span style="color: #FF0000;">Bool</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span>
<span style="color: #0600FF;">public</span> <span style="color: #0600FF;">static</span> <span style="color: #0600FF;">extern</span> <span style="color: #FF0000;">bool</span> SipGetInfo<span style="color: #000000;">&#40;</span>
	<span style="color: #0600FF;">ref</span> SIPINFO sipInfo<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
<span style="color: #008080; font-style: italic;">/// This function sets information including the state of the </span>
<span style="color: #008080; font-style: italic;">/// software-based input panel, the area of the desktop that is not </span>
<span style="color: #008080; font-style: italic;">/// obscured by the software-based input panel, the screen coordinates </span>
<span style="color: #008080; font-style: italic;">/// of the software-based input panel, and application-defined information</span>
<span style="color: #008080; font-style: italic;">/// about the input method (IM) that the software-based input panel is</span>
<span style="color: #008080; font-style: italic;">/// currently using.</span>
<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
<span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;sipInfo&quot;&gt;ointer to the SIPINFO structure that contains</span>
<span style="color: #008080; font-style: italic;">/// information about the current software-based input panel.&lt;/param&gt;</span>
<span style="color: #008080; font-style: italic;">/// &lt;returns&gt;TRUE indicates success. FALSE indicates failure. </span>
<span style="color: #008080; font-style: italic;">/// To get extended error information, call GetLastError. &lt;/returns&gt;</span>
<span style="color: #000000;">&#91;</span>DllImport<span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;coredll.dll&quot;</span>, SetLastError <span style="color: #008000;">=</span> <span style="color: #0600FF;">true</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span>
<span style="color: #000000;">&#91;</span><span style="color: #0600FF;">return</span><span style="color: #008000;">:</span> MarshalAs<span style="color: #000000;">&#40;</span>UnmanagedType.<span style="color: #FF0000;">Bool</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span>
<span style="color: #0600FF;">public</span> <span style="color: #0600FF;">static</span> <span style="color: #0600FF;">extern</span> <span style="color: #FF0000;">bool</span> SipSetInfo<span style="color: #000000;">&#40;</span>
	<span style="color: #0600FF;">ref</span> SIPINFO sipInfo<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span></pre></div></div>


<p>Yes, they really did call it &#8220;coredll.dll&#8221;.</p>

<p>You can imagine how calling these methods is now pretty simple. Assume that these methods are attached to the <code>GotFocus</code> and <code>LostFocus</code> events of a <code>TextBox</code> control:</p>


<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
<span style="color: #008080; font-style: italic;">/// Fired when the user name textbox gets focus.</span>
<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
<span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;sender&quot;&gt;The sender.&lt;/param&gt;</span>
<span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;e&quot;&gt;The &lt;see cref=&quot;System.EventArgs&quot;/&gt; instance </span>
<span style="color: #008080; font-style: italic;">/// containing the event data.&lt;/param&gt;</span>
<span style="color: #0600FF;">private</span> <span style="color: #0600FF;">void</span> WhenUserNameGotFocus<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">object</span> sender, EventArgs e<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	<span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">ShowInputPanel</span><span style="color: #000000;">&#40;</span><span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">userNameTextBox</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span>
&nbsp;
<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
<span style="color: #008080; font-style: italic;">/// Fired when the user name textbox loses focus.</span>
<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
<span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;sender&quot;&gt;The sender.&lt;/param&gt;</span>
<span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;e&quot;&gt;The &lt;see cref=&quot;System.EventArgs&quot;/&gt; instance </span>
<span style="color: #008080; font-style: italic;">/// containing the event data.&lt;/param&gt;</span>
<span style="color: #0600FF;">private</span> <span style="color: #0600FF;">void</span> WhenUserNameLostFocus<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">object</span> sender, EventArgs e<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	<span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">HideInputPanel</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>


<p>I&#8217;ve only tested this on our Windows CE 5.0-based device, but I imagine that it&#8217;d work on any later platform that was supported by the <code>InputPanel</code> control. Good luck!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=KXKlu7zCyh0:ph0dWaYX-2Y:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?a=KXKlu7zCyh0:ph0dWaYX-2Y:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/SimplyDoesNotWork?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SimplyDoesNotWork/~4/KXKlu7zCyh0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://nicholas.piasecki.name/blog/2009/10/controlling-the-location-of-the-soft-input-panel-in-netcf/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://nicholas.piasecki.name/blog/2009/10/controlling-the-location-of-the-soft-input-panel-in-netcf/</feedburner:origLink></item>
	</channel>
</rss>
