<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>Zupancic Perspective (v2.0)</title>
    <link>http://blog.devstone.com/aaron/</link>
    <description>An insight into the world of R. Aaron Zupancic, software development (.NET, et al), muses, and much more...</description>
    <language>en-us</language>
    <copyright>R. Aaron Zupancic</copyright>
    <lastBuildDate>Fri, 23 Oct 2009 02:28:57 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.0.7226.0</generator>
    <managingEditor>aaron@devstone.com</managingEditor>
    <webMaster>aaron@devstone.com</webMaster>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/ZupancicPerspective" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
      <trackback:ping>http://blog.devstone.com/aaron/Trackback.aspx?guid=1a18e011-ea44-459e-84be-55a9046bce7d</trackback:ping>
      <pingback:server>http://blog.devstone.com/aaron/pingback.aspx</pingback:server>
      <pingback:target>http://blog.devstone.com/aaron/PermaLink,guid,1a18e011-ea44-459e-84be-55a9046bce7d.aspx</pingback:target>
      <dc:creator>R. Aaron Zupancic (Administrator)</dc:creator>
      <wfw:comment>http://blog.devstone.com/aaron/CommentView,guid,1a18e011-ea44-459e-84be-55a9046bce7d.aspx</wfw:comment>
      <wfw:commentRss>http://blog.devstone.com/aaron/SyndicationService.asmx/GetEntryCommentsRss?guid=1a18e011-ea44-459e-84be-55a9046bce7d</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <font face="Tahoma">I had the need today to create an application must run with administrative
privileges.  Fortunately, this is a pretty straightforward endeavor.</font>
        </p>
        <p>
          <font face="Tahoma">On Windows Vista, Windows 7, or Windows Server 2008 (and beyond)
I wanted to take advange of the Admin Approval Mode (AAM) or Over The Shoulder (OST)
UAC elevation prompt automatically (and as a side-effect have the little shield
icon accompanying my app's icon).  This wouldn't be possible on a previous OS
(such as Windows Server 2003 or XP), so I needed to add an explicit permission check.</font>
        </p>
        <p>
          <font face="Tahoma">To get the UAC prompt all you need to do is embed an application
manifest.  Vista+, when displaying the application icon, will probe the app and,
upon finding the manifest requiring admin rights, will display the icon properly.</font>
        </p>
        <p>
          <font face="Tahoma">Create a manifest file (e.g., app.exe.manifest) in your project. 
This is what mine looked like:</font>
        </p>
        <blockquote style="MARGIN-RIGHT: 0px" dir="ltr">
          <p>
            <font face="Courier New">&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;<br />
&lt;assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"&gt;<br />
  &lt;assemblyIdentity version="1.0.0.0" name="<strong>APPLICATION_NAME</strong>"/&gt;<br />
  &lt;trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"&gt;<br />
    &lt;security&gt;<br />
      &lt;requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"&gt;<br />
        &lt;requestedExecutionLevel level="<strong>requireAdministrator</strong>"
uiAccess="false"/&gt;<br />
      &lt;/requestedPrivileges&gt;<br />
    &lt;/security&gt;<br />
  &lt;/trustInfo&gt;<br />
&lt;/assembly&gt;</font>
          </p>
        </blockquote>
        <p dir="ltr">
          <font face="Tahoma">By default (if you don't create a manifest), a .NET application
will have the &lt;requestedExecutionLevel /&gt; set to 'asInvoker' and run the application
as the user invoking it.  You can set this to one of three values: asInvoker,
highestAvailable, and requireAdministrator.  Also, don't forget to set the name
to match your application's name.</font>
        </p>
        <p dir="ltr">
          <font face="Tahoma">Then, to embed the application you can do a few things.</font>
        </p>
        <p dir="ltr">
          <font face="Tahoma">One technique is to use the <strong>mt.exe</strong> (ManifestTool)
from the Visual Studio Command Prompt:</font>
        </p>
        <blockquote style="MARGIN-RIGHT: 0px" dir="ltr">
          <p dir="ltr">
            <font face="Courier New">mt.exe -manifest app.exe.manifest -updateresource:app.exe,#1</font>
          </p>
        </blockquote>
        <p dir="ltr">
          <font face="Tahoma">But I don't believe this would work if your application is signed
with a strong name unless you were to delay-sign it.</font>
        </p>
        <p dir="ltr">
          <font face="Tahoma">The easier (and better) approach is to use the Project Properties
--&gt; Application tab.  Simply select your app.exe.manifest file in the Manifest
dropdown.  It will automatically be embedded.</font>
        </p>
        <p dir="ltr">
          <font color="#0000ff" face="Tahoma">
            <em>NOTE: In order to debug your application that
requires admin rights you'll need to run Visual Studio from an elevated token. 
Otherwise you won't have privileges enough to attach to the process.</em>
          </font>
        </p>
        <p dir="ltr">
          <font face="Tahoma">Next, I wanted to ensure that the user runs the application with
administrative rights.  This check was placed particularly for the pre-Vista
operating systems which didn't have UAC.  To do this I added the following code:</font>
        </p>
        <blockquote style="MARGIN-RIGHT: 0px" dir="ltr">
          <p dir="ltr">
            <font face="Courier New">[STAThread()]<br /><font color="#008000">private static void</font> Main() {<br />
   Application.EnableVisualStyles();<br />
   Application.SetCompatibleTextRenderingDefault(<font color="#008000">false</font>);<br /><br />
   <font color="#a9a9a9"><em>// check to make sure that the user is running
with administrative rights.<br />
   // in Vista/Win7/Svr2008 this is automatically taken care of via the<br />
   // embedded manifest (which ensures administrative rights) via UAC.</em></font><br />
   <font color="#008000">try</font> {<br />
      <font color="#008000">if</font> ( !userHasAdminRights()
) {<br />
         MessageBox.Show(<font color="#a52a2a">"This
application requires administrative privileges."</font>,<br />
                         <font color="#a52a2a">"Unauthorized
Access"</font>,<br />
                        
MessageBoxButtons.OK, MessageBoxIcon.Information);<br />
         <font color="#008000">return</font>;<br />
      }<br />
   }<br />
   <font color="#008000">catch</font> ( Exception er ) {<br />
      MessageBox.Show(er.ToString());  <font color="#a9a9a9"><em>//
Of course you'd handle this differently</em></font><br />
   }<br /><br />
   Application.Run(<font color="#008000">new</font> MainForm());<br />
}<br /><br /><br /><font color="#008000">private static bool</font> userHasAdminRights() {<br />
   WindowsIdentity identity = WindowsIdentity.GetCurrent();<br />
   <font color="#008000">return</font> ( <font color="#008000">null</font> !=
identity &amp;&amp; <font color="#008000">new</font> WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator)
);<br />
}</font>
          </p>
        </blockquote>
        <p dir="ltr">
          <font face="Tahoma">Pretty simple, really.</font>
        </p>
        <img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=1a18e011-ea44-459e-84be-55a9046bce7d" />
      </body>
      <title>Enforcing Administrative Privileges</title>
      <guid isPermaLink="false">http://blog.devstone.com/aaron/PermaLink,guid,1a18e011-ea44-459e-84be-55a9046bce7d.aspx</guid>
      <link>http://feedproxy.google.com/~r/ZupancicPerspective/~3/kOavYejK4BE/EnforcingAdministrativePrivileges.aspx</link>
      <pubDate>Fri, 23 Oct 2009 02:28:57 GMT</pubDate>
      <description>&lt;p&gt;
&lt;font face=Tahoma&gt;I had the need today to create an application must run with administrative
privileges.&amp;nbsp; Fortunately, this is a pretty straightforward endeavor.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;On Windows Vista, Windows 7, or Windows Server 2008 (and beyond)
I wanted to take advange of the Admin Approval Mode (AAM) or Over The Shoulder (OST)
UAC&amp;nbsp;elevation prompt automatically (and as a side-effect have the little shield
icon accompanying my app's icon).&amp;nbsp; This wouldn't be possible on a previous OS
(such as Windows Server 2003 or XP), so I needed to add an explicit permission check.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;To get the UAC prompt all you need to do is embed an application
manifest.&amp;nbsp; Vista+, when displaying the application icon, will probe the app and,
upon finding the manifest requiring admin rights, will display the icon properly.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;Create a manifest file (e.g., app.exe.manifest) in your project.&amp;nbsp;
This is what mine looked like:&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote style="MARGIN-RIGHT: 0px" dir=ltr&gt; 
&lt;p&gt;
&lt;font face="Courier New"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&amp;gt;&lt;br&gt;
&amp;lt;assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"&amp;gt;&lt;br&gt;
&amp;nbsp; &amp;lt;assemblyIdentity version="1.0.0.0" name="&lt;strong&gt;APPLICATION_NAME&lt;/strong&gt;"/&amp;gt;&lt;br&gt;
&amp;nbsp; &amp;lt;trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;security&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;requestedExecutionLevel level="&lt;strong&gt;requireAdministrator&lt;/strong&gt;"
uiAccess="false"/&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/requestedPrivileges&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/security&amp;gt;&lt;br&gt;
&amp;nbsp; &amp;lt;/trustInfo&amp;gt;&lt;br&gt;
&amp;lt;/assembly&amp;gt;&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p dir=ltr&gt;
&lt;font face=Tahoma&gt;By default (if you don't create a manifest), a .NET application
will have the &amp;lt;requestedExecutionLevel /&amp;gt; set to 'asInvoker' and run the application
as the user invoking it.&amp;nbsp; You can set this to one of three values: asInvoker,
highestAvailable, and requireAdministrator.&amp;nbsp; Also, don't forget to set the name
to match your application's name.&lt;/font&gt;
&lt;/p&gt;
&lt;p dir=ltr&gt;
&lt;font face=Tahoma&gt;Then, to embed the application you can do a few things.&lt;/font&gt;
&lt;/p&gt;
&lt;p dir=ltr&gt;
&lt;font face=Tahoma&gt;One technique is to use the &lt;strong&gt;mt.exe&lt;/strong&gt; (ManifestTool)
from the Visual Studio Command Prompt:&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote style="MARGIN-RIGHT: 0px" dir=ltr&gt; 
&lt;p dir=ltr&gt;
&lt;font face="Courier New"&gt;mt.exe -manifest app.exe.manifest -updateresource:app.exe,#1&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p dir=ltr&gt;
&lt;font face=Tahoma&gt;But I don't believe this would work if your application is signed
with a strong name unless you were to delay-sign it.&lt;/font&gt;
&lt;/p&gt;
&lt;p dir=ltr&gt;
&lt;font face=Tahoma&gt;The easier (and better) approach is to use the Project Properties
--&amp;gt; Application tab.&amp;nbsp; Simply select your app.exe.manifest file in the Manifest
dropdown.&amp;nbsp; It will automatically be embedded.&lt;/font&gt;
&lt;/p&gt;
&lt;p dir=ltr&gt;
&lt;font color=#0000ff face=Tahoma&gt;&lt;em&gt;NOTE: In order to debug your application that
requires admin rights you'll need to run Visual Studio from an elevated token.&amp;nbsp;
Otherwise you won't have privileges enough to attach to the process.&lt;/em&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p dir=ltr&gt;
&lt;font face=Tahoma&gt;Next, I wanted to ensure that the user runs the application with
administrative rights.&amp;nbsp; This check was placed particularly for the pre-Vista
operating systems which didn't have UAC.&amp;nbsp; To do this I added the following code:&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote style="MARGIN-RIGHT: 0px" dir=ltr&gt; 
&lt;p dir=ltr&gt;
&lt;font face="Courier New"&gt;[STAThread()]&lt;br&gt;
&lt;font color=#008000&gt;private static void&lt;/font&gt; Main() {&lt;br&gt;
&amp;nbsp;&amp;nbsp; Application.EnableVisualStyles();&lt;br&gt;
&amp;nbsp;&amp;nbsp; Application.SetCompatibleTextRenderingDefault(&lt;font color=#008000&gt;false&lt;/font&gt;);&lt;br&gt;
&lt;br&gt;
&amp;nbsp; &amp;nbsp;&lt;font color=#a9a9a9&gt;&lt;em&gt;// check to make sure that the user is running
with administrative rights.&lt;br&gt;
&amp;nbsp;&amp;nbsp; // in Vista/Win7/Svr2008 this is automatically taken care of via the&lt;br&gt;
&amp;nbsp;&amp;nbsp; // embedded manifest (which ensures administrative rights) via UAC.&lt;/em&gt;&lt;/font&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;try&lt;/font&gt; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;if&lt;/font&gt; ( !userHasAdminRights()
) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MessageBox.Show(&lt;font color=#a52a2a&gt;"This
application requires administrative privileges."&lt;/font&gt;,&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#a52a2a&gt;"Unauthorized
Access"&lt;/font&gt;,&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
MessageBoxButtons.OK, MessageBoxIcon.Information);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;return&lt;/font&gt;;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;catch&lt;/font&gt; ( Exception er ) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MessageBox.Show(er.ToString());&amp;nbsp; &lt;font color=#a9a9a9&gt;&lt;em&gt;//
Of course you'd handle this differently&lt;/em&gt;&lt;/font&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp; Application.Run(&lt;font color=#008000&gt;new&lt;/font&gt; MainForm());&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;font color=#008000&gt;private static bool&lt;/font&gt; userHasAdminRights() {&lt;br&gt;
&amp;nbsp;&amp;nbsp; WindowsIdentity identity = WindowsIdentity.GetCurrent();&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;return&lt;/font&gt; ( &lt;font color=#008000&gt;null&lt;/font&gt; !=
identity &amp;amp;&amp;amp; &lt;font color=#008000&gt;new&lt;/font&gt; WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator)
);&lt;br&gt;
}&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p dir=ltr&gt;
&lt;font face=Tahoma&gt;Pretty simple, really.&lt;/font&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=1a18e011-ea44-459e-84be-55a9046bce7d" /&gt;</description>
      <comments>http://blog.devstone.com/aaron/CommentView,guid,1a18e011-ea44-459e-84be-55a9046bce7d.aspx</comments>
      <category>C#</category>
      <category>Security</category>
    <feedburner:origLink>http://blog.devstone.com/aaron/2009/10/23/EnforcingAdministrativePrivileges.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://blog.devstone.com/aaron/Trackback.aspx?guid=bc8582e7-73de-49d7-bb91-c801bf9f71ba</trackback:ping>
      <pingback:server>http://blog.devstone.com/aaron/pingback.aspx</pingback:server>
      <pingback:target>http://blog.devstone.com/aaron/PermaLink,guid,bc8582e7-73de-49d7-bb91-c801bf9f71ba.aspx</pingback:target>
      <dc:creator>R. Aaron Zupancic (Administrator)</dc:creator>
      <wfw:comment>http://blog.devstone.com/aaron/CommentView,guid,bc8582e7-73de-49d7-bb91-c801bf9f71ba.aspx</wfw:comment>
      <wfw:commentRss>http://blog.devstone.com/aaron/SyndicationService.asmx/GetEntryCommentsRss?guid=bc8582e7-73de-49d7-bb91-c801bf9f71ba</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <font face="Tahoma">Here's something I threw together the other day to help me organize
my ripped audio books.  I have several audio books (Harry Potter, LOTR, Dresden
Files, etc) that I've been ripping to file so that I could gather an entire 10-20
CD set onto a single disc for easy listening while driving without needing to switch
discs.  I like to use WMA files for easy ripping (via Media Player) and the small
footprint.</font>
        </p>
        <p>
          <font face="Tahoma">I've found, much to my chagrin, that the information retrieved
online for these books (via CDDB, FreeDB, or All Music Guide (which WMP uses))
is unreliable, frequently contains typos and misspellings, and is extremely inconsistent
with respect to formatting and convention.</font>
        </p>
        <p>
          <font face="Tahoma">I found that when I inserted a CD I would spend a good amount
of time entering the book name, the genre, the year it was recorded, the author, and
the performer, and I'd take the time to rename the tracks.  After a handful of
CDs this was almost unbearable and extremely tedious.</font>
        </p>
        <p>
          <font face="Tahoma">I therefore set out to write a script that would do this, updating
all of the ID3 tags after the fact.  The only thing I would need to concern myself
with was that the book name (I like the form <em>Book Name - Disc XX</em>) was correct. 
This script belows makes a few assumptions about the folder and file names:</font>
        </p>
        <ul>
          <li>
            <font face="Tahoma">each folder contains a single disk and that they are named according
to the pattern <em>"Book Name - Disc XX"</em></font>
          </li>
          <li>
            <font face="Tahoma">all books will be collected into a single folder with the name
pattern <em>"Book Set - Book Name"</em></font>
          </li>
        </ul>
        <p>
          <font face="Tahoma">For example, I ripped a book by </font>
          <a href="http://www.jim-butcher.com/">
            <font face="Tahoma">Jim
Butcher</font>
          </a>
          <font face="Tahoma"> named Small Favor.  Each disc went into
a folder named "Small Favor - Disc 01", "Small Favor - Disc 02", etc.  I would
then collect all the ripped files into a single directory named "Dresden Files - Book
10 - Small Favor".  This way, when all was said and done, I'd have all the books
in order and grouped.</font>
        </p>
        <p>
          <font face="Tahoma">I decided to use <a href="http://technet.microsoft.com/en-us/scriptcenter/dd742419.aspx">PowerShell</a> as
the language of preference for automating this procedure.  Not only does it provide
a very powerful scripting environment, but I can also leverage the .NET Framework
(which I love dearly).  As such, I was able to take advantage of </font>
          <a href="http://developer.novell.com/wiki/index.php/TagLib_Sharp">
            <font face="Tahoma">TagLib#</font>
          </a>
          <font face="Tahoma">'s
ability to edit the tags within the files.  This script assumes that the taglib-sharp.dll
is in the same directory as the .ps1 script file.</font>
        </p>
        <p>
          <font face="Tahoma">The following PowerShell scripts performs all the collecting,
enumerating, and tagging of my files.  Feel free to adapt it and tweak it according
to your own preferences.  If you have suggestions, I'd welcome them.  Like
I said, I threw it together in a very short time so it's probably weak in many regards
but seems to get the job done.</font>
        </p>
        <p>
          <font face="Tahoma">Taking my example above, my command line would be:</font>
        </p>
        <blockquote style="MARGIN-RIGHT: 0px" dir="ltr">
          <p>
            <em>
              <font face="Tahoma">.\collectaudiobook "Small Favor" "Dresden Files - Book 10"
"Jim Butcher" "James Marsters" 2008</font>
            </em>
          </p>
        </blockquote>
        <p dir="ltr">
          <font face="Tahoma">Now I don't need to worry about what information was loaded from
the CDDB-esque service, the script updates it all after-the-fact. :)</font>
        </p>
        <p>
          <strong>
            <font size="3" face="Courier New">CollectAudioBook.ps1</font>
          </strong>
        </p>
        <blockquote style="MARGIN-RIGHT: 0px" dir="ltr">
          <p>
            <font face="Courier New">$a = $args.length</font>
          </p>
          <p>
            <font face="Courier New">if ( $a -lt 2 ) {<br />
  write @"</font>
          </p>
          <p>
            <font face="Courier New">USAGE:</font>
          </p>
          <p>
            <font face="Courier New">`t.\CollectAudioBook.ps1 titlePrefix targetFolderPrefix [author]
[artist] [year]</font>
          </p>
          <p>
            <font face="Courier New">REQUIRED PARAMETERS:</font>
          </p>
          <p>
            <font face="Courier New">titlePrefix<br />
`tSpecifies the subfolders to process as a single book.<br />
`t(e.g., 'Small Favor' would locate 'Small Favor - Disc 01', 'Small Favor - Disc 02',
etc)<br />
`tThe folders are processed in order by name, assuming that to be the proper sequencing
of the resulting files.</font>
          </p>
          <p>
            <font face="Courier New">targetFolderPrefix<br />
`tSpecifies the target folder to which all tracks are collected.  If this<br />
`tfolder doesn't exist, it is created.<br />
`tNOTE: The folder's full name will be comprised of the targetFolderPrefix, a hyphen,
and the titlePrefix.<br />
`t(e.g., a titlePrefix of 'Small Favor' and a targetFolderPrefix of 'Dresden Files
- Book 10' becomes<br />
`tDresden Files - Book 10 - Small Favor)</font>
          </p>
          <p>
            <font face="Courier New">author<br />
`tIdentifies the author of the book.</font>
          </p>
          <p>
            <font face="Courier New">artist<br />
`tIdentifies the name of the performer.</font>
          </p>
          <p>
            <font face="Courier New">year<br />
`tIdentifies the year of the recording.</font>
          </p>
          <p>
            <font face="Courier New">"@<br />
  exit<br />
}</font>
          </p>
          <p>
            <font face="Courier New">$bookName = $args[0]<br />
$bookSet = $args[1] + ' - ' + $bookName<br />
$author = $args[2]<br />
$artist = $args[3]<br />
$year = $args[4]</font>
          </p>
          <p>
            <font face="Courier New">$target = '.\' + $bookSet<br />
$partNum = 0</font>
          </p>
          <p>
            <font face="Courier New"># load taglib-sharp.dll which allows for the manipulation
on the media tags in the files<br />
$asm = [Reflection.Assembly]::LoadFrom((Resolve-Path ".\taglib-sharp.dll"))</font>
          </p>
          <p>
            <font face="Courier New"># create the target directory<br />
$dir = New-Item -path "$target" -type directory -force</font>
          </p>
          <p>
            <font face="Courier New"># enumerate all files in each folder that start with the
prefix, copying and renaming each file<br />
foreach ( $folder in ( Get-ChildItem .\$bookName* | Where-Object { $_.Mode.StartsWith('d')
} | Sort Name ) ) {<br />
  foreach ( $file in ( Get-ChildItem $folder | Sort Name ) ) {<br />
    ++$partNum</font>
          </p>
          <p>
            <font face="Courier New">    $targetPrefix = 'Part ' + $partNum.ToString("00")<br />
    $targetFileName = $targetPrefix + '.wma'<br />
    write "Copying $file`t--&gt;`t$targetFileName"<br />
    Copy-Item $folder\$file $target\$targetFileName</font>
          </p>
          <p>
            <font face="Courier New">    # update the media information in the file<br />
    $media = [TagLib.File]::Create((Resolve-Path "$target\$targetFileName"))<br />
    $media.Tag.Title = $bookName + ' - ' + $targetPrefix<br />
    if ( $author -ne $null ) { $media.Tag.AlbumArtists = $author }<br />
    if ( $artist -ne $null ) { $media.Tag.Performers = $artist }<br />
    $media.Tag.Genres = { Audio Book }<br />
    if ( $year -ne $null ) { $media.Tag.Year = $year }<br />
    $media.Save()<br />
  }<br />
}</font>
          </p>
        </blockquote>
        <img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=bc8582e7-73de-49d7-bb91-c801bf9f71ba" />
      </body>
      <title>Simplifying the Ripping of AudioBooks and Tagging with PowerShell</title>
      <guid isPermaLink="false">http://blog.devstone.com/aaron/PermaLink,guid,bc8582e7-73de-49d7-bb91-c801bf9f71ba.aspx</guid>
      <link>http://feedproxy.google.com/~r/ZupancicPerspective/~3/Q9N-XbjOLiI/SimplifyingTheRippingOfAudioBooksAndTaggingWithPowerShell.aspx</link>
      <pubDate>Tue, 25 Aug 2009 05:20:53 GMT</pubDate>
      <description>&lt;p&gt;
&lt;font face=Tahoma&gt;Here's something I threw together the other day to help me organize
my ripped audio books.&amp;nbsp; I have several audio books (Harry Potter, LOTR, Dresden
Files, etc) that I've been ripping to file so that I could gather an entire 10-20
CD set onto a single disc for easy listening while driving without needing to switch
discs.&amp;nbsp; I like to use WMA files for easy ripping (via Media Player) and the small
footprint.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;I've found, much to my chagrin, that the information retrieved online
for these books&amp;nbsp;(via CDDB, FreeDB, or All Music Guide (which WMP uses)) is unreliable,
frequently contains typos and misspellings, and is extremely inconsistent with respect
to formatting and convention.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;I found that when I inserted a CD I would spend a good amount of
time entering the book name, the genre, the year it was recorded, the author, and
the performer, and I'd take the time to rename the tracks.&amp;nbsp; After a handful of
CDs this was almost unbearable and extremely tedious.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;I therefore set out to write a script that would do this, updating
all of the ID3 tags after the fact.&amp;nbsp; The only thing I would need to concern myself
with was that the book name (I like the form &lt;em&gt;Book Name - Disc XX&lt;/em&gt;) was correct.&amp;nbsp;
This script belows makes a few assumptions about the folder and file names:&lt;/font&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;font face=Tahoma&gt;each folder contains a single disk and that they are named according
to the pattern &lt;em&gt;"Book Name - Disc XX"&lt;/em&gt;&lt;/font&gt; 
&lt;li&gt;
&lt;font face=Tahoma&gt;all books will be collected into a single folder with the name pattern &lt;em&gt;"Book
Set - Book Name"&lt;/em&gt;&lt;/font&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;For example, I ripped a book by &lt;/font&gt;&lt;a href="http://www.jim-butcher.com/"&gt;&lt;font face=Tahoma&gt;Jim
Butcher&lt;/font&gt;&lt;/a&gt;&lt;font face=Tahoma&gt; named Small Favor.&amp;nbsp; Each disc went into
a folder named "Small Favor - Disc 01", "Small Favor - Disc 02", etc.&amp;nbsp; I would
then collect all the ripped files into a single directory named "Dresden Files - Book
10 - Small Favor".&amp;nbsp; This way, when all was said and done, I'd have all the books
in order and grouped.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;I decided to use &lt;a href="http://technet.microsoft.com/en-us/scriptcenter/dd742419.aspx"&gt;PowerShell&lt;/a&gt; as
the language of preference for automating this procedure.&amp;nbsp; Not only does it provide
a very powerful scripting environment, but I can also leverage the .NET Framework
(which I love dearly).&amp;nbsp; As such, I was able to take advantage of &lt;/font&gt;&lt;a href="http://developer.novell.com/wiki/index.php/TagLib_Sharp"&gt;&lt;font face=Tahoma&gt;TagLib#&lt;/font&gt;&lt;/a&gt;&lt;font face=Tahoma&gt;'s
ability to edit the tags within the files.&amp;nbsp; This script assumes that the taglib-sharp.dll
is in the same directory as the .ps1 script file.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;The following PowerShell scripts performs all the collecting, enumerating,
and tagging of my files.&amp;nbsp; Feel free to adapt it and tweak it according to your
own preferences.&amp;nbsp; If you have suggestions, I'd welcome them.&amp;nbsp; Like I said,
I threw it together in a very short time so it's probably weak in many regards but
seems to get the job done.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;Taking my example above, my command line would be:&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote style="MARGIN-RIGHT: 0px" dir=ltr&gt; 
&lt;p&gt;
&lt;em&gt;&lt;font face=Tahoma&gt;.\collectaudiobook "Small Favor" "Dresden Files - Book 10" "Jim
Butcher" "James Marsters" 2008&lt;/font&gt;&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p dir=ltr&gt;
&lt;font face=Tahoma&gt;Now I don't need to worry about what information was loaded from
the CDDB-esque service,&amp;nbsp;the script&amp;nbsp;updates it all after-the-fact. :)&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;&lt;font size=3 face="Courier New"&gt;CollectAudioBook.ps1&lt;/font&gt;&lt;/strong&gt;
&lt;/p&gt;
&lt;blockquote style="MARGIN-RIGHT: 0px" dir=ltr&gt; 
&lt;p&gt;
&lt;font face="Courier New"&gt;$a = $args.length&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;if ( $a -lt 2 ) {&lt;br&gt;
&amp;nbsp; write @"&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;USAGE:&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;`t.\CollectAudioBook.ps1 titlePrefix targetFolderPrefix [author]
[artist] [year]&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;REQUIRED PARAMETERS:&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;titlePrefix&lt;br&gt;
`tSpecifies the subfolders to process as a single book.&lt;br&gt;
`t(e.g., 'Small Favor' would locate 'Small Favor - Disc 01', 'Small Favor - Disc 02',
etc)&lt;br&gt;
`tThe folders are processed in order by name, assuming that to be the proper sequencing
of the resulting files.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;targetFolderPrefix&lt;br&gt;
`tSpecifies the target folder to which all tracks are collected.&amp;nbsp; If this&lt;br&gt;
`tfolder doesn't exist, it is created.&lt;br&gt;
`tNOTE: The folder's full name will be comprised of the targetFolderPrefix, a hyphen,
and the titlePrefix.&lt;br&gt;
`t(e.g., a titlePrefix of 'Small Favor' and a targetFolderPrefix of 'Dresden Files
- Book 10' becomes&lt;br&gt;
`tDresden Files - Book 10 - Small Favor)&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;author&lt;br&gt;
`tIdentifies the author of the book.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;artist&lt;br&gt;
`tIdentifies the name of the performer.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;year&lt;br&gt;
`tIdentifies the year of the recording.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;"@&lt;br&gt;
&amp;nbsp; exit&lt;br&gt;
}&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;$bookName = $args[0]&lt;br&gt;
$bookSet = $args[1] + ' - ' + $bookName&lt;br&gt;
$author = $args[2]&lt;br&gt;
$artist = $args[3]&lt;br&gt;
$year = $args[4]&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;$target = '.\' + $bookSet&lt;br&gt;
$partNum = 0&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;# load taglib-sharp.dll which allows for the manipulation
on the media tags in the files&lt;br&gt;
$asm = [Reflection.Assembly]::LoadFrom((Resolve-Path ".\taglib-sharp.dll"))&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;# create the target directory&lt;br&gt;
$dir = New-Item -path "$target" -type directory -force&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;# enumerate all files in each folder that start with the
prefix, copying and renaming each file&lt;br&gt;
foreach ( $folder in ( Get-ChildItem .\$bookName* | Where-Object { $_.Mode.StartsWith('d')
} | Sort Name ) ) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;foreach ( $file in ( Get-ChildItem $folder | Sort Name ) ) {&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;++$partNum&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;&amp;nbsp; &amp;nbsp; $targetPrefix = 'Part ' + $partNum.ToString("00")&lt;br&gt;
&amp;nbsp; &amp;nbsp; $targetFileName = $targetPrefix + '.wma'&lt;br&gt;
&amp;nbsp; &amp;nbsp; write "Copying $file`t--&amp;gt;`t$targetFileName"&lt;br&gt;
&amp;nbsp; &amp;nbsp; Copy-Item $folder\$file $target\$targetFileName&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;&amp;nbsp; &amp;nbsp; # update the media information in the file&lt;br&gt;
&amp;nbsp; &amp;nbsp; $media = [TagLib.File]::Create((Resolve-Path "$target\$targetFileName"))&lt;br&gt;
&amp;nbsp; &amp;nbsp; $media.Tag.Title = $bookName + ' - ' + $targetPrefix&lt;br&gt;
&amp;nbsp; &amp;nbsp; if ( $author -ne $null ) { $media.Tag.AlbumArtists = $author }&lt;br&gt;
&amp;nbsp; &amp;nbsp; if ( $artist -ne $null ) { $media.Tag.Performers = $artist }&lt;br&gt;
&amp;nbsp; &amp;nbsp; $media.Tag.Genres = { Audio Book }&lt;br&gt;
&amp;nbsp; &amp;nbsp; if ( $year -ne $null ) { $media.Tag.Year = $year }&lt;br&gt;
&amp;nbsp; &amp;nbsp; $media.Save()&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
}&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt;&lt;img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=bc8582e7-73de-49d7-bb91-c801bf9f71ba" /&gt;</description>
      <comments>http://blog.devstone.com/aaron/CommentView,guid,bc8582e7-73de-49d7-bb91-c801bf9f71ba.aspx</comments>
      <category>.NET</category>
      <category>PowerShell</category>
    <feedburner:origLink>http://blog.devstone.com/aaron/2009/08/25/SimplifyingTheRippingOfAudioBooksAndTaggingWithPowerShell.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://blog.devstone.com/aaron/Trackback.aspx?guid=9cf329d9-8865-4722-ba21-25e308a28325</trackback:ping>
      <pingback:server>http://blog.devstone.com/aaron/pingback.aspx</pingback:server>
      <pingback:target>http://blog.devstone.com/aaron/PermaLink,guid,9cf329d9-8865-4722-ba21-25e308a28325.aspx</pingback:target>
      <dc:creator>R. Aaron Zupancic (Administrator)</dc:creator>
      <wfw:comment>http://blog.devstone.com/aaron/CommentView,guid,9cf329d9-8865-4722-ba21-25e308a28325.aspx</wfw:comment>
      <wfw:commentRss>http://blog.devstone.com/aaron/SyndicationService.asmx/GetEntryCommentsRss?guid=9cf329d9-8865-4722-ba21-25e308a28325</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <font size="2" face="Tahoma">
            <a href="http://windowsteamblog.com/blogs/windows7/archive/2009/07/21/when-will-you-get-windows-7-rtm.aspx" target="_blank">http://windowsteamblog.com/blogs/windows7/archive/2009/07/21/when-will-you-get-windows-7-rtm.aspx</a>
          </font>
        </p>
        <p>
          <font size="2" face="Tahoma">Can't wait! I've been using Windows 7 in the Beta and
RC (Release Candidate) builds for some time now and I LOVE it! It's been rock solid
(particularly for it's pre-release form) and very fast. It's been my primary OS now
on 3 separate computers so I'm really excited about being able to get my hands on
the RTM version in the next few weeks.</font>
        </p>
        <img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=9cf329d9-8865-4722-ba21-25e308a28325" />
      </body>
      <title>Get your hands on the Windows 7 RTM...soon!</title>
      <guid isPermaLink="false">http://blog.devstone.com/aaron/PermaLink,guid,9cf329d9-8865-4722-ba21-25e308a28325.aspx</guid>
      <link>http://feedproxy.google.com/~r/ZupancicPerspective/~3/7C-HHmurqQE/GetYourHandsOnTheWindows7RTMsoon.aspx</link>
      <pubDate>Wed, 22 Jul 2009 19:11:47 GMT</pubDate>
      <description>&lt;p&gt;
&lt;font size="2" face="Tahoma"&gt;&lt;a href="http://windowsteamblog.com/blogs/windows7/archive/2009/07/21/when-will-you-get-windows-7-rtm.aspx" target="_blank"&gt;http://windowsteamblog.com/blogs/windows7/archive/2009/07/21/when-will-you-get-windows-7-rtm.aspx&lt;/a&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font size="2" face="Tahoma"&gt;Can't wait! I've been using Windows 7 in the Beta and
RC (Release Candidate) builds for some time now and I LOVE it! It's been rock solid
(particularly for it's pre-release form) and very fast. It's been my primary OS now
on 3 separate computers so I'm really excited about being able to get my hands on
the RTM version in the next few weeks.&lt;/font&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=9cf329d9-8865-4722-ba21-25e308a28325" /&gt;</description>
      <comments>http://blog.devstone.com/aaron/CommentView,guid,9cf329d9-8865-4722-ba21-25e308a28325.aspx</comments>
      <category>Windows</category>
    <feedburner:origLink>http://blog.devstone.com/aaron/2009/07/22/GetYourHandsOnTheWindows7RTMsoon.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://blog.devstone.com/aaron/Trackback.aspx?guid=41af86d0-e4cf-47b5-abd8-8f048a3cff61</trackback:ping>
      <pingback:server>http://blog.devstone.com/aaron/pingback.aspx</pingback:server>
      <pingback:target>http://blog.devstone.com/aaron/PermaLink,guid,41af86d0-e4cf-47b5-abd8-8f048a3cff61.aspx</pingback:target>
      <dc:creator>R. Aaron Zupancic (Administrator)</dc:creator>
      <wfw:comment>http://blog.devstone.com/aaron/CommentView,guid,41af86d0-e4cf-47b5-abd8-8f048a3cff61.aspx</wfw:comment>
      <wfw:commentRss>http://blog.devstone.com/aaron/SyndicationService.asmx/GetEntryCommentsRss?guid=41af86d0-e4cf-47b5-abd8-8f048a3cff61</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <font size="2" face="Tahoma">Well, I've
always <a href="http://support.microsoft.com/default.aspx?scid=kb;en-us;261186">loved
classical music</a>...too bad I'm not on Windows 95 anymore.<br /></font>
        <p>
        </p>
        <img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=41af86d0-e4cf-47b5-abd8-8f048a3cff61" />
      </body>
      <title>Windows Classical Music</title>
      <guid isPermaLink="false">http://blog.devstone.com/aaron/PermaLink,guid,41af86d0-e4cf-47b5-abd8-8f048a3cff61.aspx</guid>
      <link>http://feedproxy.google.com/~r/ZupancicPerspective/~3/m7fuwwlrNQ8/WindowsClassicalMusic.aspx</link>
      <pubDate>Wed, 17 Jun 2009 19:20:03 GMT</pubDate>
      <description>&lt;font size="2" face="Tahoma"&gt;Well, I've always &lt;a href="http://support.microsoft.com/default.aspx?scid=kb;en-us;261186"&gt;loved
classical music&lt;/a&gt;...too bad I'm not on Windows 95 anymore.&lt;br&gt;
&lt;/font&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=41af86d0-e4cf-47b5-abd8-8f048a3cff61" /&gt;</description>
      <comments>http://blog.devstone.com/aaron/CommentView,guid,41af86d0-e4cf-47b5-abd8-8f048a3cff61.aspx</comments>
      <category>Humor</category>
    <feedburner:origLink>http://blog.devstone.com/aaron/2009/06/17/WindowsClassicalMusic.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://blog.devstone.com/aaron/Trackback.aspx?guid=21a5f7e2-3cb4-4092-a438-11015b78f657</trackback:ping>
      <pingback:server>http://blog.devstone.com/aaron/pingback.aspx</pingback:server>
      <pingback:target>http://blog.devstone.com/aaron/PermaLink,guid,21a5f7e2-3cb4-4092-a438-11015b78f657.aspx</pingback:target>
      <dc:creator>R. Aaron Zupancic (Administrator)</dc:creator>
      <wfw:comment>http://blog.devstone.com/aaron/CommentView,guid,21a5f7e2-3cb4-4092-a438-11015b78f657.aspx</wfw:comment>
      <wfw:commentRss>http://blog.devstone.com/aaron/SyndicationService.asmx/GetEntryCommentsRss?guid=21a5f7e2-3cb4-4092-a438-11015b78f657</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <font face="Tahoma">
          <font size="2">This
is definitely not news, but I wanted to blog it anyway.<br /><br />
Having recently just reset a development server to use Windows Server 2008, I needed
to open the firewall to allow ICMP packets through.  Essentially, I wanted to
have the server respond to PING requests.  On a fresh Windows Vista or Windows
Server 2008 install (and I imagine Windows 7, though I've not checked), the ICMP protocol
is blocked by default; the server won't respond to PINGs.  When you ping an IP
address and don't get a reply that doesn't mean that there isn't a computer on the
other end, but it sure is a handy way to check.<br /><br />
In Windows Vista/2008 enabling ICMP through the firewall isn't difficult, but if you
want to use a GUI, you have to do it through an inbound rule in the <b>Windows Firewall
with Advanced Security</b> option.<br /><br />
Personally, I prefer to do it via the command-line through this simple operation: <b>netsh
firewall set icmpsetting 8</b></font>
          <br />
        </font>
        <p>
        </p>
        <img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=21a5f7e2-3cb4-4092-a438-11015b78f657" />
      </body>
      <title>Enabling PING in Windows Server 2008 and Vista</title>
      <guid isPermaLink="false">http://blog.devstone.com/aaron/PermaLink,guid,21a5f7e2-3cb4-4092-a438-11015b78f657.aspx</guid>
      <link>http://feedproxy.google.com/~r/ZupancicPerspective/~3/dv0eRNddONE/EnablingPINGInWindowsServer2008AndVista.aspx</link>
      <pubDate>Fri, 12 Jun 2009 22:41:21 GMT</pubDate>
      <description>&lt;font face="Tahoma"&gt;&lt;font size="2"&gt;This is definitely not news, but I wanted to blog
it anyway.&lt;br&gt;
&lt;br&gt;
Having recently just reset a development server to use Windows Server 2008, I needed
to open the firewall to allow ICMP packets through.&amp;nbsp; Essentially, I wanted to
have the server respond to PING requests.&amp;nbsp; On a fresh Windows Vista or Windows
Server 2008 install (and I imagine Windows 7, though I've not checked), the ICMP protocol
is blocked by default; the server won't respond to PINGs.&amp;nbsp; When you ping an IP
address and don't get a reply that doesn't mean that there isn't a computer on the
other end, but it sure is a handy way to check.&lt;br&gt;
&lt;br&gt;
In Windows Vista/2008 enabling ICMP through the firewall isn't difficult, but if you
want to use a GUI, you have to do it through an inbound rule in the &lt;b&gt;Windows Firewall
with Advanced Security&lt;/b&gt; option.&lt;br&gt;
&lt;br&gt;
Personally, I prefer to do it via the command-line through this simple operation: &lt;b&gt;netsh
firewall set icmpsetting 8&lt;/b&gt;&lt;/font&gt;
&lt;br&gt;
&lt;/font&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=21a5f7e2-3cb4-4092-a438-11015b78f657" /&gt;</description>
      <comments>http://blog.devstone.com/aaron/CommentView,guid,21a5f7e2-3cb4-4092-a438-11015b78f657.aspx</comments>
      <category>Windows Vista</category>
      <category>Windows Server 2008</category>
    <feedburner:origLink>http://blog.devstone.com/aaron/2009/06/12/EnablingPINGInWindowsServer2008AndVista.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://blog.devstone.com/aaron/Trackback.aspx?guid=b1532b74-f32c-4bfb-9943-294340251147</trackback:ping>
      <pingback:server>http://blog.devstone.com/aaron/pingback.aspx</pingback:server>
      <pingback:target>http://blog.devstone.com/aaron/PermaLink,guid,b1532b74-f32c-4bfb-9943-294340251147.aspx</pingback:target>
      <dc:creator>R. Aaron Zupancic (Administrator)</dc:creator>
      <wfw:comment>http://blog.devstone.com/aaron/CommentView,guid,b1532b74-f32c-4bfb-9943-294340251147.aspx</wfw:comment>
      <wfw:commentRss>http://blog.devstone.com/aaron/SyndicationService.asmx/GetEntryCommentsRss?guid=b1532b74-f32c-4bfb-9943-294340251147</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <font face="Tahoma">As you may or may not be aware IE 7+ (and other browsers) support
using CSS 2.1 </font>
          <a href="http://www.w3.org/TR/CSS21/selector.html">
            <font face="Tahoma">attribute
selectors</font>
          </a>
          <font face="Tahoma">.  Attribute selectors allow you to specify
a style on an element whose element matches a particular pattern.  For instance:</font>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <font face="Courier New">td[x] { font-weight:bold; }</font>
          </p>
        </blockquote>
        <p>
          <font face="Tahoma">This selector will bold the text of any TD element on the page
that has an attribute "x" (regardless of value).  Other attribute selector styles
include:</font>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <font face="Tahoma">
              <font face="Courier New">...[x="value"]</font> matches where x
is exactly 'value'<br /><font face="Courier New">...[x~="value"]</font> matches where x contains a space-separated list
of values, one of which is exactly 'value'<br /><font face="Courier New">...[x^="value"]</font> matches where the attribute x begins
with 'value'<br /><font face="Courier New">...[x$="value"]</font> matches where the attribute x ends
with 'value'<br /><font face="Courier New">...[x*="value"]</font> matches where the attribute x contains
'value'<br /><font face="Courier New">...[x|="value"]</font> matches where the attribute x begins
with either 'value' or 'value-'</font>
          </p>
        </blockquote>
        <p>
          <font face="Tahoma">In and of themselves, these are pretty darn cool.  You can
do some neat things with CSS and HTML.</font>
        </p>
        <p>
          <font face="Tahoma">I ran into an interested scenario this past week that I'd like
to share.  I have some JavaScript that alters the value of attributes at runtime. 
I found that the page doesn't automatically update according to the stylesheet specification. 
Curiously, it would update when I moused-over the element in question.</font>
        </p>
        <p>
          <font face="Tahoma">I found, however, that I could force the issue by assigning the
CSS classname to the element that it already has.  This is enough to trigger
the change and have the element update according to its attribute values.</font>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <font face="Courier New">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;<br />
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;<br />
&lt;head&gt;<br />
   &lt;style type="text/css"&gt;<br />
      td[req] { font-weight:bold; }<br />
      td[err="1"] { color:red !important; }<br />
   &lt;/style&gt;<br />
   &lt;script type="text/javascript"&gt;<br />
      function fn() {<br />
         var td = document.getElementById("t");<br />
         td.err = "0";<br />
         td.className = td.className; 
// trigger the change by reassigning the CSS class<br />
      }<br />
   &lt;/script&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
   &lt;table&gt;<br />
      &lt;tr&gt;&lt;td class="test" err="1" req="1" id="t"&gt;Cell&lt;/td&gt;&lt;/tr&gt;<br />
   &lt;/table&gt;<br />
   &lt;button onclick="javascript:fn();"&gt;Remove Error&lt;/button&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;</font>
          </p>
        </blockquote>
        <p>
          <font face="Tahoma">Interestingly, for this to work properly in a non-IE browser (such
as Firefox), I found I could not use the object.property=value syntax.  Instead,
I had to use the SetAttribute() function.  Also, with Firefox, reassigning the
className was unnecessary.</font>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <font face="Courier New">td.setAttribute("err", "0");</font>
          </p>
        </blockquote>
        <p dir="ltr">
          <font face="Tahoma">That's probably the best way to handle it then, for cross-browser
compliance.</font>
        </p>
        <img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=b1532b74-f32c-4bfb-9943-294340251147" />
      </body>
      <title>CSS Attribute Selector Magic</title>
      <guid isPermaLink="false">http://blog.devstone.com/aaron/PermaLink,guid,b1532b74-f32c-4bfb-9943-294340251147.aspx</guid>
      <link>http://feedproxy.google.com/~r/ZupancicPerspective/~3/_kWxGIIenVg/CSSAttributeSelectorMagic.aspx</link>
      <pubDate>Mon, 04 May 2009 04:28:44 GMT</pubDate>
      <description>&lt;p&gt;
&lt;font face=Tahoma&gt;As you may or may not be aware IE 7+ (and other browsers) support
using CSS 2.1 &lt;/font&gt;&lt;a href="http://www.w3.org/TR/CSS21/selector.html"&gt;&lt;font face=Tahoma&gt;attribute
selectors&lt;/font&gt;&lt;/a&gt;&lt;font face=Tahoma&gt;.&amp;nbsp; Attribute selectors allow you to specify
a style on an element whose element matches a particular pattern.&amp;nbsp; For instance:&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
&lt;font face="Courier New"&gt;td[x] { font-weight:bold; }&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;font face=Tahoma&gt;This selector will bold the text of any TD element on the page that
has an attribute "x" (regardless of value).&amp;nbsp; Other attribute selector styles
include:&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
&lt;font face=Tahoma&gt;&lt;font face="Courier New"&gt;...[x="value"]&lt;/font&gt; matches where x is
exactly 'value'&lt;br&gt;
&lt;font face="Courier New"&gt;...[x~="value"]&lt;/font&gt; matches where x contains a space-separated&amp;nbsp;list
of values, one of which is exactly 'value'&lt;br&gt;
&lt;font face="Courier New"&gt;...[x^="value"]&lt;/font&gt; matches where the attribute x begins
with 'value'&lt;br&gt;
&lt;font face="Courier New"&gt;...[x$="value"]&lt;/font&gt; matches where the attribute x ends
with 'value'&lt;br&gt;
&lt;font face="Courier New"&gt;...[x*="value"]&lt;/font&gt; matches where the attribute x contains
'value'&lt;br&gt;
&lt;font face="Courier New"&gt;...[x|="value"]&lt;/font&gt; matches where the attribute x begins
with either 'value' or 'value-'&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;font face=Tahoma&gt;In and of themselves, these are pretty darn cool.&amp;nbsp; You can
do some neat things with CSS and HTML.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;I ran into an interested scenario this past week that I'd like to
share.&amp;nbsp; I have some JavaScript that alters the value of attributes at runtime.&amp;nbsp;
I found that the page doesn't automatically update according to the stylesheet specification.&amp;nbsp;
Curiously, it would update when I moused-over the element in question.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;I found, however, that I could force the issue by assigning the
CSS classname to the element that it already has.&amp;nbsp; This is enough to trigger
the change and have the element update according to its attribute values.&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
&lt;font face="Courier New"&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&amp;gt;&lt;br&gt;
&amp;lt;html xmlns="http://www.w3.org/1999/xhtml"&amp;gt;&lt;br&gt;
&amp;lt;head&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;lt;style type="text/css"&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; td[req] { font-weight:bold; }&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; td[err="1"] { color:red !important; }&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;lt;/style&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;lt;script type="text/javascript"&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; function fn() {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; var td = document.getElementById("t");&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; td.err = "0";&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;td.className = td.className;&amp;nbsp;
// trigger the change by reassigning the CSS class&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;lt;/script&amp;gt;&lt;br&gt;
&amp;lt;/head&amp;gt;&lt;br&gt;
&amp;lt;body&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;lt;table&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;tr&amp;gt;&amp;lt;td class="test" err="1" req="1" id="t"&amp;gt;Cell&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;lt;/table&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;lt;button onclick="javascript:fn();"&amp;gt;Remove Error&amp;lt;/button&amp;gt;&lt;br&gt;
&amp;lt;/body&amp;gt;&lt;br&gt;
&amp;lt;/html&amp;gt;&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;font face=Tahoma&gt;Interestingly, for this to work properly in a non-IE browser (such
as Firefox), I found I could not use the object.property=value syntax.&amp;nbsp; Instead,
I had to use the SetAttribute() function.&amp;nbsp; Also, with Firefox, reassigning the
className was unnecessary.&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
&lt;font face="Courier New"&gt;td.setAttribute("err", "0");&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p dir=ltr&gt;
&lt;font face=Tahoma&gt;That's probably the best way to handle it then, for cross-browser
compliance.&lt;/font&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=b1532b74-f32c-4bfb-9943-294340251147" /&gt;</description>
      <comments>http://blog.devstone.com/aaron/CommentView,guid,b1532b74-f32c-4bfb-9943-294340251147.aspx</comments>
      <category>CSS</category>
      <category>Web</category>
    <feedburner:origLink>http://blog.devstone.com/aaron/2009/05/04/CSSAttributeSelectorMagic.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://blog.devstone.com/aaron/Trackback.aspx?guid=eb7b0741-d973-4dda-9325-1a4cf5f3fdfc</trackback:ping>
      <pingback:server>http://blog.devstone.com/aaron/pingback.aspx</pingback:server>
      <pingback:target>http://blog.devstone.com/aaron/PermaLink,guid,eb7b0741-d973-4dda-9325-1a4cf5f3fdfc.aspx</pingback:target>
      <dc:creator>R. Aaron Zupancic (Administrator)</dc:creator>
      <wfw:comment>http://blog.devstone.com/aaron/CommentView,guid,eb7b0741-d973-4dda-9325-1a4cf5f3fdfc.aspx</wfw:comment>
      <wfw:commentRss>http://blog.devstone.com/aaron/SyndicationService.asmx/GetEntryCommentsRss?guid=eb7b0741-d973-4dda-9325-1a4cf5f3fdfc</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <font face="Tahoma">My buddy Rob Bagby has announced this exciting event called <strong>XamlFest</strong> which
will be in Salt Lake City on May 1st.  If you have the chance, I'd encourage
you to sign up and attend.</font>
        </p>
        <p>
          <font face="Tahoma">Here's the info: </font>
          <a href="http://blogs.msdn.com/bags/archive/2009/03/31/xamlfest-in-salt-lake-city-on-may-1.aspx">
            <font face="Tahoma">http://blogs.msdn.com/bags/archive/2009/03/31/xamlfest-in-salt-lake-city-on-may-1.aspx</font>
          </a>
        </p>
        <img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=eb7b0741-d973-4dda-9325-1a4cf5f3fdfc" />
      </body>
      <title>XamlFest in SLC on May 1st</title>
      <guid isPermaLink="false">http://blog.devstone.com/aaron/PermaLink,guid,eb7b0741-d973-4dda-9325-1a4cf5f3fdfc.aspx</guid>
      <link>http://feedproxy.google.com/~r/ZupancicPerspective/~3/Y0ZV4NhY5ts/XamlFestInSLCOnMay1st.aspx</link>
      <pubDate>Thu, 23 Apr 2009 19:35:44 GMT</pubDate>
      <description>&lt;p&gt;
&lt;font face=Tahoma&gt;My buddy Rob Bagby has announced this exciting event called &lt;strong&gt;XamlFest&lt;/strong&gt; which
will be in Salt Lake City on May 1st.&amp;nbsp; If you have the chance, I'd encourage
you to sign up and attend.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;Here's the info: &lt;/font&gt;&lt;a href="http://blogs.msdn.com/bags/archive/2009/03/31/xamlfest-in-salt-lake-city-on-may-1.aspx"&gt;&lt;font face=Tahoma&gt;http://blogs.msdn.com/bags/archive/2009/03/31/xamlfest-in-salt-lake-city-on-may-1.aspx&lt;/font&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=eb7b0741-d973-4dda-9325-1a4cf5f3fdfc" /&gt;</description>
      <comments>http://blog.devstone.com/aaron/CommentView,guid,eb7b0741-d973-4dda-9325-1a4cf5f3fdfc.aspx</comments>
      <category>Events</category>
    <feedburner:origLink>http://blog.devstone.com/aaron/2009/04/23/XamlFestInSLCOnMay1st.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://blog.devstone.com/aaron/Trackback.aspx?guid=994798c1-3e00-4b01-8807-6ed42fb0d446</trackback:ping>
      <pingback:server>http://blog.devstone.com/aaron/pingback.aspx</pingback:server>
      <pingback:target>http://blog.devstone.com/aaron/PermaLink,guid,994798c1-3e00-4b01-8807-6ed42fb0d446.aspx</pingback:target>
      <dc:creator>R. Aaron Zupancic (Administrator)</dc:creator>
      <wfw:comment>http://blog.devstone.com/aaron/CommentView,guid,994798c1-3e00-4b01-8807-6ed42fb0d446.aspx</wfw:comment>
      <wfw:commentRss>http://blog.devstone.com/aaron/SyndicationService.asmx/GetEntryCommentsRss?guid=994798c1-3e00-4b01-8807-6ed42fb0d446</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <font face="Tahoma">I was putting together a WinForms utility application today that
consists of a TabStrip control on the main dialog box.  On a themed system the
TabStrip displays a nice gradual gradient on the page.  As part of this
application I wanted to output statistical and detailed information about the user's
selections in a readonly fashion, but I wanted to have the text appear as though it
were written directly on the TabStrip page rather than within a control.</font>
        </p>
        <p>
          <font face="Tahoma">Of course my first thought was to use a Label control, but I almost
immediately wrote that off as the amount of information to be displayed was prohibitive
and variable.  The data being displayed might exceed the space on the TabStrip,
so scrolling the information is a must.</font>
        </p>
        <p>
          <font face="Tahoma">Next I thought of using a TextBox control, but without some pretty
intense subclassing and overriding, I wouldn't be able to achieve the 'written-on'
look I was after.  The TextBox will always render an opaque background color. 
Sure, there are ways of faking transparency, like overriding TextBox and adding a
PictureBox and telling the parent control to WM_PRINT into it, but that seems to be
a kludgy way of getting the results I wanted.</font>
        </p>
        <p>
          <font face="Tahoma">Additionally, there are mechanisms to use a RichTextBox (v5.0)
to achieve transparency that are well documented online, but try as I might with these
implementations, I found them to be quite buggy.  In particular, the appearance
of the scrollbars was erratic and sometimes didn't render properly with the control
was resized.  After battling with it for a few hours I gave up.  It wasn't
for lack of desire, it just wasn't worth it given the scope of the project I was working
on.</font>
        </p>
        <p>
          <font face="Tahoma">So this morning I went back to the drawing board and came up with
a solution in about 45 minutes that seems to do exactly what I wanted.  I've
called this control the ScrollableLabel.  Essentially, it offers the readonlyness
of a Label control and the scrollability of a TextBox.  This implementation here
is very fundamental.  I plan on enhancing it some more to incorporate user-defined
colors, headers, and much more.</font>
        </p>
        <p>
          <font face="Tahoma">I made some executive decisions about how this control should
render.  For instance, it will always use your system's colors for text and I
set the BackColor property of the UserControl to Transparent via the designer. 
For both of these I plan on making them user-selectable choices, but for not,
they're the look I was after.</font>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <font face="Courier New">
              <font color="#008000">public partial class</font> ScrollableLabel
: UserControl {<br />
   <font color="#008000">public</font> ScrollableLabel() {<br />
      InitializeComponent();<br />
      SetStyle(ControlStyles.Selectable, <font color="#008000">false</font>);<br />
      <em><font color="#a9a9a9">// the preferred mechanism
for enabling double-buffering is to set the DoubleBuffered property<br />
      // of the control rather than the equivalent SetStyle(DoubleBuffer
| UserPaint | AllPaintingInWmPaint, true).<br /></font></em>      DoubleBuffered = <font color="#008000">true</font>;<br />
      AutoScroll = <font color="#008000">true</font>;<br />
      AutoScrollMinSize = Size.Empty;<br />
   }<br /><br />
   <font color="#008000">private</font> SizeF _actualTextSize;<br /><br />
   <font color="#008000">public override string</font> Text {<br />
      <font color="#008000">get</font> { <font color="#008000">return
base</font>.Text; }<br />
      <font color="#008000">set</font> {<br />
         <font color="#008000">base</font>.Text
= <font color="#008000">value</font>;<br />
         calcLabelDimensions();<br />
         Invalidate();<br />
      }<br />
   }<br /><br />
   <font color="#008000">protected override void</font> OnScroll(ScrollEventArgs
se) {<br />
      <font color="#008000">base</font>.OnScroll(se);<br />
      Invalidate();<br />
   }<br /><br />
   <font color="#008000">public void</font> Clear() {<br />
      Text = <font color="#008000">string</font>.Empty;<br />
   }<br /><br />
   <font color="#008000">#region Hidden design-time properties</font><br />
   [Browsable(<font color="#008000">false</font>)]<br />
   <font color="#008000">public override bool</font> AutoScroll {<br />
      <font color="#008000">get</font> { <font color="#008000">return
true</font>; }<br />
      <font color="#008000">set</font> { <font color="#a9a9a9"><em>/*
do nothing for now; control is always AutoScroll */</em></font> }<br />
   }</font>
          </p>
          <p>
            <br />
            <font face="Courier New">   [Browsable(<font color="#008000">false</font>)]<br />
   <font color="#008000">public override</font> Color ForeColor {<br />
      <font color="#008000">get</font> { <font color="#008000">return</font> SystemColors.ControlText;
}<br />
      <font color="#008000">set</font> { <em><font color="#a9a9a9">/*
do nothing for now; only ControlText is currently supported */</font></em> }<br />
   }<br />
   <font color="#008000">#endregion</font><br /><br />
   <font color="#008000">private void</font> calcLabelDimensions() {<br />
      <font color="#008000">using</font> ( Graphics g = CreateGraphics()
) {<br />
         <em><font color="#a9a9a9">// assume
that no text should wrap</font></em><br />
         _actualTextSize = g.MeasureString(Text,
Font);<br />
         AutoScrollMinSize = Size.Round(_actualTextSize);<br />
      }<br />
   }<br /><br />
   <font color="#008000">protected override void</font> OnPaint(PaintEventArgs
e) {<br />
      RectangleF rct = <font color="#008000">new</font> RectangleF(AutoScrollPosition,
_actualTextSize);<br />
      </font>
            <font face="Courier New">Brush br = Enabled<br />
                   
? SystemBrushes.ControlText<br />
                   
: SystemBrushes.GrayText;<br />
      e.Graphics.DrawString(Text, Font, br, rct);<br />
   }<br />
}</font>
          </p>
        </blockquote>
        <p>
          <font face="Tahoma">When this control is added to a Form it will automatically add
scrollbars if the contents exceed the dimensions of the control.  At design-time,
however I wanted to make sure that I could see where the ScrollableLabel was positioned
so I created a simple Designer.</font>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <font face="Courier New">
              <font color="#008000">public sealed class</font> BorderlessBorderDesigner
: ControlDesigner {<br />
   <font color="#008000">protected override void</font> OnPaintAdornments(PaintEventArgs
pe) {<br />
      <font color="#008000">base</font>.OnPaintAdornments(pe);<br />
      <font color="#008000">if</font> ( BorderStyle.None
== getBorderStyle() ) {<br />
         Rectangle rct = Control.ClientRectangle;<br />
         rct.Width -= 1;<br />
         rct.Height -= 1;<br />
         <font color="#008000">using</font> (
Pen p = <font color="#008000">new</font> Pen(SystemColors.ControlDark) ) {<br />
            p.DashStyle = DashStyle.Dash;<br />
            pe.Graphics.DrawRectangle(p,
rct);<br />
         }<br />
      }<br />
   }<br /></font>
            <font face="Tahoma">
              <br />
              <font face="Courier New">   <font color="#008000">private</font> BorderStyle
getBorderStyle() {<br /></font>
              <font face="Courier New">      UserControl ctl = Control <font color="#008000">as</font> UserControl;<br />
      <font color="#008000">if</font> ( <font color="#008000">null</font> !=
ctl ) <font color="#008000">return</font> ctl.BorderStyle;<br /></font>
              <font face="Courier New">      <font color="#008000">return</font> BorderStyle.None;<br />
   }<br />
}</font>
            </font>
          </p>
        </blockquote>
        <p>
Then, I added<strong> [Designer(typeof(BorderlessBorderDesigner)]</strong> to my ScrollableLabel
class declaration.
</p>
        <p>
It's a simple control that achieves a simple goal.  I'll post my updates to it
as I get a chance to modify it and make it all the more flexible and powerful.
</p>
        <p>
Enjoy!
</p>
        <img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=994798c1-3e00-4b01-8807-6ed42fb0d446" />
      </body>
      <title>ScrollableLabel control</title>
      <guid isPermaLink="false">http://blog.devstone.com/aaron/PermaLink,guid,994798c1-3e00-4b01-8807-6ed42fb0d446.aspx</guid>
      <link>http://feedproxy.google.com/~r/ZupancicPerspective/~3/kiN8SUO2OJA/ScrollableLabelControl.aspx</link>
      <pubDate>Tue, 07 Apr 2009 04:19:13 GMT</pubDate>
      <description>&lt;p&gt;
&lt;font face=Tahoma&gt;I was putting together a WinForms utility application today that
consists of a TabStrip control on the main dialog box.&amp;nbsp; On a themed system the
TabStrip displays a nice gradual gradient on the page.&amp;nbsp;&amp;nbsp;As part of this
application I wanted to output statistical and detailed information about the user's
selections in a readonly fashion, but I wanted to have the text appear as though it
were written directly on the TabStrip page rather than within a control.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;Of course my first thought was to use a Label control, but I almost
immediately wrote that off as the amount of information to be displayed was prohibitive
and variable.&amp;nbsp; The data being displayed might exceed the space on the TabStrip,
so scrolling the information is a must.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;Next I thought of using a TextBox control, but without some pretty
intense subclassing and overriding, I wouldn't be able to achieve the 'written-on'
look I was after.&amp;nbsp; The TextBox will always render an opaque background color.&amp;nbsp;
Sure, there are ways of faking transparency, like overriding TextBox and adding a
PictureBox and telling the parent control to WM_PRINT into it, but that seems to be
a kludgy way of getting the results I wanted.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;Additionally, there are mechanisms to use a RichTextBox (v5.0) to
achieve transparency that are well documented online, but try as I might with these
implementations, I found them to be quite buggy.&amp;nbsp; In particular, the appearance
of the scrollbars was erratic and sometimes didn't render properly with the control
was resized.&amp;nbsp; After battling with it for a few hours I gave up.&amp;nbsp; It wasn't
for lack of desire, it just wasn't worth it given the scope of the project I was working
on.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;So this morning I went back to the drawing board and came up with
a solution in about 45 minutes that seems to do exactly what I wanted.&amp;nbsp; I've
called this control the ScrollableLabel.&amp;nbsp; Essentially, it offers the readonlyness
of a Label control and the scrollability of a TextBox.&amp;nbsp; This implementation here
is very fundamental.&amp;nbsp; I plan on enhancing it some more to incorporate user-defined
colors, headers, and much more.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;I made some executive decisions about how this control should render.&amp;nbsp;
For instance, it will always use your system's colors for text and I set the BackColor
property of the UserControl to Transparent via the designer.&amp;nbsp; For both of these
I plan on making&amp;nbsp;them user-selectable choices, but for not, they're the look
I was after.&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
&lt;font face="Courier New"&gt;&lt;font color=#008000&gt;public partial class&lt;/font&gt; ScrollableLabel
: UserControl {&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;public&lt;/font&gt; ScrollableLabel() {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; InitializeComponent();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SetStyle(ControlStyles.Selectable, &lt;font color=#008000&gt;false&lt;/font&gt;);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;em&gt;&lt;font color=#a9a9a9&gt;// the preferred mechanism
for enabling double-buffering is to set the DoubleBuffered property&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // of the control rather than the equivalent SetStyle(DoubleBuffer
| UserPaint | AllPaintingInWmPaint, true).&lt;br&gt;
&lt;/font&gt;&lt;/em&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DoubleBuffered = &lt;font color=#008000&gt;true&lt;/font&gt;;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; AutoScroll = &lt;font color=#008000&gt;true&lt;/font&gt;;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; AutoScrollMinSize = Size.Empty;&lt;br&gt;
&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;private&lt;/font&gt; SizeF _actualTextSize;&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;public override string&lt;/font&gt; Text {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;get&lt;/font&gt; { &lt;font color=#008000&gt;return
base&lt;/font&gt;.Text; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;set&lt;/font&gt; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;base&lt;/font&gt;.Text
= &lt;font color=#008000&gt;value&lt;/font&gt;;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; calcLabelDimensions();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Invalidate();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;protected override void&lt;/font&gt; OnScroll(ScrollEventArgs
se) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;base&lt;/font&gt;.OnScroll(se);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Invalidate();&lt;br&gt;
&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;public void&lt;/font&gt; Clear() {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Text = &lt;font color=#008000&gt;string&lt;/font&gt;.Empty;&lt;br&gt;
&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;#region Hidden design-time properties&lt;/font&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp; [Browsable(&lt;font color=#008000&gt;false&lt;/font&gt;)]&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;public override bool&lt;/font&gt; AutoScroll {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;get&lt;/font&gt; { &lt;font color=#008000&gt;return
true&lt;/font&gt;; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;set&lt;/font&gt; { &lt;font color=#a9a9a9&gt;&lt;em&gt;/*
do nothing for now; control is always AutoScroll */&lt;/em&gt;&lt;/font&gt; }&lt;br&gt;
&amp;nbsp;&amp;nbsp; }&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;br&gt;
&lt;font face="Courier New"&gt;&amp;nbsp;&amp;nbsp; [Browsable(&lt;font color=#008000&gt;false&lt;/font&gt;)]&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;public override&lt;/font&gt; Color ForeColor {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;get&lt;/font&gt; { &lt;font color=#008000&gt;return&lt;/font&gt; SystemColors.ControlText;
}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;set&lt;/font&gt; { &lt;em&gt;&lt;font color=#a9a9a9&gt;/*
do nothing for now; only ControlText is currently supported */&lt;/font&gt;&lt;/em&gt; }&lt;br&gt;
&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;#endregion&lt;/font&gt;
&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;private void&lt;/font&gt; calcLabelDimensions() {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;using&lt;/font&gt; ( Graphics g = CreateGraphics()
) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;em&gt;&lt;font color=#a9a9a9&gt;// assume
that no text should wrap&lt;/font&gt;&lt;/em&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _actualTextSize = g.MeasureString(Text,
Font);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; AutoScrollMinSize = Size.Round(_actualTextSize);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;protected override void&lt;/font&gt; OnPaint(PaintEventArgs
e) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; RectangleF rct = &lt;font color=#008000&gt;new&lt;/font&gt; RectangleF(AutoScrollPosition,
_actualTextSize);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font face="Courier New"&gt;Brush br = Enabled&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
? SystemBrushes.ControlText&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
: SystemBrushes.GrayText;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; e.Graphics.DrawString(Text, Font, br, rct);&lt;br&gt;
&amp;nbsp;&amp;nbsp; }&lt;br&gt;
}&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;font face=Tahoma&gt;When this control is added to a Form it will automatically add scrollbars
if the contents exceed the dimensions of the control.&amp;nbsp; At design-time, however
I wanted to make sure that I could see where the ScrollableLabel was positioned so
I created a simple Designer.&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
&lt;font face="Courier New"&gt;&lt;font color=#008000&gt;public sealed class&lt;/font&gt; BorderlessBorderDesigner
: ControlDesigner {&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;protected override void&lt;/font&gt; OnPaintAdornments(PaintEventArgs
pe) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;base&lt;/font&gt;.OnPaintAdornments(pe);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;if&lt;/font&gt; ( BorderStyle.None ==
getBorderStyle() ) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Rectangle rct = Control.ClientRectangle;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rct.Width -= 1;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rct.Height -= 1;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;using&lt;/font&gt; (
Pen p = &lt;font color=#008000&gt;new&lt;/font&gt; Pen(SystemColors.ControlDark) ) {&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; p.DashStyle = DashStyle.Dash;&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; pe.Graphics.DrawRectangle(p,
rct);&lt;br&gt;
&amp;nbsp;&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; }&lt;br&gt;
&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;/font&gt;&lt;font face=Tahoma&gt;
&lt;br&gt;
&lt;font face="Courier New"&gt;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;private&lt;/font&gt; BorderStyle
getBorderStyle() {&lt;br&gt;
&lt;/font&gt;&lt;font face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; UserControl ctl = Control &lt;font color=#008000&gt;as&lt;/font&gt; UserControl;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;if&lt;/font&gt; ( &lt;font color=#008000&gt;null&lt;/font&gt; !=
ctl ) &lt;font color=#008000&gt;return&lt;/font&gt; ctl.BorderStyle;&lt;br&gt;
&lt;/font&gt;&lt;font face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color=#008000&gt;return&lt;/font&gt; BorderStyle.None;&lt;br&gt;
&amp;nbsp;&amp;nbsp; }&lt;br&gt;
}&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Then, I added&lt;strong&gt; [Designer(typeof(BorderlessBorderDesigner)]&lt;/strong&gt; to my ScrollableLabel
class&amp;nbsp;declaration.
&lt;/p&gt;
&lt;p&gt;
It's a simple control that achieves a simple goal.&amp;nbsp; I'll post my updates to it
as I get a chance to modify it and make it all the more flexible and powerful.
&lt;/p&gt;
&lt;p&gt;
Enjoy!&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=994798c1-3e00-4b01-8807-6ed42fb0d446" /&gt;</description>
      <comments>http://blog.devstone.com/aaron/CommentView,guid,994798c1-3e00-4b01-8807-6ed42fb0d446.aspx</comments>
      <category>.NET</category>
      <category>C#</category>
      <category>WinForms</category>
      <category>Controls</category>
    <feedburner:origLink>http://blog.devstone.com/aaron/2009/04/07/ScrollableLabelControl.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://blog.devstone.com/aaron/Trackback.aspx?guid=fb1bbf27-9f81-4a3d-b600-456291ac6711</trackback:ping>
      <pingback:server>http://blog.devstone.com/aaron/pingback.aspx</pingback:server>
      <pingback:target>http://blog.devstone.com/aaron/PermaLink,guid,fb1bbf27-9f81-4a3d-b600-456291ac6711.aspx</pingback:target>
      <dc:creator>R. Aaron Zupancic (Administrator)</dc:creator>
      <wfw:comment>http://blog.devstone.com/aaron/CommentView,guid,fb1bbf27-9f81-4a3d-b600-456291ac6711.aspx</wfw:comment>
      <wfw:commentRss>http://blog.devstone.com/aaron/SyndicationService.asmx/GetEntryCommentsRss?guid=fb1bbf27-9f81-4a3d-b600-456291ac6711</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <font face="Tahoma">I have an external HDD that I use to store various files and products
that I download.  Today, while downloading one such application my computer decided
to freeze.  I've been having a sporatic issue with my hardware lately, so this
freeze (while not entirely unexpected) happened at a most inopportune moment.</font>
        </p>
        <p>
          <font face="Tahoma">When my computer 'came-to' after rebooting, my HDD was put into
a read-only state.  Any change I tried to make to the drive was greeted with
a "The media is write protected" error message.  The only <em>fix</em> I could
come up with was the following:</font>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <font face="Tahoma">1. Open the command prompt.<br />
2. Type <strong>DISKPART</strong><br />
3. <strong>LIST VOLUME</strong> (to identify the volume in question)<br />
4. <strong>SELECT VOLUME #</strong> (where # represents the volume identifier)<br />
5. <strong>ATTRIBUTES VOLUME CLEAR READONLY</strong></font>
          </p>
        </blockquote>
        <p>
          <font face="Tahoma">After this, I could select the folders on my drive and unmark
their read-only state.  Note that I had to clear the read-only flag even
though DISKPART reported the volume as not being read-only.</font>
        </p>
        <p>
          <font face="Tahoma">We'll see whether the drive falls back into its read-only state
in the future.</font>
        </p>
        <img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=fb1bbf27-9f81-4a3d-b600-456291ac6711" />
      </body>
      <title>Working through "The media is write protected"</title>
      <guid isPermaLink="false">http://blog.devstone.com/aaron/PermaLink,guid,fb1bbf27-9f81-4a3d-b600-456291ac6711.aspx</guid>
      <link>http://feedproxy.google.com/~r/ZupancicPerspective/~3/uzpRAw_G-Jk/WorkingThroughTheMediaIsWriteProtected.aspx</link>
      <pubDate>Tue, 17 Mar 2009 23:31:52 GMT</pubDate>
      <description>&lt;p&gt;
&lt;font face=Tahoma&gt;I have an external HDD that I use to store various files and products
that I download.&amp;nbsp; Today, while downloading one such application my computer decided
to freeze.&amp;nbsp; I've been having a sporatic issue with my hardware lately, so this
freeze (while not entirely unexpected) happened at a most inopportune moment.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;When my computer 'came-to' after rebooting, my HDD was put into
a read-only state.&amp;nbsp; Any change I tried to make to the drive was greeted with
a "The media is write protected" error message.&amp;nbsp; The only &lt;em&gt;fix&lt;/em&gt; I could
come up with was the following:&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
&lt;font face=Tahoma&gt;1. Open the command prompt.&lt;br&gt;
2. Type &lt;strong&gt;DISKPART&lt;/strong&gt;
&lt;br&gt;
3. &lt;strong&gt;LIST VOLUME&lt;/strong&gt; (to identify the volume in question)&lt;br&gt;
4. &lt;strong&gt;SELECT VOLUME #&lt;/strong&gt; (where # represents the volume identifier)&lt;br&gt;
5. &lt;strong&gt;ATTRIBUTES VOLUME CLEAR READONLY&lt;/strong&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;font face=Tahoma&gt;After this, I could select the folders on my drive and unmark their
read-only state.&amp;nbsp; Note that I had to clear the read-only&amp;nbsp;flag even though
DISKPART reported the volume as not being read-only.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;We'll see whether the drive falls back into its read-only state
in the future.&lt;/font&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=fb1bbf27-9f81-4a3d-b600-456291ac6711" /&gt;</description>
      <comments>http://blog.devstone.com/aaron/CommentView,guid,fb1bbf27-9f81-4a3d-b600-456291ac6711.aspx</comments>
      <category>Utilities</category>
      <category>Windows Vista</category>
    <feedburner:origLink>http://blog.devstone.com/aaron/2009/03/17/WorkingThroughTheMediaIsWriteProtected.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://blog.devstone.com/aaron/Trackback.aspx?guid=81ef7512-4e8d-463f-9acf-12268085a723</trackback:ping>
      <pingback:server>http://blog.devstone.com/aaron/pingback.aspx</pingback:server>
      <pingback:target>http://blog.devstone.com/aaron/PermaLink,guid,81ef7512-4e8d-463f-9acf-12268085a723.aspx</pingback:target>
      <dc:creator>R. Aaron Zupancic (Administrator)</dc:creator>
      <wfw:comment>http://blog.devstone.com/aaron/CommentView,guid,81ef7512-4e8d-463f-9acf-12268085a723.aspx</wfw:comment>
      <wfw:commentRss>http://blog.devstone.com/aaron/SyndicationService.asmx/GetEntryCommentsRss?guid=81ef7512-4e8d-463f-9acf-12268085a723</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <font face="Tahoma">Years ago I created an InstallShield (InstallScript) installer
for some software that I've maintained over the years.  While the installer has
been run countless times (successfully, I might add), I recently witnessed the following
error message:</font>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <font face="Courier New">An error (-5006 : 0x80070002) has occurred while running
the setup.</font>
          </p>
          <p>
            <font face="Courier New">Please make sure that you have finished any previous setup
and closed other applications.</font>
          </p>
        </blockquote>
        <p>
          <font face="Tahoma">This usually happens after installing a related, but completely
stand-alone and distinct product.  After a reboot (having supposed that the previous
setup didn't completely finish) we get the same error message.  It turns out,
that the error would occur whether or not the previous application had been installed.</font>
        </p>
        <p>
          <font face="Tahoma">Well, long story story short, I figured out that the reason this
error message was cropping up was because the software was being installed on a Terminal
Server.  In order to install some (not all) software on a Terminal Server, you
must first put the server in Install mode, then run the installer (via the Control
Panel), and then put the server back into its default Execute mode:</font>
        </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <font face="Tahoma">1. From the Command Prompt, type the following command:  <strong>change
user /install</strong>.<br />
2. Install the software via Add/Remove Programs in the Control Panel.<br />
3. When complete, type <strong>change user /execute</strong> from the command prompt.</font>
          </p>
        </blockquote>
        <p>
          <font face="Tahoma">While I'm not a systems guy, this leads me to wonder why I had
to do this for my installer (which I wrote with InstallScript) but I don't for other
installers.  Perhaps there's a switch I can set or a script I can invoke that
will do this automatically?  I must investigate.</font>
        </p>
        <img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=81ef7512-4e8d-463f-9acf-12268085a723" />
      </body>
      <title>Installing Software on a Terminal Server</title>
      <guid isPermaLink="false">http://blog.devstone.com/aaron/PermaLink,guid,81ef7512-4e8d-463f-9acf-12268085a723.aspx</guid>
      <link>http://feedproxy.google.com/~r/ZupancicPerspective/~3/-kYdN7FF_tE/InstallingSoftwareOnATerminalServer.aspx</link>
      <pubDate>Tue, 17 Feb 2009 16:47:23 GMT</pubDate>
      <description>&lt;p&gt;
&lt;font face=Tahoma&gt;Years ago I created an InstallShield (InstallScript)&amp;nbsp;installer
for some software that I've maintained over the years.&amp;nbsp; While the installer has
been run countless times (successfully, I might add), I recently witnessed the&amp;nbsp;following
error message:&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
&lt;font face="Courier New"&gt;An error (-5006 : 0x80070002) has occurred while running
the setup.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;Please make sure that you have finished any previous setup
and closed other applications.&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;font face=Tahoma&gt;This usually happens after installing a related, but completely
stand-alone and distinct product.&amp;nbsp; After a reboot (having supposed that the previous
setup didn't completely finish) we get the same error message.&amp;nbsp; It turns out,
that the error would occur whether or not the previous application had been installed.&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face=Tahoma&gt;Well, long story story short, I figured out that the reason this
error message was cropping up was because the software was being installed on a Terminal
Server.&amp;nbsp; In order to install some (not all) software on a Terminal Server, you
must first put the server in Install mode, then run the installer (via the Control
Panel), and then put the server back into its default Execute mode:&lt;/font&gt;
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
&lt;font face=Tahoma&gt;1. From the Command Prompt, type the following command:&amp;nbsp; &lt;strong&gt;change
user /install&lt;/strong&gt;.&lt;br&gt;
2. Install the software via Add/Remove Programs in the Control Panel.&lt;br&gt;
3. When complete, type &lt;strong&gt;change user /execute&lt;/strong&gt; from the command prompt.&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;font face=Tahoma&gt;While I'm not a systems guy, this leads me to wonder why I had to
do this for my installer (which I wrote with InstallScript) but I don't for other
installers.&amp;nbsp; Perhaps there's a switch I can set or a script I can invoke that
will do this automatically?&amp;nbsp; I must investigate.&lt;/font&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.devstone.com/aaron/aggbug.ashx?id=81ef7512-4e8d-463f-9acf-12268085a723" /&gt;</description>
      <comments>http://blog.devstone.com/aaron/CommentView,guid,81ef7512-4e8d-463f-9acf-12268085a723.aspx</comments>
      <category>Installation</category>
    <feedburner:origLink>http://blog.devstone.com/aaron/2009/02/17/InstallingSoftwareOnATerminalServer.aspx</feedburner:origLink></item>
  </channel>
</rss>
