Compact that Virtual PC

I have long been a fan of Virtualization. Ever since the early days of Virtual PC, I have been spinning off virtual machines to test and install software applications and code. It has even gotten to the point where I do very little on my host machine. I even do most of my web browsing within a Virtual PC (you can't always be certain what sites will do to your host machine). The flexibility of being able to install, test and uninstall applications without affecting the host offers many benefits. There is also a bonus with the Undo Disk option within Virtual PC. With an Undo Disk you can start up a Virtual PC and do “your thing” and then have the option of committing or deleting the session changes upon shut down. Take the benefits of virtualization and the fact that Microsoft Virtual PC 2007 is free and it is no wonder why Virtualization is now mainstream.

One thing that I had noticed using Virtual PCs is the disk size of the virtual hard disks. The virtual hard disks can be of fixed or variable size. If you opt for a variable sized hard disk, the disk will grow as you use it. The installation of application, copying of files and general processing use will cause the amount of space the virtual disk uses on the host machine to grow. As files are removed, applications are uninstalled and processing decreases I noticed that the virtual hard disk size doesn't decrease. In the help file there is a section that explains how to "Compact a virtual hard disk". The steps are pretty straight forward as they explain how to use the Virtual Disk Compaction option through the Virtual Disk Wizard. I did this on a number of virtual hard disks and really wasn't impressed with the results. To be honest, I didn't notice any change in the size of the virtual hard disk after running this process.

After a little confusion I noticed one important note that is in the help file, "Before compacting the disk, we recommend that you use a disk utility to zero out blank space, which should result in a smaller compacted virtual hard disk". After I thought about it, it did make a lot of sense. Now, where do I get one of these little utilities?

In the Virtual Machine Additions folder (under the Microsoft Virtual PC program folder) there is a Virtual Disk Precompactor.iso file (I found the "Using Virtual Disk Precompactor" section of the help file afterwards). It didn’t take much for me to figure out that this utility probably should be used prior to compacting a Virtual Hard Disk. It was a simple enough test; after all I was only trying it within a virtual PC. If you capture this iso file from within the Virtual PC and autoplay it, this utility will "prepare the virtual hard disk for compacting". After you run this utility, close down the Virutal PC and follow the steps for compacting a virtual hard disk found in the help file (you'll need to commit the changes if you are using an Undo disk). Take a look at the size of your vhd's before and after, the difference will be shocking. I know I reclaimed many many gigabytes of space on my hard disk.

Another great feature that is worth looking into is a Differencing disk….



   

Is it Hammer Time?

Stop! It almost was hammer time, sledge hammer time, for my new Hammer Storage MyShare™. With all of the data that I have on my machines, the conventional back-up strategy I had didn't really cut it. I decided that I needed to find a solution that had reliability, accessibility, convenience and ease of use. I needed something that would allow me to do frequent back-ups (of just critical data) effectively and efficiently without having to do too much. After reviewing a number of strategies, I determined that a NAS (Network Attached Storage) device was my best route. Without getting into boring details, I opted for the Hammer Storage MyShare™. I hadn't read too many unfavorable reviews for the product (besides the frequent drop in connect, which the latest firmware was supposed to fix). The MyShare™ also had what I was looking for; Network Storage, USB connectivity, RJ-45 connectivity, RAID (mirror or stripe), a Print Server (perfect opportunity to replace the one I have), HTTP access, FTP access and of course user security (local and domain).

After getting clearance from the finance committee I popped over to NewEgg.com and ordered myself up a MyShare™. Excitement wasn't the word for my emotion after I received the confirmation order, and for the rest of my week. After all, who doesn't want a NAS? My package was shipped UPS 3 day. I often don't find the tracking information accurate (meaning I usually get a package before it arrives) so on day 3, I constantly checked to see if Big Brown delivered my package (even though the tracking page showed it on the other side of the state; not at the local facility). Well, day 3 came to an end and my package didn't show up (frustration level rises). Day 4, well it almost came to a close before my shipment arrived. I wasn't really excited about the delay, but my NAS did arrive and as I opened the box shipping delay frustration went away.

As I opened the box, I was thinking of how I was going to set this up with file shares, security and what scripts I need to change to transfer base and incremental files. The biggest thing on my mind was that I needed to upgrade the firmware. I connected the storage device and set it up. I must admit I was extremely satisfied with the ease of setup, use, and configuration of the MyShare™. The user interface is nice as well; however the one piece they should have included more information on is the security keys that it can generate and how to configure them for the device. I downloaded and applied the latest firmware update (which was a breeze to do). I received the success message and then setup the device to use the drives as a mirrored RAID, another easy thing to do. The device needed some time to sync the drives (understandable) so I decided to go do something else for a bit.

Upon my return, I decided to first setup the Print Server. I connected the printer and it was immediately recognized. I then went over to one of the computers and connected to the now shared printer. Next step, print a test page – result NOTHING. I tried setting it up again and the same result. I thought it could have something to do with the computer so I jumped on another one and had the same issue. The print server wasn’t my main priority so I figured I’d fuss with it later. My next attempt was to back up some data. After all, this was the primary excuse, I mean reason that I presented for the purchase (who doesn’t want to make sure all their photos are backed up). I modified my scripts to point to the MyShare™ for the destination device and began to backup my data. I do have a lot of data, and the frustration level went through the roof when my connection kept getting dropped while copying data over to the device. I tried to copy files directly, only getting so far before WHAMO – Dropped! I tried deleting files that were copied over to the device, same result, dropped! I tried for a while and kept having the same result. I did confirm that the firmware update was applied (version was correct on the device). The MC Hammer song started playing in my head overlaid by the Peter Gabriel song. Needless to say, it was almost Sledge Hammer Time. Before, I got too crazy and had a Hammer (storage) versus (sledge) Hammer grudge match; I powered down the device and walked away. It might have been tired from its trip and needed a rest.

I returned several hours later and to try this all again. I powered everything up and logged into the computer. Hrm, what should I try first, I thought. I opened up the printer and attempted to print a test page. My jaw hit the floor when I heard the printer started spitting out paper. I then proceeded to do the same file transfer actions that frustrated me to no end a few hours earlier. Too my pleasant surprise – everything worked like a charm. I transferred, deleted and moved gigabyte after gigabyte (simultaneously) and the MyShare™ kept up with me and handled it all with no problems (or dropped connections). The level of my excitement was greater than that of when I ordered the device. All that was needed was a nice cold (hard) boot. I only wish I had known that when I applied the firmware.

At this point (several days and gigabytes later) I can’t say I could be any happier with the Hammer Storage MyShare™. It turned out to be a lot better than I had expected. If you are looking for a back up device or strategy, you might want to consider one of these little things.



   

DSOFile and Summary Properties

Yesterday I posted about using ShellExecuteEx to display the document properties dialog for a file or folder. Displaying the properties dialog is nice, however I also need to access the OLE document properties (Document Summary Properties), the information that is stored on the Summary and Custom tabs of the properties dialog. I did quite a bit of searching, reading and testing in an attempt to find a simple solution. I did get to learn a lot about the Document Summary Properties and it looked like my only option was to head down the road using the IPropertyStorage Interface. As I was testing some code I came across the best little ActiveX component that can quickly access the property information. The Dsofile.dll is an ActiveX component is available from Microsoft. They even include a sample application (although the samples are in VB6 and VB7 they are useable). This component simplifies (I like things simple) setting and getting the document summary properties. The KB article and download mention that this is meant for Office files, however I have found that it works fine on other files as well (the exception being that the Office documents seem to be the only types of files with Custom Properties). The other great thing about this component is that "You have a royalty-free right to use, to modify, to reproduce, and to distribute the Dsofile.dll sample file component and the C++ source code files in any way you find useful." That quote is taken directly from the DSOfile.dll Article ID: 224351 that is listed on Microsoft's Support site. My thoughts, why reinvent the wheel when you really don't need to. I highly recommend using this component if you need to access the extended properties. As usual, I whipped up a sample application testing this components functionality. The meager sample code is listed here (image of application screen is also included in this post):

namespace FileProperties1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnSelectFile_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                textBox1.Text = openFileDialog1.FileName;
                toolTip1.SetToolTip(textBox1, textBox1.Text);
                lstSummary.Items.Clear();

                OleDocumentPropertiesClass odpc = new OleDocumentPropertiesClass();
                odpc.Open(
                @openFileDialog1.FileName,
                false,
                dsoFileOpenOptions.dsoOptionOpenReadOnlyIfNoWriteAccess
                );
                // Summary "Standard" Properties
                ListViewItem lvTitle = new ListViewItem();
                lvTitle.Group = lstSummary.Groups[0];
                lvTitle.Text = "Title";
                lvTitle.SubItems.Add(odpc.SummaryProperties.Title);
                lstSummary.Items.Add(lvTitle);

                ListViewItem lvSubject = new ListViewItem();
                lvSubject.Group = lstSummary.Groups[0];
                lvSubject.Text = "Subject";
                lvSubject.SubItems.Add(odpc.SummaryProperties.Subject);
                lstSummary.Items.Add(lvSubject);

                ListViewItem lvCategory = new ListViewItem();
                lvCategory.Group = lstSummary.Groups[0];
                lvCategory.Text = "Category";
                lvCategory.SubItems.Add(odpc.SummaryProperties.Category);
                lstSummary.Items.Add(lvCategory);

                ListViewItem lvKeyword = new ListViewItem();
                lvKeyword.Group = lstSummary.Groups[0];
                lvKeyword.Text = "Keywords";
                lvKeyword.SubItems.Add(odpc.SummaryProperties.Keywords);
                lstSummary.Items.Add(lvKeyword);

                ListViewItem lvComments = new ListViewItem();
                lvComments.Group = lstSummary.Groups[0];
                lvComments.Text = "Comments";
                lvComments.SubItems.Add(odpc.SummaryProperties.Comments);
                lstSummary.Items.Add(lvComments);

                ListViewItem lvAuthor = new ListViewItem();
                lvAuthor.Group = lstSummary.Groups[1];
                lvAuthor.Text = "Author";
                lvAuthor.SubItems.Add(odpc.SummaryProperties.Author);
                lstSummary.Items.Add(lvAuthor);

                ListViewItem lvRevision = new ListViewItem();
                lvRevision.Group = lstSummary.Groups[1];
                lvRevision.Text = "Revision Number";
                lvRevision.SubItems.Add(odpc.SummaryProperties.RevisionNumber);
                lstSummary.Items.Add(lvRevision);

                // Custom Properties
                foreach (DSOFile.CustomProperty cp in odpc.CustomProperties)
                {
                    ListViewItem lvc = new ListViewItem();
                    lvc.Group = lstSummary.Groups[2];
                    lvc.Text=cp.Name;
                    lvc.SubItems.Add(cp.get_Value().ToString());
                    lstSummary.Items.Add(lvc);
                }
                odpc.Close(false);
            }
        }
   }
}



   

ShellExecuteEX and ShellExecuteInfo Revisited

Who says history doesn't repeat itself? I am working on a project that needs to display and access file properties. A quick search through the .NET 2.0 Framework didn't yield anything that popped out. I did however, remember our wonderful friend - the SHELL32 API. Previously, I had posted on using ShellExecuteEX with Delphi (I am a huge Delphi fan; I may not be posting much about it recently, but I did not forget it). Here is that same sample in using C#.


1 public const uint SW_SHOW =0x5;
2 public const uint SEE_MASK_INVOKEIDLIST = 0xC;
3
4 public enum verbs
5 {
6 properties,
7 open,
8 edit,
9 explore,
10 print
11 }

12
13 [StructLayout(LayoutKind.Sequential)]
14 public struct SHELLEXECUTEINFO
15 {
16 public int cbSize;
17 public uint fMask;
18 public IntPtr hwnd;
19 public String lpVerb;
20 public String lpFile;
21 public String lpParameters;
22 public String lpDirectory;
23 public uint nShow;
24 public int hInstApp;
25 public int lpIDList;
26 public String lpClass;
27 public int hkeyClass;
28 public uint dwHotKey;
29 public int hIcon;
30 public int hProcess;
31 }

32
33 [DllImport("shell32.dll")]
34 static extern bool ShellExecuteEx(ref SHELLEXECUTEINFO lpExecInfo);
35
36 public void MyShellExecuteInfo(string filename, verbs verb)
37 {
38 SHELLEXECUTEINFO info = new SHELLEXECUTEINFO();
39 info.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(info);
40 switch (verb)
41 {
42 case verbs.properties:
43 info.lpVerb = "properties";
44 break;
45 case verbs.print:
46 info.lpVerb = "print";
47 break;
48 case verbs.open:
49 info.lpVerb = "open";
50 break;
51 case verbs.explore:
52 info.lpVerb = "explore";
53 break;
54 case verbs.edit:
55 info.lpVerb = "edit";
56 break;
57 }

58
59 info.lpFile = filename;
60 info.nShow = SW_SHOW;
61 info.fMask = SEE_MASK_INVOKEIDLIST;
62 ShellExecuteEx(ref info);
63 }

64



   

A ToolStripMenuItem and a Check

One nice addition to the .NET 2.0 framework is the ToolStripMenuItem Class. The ToolStripMenuItem Class replaces the MenuItem Class. The ToolStripMenuItem has a Checked property that gets or sets a value indicating if the item is checked or not. Coupled with the ToolStripMenuItem.CheckOnClick property, this can be useful for identifying which item has been selected or activated. Unfortunately, there isn't some sort of 'allow only one checked' property which allows for only one item in a menu to be 'Checked' at a time. This functionality can be easily added in code (or you could derive your own class that has this functionality; a nice addition to a personal control library). Create an OnClick and OnCheckChanged method that are referenced by each of the ToolStripMenuItems. Basically, you check to see if the current item is checked or not and then toggle the check for the other menu items. You could also check another property of the sender (such as the Tag property) to perform some other action.

Here is an example:

1 private void CheckedIconsToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
2 {
3 if (sender is ToolStripMenuItem)
4 {
5 if (!((ToolStripMenuItem)sender).Checked) return;
6 foreach (ToolStripMenuItem item in (((ToolStripMenuItem)sender).GetCurrentParent().Items))
7 {
8 if (item != null && item != sender && item.Checked)
9 {
10 item.Checked = false;
11 return;
12 }

13 }

14 }

15 }

16
17 private void CheckedToolStripMenuItem_Click(object sender, EventArgs e)
18 {
19 if (sender is System.Windows.Forms.ToolStripMenuItem)
20 {
21 if (!((ToolStripMenuItem)sender).Checked)
22 {
23 ((ToolStripMenuItem)sender).Checked = !((ToolStripMenuItem)sender).Checked;
24 }
;
25 switch (((ToolStripMenuItem)sender).Tag.ToString())
26 {
27 case "1":
28 break;
29 case "2":
30 break;
31 case "3":
32 break;
33 case "4":
34 break;
35 case "5":
36 break;
37 default:
38 break;
39 }
;
40 }

41 }

42