<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://www.atalasoft.com/cs/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Atalasoft Community</title><link>http://www.atalasoft.com/cs/blogs/default.aspx</link><description /><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Beauty is only Skin-Deep: Skinning your WinForms Application</title><link>http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/09/beauty-is-only-skin-deep-skinning-your-winforms-application.aspx</link><pubDate>Fri, 09 May 2008 15:00:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13951</guid><dc:creator>jacobl</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;We all want our Windows applications to stand out, and I think most people would like to believe that there are a few distinct approaches to achieving this. You can either have an app that does great things, one that does things great, or one that does things while looking great. The ideal approach is to combine all three and make great applications that do things very well while looking amazing. The first impression is everything, right? So this post is all about how to skin your application. While I can't turn you into Monet, I can show you what a paint brush looks like.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Eat Your Cake Without Having to Wait for Your Oven to Preheat&lt;br&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;There are toolkits out there that allow you to skin your apps very easily like &lt;a href="http://www.dotnetskin.net/" target="_blank"&gt;DotNetSkin&lt;/a&gt; or &lt;a href="http://www.sunisoft.com/" target="_blank"&gt;Sunisoft's IrisSkin&lt;/a&gt;, but most of them cost money and all you might want to do is change a few things without overhauling everything that is Windows UI.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Replacing Your Lamp Because Your Light Bulb Burnt Out&lt;/b&gt;&lt;br&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;i&gt;Alek Trebec - "Answer: All the things that make windows behave like windows."&lt;br&gt;&lt;/i&gt; &lt;/p&gt;

&lt;p&gt;&lt;i&gt;Contestant - "What are 'things I took for granted'?"&amp;nbsp;&lt;/i&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p class="MsoPlainText"&gt;&lt;img src="http://www.atalasoft.com/cs/photos/jacobs_blog_photos/images/13960/original.aspx" align="left" height="298" hspace="10" width="301"&gt;Just a forewarning: you are opening somewhat of a can of
worms here; albeit a small one. When you skin an app, there will be many things
that you got for free before but will now have to do yourself. Window-close,
-minimize, and -maximize are gone but easy enough to correct.&lt;span&gt; &lt;/span&gt;&lt;/p&gt;

&lt;p class="MsoPlainText"&gt;Window dragging requires a little bit of finesse and
window resizing requires a bit more. I'll explain all that with sample code
below, but first, let's talk about getting rid of that awful XP-blue menu-bar.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Removing the Menu-Bar&lt;/b&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.atalasoft.com/cs/photos/jacobs_blog_photos/images/13962/original.aspx" align="right" height="123" hspace="10" width="133"&gt;After you have your project set up and are looking at your form in design-time. Open the &lt;u&gt;Properties&lt;/u&gt; pane form the main form object. Here, you need to find the Appearance labeled "FormBorderStyle". Change it from "Sizable" to "None". You will notice that in the design, your top menu bar and the border of the window are now gone! Excellent, a clean slate.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Readding Basic Window Controls&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;You can add all or none of these, but I suggest (for the sake of your users) that you at least add a close button. Here's what you do. &lt;/p&gt;

&lt;p&gt;&lt;u&gt;Close&lt;/u&gt; &lt;br&gt;&lt;/p&gt;

&lt;p&gt;Create a button in the upper right hand corner of your form; the location is by convention, you can put it anywhere you'd like of course. Change the name of the button to closeButton and double-click it so that Visual Studio brings you to the code view and creates you a OnClick event handler. Add the following code to it:&lt;br&gt;&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;private void closeButton_Click(object sender, EventArgs e)&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp; Application.Exit();&lt;br&gt;}&lt;br&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Very simple.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Minimize&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;Create another button on your form and change its name to minButton. Double click it to open code view to its OnClick event handler. Add the following code to that one:&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;
private void minButton_Click(object sender, EventArgs e)
        {&lt;br&gt;&amp;nbsp;&amp;nbsp; WindowState = FormWindowState.Minimized;&lt;br&gt;}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Maximized / Normal&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;There are two ways to do a "Maximize" button because you either have to change the button after it is maximized to a "Normal" button or you have to make the button's label generic enough that the one button can be used for both tasks. To keep things simple, we will do the latter.&lt;/p&gt;

&lt;p&gt;Create a button and change its name to maxNormButton and double click it like the last two examples. Add the following code to your event handler:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
private void maxNormButton_Click(object sender, EventArgs e)
        {&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; if (WindowState == FormWindowState.Maximized)&lt;br&gt;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; WindowState = FormWindowState.Normal;&lt;br&gt;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp; else&lt;br&gt;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; WindowState = FormWindowState.Maximized;&lt;br&gt;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
}&lt;/code&gt; &lt;br&gt;&lt;/p&gt;

&lt;p&gt;I will leave creating that generic-enough label up to you because I can't really think of anything right now. How about a ~ (tilde). That's never used enough.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Moving that Window Around&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.atalasoft.com/cs/photos/jacobs_blog_photos/images/13959/original.aspx" align="left" height="268" hspace="10" width="294"&gt;To move your window around, you will need to handle the mouse down event as well as the mouse move event. We'll have to do some simple math to determine the offset from where the mouse was clicked to where it is after it has moved. But before we can do anything with that, we need to add something to the form to grab on to.&lt;/p&gt;

&lt;p&gt;You can either add a PictureBox or a Panel to your form. If you're looking to put something other than a solid color in the area, you'll want to go with the PictureBox, otherwise just drop a simple Panel up there and change it's BackColor property to something other than Control-gray. I will be using the Panel in this example.&lt;/p&gt;

&lt;p&gt;Add a Panel to your form and stretch it the length of your form placing it along your top edge. You can even Dock it on the top if you'd like, but if you want to add rounded corners, you wont want to do that. Change the name of the panel windowbarPanel.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Right click on your form and choose View Code. We need to capture when the user mouses down on your menu bar. Add a MouseDown event handler to the constructor of your form.&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;
windowbarPanel.MouseDown += new MouseEventHandler(CaptureMouseDown);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The function that will handle the event, &lt;code&gt;void CaptureMouseDown&lt;/code&gt;, needs to save the mouse's position relative to your form's upper left hand corner. And it should only do this if the left mouse button is pressed. Create a private member variable _OffsetPoint of type Point to store your mouse position in. In the end, it should look like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;void CaptureMouseDown(object sender, MouseEventArgs e)&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp; if (e.Button == MouseButtons.Left)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _OffsetPoint = new Point(e.X, e.Y);&lt;br&gt;}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next we need to handle when the mouse is moved. Add a MouseMove event handler to the constructor of your form.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;windowbarPanel.MouseMove += new MouseEventHandler(MoveWindow);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The function that will be handling this event, &lt;code&gt;void MoveWindow&lt;/code&gt;, needs to offset the mouse's new position against it's MouseDown one and set the location of the window to that point. Again, only if the left mouse button is being pressed. Here it is:&lt;br&gt;&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;
void MoveWindow(object sender, MouseEventArgs e)&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp; if (e.Button == MouseButtons.Left)&lt;br&gt;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Point mousePos = Control.MousePosition;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mousePos.Offset(-_OffsetPoint.X, -_OffsetPoint.Y);
                &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Location = mousePos;&lt;br&gt;&amp;nbsp;&amp;nbsp; }&lt;br&gt;}
&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;Save it and build it and you've got yourself a form that doesn't have traditional Windows form borders but behaves a lot like one! Now, if only we could resize this thing...&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Resizing It&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;In traditional WinForms, you can grab any edge of a window and resize it. That's more than I want to get into in this post, so I'll only go over resizing your form from the lower left hand corner of the screen.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;In design-view, create a Panel in the lower left making it the size of your desired click area. Mine is about the size of an eraser head. Name it resizePanel.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;In code-view, you need to capture the position of the mouse relative to the screen with a mouse down event handler and save the current size of the window. You'll have to create new member variables for the window's width and height (they're of type int) but we can reuse the _OffsetPoint from before since you can't resize and move a window at the same time. In the constructor of the form, add the following: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;resizePanel.MouseDown += new MouseEventHandler(CaptureMousePosition);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The CaptureMousePosition method should look like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;int _Width;&lt;br&gt;int _Height;&lt;br&gt;&lt;br&gt;
void CaptureMousePosition(object sender, MouseEventArgs e)
        &lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp; if (e.Button == MouseButtons.Left)&lt;br&gt;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _Width = Width;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _Height = Height;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _OffsetPoint = new Point(Control.MousePosition.X, Control.MousePosition.Y);&lt;br&gt;&amp;nbsp;&amp;nbsp; }&lt;br&gt;}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next, we need to set the width and height of the window every time the MouseMove event is fired. Add the following line to your form's constructor:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
resizePanel.MouseMove += new MouseEventHandler(ResizeWindow);&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The ResizeWindow method needs to figure out how far the mouse has moved and apply that to the width and height of the form. It should end up looking like this:&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;
void ResizeWindow(object sender, MouseEventArgs e)&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp; if (e.Button == MouseButtons.Left)&lt;br&gt;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Point mousePos = new Point(Control.MousePosition.X, Control.MousePosition.Y);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mousePos.Offset(-_OffsetPoint.X, -_OffsetPoint.Y);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Width = _Width + mousePos.X;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Height = _Height + mousePos.Y;&lt;br&gt;&amp;nbsp;&amp;nbsp; }
       &lt;br&gt;}&lt;/code&gt;&lt;/p&gt;&lt;p&gt;That's about it. It could definitely use some work, but it's a great start.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Just to Recap&lt;/b&gt;&lt;/p&gt;&lt;p&gt;With the information above, you can now create applications that have custom border elements. We had to rewrite the most basic window functions, but that's OK. It wasn't &lt;i&gt;that &lt;/i&gt;painful. I hope to see better-looking WinForm applications from all of you. The only piece that's up to you is embedding beautiful Photoshopped graphics for all of your buttons and borders.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Update&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://www.atalasoft.com/cs/photos/jacobs_blog_photos/images/13961/original.aspx" align="right" height="94" hspace="10" width="123"&gt;I've added some pictures that go along with the process. Also, here are a few notes about anchoring your new elements correctly. If you don't correctly anchor, your resizing will not work correctly.&lt;/p&gt;&lt;p&gt;Your close, minimize, and maximize buttons should be anchored to the upper right. Your windowBarPanel should be anchored to the left-top-right so it stretches accordingly. Lastly, your resizePanel should be anchored to the bottom right so that it moves with your mouse as you resize.&lt;br&gt;&lt;/p&gt;&lt;p&gt;Here's a sample project that does everything we've talked about in this blog:&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/files/folders/13964/download.aspx" target="_blank"&gt;SkinFormsBlog.zip&lt;/a&gt;&lt;br&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/09/beauty-is-only-skin-deep-skinning-your-winforms-application.aspx&amp;amp;;subject=Beauty+is+only+Skin-Deep%3a+Skinning+your+WinForms+Application" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/09/beauty-is-only-skin-deep-skinning-your-winforms-application.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/09/beauty-is-only-skin-deep-skinning-your-winforms-application.aspx&amp;amp;;title=Beauty+is+only+Skin-Deep%3a+Skinning+your+WinForms+Application" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/09/beauty-is-only-skin-deep-skinning-your-winforms-application.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/09/beauty-is-only-skin-deep-skinning-your-winforms-application.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/09/beauty-is-only-skin-deep-skinning-your-winforms-application.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/09/beauty-is-only-skin-deep-skinning-your-winforms-application.aspx&amp;amp;title=Beauty+is+only+Skin-Deep%3a+Skinning+your+WinForms+Application" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/09/beauty-is-only-skin-deep-skinning-your-winforms-application.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/09/beauty-is-only-skin-deep-skinning-your-winforms-application.aspx&amp;amp;;title=Beauty+is+only+Skin-Deep%3a+Skinning+your+WinForms+Application" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/09/beauty-is-only-skin-deep-skinning-your-winforms-application.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/09/beauty-is-only-skin-deep-skinning-your-winforms-application.aspx&amp;amp;;title=Beauty+is+only+Skin-Deep%3a+Skinning+your+WinForms+Application&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/09/beauty-is-only-skin-deep-skinning-your-winforms-application.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13951" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/jake/archive/tags/WinForms/default.aspx">WinForms</category><category domain="http://www.atalasoft.com/cs/blogs/jake/archive/tags/UI/default.aspx">UI</category></item><item><title>Cloudscape Wallpaper Generator</title><link>http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/09/cloudscape-wallpaper-generator.aspx</link><pubDate>Fri, 09 May 2008 10:04:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13929</guid><dc:creator>kvwtrav</dc:creator><slash:comments>2</slash:comments><description>&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;br&gt;
&lt;img src="http://www.atalasoft.com/cs/photos/kenspics/images/13943/original.aspx" height="264" width="425"&gt;&lt;/p&gt;

&lt;p&gt;Welcome to the ninth of 31 applications we will post (in addition to the &lt;a href="http://www.atalasoft.com/events/31appsin31days/"&gt;contest&lt;/a&gt; participants' submissions). Make sure you add this blog to your &lt;b&gt;&lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/rss.aspx"&gt;RSS&lt;/a&gt; / &lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/atom.aspx"&gt;Atom&lt;/a&gt; &lt;/b&gt;feed and check the 
&lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/pages/31-Apps-in-31-Days-Gallery.aspx" title="Gallery Page"&gt;gallery&lt;/a&gt; for summaries of all the apps as they are released.&amp;nbsp; &lt;br&gt;&lt;/p&gt;


&lt;p&gt;This application demonstrates how to combine various DotImage commands to create an image of a skyline. The process for &lt;a href="http://freespace.virgin.net/hugo.elias/models/m_clouds.htm"&gt;drawing the clouds is based on this Hugo Elias description&lt;/a&gt;.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;To use this application, click &lt;b&gt;Create Cloudscape&lt;/b&gt; to preview the generated image. &amp;nbsp;Once the image is
loaded you can simply click &lt;b&gt;Set as Wallpaper&lt;/b&gt; to set as your desktop wallpaper. Your wallpaper will be randomly generated and totally unique.&lt;br&gt;&lt;/p&gt;


&lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/files/folders/13945/download.aspx"&gt;Download the installer&lt;/a&gt;.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/files/folders/13944/download.aspx"&gt;Download the source&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/09/cloudscape-wallpaper-generator.aspx&amp;amp;;subject=Cloudscape+Wallpaper+Generator" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/09/cloudscape-wallpaper-generator.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/09/cloudscape-wallpaper-generator.aspx&amp;amp;;title=Cloudscape+Wallpaper+Generator" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/09/cloudscape-wallpaper-generator.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/09/cloudscape-wallpaper-generator.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/09/cloudscape-wallpaper-generator.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/09/cloudscape-wallpaper-generator.aspx&amp;amp;title=Cloudscape+Wallpaper+Generator" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/09/cloudscape-wallpaper-generator.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/09/cloudscape-wallpaper-generator.aspx&amp;amp;;title=Cloudscape+Wallpaper+Generator" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/09/cloudscape-wallpaper-generator.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/09/cloudscape-wallpaper-generator.aspx&amp;amp;;title=Cloudscape+Wallpaper+Generator&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/09/cloudscape-wallpaper-generator.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13929" width="1" height="1"&gt;</description></item><item><title>Linked Image Viewer</title><link>http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/08/linked-image-viewer.aspx</link><pubDate>Thu, 08 May 2008 12:54:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13867</guid><dc:creator>Glenn</dc:creator><slash:comments>1</slash:comments><description>&lt;p style="text-align:center;"&gt;&amp;nbsp;&lt;br&gt;&lt;img src="http://www.atalasoft.com/cs/photos/gchittenden/images/13866/425x264.aspx" height="264" width="425"&gt;&lt;/p&gt;
&lt;p&gt;Welcome to the eighth of 31 applications we will post (in addition to the &lt;a href="http://www.atalasoft.com/events/31appsin31days/"&gt;contest&lt;/a&gt; participants' submissions). Make sure you add this blog to your &lt;b&gt;&lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/rss.aspx"&gt;RSS&lt;/a&gt; / &lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/atom.aspx"&gt;Atom&lt;/a&gt; &lt;/b&gt;feed and check the &lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/pages/31-Apps-in-31-Days-Gallery.aspx" title="Gallery Page"&gt;gallery&lt;/a&gt; for summaries of all the apps as they are released.&amp;nbsp; &lt;br&gt;&lt;/p&gt;&lt;p&gt;This application demonstrates linking two viewer controls
together; one working as the main viewer while the other provides an overview
of the entire image, outlining the currently viewable area of the main viewer.&lt;/p&gt;



&lt;p&gt;This setup allows the end-user to quickly scroll to a
specific area of the image by dragging the outline in the overview image.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;To use this application, select &lt;b&gt;Open&lt;/b&gt; from the &lt;b&gt;File&lt;/b&gt; menu and
choose a file to view. &amp;nbsp;Once the image is
loaded you will see a blue outline in the image overview.&amp;nbsp; Grab this outline and drag it to the area of
interest and the main viewer will automatically scroll to this position.&lt;/p&gt;



&lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/files/folders/13868/download.aspx"&gt;Download the installer&lt;/a&gt;.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/files/folders/13869/download.aspx"&gt;Download the source&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/08/linked-image-viewer.aspx&amp;amp;;subject=Linked+Image+Viewer" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/08/linked-image-viewer.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/08/linked-image-viewer.aspx&amp;amp;;title=Linked+Image+Viewer" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/08/linked-image-viewer.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/08/linked-image-viewer.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/08/linked-image-viewer.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/08/linked-image-viewer.aspx&amp;amp;title=Linked+Image+Viewer" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/08/linked-image-viewer.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/08/linked-image-viewer.aspx&amp;amp;;title=Linked+Image+Viewer" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/08/linked-image-viewer.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/08/linked-image-viewer.aspx&amp;amp;;title=Linked+Image+Viewer&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/08/linked-image-viewer.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13867" width="1" height="1"&gt;</description></item><item><title>Extending NAnt with your own types</title><link>http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx</link><pubDate>Thu, 08 May 2008 10:51:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13937</guid><dc:creator>dterrell</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx" title="Extending NAnt"&gt;Last time&lt;/a&gt; I talked about how to nest existing elements in your custom NAnt tasks.&amp;nbsp; Now that you've had a good look at that, and Jacob's custom task, there's only one other thing to cover in this subject: a new type.&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Types end up looking a lot like a new task, but throwing this all together should be a lot of fun.&lt;/p&gt;&lt;p&gt;Last time, I explained how I envisioned this working; a neat little task that I would give a FileSet to, and a regular expression plus a replacement string on match.&amp;nbsp; Considering this is a build process, you're going to be manipulating a lot of files with the same regex, that we have covered.&amp;nbsp; But what if I want to apply more than one regex to each file that's processed; I'd like to pass a collection of regex elements to my AtalaFileRegex task &lt;i&gt;along with&lt;/i&gt; my FileSet.&amp;nbsp; For that you need the BuildElementCollection decorator on one of your field types, like this:&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// A collection of regex/replace pairs that will be used on the file&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [BuildElementCollection("regexs", "regex", Required = true)]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [StringValidator(AllowEmpty = false)]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public AtalaRegexCollection Regexs&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return _regexs; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p&gt;As Jacob explained, we're requiring this field exist in our task, and that it cannot be empty.&amp;nbsp; But what about those first two arguments to BuildElementCollection?&amp;nbsp; Those define the outer element's name, and the inner elements name, respectively.&amp;nbsp; This will make your task have the following form:&lt;/p&gt;&lt;p&gt;&amp;lt;task someattribute=something someotherattribute=somethingelsle&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;regexs&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;lt;regex ...&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;lt;regex ...&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;/regexs&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;fileset&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp; &amp;lt;include ...&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp; &amp;lt;exclude ...&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;lt;/fileset&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;lt;/task&amp;gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Now, all we're missing is the two types we said we're going to use in the BuildElementCollection.&lt;/p&gt;&lt;p&gt;First, we need our regex type so that we can work with it in our collection.&amp;nbsp; For a type, you decorate the class itself, extend the Element type, and then decorate elements within the class as we've done before:&lt;/p&gt;&lt;p&gt;using System;&lt;br&gt;using NAnt.Core;&lt;br&gt;using NAnt.Core.Attributes;&lt;br&gt;&lt;br&gt;namespace Atalasoft.NAnt.Types&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Represents an regex pattern&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [ElementName("regex")]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [Serializable()]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public class AtalaRegex : Element&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Public Instance Constructors&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Initializes a new instance of the &amp;lt;see cref="AtalaRegex" /&amp;gt; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// class.&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public AtalaRegex()&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion Public Instance Constructors&lt;/p&gt;&lt;p&gt;I threw in the empty constructor since it's uninteresting.&lt;br&gt;&lt;/p&gt;&lt;p&gt;Cool, now, we said we want the regex type to accept both a matching pattern and a replacement string, so let's get a couple of instance fields going on to hold those:&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Private Instance Fields&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private string _value;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private string _replace;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion Private Instance Fields &lt;/p&gt;&lt;p&gt;&amp;nbsp;And finally, our getters and setters, properly decorated:&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Public Instance Properties&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// The actual regex string&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [TaskAttribute("value")]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [StringValidator(AllowEmpty = false)]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string Value&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return _value; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set { _value = value; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// The replacement string on match&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [TaskAttribute("replace")]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [StringValidator(AllowEmpty = true)]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string Replace&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return _replace; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set { _replace = value; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion Public Instance Properties&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;} &lt;/p&gt;&lt;p&gt;Notice on each, we've named the attribute (I called the regex string 'value' because I didn't want an element like &amp;lt;regex regex...).&amp;nbsp; Also note, the replace string can be empty. &lt;/p&gt;&lt;p&gt;That's all there is to making your own, simple type.&amp;nbsp; We'll move on to the more "complicated" part of the task at hand. &lt;br&gt;&lt;/p&gt;&lt;p&gt;Second, realize that we told NAnt it's a collection, so when we make our regexs type it's going to need to extend the CollectionBase abstract class.&amp;nbsp; You need nothing from the NAnt core.&amp;nbsp; Let's set up the class, and the default constructors:&lt;/p&gt;&lt;p&gt;using System;&lt;br&gt;using System.Collections;&lt;br&gt;&lt;br&gt;namespace Atalasoft.NAnt.Types&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Contains a strongly typed collection of &amp;lt;see cref="AtalaRegex" /&amp;gt; objects.&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [Serializable()]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public class AtalaRegexCollection : CollectionBase&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Public Instance Constructors&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Initializes a new instance of the &amp;lt;see cref="AtalaRegexCollection"/&amp;gt; class.&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public AtalaRegexCollection()&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Initializes a new instance of the &amp;lt;see cref="AtalaRegexCollection"/&amp;gt; class&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// with the specified &amp;lt;see cref="AtalaRegexCollection"/&amp;gt; instance.&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public AtalaRegexCollection(AtalaRegexCollection value)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; AddRange(value);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Initializes a new instance of the &amp;lt;see cref="AtalaRegexCollection"/&amp;gt; class&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// with the specified array of &amp;lt;see cref="AtalaRegex"/&amp;gt; instances.&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public AtalaRegexCollection(AtalaRegex[] value)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; AddRange(value);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion Public Instance Constructors &lt;br&gt;&lt;/p&gt;&lt;p&gt;From here, there's a lot of things to implement from the CollectionsBase class, and an enumerator.&amp;nbsp; Suffice it to say, you're going to end up filling in a lot of stubs for insert, add, copyto, remove, etc.&amp;nbsp; There's not much to cover here, it's a stong-typed collection.&lt;/p&gt;&lt;p&gt;Next time we'll put these things to work in our task. &lt;br&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx&amp;amp;;subject=Extending+NAnt+with+your+own+types" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx&amp;amp;;title=Extending+NAnt+with+your+own+types" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx&amp;amp;title=Extending+NAnt+with+your+own+types" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx&amp;amp;;title=Extending+NAnt+with+your+own+types" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx&amp;amp;;title=Extending+NAnt+with+your+own+types&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13937" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/dterrell/archive/tags/NAnt/default.aspx">NAnt</category><category domain="http://www.atalasoft.com/cs/blogs/dterrell/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://www.atalasoft.com/cs/blogs/dterrell/archive/tags/Visual+Studio/default.aspx">Visual Studio</category></item><item><title>Writing NAnt tasks with nested types</title><link>http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx</link><pubDate>Wed, 07 May 2008 20:04:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13933</guid><dc:creator>dterrell</dc:creator><slash:comments>2</slash:comments><description>&lt;br&gt;
&lt;p&gt;If you follow the &lt;a href="http://www.atalasoft.com/cs/ControlPanel/Blogs/www.atalasoft.com/blogs" title="Atalasoft Blogs"&gt;Atalasoft Blogs&lt;/a&gt; by whatever means, and you're reading this, it's quite possible you've also read &lt;a href="http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/07/writing-custom-nant-tasks.aspx" title="Writing Custom NAnt Tasks"&gt;Jacob's blog post about extending NAnt&lt;/a&gt;.&amp;nbsp; If you haven't already, go check it out since he's covered a huge amount of ground related to what I'm going to show in this and subsequent posts.&amp;nbsp; In fact, I'll assume you've either read his post, or have some general idea about extending NAnt.&lt;/p&gt;
&lt;p&gt;First, let me give some background on why I did this task.&lt;/p&gt;
&lt;p&gt;At Atalasoft, our builds (built by Jacob) can run in parallel, but our .NET 2.0 and 64-bit builds cannot.&amp;nbsp; Before our installer is created we want the .NET 2.0 and 64-bit assemblies to have the same version numbers.&amp;nbsp; In order for that to happen, we introduced a dependency on the .NET 2.0 build by the 64-bit build (the version number is a guaranteed increasing, randomly generated number that, in the case of the 64-bit build, is obtained from the built .NET 2.0 assemblies).&amp;nbsp; For continuous integration, the version numbering is internal, and not as important to our engineering department.&amp;nbsp; With that in mind, it should be easy to break the dependency just for a nightly build, but how?&amp;nbsp; Enter ChangeSetId, LastChangeLabeller, and a special Atalasoft NAnt task called AtalaFileRegex (the "Atala" prefix is somewhat of a running joke internally, but helps future build engineers realize it's not a built-in task for NAnt, yet).&amp;nbsp; The ChangeSetId and LastChangeLabeller topics will be covered in another, upcoming post.&lt;/p&gt;
&lt;p&gt;Now, you ask, why the FileRegex task when we're dealing with version numbers?&amp;nbsp; Ah, well, assembly version numbers are gotten a few different ways, and I wanted to alleviate a pain in our current build setup (preceding Jacob) where we use no less than 3 different approaches for updating version numbers for 3 different file types (AssemblyInfo.cs/.cpp, and any .rc files).&amp;nbsp; Enter AtalaFileRegex!&lt;/p&gt;
&lt;p&gt;I imagined a task that I could give a &lt;a href="http://nant.sourceforge.net/release/latest/help/types/fileset.html" title="NAnt FileSet"&gt;FileSet&lt;/a&gt; to, a regular expression to match, and a string to replace that match with.&amp;nbsp; It's a sharp (no pun intended) tool that you can easily break things with if you're not careful, but incredibly powerful if you are careful!&lt;/p&gt;
&lt;p&gt;So we set out to make our task (this is where you read Jacob's blog).&amp;nbsp; And in our shiny new task, we'd like to have a FileSet.&amp;nbsp; Easy, peasy!&amp;nbsp; In your public instance properties, make a field that is the NAnt.Core.Types.FileSet, and add some getter/setter code, like the following:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// All the matching files in this set will be updated according&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// to the given regex/replace&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [BuildElement("fileset")]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [StringValidator(AllowEmpty = false)]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public FileSet RegexFileSet&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return _fileSet; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set { _fileSet = value; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;Notice I use the BuildElement() decorator here, instead of the already familiar TaskAttribute() decorator.&amp;nbsp; This means that it's a nested element.&amp;nbsp; The way you'd write your NAnt task with this is&lt;/p&gt;
&lt;p&gt;&amp;lt;taskname taskattribute=something taskattribute2=somethingelse&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;fileset basedir="${Dir.Source}"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;include name="**\AssemblyInfo.cs" /&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;include name="**\AssemblyInfo.cpp" /&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/fileset&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/taskname&amp;gt;&lt;/p&gt;
&lt;p&gt;Sweet!&amp;nbsp; That was easy...&lt;/p&gt;
&lt;p&gt;Next time I'll write a walk through on how to make your own type, and add that to your new task.&amp;nbsp;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx&amp;amp;;subject=Writing+NAnt+tasks+with+nested+types" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx&amp;amp;;title=Writing+NAnt+tasks+with+nested+types" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx&amp;amp;title=Writing+NAnt+tasks+with+nested+types" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx&amp;amp;;title=Writing+NAnt+tasks+with+nested+types" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx&amp;amp;;title=Writing+NAnt+tasks+with+nested+types&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13933" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/dterrell/archive/tags/NAnt/default.aspx">NAnt</category><category domain="http://www.atalasoft.com/cs/blogs/dterrell/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://www.atalasoft.com/cs/blogs/dterrell/archive/tags/Visual+Studio/default.aspx">Visual Studio</category></item><item><title>Custom Serializing Objects for Use in a Debugger Visualizer</title><link>http://www.atalasoft.com/cs/blogs/rickm/archive/2008/05/07/custom-serializing-objects-for-use-in-a-debugger-visualizer-codeproject.aspx</link><pubDate>Wed, 07 May 2008 19:02:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13930</guid><dc:creator>RickM</dc:creator><slash:comments>0</slash:comments><description>I have a new CodeProject article up which details how to make a Debugger Visualizer in the case where you need to custom serialize the object. The actual classes I build in the tutorial are only useful with our DotImage project line. However, the process of creating a Custom Serializer should be useful to any .NET developer. In our case, we automatically serialize AtalaImages to PNG format by default. It turns out that PNG encoding and decoding is slow enough that visualizing a medium sized image...(&lt;a href="http://www.atalasoft.com/cs/blogs/rickm/archive/2008/05/07/custom-serializing-objects-for-use-in-a-debugger-visualizer-codeproject.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13930" width="1" height="1"&gt;</description><enclosure url="http://www.atalasoft.com/cs/blogs/rickm/attachment/13930.ashx" length="53959" type="image/jpeg" /><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/code/default.aspx">code</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/.NET/default.aspx">.NET</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/VB.NET/default.aspx">VB.NET</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/Tutorials/default.aspx">Tutorials</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/Debugger/default.aspx">Debugger</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/VS2008/default.aspx">VS2008</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/VS2005/default.aspx">VS2005</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/Visualizer/default.aspx">Visualizer</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/Debugger+Visualizer/default.aspx">Debugger Visualizer</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/CodeProject/default.aspx">CodeProject</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/Visual+Studio/default.aspx">Visual Studio</category></item><item><title>Writing Custom NAnt Tasks</title><link>http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/07/writing-custom-nant-tasks.aspx</link><pubDate>Wed, 07 May 2008 17:23:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13576</guid><dc:creator>jacobl</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;Working as a Build Engineer for about 9 months, I've had the opportunity to push NAnt build scripting to the limits. Our DotImage product is made up of both managed and unmanaged code, third party libraries with .NET wrappers, code that sometimes differs from .NET 1.1 to .NET 2.0 (both x86 and x64)&amp;nbsp; and a slew of other complications. In addition to that and the multiple systems it takes to put it all together, there comes a time where a custom solution might be the best way to do things. In the world of NAnt scripts, this can come in many forms, but personally I prefer to stay away from batch files and calls to the command-line. In my mind, the most elegant option is to write a NAnt task.&lt;/p&gt;

&lt;p&gt;For most things, NAnt tasks already exist and can be found at either &lt;a href="http://nant.sourceforge.net/" target="_blank"&gt;their official website&lt;/a&gt; or at the &lt;a href="http://nantcontrib.sourceforge.net/" target="_blank"&gt;NAntContrib&lt;/a&gt; sourceforge project, but it may surprise you that one of my first projects at Atalasoft was to create a NAnt task for integrating with Team Foundation Server.&lt;br&gt;&lt;br&gt;We had been using Visual Source Safe so the &lt;a href="http://nantcontrib.sourceforge.net/release/0.85-rc2/help/tasks/vssget.html" target="_blank"&gt;vssget&lt;/a&gt; task served us well for a long time. When we migrated to TFS, we were essentially left hanging          and had nothing to go on but settle for a few batch scripts that handled the task pretty well. Needless-to-say, five or so calls to tf.exe (the Team Foundation command-line utility) is not as easy to maintain as one task in a NAnt script.&lt;/p&gt;

&lt;p&gt;In this post, I will walk you through creating a custom NAnt task with some more "advanced" features, such as adding nested elements and setting a return value. Then, in the near future, I will post my code for the tasks that I've written including tfsGet, tfsCheckOut, tfsCheckIn, removeSourceControlBindings, and others. You'll then be able to add them to your build systems and get all of the same TFS goodness that we do. I might even add them to NAntContrib as well.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Design your Task&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Before I start writing a task, I like to have a good idea of what it will look like and how it will behave in a NAnt script. In the case of TFSGet, I decided to model it after the VSSGet task which is in NAntContrib.&lt;/p&gt;

&lt;p&gt;This is what the VSSGet task looks like:&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;
&amp;lt;vssget verbose="true"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; username="user"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; password="pass"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; localpath="."&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; recursive="false"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; replace="true"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; writable="true"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; dbpath="\\path\to\srcsave.ini" &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; path="$/path/to/project/location" /&amp;gt;
&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;and this is what my TFSGet task looks like:&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;
&amp;lt;tfsget server="servername"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ssl="false"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; port="8080"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; projectPath="$/path/to/project/location"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; localPath="."&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; recursionType="None"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; getOptions="Force"&amp;gt;
&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;lt;source path="*" /&amp;gt;&lt;br&gt;&amp;lt;/tfsget&amp;gt;&amp;nbsp;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Since I wrote it last year, &lt;a href="http://www.atalasoft.com/blogs/dterrell/" target="_blank"&gt;Dave Terrell&lt;/a&gt;, our Build Engineer has made a few important additions such as non-default network credentials as well as the ability to return a changeset number back to the NAnt script. With these new changes, the task looks like this:&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;
&amp;lt;tfsget server="servername"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; username="user"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; password="pass"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ssl="false"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; port="8080"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; projectPath="$/path/to/project/location"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; localPath="."&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; recursionType="None"&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; getOptions="Force"&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; changeset="changeset"&amp;gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;lt;source path="*" /&amp;gt;&lt;br&gt;&amp;lt;/tfsget&amp;gt;&lt;br&gt;&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Let's Get Started&lt;/b&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.atalasoft.com/cs/photos/jacobs_blog_photos/images/13921/original.aspx" align="right" height="218" width="300"&gt;Open Visual Studio and create a new project. NAnt tasks start their lives as Class Libraries, so that's the template that we'll choose. For this example, I'm going to create a project called TFS since it will hold all the tasks related to TFS. I might want to add more tasks in the future that aren't related to TFS so my overarching solution will be called Tasks.&lt;/p&gt;

&lt;p&gt;After your project and solution appear in the Solution Explorer, we need to rename the Class1.cs file to TFSGet.cs. Visual Studio may ask you if&amp;nbsp; would like Visual studio to rename all references to Class1 in the project to TFSGet. Say Yes, otherwise do it manually.&lt;/p&gt;

&lt;p&gt;Before we get started writing any code, we need to reference &lt;code&gt;NAnt.Core.dll&lt;/code&gt;. That assembly is located in the directory structure of your NAnt install right next to NAnt.exe. Once you've done that, add the appropriate &lt;code&gt;using&lt;/code&gt; statements to the top of your TFSGet.cs file.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Five Steps to Success&lt;/b&gt; &lt;br&gt;&lt;/p&gt;

&lt;p&gt;To define a NAnt task, there are five things we need to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define the name of the task using the &lt;code&gt;TaskName&lt;/code&gt; class decorator.&lt;/li&gt;

&lt;li&gt;Extend &lt;code&gt;NAnt.Core.Task&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;Create any attributes and label them with the &lt;code&gt;TaskAttribute&lt;/code&gt; property decorator.&lt;/li&gt;

&lt;li&gt;Override the &lt;code&gt;ExecuteTask&lt;/code&gt; method.&lt;/li&gt;

&lt;li&gt;Make sure you're output assembly ends in &lt;code&gt;Tasks.dll&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
&lt;b&gt;The Basic Layout&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Here's the skeleton for our TFSGet task:&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;
// using ...&lt;br&gt;using NAnt.Core;&lt;br&gt;using NAnt.Core.Attributes;&lt;br&gt;// ...&lt;br&gt;&lt;br&gt;namespace TFS&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp; public class TFSGet : Task&lt;br&gt;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Task Attributes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private string _server;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [TaskAttribute("server", Required = true)]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [StringValidator(AllowEmpty = false)]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string Server&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { return _server; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set { _server = value; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
      &lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // ... other attributes ...
      &lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion
      &lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #region Execute
      &lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected override void ExecuteTask()&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // The Leg Work&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
      &lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endregion&lt;br&gt;&amp;nbsp;&amp;nbsp; }&lt;br&gt;}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With this basic model, you can write almost any task you can think of. There are two other important concepts that this particular task employs and you should know about them and how to use them. One is returning values and the other is nested attributes. I'll explain return values shortly, but nested attributes are a bit more complicated and deserve a dedicated post. I will leave that to Dave to explain further. He's written about &lt;a href="http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx" target="_blank"&gt;writing NAnt tasks with nested types&lt;/a&gt; as well as &lt;a href="http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx" target="_blank"&gt;extending NAnt with your own types&lt;/a&gt;.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Using "Project"&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;Project&lt;/code&gt; gives you access to the currently running NAnt script. This is essentially the parent of your NAnt task. With it, you can log events, warnings, or errors. You also have access to properties within the project allowing you to return values from your task to the outer build script.&lt;/p&gt;

&lt;p&gt;In the case of this example, it is incredibly useful for the build script to know the changeset of the code we got from TFS. In the script, we can then use that number to ... maybe set the version number of our assemblies for quick debugging if a customer has a question. If they give us that, we can instantly see the code that their running without having to think about it. Currently, our assembly version numbers at Atalasoft are:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;6.0.&amp;lt;randomish number bigger than the last build&amp;gt;.&amp;lt;randomish number&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For future versions of our product we are working toward version numbers like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;x.0.&amp;lt;number representing the letter of the build&amp;gt;.&amp;lt;changeset number&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For example, if you called our office with a question about your 6.0.0001.38983 assemblies, we would instantly know that you are running 6.0a and we can get changeset 38983 from source control and read exactly what you've got.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Setting project properties is very simple. To set a property, you simply set the value of item indexed by the property you are setting. That was a mouthful... If you are trying to set the "changeset" property, this is what you would do:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Project.Properties["changeset"] = value;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That's it!&lt;/p&gt;
&lt;p&gt;Logging is just as easy. To log you simply call:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Project.Log(Level.Info, "Your logged message goes here");&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;That message will now appear in the console if you're running your NAnt script via command line. It will also appear in your CruiseControl logs if you're using that to manage your Continuous Integration process.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Deploying a Custom Built NAnt Task&lt;/b&gt;&lt;/p&gt;&lt;p&gt;To deploy a custom NAnt task, you simply need to put it in the NAnt directory next to the nant.exe and NAnt.Core.dll that you will be running it from. The next time you call nant.exe, your newly built task will be loaded and available to be scripted against.&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;br&gt;&lt;b&gt;The Code&lt;/b&gt; &lt;br&gt;&lt;/p&gt;&lt;p&gt;Here's the &lt;a href="http://www.atalasoft.com/cs/files/folders/13927/download.aspx" target="_blank"&gt;code for this task in full&lt;/a&gt; and here's a &lt;a href="http://www.atalasoft.com/cs/files/folders/13928/download.aspx" target="_blank"&gt;link to a prebuilt assembly&lt;/a&gt;. You will need to download and install NAnt and you may or may not have to download and install Visual Studio TeamFoundation Server SDK for access to the Microsoft.TeamFoundation namespace items.&lt;/p&gt;&lt;p&gt;Check back in the future for more NAnt tasks and be sure to read Dave's articles on &lt;a href="http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/writing-nant-tasks-with-nested-types.aspx" target="_blank"&gt;using nested types&lt;/a&gt; as well as &lt;a href="http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/08/extending-nant-with-your-own-types.aspx" target="_blank"&gt;creating your own&lt;/a&gt;.&amp;nbsp;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/07/writing-custom-nant-tasks.aspx&amp;amp;;subject=Writing+Custom+NAnt+Tasks" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/07/writing-custom-nant-tasks.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/07/writing-custom-nant-tasks.aspx&amp;amp;;title=Writing+Custom+NAnt+Tasks" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/07/writing-custom-nant-tasks.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/07/writing-custom-nant-tasks.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/07/writing-custom-nant-tasks.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/07/writing-custom-nant-tasks.aspx&amp;amp;title=Writing+Custom+NAnt+Tasks" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/07/writing-custom-nant-tasks.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/07/writing-custom-nant-tasks.aspx&amp;amp;;title=Writing+Custom+NAnt+Tasks" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/07/writing-custom-nant-tasks.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/07/writing-custom-nant-tasks.aspx&amp;amp;;title=Writing+Custom+NAnt+Tasks&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/07/writing-custom-nant-tasks.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13576" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/jake/archive/tags/VSS/default.aspx">VSS</category><category domain="http://www.atalasoft.com/cs/blogs/jake/archive/tags/NAnt/default.aspx">NAnt</category><category domain="http://www.atalasoft.com/cs/blogs/jake/archive/tags/Build+Systems/default.aspx">Build Systems</category><category domain="http://www.atalasoft.com/cs/blogs/jake/archive/tags/TFS/default.aspx">TFS</category><category domain="http://www.atalasoft.com/cs/blogs/jake/archive/tags/Task/default.aspx">Task</category></item><item><title>Scan Documents to Scribd</title><link>http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/07/scan-documents-to-scribd.aspx</link><pubDate>Wed, 07 May 2008 13:15:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13842</guid><dc:creator>loufranco</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;&lt;img src="http://www.atalasoft.com/cs/photos/loufranco/images/13837/425x334.aspx"&gt;&lt;/p&gt;
&lt;p&gt;Welcome to the 7th of 31 applications we will post (in addition to the &lt;a href="http://www.atalasoft.com/events/31appsin31days/"&gt;contest&lt;/a&gt; participants' submissions). Make sure you add this blog to your &lt;b&gt;&lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/rss.aspx"&gt;RSS&lt;/a&gt; / &lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/atom.aspx"&gt;Atom&lt;/a&gt; &lt;/b&gt;feed and check the &lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/pages/31-Apps-in-31-Days-Gallery.aspx" title="Gallery Page"&gt;gallery&lt;/a&gt; for summaries of all the apps as they are released.&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Just in time for the Scribd "&lt;a href="http://www.scribd.com/contest"&gt;Most Interesting Hard Drive Contest&lt;/a&gt;", here's a free application that can scan documents and upload them to your &lt;a href="http://www.scribd.com/"&gt;Scribd&lt;/a&gt; account. You can choose to OCR them first, so that your scanned documents will show up in search queries (courtesy of the &lt;a href="http://code.google.com/p/tesseract-ocr/"&gt;Google Tesseract OCR engine&lt;/a&gt;). Now you can try to win a MacBook Air from Scribd with the scraps of paper lying around your office.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/files/folders/13843/download.aspx"&gt;Download the Scan To Scribd installer&lt;/a&gt; and run it. &lt;/p&gt;
&lt;p&gt;Scan in a document, then Click the "Upload to Scribd..." icon and provide your API Account and Scribd login info (it will be saved for next time).&lt;/p&gt;
&lt;p&gt;You can give your document a title and specify whether it's public or private. You can also choose to OCR the file before uploading it. When it's done, &lt;a href="http://www.scribd.com/"&gt;go to Scribd&lt;/a&gt; and view your document. &lt;/p&gt;
&lt;p&gt;This application uses the amazing &lt;a href="http://www.codeplex.com/scribdnet"&gt;Scribd.Net&lt;/a&gt;, which makes it easy to interact with Scribd from .NET.&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.atalasoft.com/cs/files/folders/13843/download.aspx"&gt;Download the application&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.atalasoft.com/cs/files/folders/13844/download.aspx"&gt;Download the source&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;To build your own version from this source, you'll need to &lt;a href="http://www.scribd.com/platform/account"&gt;get an API Key from Scribd first&lt;/a&gt;.
Sign in and then go to your platform account page (click on your own
name in the upper right corner), your API Account information is on the
right side. It will take a few minutes to become active.)&amp;nbsp; In the downloaded source, you can hardcode your own API Key.&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/04/14/31-ways-you-can-add-imaging-value-to-your-application.aspx"&gt;About Atalasoft's 31 Apps in 31 Days&lt;/a&gt; &lt;br&gt;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/07/scan-documents-to-scribd.aspx&amp;amp;;subject=Scan+Documents+to+Scribd" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/07/scan-documents-to-scribd.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/07/scan-documents-to-scribd.aspx&amp;amp;;title=Scan+Documents+to+Scribd" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/07/scan-documents-to-scribd.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/07/scan-documents-to-scribd.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/07/scan-documents-to-scribd.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/07/scan-documents-to-scribd.aspx&amp;amp;title=Scan+Documents+to+Scribd" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/07/scan-documents-to-scribd.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/07/scan-documents-to-scribd.aspx&amp;amp;;title=Scan+Documents+to+Scribd" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/07/scan-documents-to-scribd.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/07/scan-documents-to-scribd.aspx&amp;amp;;title=Scan+Documents+to+Scribd&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/07/scan-documents-to-scribd.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13842" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/31+apps+apps+in+31+days/default.aspx">31 apps apps in 31 days</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/OCR/default.aspx">OCR</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/Scribd/default.aspx">Scribd</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/Scribd.Net/default.aspx">Scribd.Net</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/Scan/default.aspx">Scan</category></item><item><title>Update on another post</title><link>http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/update-on-another-post.aspx</link><pubDate>Wed, 07 May 2008 11:43:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13914</guid><dc:creator>dterrell</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;You may have seen &lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/02/Atala-Auto-Rotater.aspx" title="AtalaAutoRotate"&gt;my post&lt;/a&gt; in the &lt;a href="http://www.atalasoft.com/blogs/31appsin31days" title="31 Apps in 31 Days"&gt;31 Apps in 31 Days &lt;/a&gt;blog.&amp;nbsp; If you haven't already seen the 31 Apps in 31 Days blog, definitely check it out!&amp;nbsp; There's already a week's worth of applications you can make using the Atalasoft family of tools in one way or another.&lt;/p&gt;&lt;p&gt;I got some requests to expand the functionality of my autorotater application, namely that it have some additional &lt;u&gt;rotational&lt;/u&gt; functionality.&amp;nbsp; Sometimes you'll stumble on those pictures that were taken with an orientation 90 degrees to the right or left, or even upside-down.&amp;nbsp; Some viewers will read this orientation information and rotate the picture for you while viewing, but at the same time they don't update the orientation flag of the image.&amp;nbsp; As a result the image may continue to be rotated by other viewers, or in this case, it'll be rotated by the AtalaAutoRotater.&lt;/p&gt;&lt;p&gt;&amp;nbsp;To fix this, I've added two new buttons to the autorotater.&amp;nbsp; This functionality was pretty easy to add with these few steps (technical stuff here, skip to MultiSelect if you don't like techie stuff).&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Modify the &lt;i&gt;selectedIndexChanged &lt;/i&gt;event handler to enable/disable the rotation buttons.&amp;nbsp; This is just an added visual to let users know they must select one or more images before rotating&lt;br&gt;&lt;/li&gt;&lt;li&gt;Add two buttons, and give them appropriate names &lt;i&gt;btnRotLeft &lt;/i&gt;and &lt;i&gt;btnRotRight&lt;/i&gt;.&lt;/li&gt;&lt;li&gt;Add a wrapper function&lt;i&gt; rotate_()&lt;/i&gt; that will gather a collection of thumbnails into a new&lt;i&gt; ICollection&amp;lt;Thumbnail&amp;gt;() &lt;/i&gt;before calling&lt;i&gt; rotate()&lt;br&gt;&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Add a new &lt;i&gt;enum &lt;/i&gt;that contains Left, Right, All&lt;/li&gt;&lt;li&gt;Have the &lt;i&gt;btnRotLeft &lt;/i&gt;and &lt;i&gt;btnRotRight &lt;/i&gt;(modify &lt;i&gt;btnRotate) &lt;/i&gt;call the wrapper with its direction&lt;/li&gt;&lt;li&gt;Modify &lt;i&gt;rotate()&lt;/i&gt; so that it accepts an &lt;i&gt;ICollection&amp;lt;Thumbnail&amp;gt;&lt;/i&gt; and a Rotation &lt;i&gt;enum&lt;/i&gt;.&amp;nbsp; Check, before the &lt;i&gt;switch&lt;/i&gt;, whether it's rotating all images, or a selection and update the &lt;i&gt;orientation int&lt;/i&gt; if it's a selection Left/Right.&lt;/li&gt;&lt;li&gt;Let the rest of the code do the work!&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;b&gt;MultiSelect&lt;/b&gt; &lt;br&gt;&lt;/p&gt;&lt;p&gt;But wait!&amp;nbsp; You don't want your users having to select individual files and hit rotate buttons each time.&amp;nbsp; So we'll make it possible to select a whole set of images to rotate.&amp;nbsp; To select multiple images, users can either hold down the Ctrl key while selecting individual pictures, or the Shift key to select two endpoints of a range of photos.&lt;br&gt;&lt;/p&gt;&lt;p&gt;For this functionality, the &lt;i&gt;FolderThumbnailViewer &lt;/i&gt;needs to be updated as well.&amp;nbsp; This might be a bit confusing, because there are two spots where you need to change options to get multiselect working, both in the &lt;i&gt;FolderThumbnailView&lt;/i&gt; properties matrix.&amp;nbsp; First, you have to enable &lt;i&gt;MultiSelect&lt;/i&gt;, then you have the change the &lt;i&gt;SelectionMode&lt;/i&gt; to &lt;i&gt;MultiSelect&lt;/i&gt; from &lt;i&gt;Single&lt;/i&gt;.&amp;nbsp; Once that's done, the app is ready to go!&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://www.atalasoft.com/cs/photos/dterrell/images/13917/original.aspx" title="New buttons!" alt="New buttons!" height="260" width="345"&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;To make this a bit easier, I've included the source in the installer this time so there's only one file to download.&lt;/p&gt;&lt;p&gt;Get the &lt;a href="http://www.atalasoft.com/cs/files/folders/13931/download.aspx" title="Atala rotater with more buttons!"&gt;installer&lt;/a&gt; &lt;br&gt;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/update-on-another-post.aspx&amp;amp;;subject=Update+on+another+post" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/update-on-another-post.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/update-on-another-post.aspx&amp;amp;;title=Update+on+another+post" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/update-on-another-post.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/update-on-another-post.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/update-on-another-post.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/update-on-another-post.aspx&amp;amp;title=Update+on+another+post" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/update-on-another-post.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/update-on-another-post.aspx&amp;amp;;title=Update+on+another+post" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/update-on-another-post.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/update-on-another-post.aspx&amp;amp;;title=Update+on+another+post&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/dterrell/archive/2008/05/07/update-on-another-post.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13914" width="1" height="1"&gt;</description></item><item><title>Lou Francos</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/06/lou-francos.aspx</link><pubDate>Tue, 06 May 2008 19:25:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13905</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;I was playing with the &lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/03/product-box-generator.aspx"&gt;Product Box Generator&lt;/a&gt; and created the following bit of fun:&lt;br&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;blockquote&gt;&lt;p&gt;&lt;img src="http://www.atalasoft.com/cs/photos/techtalkgallery/images/13904/original.aspx"&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;p&gt;I love software.&lt;/p&gt;&lt;p&gt;Thanks, Lou, for tolerating me.&amp;nbsp;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/06/lou-francos.aspx&amp;amp;;subject=Lou+Francos" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/06/lou-francos.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/06/lou-francos.aspx&amp;amp;;title=Lou+Francos" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/06/lou-francos.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/06/lou-francos.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/06/lou-francos.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/06/lou-francos.aspx&amp;amp;title=Lou+Francos" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/06/lou-francos.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/06/lou-francos.aspx&amp;amp;;title=Lou+Francos" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/06/lou-francos.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/06/lou-francos.aspx&amp;amp;;title=Lou+Francos&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/06/lou-francos.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13905" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/stevehawley/archive/tags/silly+image/default.aspx">silly image</category></item><item><title>TPS Coversheet Enforcement</title><link>http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/06/tps-coversheet-enforcement.aspx</link><pubDate>Tue, 06 May 2008 13:35:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13840</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>2</slash:comments><description>&lt;P&gt;&lt;IMG src="http://www.atalasoft.com/cs/photos/techtalkgallery/images/13839/original.aspx"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;Welcome to the sixth of 31 applications we will post (in addition to the &lt;A href="http://www.atalasoft.com/events/31appsin31days/"&gt;contest&lt;/A&gt; participants' submissions). Make sure you add this blog to your &lt;A href="http://www.atalasoft.com/cs/blogs/31appsin31days/rss.aspx"&gt;&lt;SPAN style="FONT-WEIGHT:bold;"&gt;RSS&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN style="FONT-WEIGHT:bold;"&gt; / &lt;/SPAN&gt;&lt;A href="http://www.atalasoft.com/cs/blogs/31appsin31days/atom.aspx"&gt;&lt;SPAN style="FONT-WEIGHT:bold;"&gt;Atom&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN style="FONT-WEIGHT:bold;"&gt; &lt;/SPAN&gt;feed and check the &lt;A href="http://www.atalasoft.com/cs/blogs/31appsin31days/pages/31-Apps-in-31-Days-Gallery.aspx"&gt;gallery&lt;/A&gt; for summaries of all the apps as they are released.&lt;/P&gt;
&lt;P&gt;This app is a frivolous way to solve the general problem "how do I detect and act on the content of a scanned document"?&lt;/P&gt;
&lt;P&gt;If you've seen the movie &lt;A href="http://www.imdb.com/title/tt0151804/" target=_blank&gt;Office Space&lt;/A&gt;, you're well aware that all &lt;A href="http://en.wikipedia.org/wiki/TPS_report" target=_blank&gt;TPS reports&lt;/A&gt; are required to have a specific &lt;A href="http://www.chrisglass.com/journal/downloads/TPSreport.pdf" target=_blank&gt;cover sheet&lt;/A&gt;.&amp;nbsp; I've written an application that does two things - first, given a folder it will find all TIFF documents within the folder and flag any TIFF wherein the first page is NOT a TPS cover sheet.&amp;nbsp; The second thing the application does is to insert a TPS cover sheet into files that are missing one.&lt;/P&gt;
&lt;P&gt;The first task is simple, if you have the right pieces at your fingertips.&amp;nbsp; Using the Tesseract OCR engine, I recognize the first page in each document and attempt to match text on the page via a regular expression.&amp;nbsp; If there is a match, then the document has a TPS report cover sheet.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The second task uses our new TiffDocument class to add in the cover sheet.&amp;nbsp; Because of this class, this task is literally a one-liner.&lt;/P&gt;
&lt;P&gt;While this particular application is frivolous, you could imagine using the same structure to auto-sort documents that come in from a fax source or do keyword searching.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;You can &lt;A href="http://www.atalasoft.com/cs/files/folders/13832/download.aspx"&gt;download an installer for the app here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;You can &lt;A href="http://www.atalasoft.com/cs/files/folders/13833/download.aspx"&gt;download the source here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;A href="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/04/14/31-ways-you-can-add-imaging-value-to-your-application.aspx"&gt;About Atalasoft's 31 Apps in 31 Days&lt;/A&gt;&lt;BR&gt;&amp;nbsp;&lt;/P&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/06/tps-coversheet-enforcement.aspx&amp;amp;;subject=TPS+Coversheet+Enforcement" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/06/tps-coversheet-enforcement.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/06/tps-coversheet-enforcement.aspx&amp;amp;;title=TPS+Coversheet+Enforcement" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/06/tps-coversheet-enforcement.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/06/tps-coversheet-enforcement.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/06/tps-coversheet-enforcement.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/06/tps-coversheet-enforcement.aspx&amp;amp;title=TPS+Coversheet+Enforcement" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/06/tps-coversheet-enforcement.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/06/tps-coversheet-enforcement.aspx&amp;amp;;title=TPS+Coversheet+Enforcement" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/06/tps-coversheet-enforcement.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/06/tps-coversheet-enforcement.aspx&amp;amp;;title=TPS+Coversheet+Enforcement&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/06/tps-coversheet-enforcement.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13840" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/31+apps+apps+in+31+days/default.aspx">31 apps apps in 31 days</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/OCR/default.aspx">OCR</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/cover+sheet/default.aspx">cover sheet</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/Atalasoft+DotImage/default.aspx">Atalasoft DotImage</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/TIFF/default.aspx">TIFF</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/Tesseract/default.aspx">Tesseract</category></item><item><title>When &quot;new&quot; is Too Slow</title><link>http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/05/when-new-is-too-slow.aspx</link><pubDate>Mon, 05 May 2008 13:46:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13887</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>2</slash:comments><description>
&lt;p&gt;I was working on some prototype code that needed to be super fast.&amp;nbsp; After getting basic functionality up and running, I found that the biggest chunk of time was getting lost in operator new.&amp;nbsp; In this particular chunk of code, I had some simulated recursion that was making lots and lots of little objects that were being pushed and popped onto a stack.&amp;nbsp; The issue was that these objects are tiny and transient.&amp;nbsp; This means that all the overhead imposed by new and delete will get charged again and again and again.&lt;/p&gt;

&lt;p&gt;There are a number of choices available to you when you do this.&amp;nbsp; I'll pass on one that breaks a number of conventional OO design rules, specifically is-a/has-a.&amp;nbsp; In my case, I had some objects that have two purposes in life - to hold data and to live in a stack.&amp;nbsp; If you are a fan of STL, you will probably haul out stack&amp;lt;t&amp;gt; and call it good.&amp;nbsp; In my case, STL's performance was heinous, so I chose to smudge the is-a/has-a line and make my little object into a stack element rather than using a stack element to hold it:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;class StackPoint {&lt;br&gt;public:&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; StackPoint(unsigned int x, unsigned int y) : m_next(NULL)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; m_pt.x = x; m_pt.y = y;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; StackPoint (POINT pt) : m_pt(pt), m_next(NULL) { }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; virtual ~StackPoint () { }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int X() { return m_pt.x; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int Y() { return m_pt.y; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; void SetX(int x) { m_pt.x = x; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; void SetY(int y) { m_pt.y = y; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; StackPoint *GetNext() { return m_next; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; void SetNext(StackPoint *next) { m_next = next; }&lt;br&gt;private:&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; POINT m_pt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; StackPoint *m_next;&lt;br&gt;};&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&lt;br&gt;
class MyStack {&lt;br&gt;public:&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; MyStack() : m_stack(NULL) { }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; virtual ~MyStack();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; bool IsEmpty() { return m_stack == NULL; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; void Push(StackPoint *item) { item-&amp;gt;SetNext(m_stack); m_stack = item; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; StackPoint *Pop();&lt;br&gt;private:&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; StackPoint *m_stack;&lt;br&gt;}; &lt;br&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;In these snippets, I'm leaving out some of the methods, but they're simple to write.&amp;nbsp; Pop() returns null if the stack is empty, or the top of the stack otherwise, resetting the stack pointer.&amp;nbsp; The destructor rips the entire stack, disposing each element in turn.&amp;nbsp; From these two classes, I can now create an allocator like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;class StackPointAllocator {&lt;br&gt;public:&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; StackPointAllocator() {&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; virtual ~StackPointAllocator() { }&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; StackPoint *Alloc(int x, int y);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; void Free(StackPoint *p);&lt;br&gt;private:&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; MyStack m_stack;&lt;br&gt;}; &lt;br&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;In this case, the StackPointAllocator has a method called Alloc which will do one of two things.&amp;nbsp; If m_stack.IsEmpty() is true, it will call operator new.&amp;nbsp; If m_stack.IsEmpty() is false, it will pop the top item off, set x and y and return it.&amp;nbsp; In the typical case, there is an item left on the stack and so "allocation" (really recycling), is only a few assignment statements.&amp;nbsp; Note that m_stack is a NOT a pointer, which means that its destructor will automatically get called when the allocator goes out of scope or is deleted.&lt;br&gt;&lt;/p&gt;&lt;p&gt;To give you a sense of the power of doing this, the original problem with allocation was costly because I was allocating tens of millions of these objects, each of which has a very short life span.Even though the individual cost was small, multiplying by 10M added up.&amp;nbsp; I'd rather do 40M assignments.&amp;nbsp; Once the code was refactored (easy), the time for allocation totally vanished from the performance profile.&lt;/p&gt;&lt;p&gt;Now, the real C++ programmer question is "Why didn't I override global operator new for StackPoint?" &lt;br&gt;&lt;/p&gt;&lt;p&gt;Overriding global operator new means that all code that allocates these objects will go through the global allocator - that's a bigger deal.&amp;nbsp; I use this code in other places that shouldn't use this allocator.&amp;nbsp; I end up making the allocators I use stack objects, which means that objects in the free list disappear when they go out of scope.&lt;/p&gt;&lt;p&gt;Classic engineering dilemma: which is more important? performance or OO design?&amp;nbsp; In this case, the API is NOT public, so the dirty little secret is hidden away, making this a perfectly acceptable choice.&amp;nbsp; Performance, FTW.&amp;nbsp; In addition, there were two other considerations - readability and expedience.&amp;nbsp; Readability was not lost at all, and since I could knock this out inside a half hour, I won on expedience too.&amp;nbsp;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/05/when-new-is-too-slow.aspx&amp;amp;;subject=When+%26quot%3bnew%26quot%3b+is+Too+Slow" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/05/when-new-is-too-slow.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/05/when-new-is-too-slow.aspx&amp;amp;;title=When+%26quot%3bnew%26quot%3b+is+Too+Slow" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/05/when-new-is-too-slow.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/05/when-new-is-too-slow.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/05/when-new-is-too-slow.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/05/when-new-is-too-slow.aspx&amp;amp;title=When+%26quot%3bnew%26quot%3b+is+Too+Slow" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/05/when-new-is-too-slow.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/05/when-new-is-too-slow.aspx&amp;amp;;title=When+%26quot%3bnew%26quot%3b+is+Too+Slow" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/05/when-new-is-too-slow.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/05/when-new-is-too-slow.aspx&amp;amp;;title=When+%26quot%3bnew%26quot%3b+is+Too+Slow&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/05/05/when-new-is-too-slow.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13887" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/stevehawley/archive/tags/code+C_2B002B00_+performance/default.aspx">code C++ performance</category></item><item><title>When just one watermarked image simply isn't enough</title><link>http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/05/when-one-watermarked-image-just-isn-t-enough.aspx</link><pubDate>Mon, 05 May 2008 13:10:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13824</guid><dc:creator>Kevin Hulse</dc:creator><slash:comments>1</slash:comments><description>
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Finally, the &lt;a href="http://www.atalasoft.com/cs/files/folders/13849/download.aspx" title="Batch Watermarker Download"&gt;Atalasoft Batch Watermarker&lt;/a&gt;, the cure to all your watermarking woes! With this application, you no longer need to spend hours toiling&amp;nbsp;in Photoshop repeating the same action over and over again!&amp;nbsp;No more--::Mute::&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/files/folders/13849/download.aspx"&gt;&lt;img src="http://www.atalasoft.com/cs/photos/khulse/images/original/Batch-Watermarker.aspx" title="Batch Watermarker" alt="Batch Watermarker" align="middle" height="335" width="407"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;While this application might not be that ultimately useful, it stands to save some intern a lot of time, or even you a lot of time. As someone new here at Atalasoft, I have been astounded with what we have to offer. The Atalasoft toolkit is so mind-blazingly fast; both in running speed and developer time. &lt;/p&gt;

&lt;p&gt;Three lines of code to allow the user to select&amp;nbsp;any supported format&amp;nbsp;image and display it&amp;nbsp;in a Windows form: Two lines of code to perform an operation on it: One line of code to save the image in any supported format. The basic&amp;nbsp;image processor is 6 lines of code.&lt;/p&gt;

&lt;p&gt;I designed this 31 app to show off the ability to&amp;nbsp;use DotImage to do many steps of&amp;nbsp;photoshop style processing (that noone really wants to do by hand) automatically.&amp;nbsp;Simply point the watermarker at a folder containing jpgs, configure your watermark in real time, and select Apply Watermark, and another folder is created containing all the images with your watermark applied.&lt;/p&gt;

&lt;p&gt;Give the &lt;a href="http://www.atalasoft.com/cs/files/folders/13849/download.aspx" title="Batch Watermarker"&gt;Atalasoft Batch Watermarker&lt;/a&gt; a try!&lt;br&gt;Feel free to check out my &lt;a href="http://www.atalasoft.com/cs/files/folders/13850/download.aspx" title="Batch Watermarker Source"&gt;source code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;~Kevin&lt;br&gt;Atalasoft Developer Support Engineer&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/04/14/31-ways-you-can-add-imaging-value-to-your-application.aspx"&gt;About
Atalasoft's 31 Apps in 31 Days&lt;/a&gt;
&lt;/p&gt;&lt;p&gt;Make sure you add
this blog to your &lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/rss.aspx"&gt;&lt;span style="font-weight:bold;"&gt;RSS&lt;/span&gt;&lt;/a&gt;&lt;span style="font-weight:bold;"&gt; / &lt;/span&gt;&lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/atom.aspx"&gt;&lt;span style="font-weight:bold;"&gt;Atom&lt;/span&gt;&lt;/a&gt;&lt;span style="font-weight:bold;"&gt; &lt;/span&gt;feed
and check the &lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/pages/31-Apps-in-31-Days-Gallery.aspx"&gt;gallery&lt;/a&gt;
for summaries of all the apps as they are released.



&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/05/when-one-watermarked-image-just-isn-t-enough.aspx&amp;amp;;subject=When+just+one+watermarked+image+simply+isn%27t+enough" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/05/when-one-watermarked-image-just-isn-t-enough.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/05/when-one-watermarked-image-just-isn-t-enough.aspx&amp;amp;;title=When+just+one+watermarked+image+simply+isn%27t+enough" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/05/when-one-watermarked-image-just-isn-t-enough.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/05/when-one-watermarked-image-just-isn-t-enough.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/05/when-one-watermarked-image-just-isn-t-enough.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/05/when-one-watermarked-image-just-isn-t-enough.aspx&amp;amp;title=When+just+one+watermarked+image+simply+isn%27t+enough" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/05/when-one-watermarked-image-just-isn-t-enough.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/05/when-one-watermarked-image-just-isn-t-enough.aspx&amp;amp;;title=When+just+one+watermarked+image+simply+isn%27t+enough" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/05/when-one-watermarked-image-just-isn-t-enough.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/05/when-one-watermarked-image-just-isn-t-enough.aspx&amp;amp;;title=When+just+one+watermarked+image+simply+isn%27t+enough&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/05/when-one-watermarked-image-just-isn-t-enough.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13824" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/DotImage/default.aspx">DotImage</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/31+apps+apps+in+31+days/default.aspx">31 apps apps in 31 days</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/watermarks/default.aspx">watermarks</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/batch+watermarker/default.aspx">batch watermarker</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/automated+watermarks/default.aspx">automated watermarks</category></item><item><title>Presenting at the Western Mass.NET Users Group</title><link>http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/05/presenting-at-the-western-mass-net-users-group.aspx</link><pubDate>Mon, 05 May 2008 12:59:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13886</guid><dc:creator>jacobl</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;I will be doing a &lt;a href="http://wmassdotnet.org/blogs/events/archive/2008/04/29/tuesday-may-6th-introduction-to-build-automation-using-nant-and-cruisecontrol.aspx" target="_blank"&gt;presentation on build automation using CruiseControl and NAnt&lt;/a&gt; at the Western Mass .NET Users Group meeting on May 6th at 6pm.&lt;/p&gt;&lt;p&gt;The presentation will cover the basics of &lt;a href="http://cruisecontrol.sourceforge.net/" target="_blank"&gt;CruiseControl&lt;/a&gt; and &lt;a href="http://nant.sourceforge.net/" target="_blank"&gt;NAnt&lt;/a&gt; as well as developing custom tasks to stretch this already flexible framework even further.&lt;br&gt;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/05/presenting-at-the-western-mass-net-users-group.aspx&amp;amp;;subject=Presenting+at+the+Western+Mass.NET+Users+Group" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/05/presenting-at-the-western-mass-net-users-group.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/05/presenting-at-the-western-mass-net-users-group.aspx&amp;amp;;title=Presenting+at+the+Western+Mass.NET+Users+Group" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/05/presenting-at-the-western-mass-net-users-group.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/05/presenting-at-the-western-mass-net-users-group.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/05/presenting-at-the-western-mass-net-users-group.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/05/presenting-at-the-western-mass-net-users-group.aspx&amp;amp;title=Presenting+at+the+Western+Mass.NET+Users+Group" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/05/presenting-at-the-western-mass-net-users-group.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/05/presenting-at-the-western-mass-net-users-group.aspx&amp;amp;;title=Presenting+at+the+Western+Mass.NET+Users+Group" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/05/presenting-at-the-western-mass-net-users-group.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/05/presenting-at-the-western-mass-net-users-group.aspx&amp;amp;;title=Presenting+at+the+Western+Mass.NET+Users+Group&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/05/presenting-at-the-western-mass-net-users-group.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13886" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/jake/archive/tags/NAnt/default.aspx">NAnt</category><category domain="http://www.atalasoft.com/cs/blogs/jake/archive/tags/Build+Systems/default.aspx">Build Systems</category><category domain="http://www.atalasoft.com/cs/blogs/jake/archive/tags/Presentations/default.aspx">Presentations</category></item><item><title>Batch Thumbnails</title><link>http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/04/batch-thumbnails.aspx</link><pubDate>Sun, 04 May 2008 15:35:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13819</guid><dc:creator>Steve Hawley</dc:creator><slash:comments>2</slash:comments><description>&lt;p&gt;This application is a command line tool for generating thumbnail images.&amp;nbsp; To use it, unzip the executable and run it from a command prompt.&amp;nbsp; The typical usage is:&lt;/p&gt;&lt;p&gt;thumbnailer /maxwidth &lt;i&gt;width &lt;/i&gt;/maxheight &lt;i&gt;height &lt;/i&gt;folder1 folder2 folder3&lt;/p&gt;&lt;p&gt;Thumbnailer will open every image in every folder supplied and will create a thumbnail image is the same proportions as the original image, but will not exceed the maximum width or height.&lt;/p&gt;&lt;p&gt;By default, output thumbnails will be put into the same folder as the original image.&amp;nbsp; If the original image is named &lt;b&gt;&lt;i&gt;originalname.ext&lt;/i&gt;&lt;/b&gt;, the output thumbnail will be named tn&lt;b&gt;&lt;i&gt;originalname&lt;/i&gt;&lt;/b&gt;.jpg.&amp;nbsp; If tnoriginalname.jpg exists, it will not be overwritten.&lt;/p&gt;&lt;p&gt;thumbnailer needs at least one folder to operate on, but it can accept any number.&amp;nbsp;&lt;/p&gt;&lt;p&gt;If you omit maxwidth or maxheight, they will be 64 by default.&lt;/p&gt;&lt;p&gt;The complete set of options are as follows:&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;/nobanner - when this option is present, thumbnailer will not print a banner message to the error output stream.&lt;/li&gt;&lt;li&gt;/prefix thumbnailprefix - sets the prefix to use on output files.&amp;nbsp; The default value is tn.&amp;nbsp; Output files will be named thumnailprefix&lt;i&gt;&lt;b&gt;originalfilename&lt;/b&gt;&lt;/i&gt;.jpg&lt;br&gt;&lt;/li&gt;&lt;li&gt;/suffix thumbnailsuffix - sets the suffix to use on output files.&amp;nbsp; The default value is the empty string.&amp;nbsp; Outputfiles will be named &lt;i&gt;&lt;b&gt;originalfilename&lt;/b&gt;&lt;/i&gt;thumbnailsuffix.jpg&lt;/li&gt;&lt;li&gt;/maxwidth width - sets the maximum width for an output thumbnail&lt;/li&gt;&lt;li&gt;/maxheight height - sets the maximum height for an output thumbnail&lt;/li&gt;&lt;li&gt;/outputfolder folder - puts all thumbnails from all original folders into the specified output folder.&amp;nbsp; The default action is to put them in the same folder as the source images&lt;/li&gt;&lt;li&gt;/overwritethumbs - if present, this options will cause existing thumbnails to be overwritten, otherwise existing thumbnails are ignored.&lt;/li&gt;&lt;li&gt;/doprefixedfiles - if present, this option will cause files that start with the thumbnail prefix to be turned into thumbnails.&amp;nbsp; By default, they are ignored.&lt;/li&gt;&lt;/ul&gt;Options can start with / or - to make both DOS users and UNIX users happy.&lt;br&gt;&lt;p&gt;&lt;b&gt;Inside the Source Code&lt;/b&gt;&lt;/p&gt;&lt;p&gt;The source code is very simple - most of the code handles command line arguments.&amp;nbsp; If you look at the Main method, you will see that the app makes a single eponymous object, processes arguments, prints a banner, then makes thumbnails.&lt;/p&gt;&lt;p&gt;The method MakeThumbs with no arguments loops over a list of folders and delegates the task of creating thumbs to another flavor of MakeThumbs which loops over each image file in a folder, makes a thumbnail image, then writes out the file, if appropriate.&lt;/p&gt;&lt;p&gt;MakeThumb reads in an image, turns it into a thumbnail using a ResampleCommand object then returns the thumb.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/files/folders/13820/download.aspx"&gt;Download executable&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.atalasoft.com/cs/files/folders/13821/download.aspx"&gt;Download source&lt;/a&gt;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/04/batch-thumbnails.aspx&amp;amp;;subject=Batch+Thumbnails" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/04/batch-thumbnails.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/04/batch-thumbnails.aspx&amp;amp;;title=Batch+Thumbnails" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/04/batch-thumbnails.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/04/batch-thumbnails.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/04/batch-thumbnails.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/04/batch-thumbnails.aspx&amp;amp;title=Batch+Thumbnails" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/04/batch-thumbnails.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/04/batch-thumbnails.aspx&amp;amp;;title=Batch+Thumbnails" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/04/batch-thumbnails.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/04/batch-thumbnails.aspx&amp;amp;;title=Batch+Thumbnails&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/04/batch-thumbnails.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13819" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/thumbnail+image+imageprocessing/default.aspx">thumbnail image imageprocessing</category></item><item><title>Product Box Generator</title><link>http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/03/product-box-generator.aspx</link><pubDate>Sat, 03 May 2008 15:11:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13812</guid><dc:creator>Glenn</dc:creator><slash:comments>3</slash:comments><description>&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;font face="Times New Roman" size="3"&gt;&lt;/font&gt;&amp;nbsp;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;text-align:center;"&gt;&lt;font face="Arial" size="3"&gt;&lt;img src="http://www.atalasoft.com/cs/photos/gchittenden/images/13816/original.aspx" title="Product Box Generator" style="width:344px;height:425px;" alt="Product Box Generator" align="absmiddle" height="425" width="344"&gt;&amp;nbsp;&lt;/font&gt;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;font face="Arial" size="3"&gt;&amp;nbsp;&lt;/font&gt;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;font face="Arial" size="3"&gt;Welcome to the third of 31 applications we will post (in addition to the &lt;a href="http://www.atalasoft.com/events/31appsin31days/"&gt;contest&lt;/a&gt; participants' submissions). Make sure you add this blog to your &lt;b&gt;&lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/rss.aspx"&gt;RSS&lt;/a&gt; / &lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/atom.aspx"&gt;Atom&lt;/a&gt; &lt;/b&gt;feed and check the &lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/pages/31-Apps-in-31-Days-Gallery.aspx" title="Gallery Page"&gt;gallery&lt;/a&gt; for summaries of all the apps as they are released. &lt;br&gt;&lt;/font&gt;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&amp;nbsp;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;font face="Arial" size="3"&gt;This application will generate a software package box image with up to three images for the front, side and top of the box.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Each image can be stretched to fit its area or centered with a background color.&lt;/font&gt;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;o:p&gt;&lt;font face="Times New Roman" size="3"&gt;&amp;nbsp;&lt;/font&gt;&lt;/o:p&gt;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;font size="3"&gt;&lt;font face="Times New Roman"&gt;&lt;b&gt;Usage&lt;/b&gt;:&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;

&lt;ol style="margin-top:0in;"&gt;
&lt;li class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;font face="Arial" size="3"&gt;Choose the images to use for the box areas by either typing the location of the file or clicking the button to the right of the textbox for a file dialog.&lt;span&gt;&amp;nbsp; &lt;/span&gt;If an image is not supplied, that area will be filled with the background color.&lt;br&gt;&lt;/font&gt;&lt;/li&gt;

&lt;li class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;font face="Arial" size="3"&gt;Place a checkmark in the &lt;b&gt;Stretch&lt;/b&gt; checkbox to have the image stretched to fit the area.&lt;span&gt;&amp;nbsp; &lt;/span&gt;When unchecked the image will be centered within the area.&lt;br&gt;&lt;/font&gt;&lt;/li&gt;

&lt;li class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;font face="Arial" size="3"&gt;Click the button to the right of “&lt;b&gt;Background Color&lt;/b&gt;:” to select the color used when an image does not fill the area.&lt;br&gt;&lt;/font&gt;&lt;/li&gt;

&lt;li class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;font face="Arial" size="3"&gt;Click the &lt;b&gt;Generate&lt;/b&gt; button to create the image.&lt;/font&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;font face="Arial" size="3"&gt;Once the image has been generated, it can be saved using the &lt;b&gt;File&lt;/b&gt; &amp;gt; &lt;b&gt;Save&lt;/b&gt; menu item.&lt;/font&gt;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&amp;nbsp;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;u&gt;&lt;b&gt;&lt;a href="http://www.atalasoft.com/cs/files/folders/13827/download.aspx"&gt;Download the installer&lt;/a&gt;.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;br&gt;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;u&gt;&lt;b&gt;&lt;a href="http://www.atalasoft.com/cs/files/folders/13815/download.aspx"&gt;Download the source&lt;/a&gt;.&amp;nbsp;&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;br&gt;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&lt;u&gt;&lt;b&gt;&lt;a href="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/04/14/31-ways-you-can-add-imaging-value-to-your-application.aspx"&gt;About Atalasoft's 31 Apps in 31 Days&lt;/a&gt; &lt;/b&gt;&lt;/u&gt;&lt;br&gt;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&amp;nbsp;&lt;/p&gt;

&lt;p class="MsoNormal" style="margin:0in 0in 0pt;"&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class = "shareblock"&gt;&lt;strong&gt;Share this post:&lt;/strong&gt; &lt;a href = "mailto:?body=Thought you might like this: http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/03/product-box-generator.aspx&amp;amp;;subject=Product+Box+Generator" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/03/product-box-generator.aspx"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/03/product-box-generator.aspx&amp;amp;;title=Product+Box+Generator" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/03/product-box-generator.aspx"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/03/product-box-generator.aspx&amp;amp;;phase=2" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/03/product-box-generator.aspx"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/03/product-box-generator.aspx&amp;amp;title=Product+Box+Generator" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/03/product-box-generator.aspx"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/03/product-box-generator.aspx&amp;amp;;title=Product+Box+Generator" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/03/product-box-generator.aspx"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;;mkt=en-us&amp;amp;;url=http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/03/product-box-generator.aspx&amp;amp;;title=Product+Box+Generator&amp;amp;;top=1" target="_blank" title = "Post http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/03/product-box-generator.aspx"&gt;live it!&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13812" width="1" height="1"&gt;</description><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/stretch+images/default.aspx">stretch images</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/source+code/default.aspx">source code</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/product+box+generator/default.aspx">product box generator</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/generator/default.aspx">generator</category><category domain="http://www.atalasoft.com/cs/blogs/31appsin31days/archive/tags/Atalasoft+31+Apps+in+31+Days/default.aspx">Atalasoft 31 Apps in 31 Days</category></item><item><title>Using PNG Predictors to Enhance GZIP/PKZIP/FLATE Compression</title><link>http://www.atalasoft.com/cs/blogs/rickm/archive/2008/05/02/using-png-predictors-to-enhance-gzip-pkzip-flate-compression.aspx</link><pubDate>Fri, 02 May 2008 20:25:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13874</guid><dc:creator>RickM</dc:creator><slash:comments>1</slash:comments><description>I’ve been doing a lot of work in the PDF space lately. While implementing Binary Cross Reference Streams I was surprised to see that they could be encoded with PNG Predictors. This was surprising to me because binary cross reference streams aren’t images, they are byte tables: While the values vary, they are often within the same ranges. The first byte can only contain the numbers 0, 1 and 2 and are often the same, the middle two bytes are often the same and the last byte is generally increasing...(&lt;a href="http://www.atalasoft.com/cs/blogs/rickm/archive/2008/05/02/using-png-predictors-to-enhance-gzip-pkzip-flate-compression.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://www.atalasoft.com/cs/aggbug.aspx?PostID=13874" width="1" height="1"&gt;</description><enclosure url="http://www.atalasoft.com/cs/blogs/rickm/attachment/13874.ashx" length="1109" type="image/x-png" /><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/programming/default.aspx">programming</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/optimization/default.aspx">optimization</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/Tutorials/default.aspx">Tutorials</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/memory/default.aspx">memory</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/pdf/default.aspx">pdf</category><category domain="http://www.atalasoft.com/cs/blogs/rickm/archive/tags/compression/default.aspx">compression</category></item><item><title>Atala Auto Rotater</title><link>http://www.atalasoft.com/cs/blogs/31appsin31days/archive/2008/05/02/Atala-Auto-Rotater.aspx</link><pubDate>Fri, 02 May 2008 14:00:00 GMT</pubDate><guid isPermaLink="false">647108ca-f046-4d8d-9feb-a7fbd2049b37:13780</guid><dc:creator>dterrell</dc:creator><slash:comments>2</slash:comments><description>&lt;p&gt;&lt;img src="http://www.atalasoft.com/cs/photos/dterrell/images/13810/original.aspx" title="AtalaAutoRotater" alt="AtalaAutoRotater" height="260" width="345"&g