Tuesday, November 22, 2011

Enkompass 11.30 unfit for ASP.NET hosting

After facing various issues with Enkompass, I’m giving up on it and moving to Plesk. I shall document the issues to remind myself not to go back to Enkompass until the issues are resolved. Hopefully, this also serves as a guide to those evaluating whether Enkompass caters to their needs.

  1. Enkompass supports only one ASP.NET application. There is no way to configure virtual directories or new ASP.NET application in subdirectories. This is a blocker if you wish to have a different application, say landing page on www.example.com, and a separate blog application on www.example.com/blog.
  2. The workaround for the one ASP.NET application limitation is to use subdomains. Each subdomain supports one ASP.NET application. So you can have a landing page on www.example.com and your blog on blog.example.com.
  3. However, I need to secure all communications, so I had to install an SSL certificate to enable HTTPS. SSL works on a per IP basis. There are two types of SSL – one which secures one domain only, and another called a wildcard certificate that secures multiple domains. Enkompass supports only one dedicated IP per account, so getting many one domain certificates is not an option.
  4. As for getting a wildcard certificate, Enkompass does not allow me to change the host field of the CSR to *.example.com, so wildcard certificate can’t be used as well. Moreover, there are reports that even if you are successful in generating a wildcard CSR using WHM, when accessing the HTTPS subdomain, web pages from the main domain get served out instead.

Enough of Enkompass. Simple interface, crippled internals.

Tuesday, May 10, 2011

Recovering DotNetNuke Host menu after unchecking Include in Menu

The Admin and Host pages in DotNetNuke can be hidden from the menu, just like other pages. However, a bug in DotNetNuke causes the Host page to lose its connection to its subpages. Luckily, it is reversible, as mentioned in http://www.dnncreative.com/Forum/tabid/88/aft/31023/Default.aspx. Just type the following

UPDATE {databaseOwner}[{objectQualifier}Tabs] SET PortalID = NULL WHERE TabID = 7

in /Host/SQL/tabid/21/portalid/0/Default.aspx, check Run as Script and execute.

For those who check Include in Menu after unchecking it, there will be a red admin border saying Visible By Administrators Only on the Host page. To remove it, run the following script

DELETE FROM {databaseOwner}[{objectQualifier}TabPermission] WHERE TabID = 7

Wednesday, April 20, 2011

Prevent getting disconnected/blocked from school network when running virtual machine

In Nanyang Technological University’s (NTU) Local Area Network (LAN), whenever one plugs a personal router into a LAN port, the port will be blocked for 10 minutes. If the router is still present after 10 minutes, it gets blocked again. This is probably to ensure that nobody connects a wireless router/access point and turn the non-password secured physical port into a wireless one.

However, this security measure interferes with virtual machines as well. Whenever I start XP Mode, VirtualPC or VirtualBox, I get disconnected from the network. This is probably due to virtualization turning my network card into a Network Address Translation (NAT) device, thus appearing as a router from the outside.

The solution is to connect to NTU Virtual Private Network (VPN) first. Instructions can be found at http://www.ntu.edu.sg/cits/itnetworking/remoteaccess/Pages/quickstartguide.aspx#sslvpn. By doing so, I can access the Internet both from my host and guest OS without getting blocked.

Sunday, February 27, 2011

Bing Maps 7 API bug in MouseEventArgs.getX and getY

The new Bing Maps is a lot more lightweight, and the changes in event handling makes more sense. For example, it is now possible to detect viewchangeend event instead of using an assortment of onendpan, timers and getCenter to detect whether the view has changed.

However, I ran into the same problem mentioned here http://www.ms-windows.info/Help/map-control-v7-mouse-wheel-double-29660.aspx. The mouse wheel and double click do not zoom at the location of the mouse. Worse still, adding a pushpin when the user clicked on the map results in the pushpin being placed too high up on the map. How much higher the pushpin is placed also depends on the browser used.

Upon investigating the MouseEventArgs.getX and getY functions, I found that they depended on getViewportX and getViewportY functions. By replacing the getViewportY function with one that uses jQuery to calculate the correct offset, I managed to get the mouse wheel, double click and pushpins to all work correctly.

var map = new Microsoft.Maps.Map($("#map")[0],

{

    credentials: "",

    center: new Microsoft.Maps.Location(1.35, 103.82),

    zoom: 11,

    showDashboard: false

});

 

map.getViewportY = function () {

    return $("#map").offset().top + $("#map").height() / 2;

};

However, it does introduce a problem whereby the dashboards navigations no longer work correctly and the view type menu displays too far down. It thus necessitates writing my own dashboard.

Tuesday, February 08, 2011

Oddities of Facebook events API

Using the the Graph API of https://graph.facebook.com/[userId]/events, one can retrieve the events that the user is attending. The same applies to page, using https://graph.facebook.com/[pageId]/events. However, what does it mean by the event attended by a page? It is not the same as the events created by the page, as the API returns less results that what you would see in the events tab of the page. The result return from FQL and REST API are similar.

After spending an entire day figuring out what happens behind the scene, I came to the following conclusion:

  1. User A creates Page P.
  2. User A makes User B also the admin of Page P.

During creation of event:

  1. If User A creates event on Page P, Page P will be attending the event.
  2. If User B creates event on Page P, Page P will not be attending the event.

Unfortunately, as FQL does not allow querying the event by its creator, there is hence no way to fool-proof way to get the events that a page has created.

Monday, February 07, 2011

Oddities of Facebook event date/time

Facebook is very popular globally, crossing several time zones. Yet to my surprise, it has no concept of time zones. Quote from the Legacy REST API

Note that the start_time and end_time are the times that were inputted by the event creator. Facebook Events have no concept of timezone, so, in general, you can should not treat the value returned as occurring at any particular absolute time. When an event is displayed on facebook, no timezone is specified or implied.

However, using the Graph API to retrieve events of a page, I got the following:

{
  "data":
  [
    {
      "name":"Event Name",
      "start_time":"2010-11-20T02:30:00+0000",
      "end_time":"2010-11-20T03:00:00+0000",
      "location":"5th Street",
      "id":"1234"
    }
  ],
  "paging":
  {
    "previous":"https:\/\/graph.facebook.com\/11\/events?access_token=15\u00257&limit=5000&since=2010-11-20T02\u00253A30\u00253A00\u00252B0000",
    "next":"https:\/\/graph.facebook.com\/11\/events?access_token=15\u00257&limit=5000&until=2010-09-22T01\u00253A29\u00253A59\u00252B0000"
  }
}

The start_time and end_time are displayed as GMT+0. These times are 8 hours late. On some other events, they are 7 hours late. Clearly, Facebook is trying to store the time in GMT, but isn’t using the correct time zone where I am at.

According to http://www.webos-internals.org/wiki/Facebook_timezone_issue, Facebook assumes all time to be in Pacific Time. Thus the GMT-8 during Standard Time and GMT-7 during Daylight Savings.

In order to use the time from the Graph API, I used the TimeZoneInfo to convert the time from GMT to Pacific Time. Code as follows

private static PacificDateTime StringToDate(string value)
{
    DateTime fakeUtc = DateTime.Parse(value, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
 
    // See http://www.webos-internals.org/wiki/Facebook_timezone_issue.
    // Facebook assumes all time in events to be in Pacific Time.
    const string pacificTimeZoneId = "Pacific Standard Time";
    TimeZoneInfo pacificTimeZone = TimeZoneInfo.FindSystemTimeZoneById(pacificTimeZoneId);
    DateTime pacificTime = TimeZoneInfo.ConvertTimeFromUtc(fakeUtc, pacificTimeZone);
 
    return new PacificDateTime(pacificTime, pacificTimeZone.IsAmbiguousTime(pacificTime));
}

By treating all times as Pacific Time, Facebook introduced oddities to places that do not practise daylight savings, or that has daylight savings on a different schedule. Effectively, there is no way for me to meet on 13 March 2011 at 2.30am. Since daylight savings starts at 2am on the 2nd Sunday of March, and it adjusts the clock to 3am, 2.30am is an invalid time in Pacific Time. Events specified as 2.30am becomes 3.30am.

On the 6 November 2011, daylight savings ends and the clock jumps back an hour. This creates ambiguous time between 1am and 2am, which Facebook behaves in a very weird way when creating events that are at that time. Try it for yourself.

Monday, October 18, 2010

A comparison of DjVu and JPEG2000 in PDF

Some time ago, I stumbled upon DjVu, a document archiving format. I have previously scanned several printed documents into JPEG and compiled them in ZIP archive. The method is sub-optimal,  producing large JPEG files and creating non-viewable files, unless uncompressed. Placing the JPEG files in PDF, while making it viewable, increases the file size further.

DjVu presented a much better alternative. It has a better compression method, based on wavelet, that is able to achieve the same quality of the JPEG files at half the file size. The several compressed DjVu photos can be compiled into a single DjVu document. With the benefit of halving the size and ability to view the scanned files like a PDF document, I migrated to using DjVu to archive my paper documents.

Then recently, I discovered that PDF is able to make use of JPEG2000 compression. PDF has supported JPEG2000 since version 1.5/Acrobat 6.0. JPEG2000 uses similar wavelet compression as DjVu, producing similar quality images at similar file size. Due to the ability to easily comment on PDF files, I have decided to migrate to JPEG2000 in PDF. Below is a comparison of the two formats:

  DjVu JPEG2000 in PDF
Creation tools Free and open source command line tools, fi_c44 and djvm. Typing two commands convert PNG to DjVu documents.
(Better in terms of cost and keystrokes/mouse input needed)
Adobe Acrobat, with compression for imported PNG set to JPEG2000. Two steps to create PDF from PNG: create the first page using Create File from Image, and subsequent pages by Inserting Page from Image.
Viewing tools WinDjView (free)
Load extremely fast; remembers last position of page viewed; smooth scrolling
(Better in terms of speed)
PDF-XChange Viewer (free)
Load a little slower than WinDjView; remembers last position of page viewed; smooth scrolling
Annotating / commenting tools DjVu Solo (free)
Very primitive commenting, limited to highlighting and hyper-linking.
PDF-XChange Viewer (free)
Rich set of commenting tools. Add text, highlight and draw easily
Editing tools WinDjView (free)
Exports page into various formats for editing in external program.
The to place the page back, to process of creating the DjVu page has to be repeated.
(Better in terms of cost)
Adobe Acrobat
Scanned image selectable. By choosing to edit the image, Photoshop launches.
(Better in terms of requiring less steps)
Exchanging documents A DjVu viewer is required. Most people do not have one installed. A PDF viewer is required. Adobe Reader is installed on most computers.

Friday, September 03, 2010

Downloading Facebook Profile Pictures to Outlook Contacts

Microsoft Office 2010 introduced the Social Connectors. With the Facebook Connector, emails now come with faces, thanks to the connector downloading profile pictures from Facebook. Opening contact items shows faces as well.

The next logical step is to use that contact item’s profile picture as the business card picture. However, no matter how I click-and-drag the picture over to the placeholder, nothing happens. Searching the Internet yields a program called OutSync. However, it managed to only download 3 profile pictures to my Outlook. Looking at its source code revealed the reason – it compares the full name on Facebook and Outlook. Since most of my Facebook friends registered only with their first names or initials, OutSync failed to match them to my Outlook contacts.

So now I have a problem that seems to be easily solvable. I thought I could change OutSync such that it will download email addresses of my friends and match them with my Outlook. However, Facebook always return null for emails.

Another approach is necessary. and in the end, I wrote a program – Outbook – that matches email addresses of Facebook and Outlook. It does so by running multiple search requests, downloading the information of the search results, then downloading the photos.

PS: As I’m running on Windows 7 64-bit and Office 2010 64-bit, I cannot promise that it will work on other OS and Office versions.

Download the application here: https://www.facebook.com/apps/application.php?id=143431545697835

Monday, August 30, 2010

Restoring Windows 7 Image Backup to any partition

With my C: running out of space, I deleted the recovery partition on my hard disk. However, as the recovery partition occupied the space before C:, Windows was unable to expand C: to take the space. To move C:, I used GParted Live USB. However, GParted only created the partition, totally wrecking the data and Windows can no longer boot (WinRE cannot even recognize that I had Windows 7 installed). Luckily, I had heeded the advice to backup my computer before running GParted.

Recovering from the system image is not so straight forward. Firstly, the “repartition and format drive” is checked and cannot be unchecked. Thus, there is no way for me to restore Windows to a larger partition I wanted. Secondly, I had a Fedora partition which I suspect will be wiped out by the formatting. An alternative to overcome the restrictive options is needed.

After looking at these websites, Howto: Duplicate any Windows installation to a new hard disk using only a Vista DVD (!) and How to restore VHD file backup?, inspiration came to me. I could combine both instructions to recover my system image, which is a VHD, to any partition with no restrictions.

Firstly, I booted off the Windows 7 DVD and selected “Repair Windows”. Cancelling the wizard brings me to the advanced options. Selecting “Command Prompt”, I mounted the backup file (on E:) as F: by entering the following:

diskpart
select vdisk file="E:\…\Backup Set…\Backup….vhd"
attach vdisk

Then, following the instructions on duplicating Windows installation, I typed

ROBOCOPY F:\ C:\ /e /efsraw /copyall /dcopy:t /r:0

It took an entire night for the copy to complete. Once done, I booted into the Windows 7 DVD and selected “Repair Windows” again. This time, the wizard detected a problem with the boot up and did the appropriate repairs.

I was overjoyed when I could boot into Windows again. However, Avast! antivirus prompted me for a new license key. Entering an old one made the dialog go away. Another program that I found broken was Microsoft Outlook, which responded with “Not Implemented” pop-ups when many of the ribbon buttons are clicked. Repairing Microsoft Office through Control Panel > Program Features solved the problem.

Monday, March 29, 2010

Red Black Tree Tutorial

On examining the red black tree used for the SortedDictionary class, I realized Microsoft did not use any recursion for insertion and deletion. This seems weird, because I have never come across a top-down tree balancing method. Then I found the Eternally Confuzzled - Red Black Tree Tutorial, which clearly explains how it is done. Thanks Julienne!

Sunday, March 28, 2010

Runtime Complexity of .NET Generic Collection

I had to implement some data structures for my computational geometry class. Deciding whether to implement the data structures myself or using the build-in classes turned out to be a hard decision, as the runtime complexity information is located at the method itself, if present at all. So I went ahead to consolidate all the information in one table, then looked at the source code in Reflector and verified them. Below is my result.
Internal Implement-
ation
Add/insert Add beyond capacity Queue/Push Dequeue/
Pop/Peek
Remove/
RemoveAt
Item[index]/ElementAt(index) GetEnumerator Contains(value)/IndexOf/ContainsValue/Find
List Array O(1) to add, O(n) to insert O(n) - - O(n) O(1) O(1) O(n)
LinkedList Doubly linked list O(1), before/after given node O(1) O(1) O(1) O(1), before/after given node O(n) O(1) O(n)
Stack Array O(1) O(n) O(1) O(1) - - O(1) O(n)
Queue Array O(1) O(n) O(1) O(1) - - O(1) O(n)
Dictionary Hashtable with links to another array index for collision O(1), O(n) if collision O(n) - - O(1), O(n) if collision O(1), O(n) if collision O(1) O(n)
HashSet Hashtable with links to another array index for collision O(1), O(n) if collision O(n) - - O(1), O(n) if collision O(1), O(n) if collision O(1) -
SortedDictionary Red-black tree O(log n) O(log n) - - O(log n) O(log n) O(log n) O(n)
SortedList Array O(n), O(log n) if added to end of list O(n) - - O(n) O(log n) O(1) O(n)
SortedSet Red-black tree O(log n) O(log n) - - O(log n) O(log n) O(log n) -
Note:
Dictionary Add, remove and item[i] has expected O(1) running time
HashSet Add, remove and item[i] has expected O(1) running time
Update 25 April 2010: Added SortedSet

Saturday, October 10, 2009

Programmers are Tiny Gods

Derek Powazek says Programmers are Tiny Gods. Maybe this explains why some people call me god? =P

Rasterizing a vector brush for fast scaling animation

When animating (scaling) a complex WPF vector brush, 100% of my CPU is used. The animation also looks jerky. To speed things up, I rasterized the vector brush into a bitmap brush. The CPU load decreases below 30% and the animation became much smoother.

So how do I create a bitmap brush? There is no meaningful properties or methods to override in the Brush class, as most of the workings of brush are marked as internal. To overcome the problem, the brush is implemented as a markup extension.

To use the code, pass your vector brush into the RasterizeBrush class.

<Button
    x:Name="helloButton"
    Background="{app:RasterizeBrush {StaticResource HelloBrush}}"
    >
        <TextBlock>Hello</TextBlock>
</Button>

And place the following code inside your project.

/-----------------------------------------------------------------------
// <copyright file="RasterizeBrushExtension.cs" company="Jeow Li Huan">
// Copyright (c) Jeow Li Huan. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
 
namespace Huan.Windows.Markup
{
    using System;
    using System.Windows;
    using System.Windows.Markup;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
 
    /// <summary>
    /// Converts a vector brush into a bitmap brush to speed up scaling.
    /// </summary>
    [MarkupExtensionReturnType(typeof(ImageBrush))]
    public class RasterizeBrushExtension : MarkupExtension
    {
        /// <summary>
        /// Object used to synchronize access to the static properties <see cref="P:DefaultWidth"/> and <see cref="P:DefaultHeight"/>.
        /// </summary>
        private static object sync = new object();
 
        /// <summary>
        /// Backing field for the <see cref="P:DefaultWidth"/> property.
        /// </summary>
        private static int defaultWidth = 64;
 
        /// <summary>
        /// Backing field for the <see cref="P:DefaultHeight"/> property.
        /// </summary>
        private static int defaultHeight = 64;
 
        /// <summary>
        /// Backing field for the <see cref="P:OriginalBrush"/> property.
        /// </summary>
        private Brush originalBrush;
 
        /// <summary>
        /// The converted bitmap brush.
        /// </summary>
        private ImageBrush rasteredBrush;
 
        /// <summary>
        /// Backing field for the <see cref="P:Width"/> property.
        /// </summary>
        private int width;
 
        /// <summary>
        /// Backing field for the <see cref="P:Height"/> property.
        /// </summary>
        private int height;
 
        /// <summary>
        /// Initializes a new instance of the <see cref="RasterizeBrushExtension"/> class.
        /// </summary>
        public RasterizeBrushExtension()
        {
        }
 
        /// <summary>
        /// Initializes a new instance of the <see cref="RasterizeBrushExtension"/> class.
        /// </summary>
        /// <param name="originalBrush">The original brush that is to be converted into a bitmap brush.</param>
        public RasterizeBrushExtension(Brush originalBrush)
            : this()
        {
            this.originalBrush = originalBrush;
        }
 
        /// <summary>
        /// Gets or sets the default number of horizontal pixels for the bitmap to render on.
        /// </summary>
        /// <value>The default number of horizontal pixels for the bitmap to render on.</value>
        public static int DefaultWidth
        {
            get
            {
                lock (sync)
                    return defaultWidth;
            }
 
            set
            {
                lock (sync)
                    defaultWidth = value;
            }
        }
 
        /// <summary>
        /// Gets or sets the default number of vertical pixels for the bitmap to render on.
        /// </summary>
        /// <value>The default number of vertical pixels for the bitmap to render on.</value>
        public static int DefaultHeight
        {
            get
            {
                lock (sync)
                    return defaultHeight;
            }
 
            set
            {
                lock (sync)
                    defaultHeight = value;
            }
        }
 
        /// <summary>
        /// Gets or sets the original brush that is to be converted into a bitmap brush.
        /// </summary>
        /// <value>The original brush that is to be converted into a bitmap brush.</value>
        [ConstructorArgument("originalBrush")]
        public Brush OriginalBrush
        {
            get
            {
                return this.originalBrush;
            }
 
            set
            {
                if (this.originalBrush != value)
                {
                    this.rasteredBrush = null;
                    this.originalBrush = value;
                }
            }
        }
 
        /// <summary>
        /// Gets or sets the number of horizontal pixels for the bitmap to render on.
        /// </summary>
        /// <value>The number of horizontal pixels for the bitmap to render on.</value>
        public int Width
        {
            get
            {
                return this.width;
            }
 
            set
            {
                ifthis.width != value)
                {
                    this.rasteredBrush = null;
                    this.width = value;
                }
            }
        }
 
        /// <summary>
        /// Gets or sets the number of vertical pixels for the bitmap to render on.
        /// </summary>
        /// <value>The number of vertical pixels for the bitmap to render on.</value>
        public int Height
        {
            get
            {
                return this.height;
            }
 
            set
            {
                if (this.height != value)
                {
                    this.rasteredBrush = null;
                    this.height = value;
                }
            }
        }
 
        /// <summary>
        /// Returns the converted bitmap brush.
        /// </summary>
        /// <param name="serviceProvider">Not used.</param>
        /// <returns>
        /// The converted bitmap brush.
        /// </returns>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            int width = (this.width == 0) ? RasterizeBrushExtension.defaultWidth : this.width;
            int height = (this.height == 0) ? RasterizeBrushExtension.defaultHeight : this.height;
            if (this.originalBrush == null || width == 0 || height == 0)
                return null;
 
            if (this.rasteredBrush == null)
            {
                RenderTargetBitmap targetBitmap = new RenderTargetBitmap(width, height, 96.0, 96.0, PixelFormats.Default);
                Rectangle rectangle = new Rectangle();
                rectangle.Width = width;
                rectangle.Height = height;
                rectangle.Fill = this.originalBrush;
 
                rectangle.Measure(new Size(width, height));
                rectangle.Arrange(new Rect(0, 0, width, height));
 
                targetBitmap.Render(rectangle);
                targetBitmap.Freeze();
                this.rasteredBrush = new ImageBrush(targetBitmap);
 
                TileBrush tileBrush = this.originalBrush as TileBrush;
                if (tileBrush != null)
                {
                    this.rasteredBrush.AlignmentX = tileBrush.AlignmentX;
                    this.rasteredBrush.AlignmentY = tileBrush.AlignmentY;
                    this.rasteredBrush.Stretch = tileBrush.Stretch;
                    this.rasteredBrush.TileMode = tileBrush.TileMode;
                    this.rasteredBrush.Viewbox = tileBrush.Viewbox;
                    this.rasteredBrush.ViewboxUnits = tileBrush.ViewboxUnits;
                    this.rasteredBrush.Viewport = tileBrush.Viewport;
                    this.rasteredBrush.ViewportUnits = tileBrush.ViewportUnits;
                }
            }
 
            return this.rasteredBrush;
        }
    }
}

Wednesday, September 23, 2009

Creating Shortcut to Application Inside Windows XP Mode

The easiest way to get a Windows 7 shortcut to an application inside XP Mode is to load up the Virtual Machine and within the guest Windows XP, create a shortcut in C:\Documents and Settings\All Users\Start Menu.

This method can be used to create shortcut for Internet Explorer 6 and Outlook Express. However, when I use the same method to create a shortcut to Pinball Space Cadet, the Windows 7 shortcut isn’t created.

I found out that there is a manual way to create shortcut. The steps are as follows

  1. In Windows XP, create the registry entries for the Terminal Services Application Allowed List
  2. In Windows 7, create a shortcut to the application in XP Mode.

Creating the registry entries

I will attempt to create a shortcut to Pinball. The following is the registry entry I created.

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\TsAppAllowList\Applications\1234567]
"CommandLineSetting"=dword:00000000
"IconIndex"=dword:00000000
"IconPath"="%SYSTEMDRIVE%\\Program Files\\Windows NT\\Pinball\\PINBALL.EXE"
"Name"="Pinball"
"Path"="C:\\Program Files\\Windows NT\\Pinball\\PINBALL.EXE"
"RequiredCommandLine"=""
"ShortPath"="C:\\PROGRA~1\\WINDOW~1\\Pinball\\PINBALL.EXE"
"ShowInTSWA"=dword:00000000
"VPath"="%SYSTEMDRIVE%\\Program Files\\Windows NT\\Pinball\\PINBALL.EXE"

image

The “1234567” part in [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\TsAppAllowList\Applications\1234567] is some random numbers that I had come up with. This number will be used later in the Windows 7 shortcut.

The "CommandLineSetting"=dword:00000000 "IconIndex"=dword:00000000 "RequiredCommandLine"="" "ShowInTSWA"=dword:00000000 are some default values that I have copied over from the 5664112 entry, which is the entry to Internet Explorer 6.

"IconPath"="%SYSTEMDRIVE%\\Program Files\\Windows NT\\Pinball\\PINBALL.EXE" determines what icon will be used. Windows 7 will extract the icon at this location and store it in Windows 7’s folder at %USERPROFILE%\AppData\Local\Microsoft\Windows Virtual PC\Virtual Applications\Windows XP Mode

"Name"="Pinball" is used for naming the icon that is extracted in the previous step. It will be used in the Windows 7 shortcut later.

"Path"="C:\\Program Files\\Windows NT\\Pinball\\PINBALL.EXE" and "VPath"="%SYSTEMDRIVE%\\Program Files\\Windows NT\\Pinball\\PINBALL.EXE" are the path to Pinball.

"ShortPath"="C:\\PROGRA~1\\WINDOW~1\\Pinball\\PINBALL.EXE" is the 8.3 path to Pinball.

We can get the 8.3 filenames step-by-step. To get the 8.3 filename of c:\Program files, type cd \ dir "Program files*" /x You will see something similar to Volume in drive C has no label. Volume Serial Number is 24FE-A31E

Directory of C:\

07/26/2009 05:57 PM <DIR> PROGRA~1 Program Files 0 File(s) 0 bytes 1 Dir(s) 134,463,721,472 bytes free

PROGRA~1 is hence the 8.3 filename for Program files.

image

Creating the Windows 7 shortcut

Create a shortcut in C:\Users\<username>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Windows Virtual PC

image

Set the Target to %SystemRoot%\system32\rundll32.exe %SystemRoot%\system32\VMCPropertyHandler.dll,LaunchVMSal "Windows XP Mode" "||1234567" "Pinball"

"||1234567" "Pinball" correspond to the random number and the Name that I have specified in the Create the registry entries step.

Tuesday, September 22, 2009

Office 2010 CTP compatibility with Nokia PC Suite and Visual Studio 2008

I use the Nokia PC Sync feature to get my handphone calendar and Outlook calendar in sync.

A clean install of Windows 7 Professional, Office 2010 64-bit edition and Nokia PC Suite 7.1.30.9 didn’t work out well—the PC Sync could not detect Outlook and thus cannot synchronize.

Apparently, Nokia PC Sync can only detect the 32-bit version of Office 2010. So I uninstalled the 64-bit version and installed the 32-bit version and everything works fine.

Then I installed Visual Studio 2008 Team Suite. It hung when I load up the designer for WebForms. Editing the ASPX file is OK though.

The solution I found was to reinstall

C:\Program Files (x86)\Common Files\microsoft shared\OFFICE12\Office Setup Controller\Setup.exe

There are incompatible programs that I have not found a solution to. Office Live Workspace Addin cannot be installed and Acrobat Professional Addin needs to be disabled or it crashes Office. Please comment if you have the solution. Thanks!

Monday, September 21, 2009

Getting Chinese Handwriting Recognition on Windows 7 Professional

Installing Language Pack

To have Chinese Handwriting Recognition, the Chinese Language Pack needs to be installed. According to Microsoft Help and Support, Windows 7 language packs are available for computers that are running Windows 7 Ultimate. Implicitly, it means that other editions of Windows do not have language packs.

To verify that, the instruction from Windows 7 Center showed the following UI in Control Panel>Regional and Language that can be used to install additional language packs.

image

However, as I am running Professional Edition, there is no Display language group.

image

Does this really mean I can’t get language pack into my Windows 7 Professional? My previous experience says that it is possible to turn Windows XP into Windows Server 2000, and also enable RAID-5 on Windows XP Pro. There must be some way to get language pack.

Sure enough, I discovered that there is another way for me to install a language pack. On WinMatrix forum, the instruction given is as follows

MUI can be also installed on Professional edition avaliable at MSDNAA: Run CMD as administrator and type: DISM /Online /Add-Package /PackagePath:(path to lp) then: bcdedit /set {current} locale (your locale) and: bcdboot %WinDir% /l (your locale) Then in registry: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\MUI\UILanguages remove key en-US Reboot and it's done

To get Simplified Chinese and Traditional Chinese language pack into my system, I typed for the first part of the instruction

DISM /Online /Add-Package /PackagePath:D:\langpacks\zh-cn\lp.cab

and

DISM /Online /Add-Package /PackagePath:D:\langpacks\zh-hk\lp.cab

image

Installing Handwriting Recognition

Go to Control Panel>Regional and Language

Click on Change keyboards…

Click on Add…

Check Chinese (Simplified) – Microsoft Pinyin New Experience Input St and Chinese (Traditional) – New Phonetic in the following dialog

image

Once added, you will see the following dialog

image

and on your task bar, you will see a new EN button added

image

Turning the Input Panel on and switching to Chinese, I can start writing.

image

Edit: The language pack seems to un-install itself. Anyone knows how to get it to stay?

Edit (April 25, 2010): Read the comments for the method to stop the "uninstall".

Edit (March 27, 2010): I managed to get both English and Simplified Chinese to stay installed some time ago. The method will most likely not work with more than two language packs though.

  1. We need to continue with the next step of deleting registry keys as mentioned in the WinMatrix forum. So launch the registry editor, navigate to HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlMUIUILanguages and delete the "en-US"
  2. Restart computer. Now, everything should be displayed in the language you installed previously.
  3. Install the en-US language pack using DISM. Launch the registry editor, navigate to HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlMUIUILanguages , export the registry entry for the language you had installed before restarting and delete the registry entry.
  4. Restart computer. Now, everything should be in English again.
  5. Import the registry entry back.
  6. The two language packs should stay even after restarting.

PS: Although this method seems to work, on examining the registry entries that are changed, they are in a wreck, with some settings referring to en-US and others zh-CN. So far, I did not notice any consequence. Try it at your own risk!

Wednesday, July 01, 2009

Virtual Box Seamless Mode

Just discovered Virtual Box had seamless mode. Virtual PC has a lot to catch up! The latest version with seamless mode is still in beta… Here, I’m running Fedora 11 in virtual machine, sharing the same desktop as Windows 7 RC. Cool, isn’t it?

Some minor problems though. All the Linux applications, including the panels, appear as a window on Windows, so clicking on any Linux app will bring all Linux app to the foreground. Not too nice. Resizing windows doesn’t seem to work after a while of usage.

I wish Virtual PC can play well with Virtual Box. Launching IE 6 (Virtual Window), with Virtual Box running, froze the computer, requiring a hard reset. It could have given me a warning that I shouldn’t be running 2 VMs at the same time…

Monday, June 29, 2009

LUA bug for Windows 7 XP Mode setup

There are 2 files that need to be installed for XP mode. Installation of Windows6.1-KB958559-x64.msu went OK, but VirtualWindowsXP.msi gave an error – your administrator prevented the installation.

To install correctly, I had to Shift+Right Click on the VirtualWindowsXP.msi, and click Run as a different user.

Once it is installed, clicking on Start>Programs>Windows Virtual PC>Virtual Windows XP will bring up this window.

And after some time, we’ve got XP in the virtual machine.

A differencing disk is used. If your computer has several users using XP mode, this could turn out to be a substantial saving on disk space, since only changes to the base XP image is saved in the each user’s virtual hard disk.

Tuesday, June 23, 2009

ASP.NET Label with DropDownList functions to reference another data source

I often encounter the following situation in ASP.NET when using a DetailsView to display a row that contains a reference to a table

<asp:DetailsView ID="detailsView" runat="server" AutoGenerateRows="False"

    DataSourceID="dataSource" DataKeyNames="Id">

    <Fields>

        <asp:TemplateField HeaderText="Name" SortExpression="Id">

            <EditItemTemplate>

                <asp:DropDownList ID="dropDownList" runat="server"

                    DataSourceID="referenceDataSource" DataTextField="Name" DataValueField="Id"

                    SelectedValue='<%# Bind("Id") %>' />

            </EditItemTemplate>

            <ItemTemplate>

                <asp:Label ID="label" runat="server" Text='<%# Eval(" What do I bind to here? ") %>' />

            </ItemTemplate>

        </asp:TemplateField>

    </Fields>

</asp:DetailsView>

I need the DetailsView to display in 3 modes, namely Insert, Edit and ReadOnly. For Insert and Edit modes, a DropDownList takes care of getting the values from the referenceDataSource. However, in ReadOnly mode, I do not want to introduce the DropDownList, for it would have unnecessarily bloat the ViewState and post-back values.

A label should be all that is needed to display, but what do I type to data bind the label to the referenceDataSource? Most of the time, I end up casting the Eval to a DataRowView, getting the Row, and calling GetParentRow. However, that is not a general solution that can be applied everywhere. By changing the data source to use DataReader instead of DataSet, the code in the label will break.

So I decided to roll out my own server control. Taking reference from Creating a Databound Label Control, I created a label control that takes similar attributes as DropDownList, so that all that is needed is to copy the DropDownList from the EditItemTemplate, paste it in ItemTemplate, and changing the tag to ReferenceLabel.

<asp:DetailsView ID="detailsView" runat="server" AutoGenerateRows="False"

    DataSourceID="dataSource" DataKeyNames="Id">

    <Fields>

        <asp:TemplateField HeaderText="Name" SortExpression="Id">

            <EditItemTemplate>

                <asp:DropDownList ID="dropDownList" runat="server"

                    DataSourceID="referenceDataSource" DataTextField="Name" DataValueField="Id"

                    SelectedValue='<%# Bind("Id") %>' />

            </EditItemTemplate>

            <ItemTemplate>

                <huan:ReferenceLabel ID="label" runat="server"

                    DataSourceID="referenceDataSource" DataTextField="Name" DataValueField="Id"

                    SelectedValue='<%# Bind("Id") %>' />

            </ItemTemplate>

        </asp:TemplateField>

    </Fields>

</asp:DetailsView>

Neat huh? Below is the code for the ReferenceLabel. Place it in App_Code and add the following into Web.config.

<configuration>

  <system.web>

    <pages>

      <controls>

        <add tagPrefix="huan" namespace="Huan.Web.UI.WebControls" />

      </controls>

    </pages>

  </system.web>

</configuration>

//-----------------------------------------------------------------------

// <copyright file="ReferenceLabel.cs" company="Jeow Li Huan">

// Copyright (c) Jeow Li Huan. All rights reserved.

// </copyright>

// <remarks>See <see href="http://aspnet.4guysfromrolla.com/articles/081308-1.aspx">Creating a Databound Label Control</see>

// for original implementation.</remarks>

//-----------------------------------------------------------------------

 

namespace Huan.Web.UI.WebControls

{

    using System;

    using System.Collections;

    using System.ComponentModel;

    using System.Web;

    using System.Web.UI;

    using System.Web.UI.WebControls;

 

    /// <summary>

    /// Represents a label control, which displays text referenced from another data source, on a Web page.

    /// </summary>

    [DataBindingHandler("System.Web.UI.Design.WebControls.ListControlDataBindingHandler, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]

    [ParseChildren(false)]

    [ToolboxData("<{0}:ReferenceLabel runat=\"server\" />")]

    public class ReferenceLabel : DataBoundControl

    {

        /// <summary>

        /// Gets or sets the field of the data source that provides the text content of the list items.

        /// </summary>

        /// <value>

        /// A <see cref="T:System.String"/> that specifies the field of the data source that provides the text content of the list items. The default is <see cref="F:System.String.Empty"/>.

        /// </value>

        [Category("Data")]

        [DefaultValue("")]

        [Description("The field in the data source that provides the text.")]

        [Themeable(false)]

        public virtual string DataTextField

        {

            get

            {

                return (string)this.ViewState["DataTextField"] ?? string.Empty;

            }

 

            set

            {

                this.ViewState["DataTextField"] = value;

                this.OnDataPropertyChanged();

            }

        }

 

        /// <summary>

        /// Gets or sets the formatting string used to control how data bound to the label control is displayed.

        /// </summary>

        /// <value>

        /// The formatting string for data bound to the control. The default value is <see cref="F:System.String.Empty"/>.

        /// </value>

        [Category("Data")]

        [DefaultValue("")]

        [Description("The formatting applied to the text. For example, {0:d}.")]

        [Themeable(false)]

        public virtual string DataTextFormatString

        {

            get

            {

                return (string)this.ViewState["DataTextFormatString"] ?? string.Empty;

            }

 

            set

            {

                this.ViewState["DataTextFormatString"] = value;

                this.OnDataPropertyChanged();

            }

        }

 

        /// <summary>

        /// Gets or sets the field of the data source that provides the value of each

        /// list item.

        /// </summary>

        /// <value>

        /// A <see cref="T:System.String"/> that specifies the field of the data source that provides

        /// the value of each list item. The default is <see cref="System.String.Empty"/>.</value>

        [Category("Data")]

        [DefaultValue("")]

        [Description("The field in the data source which provides the item value.")]

        [Themeable(false)]

        public string DataValueField

        {

            get { return (string)this.ViewState["DataValueField"] ?? string.Empty; }

            set { this.ViewState["DataValueField"] = value; }

        }

 

        /// <summary>

        /// Gets or sets the value of the selected item in the list control.

        /// </summary>

        /// <value>

        /// The value of the selected item in the label control. The default is an empty string ("").

        /// </value>

        [Bindable(true, BindingDirection.TwoWay)]

        [Browsable(false)]

        [DefaultValue("")]

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]

        [Themeable(false)]

        public object SelectedValue

        {

            get { return this.ViewState["SelectedValue"]; }

            set { this.ViewState["SelectedValue"] = value; }

        }

 

        /// <summary>

        /// Gets or sets the identifier for a server control that the <see cref="T:Huan.Web.UI.WebControls.ReferenceLabel"/> control is associated with.

        /// </summary>

        /// <value>

        /// A string value corresponding to the <see cref="P:System.Web.UI.Control.ID"/> for a server control contained in the Web form. The default is an empty string (""), indicating that the <see cref="T:Huan.Web.UI.WebControls.ReferenceLabel"/> control is not associated with another server control.

        /// </value>

        [Category("Accessibility")]

        [DefaultValue("")]

        [Description("The ID of the control associated with the Label.")]

        [IDReferenceProperty]

        [Themeable(false), TypeConverter(typeof(AssociatedControlConverter))]

        public virtual string AssociatedControlID

        {

            get { return (string)this.ViewState["AssociatedControlID"] ?? string.Empty; }

            set { this.ViewState["AssociatedControlID"] = value; }

        }

 

        /// <summary>

        /// Gets the text content of the label.

        /// </summary>

        /// <value>

        /// The text content of the control. The default value is <see cref="System.String.Empty"/>.

        /// </value>

        [Category("Appearance")]

        [DefaultValue("")]

        [Description("The text to be shown for the label.")]

        [Localizable(true)]

        public virtual string Text

        {

            get { return (string)this.ViewState["Text"] ?? string.Empty; }

        }

 

        /// <summary>

        /// Gets the HTML tag that is used to render the label.

        /// </summary>

        /// <value>

        /// The <see cref="T:System.Web.UI.HtmlTextWriterTag"/> value used to render the label.

        /// </value>

        protected override HtmlTextWriterTag TagKey

        {

            get

            {

                if (this.AssociatedControlID.Length != 0)

                {

                    return HtmlTextWriterTag.Label;

                }

 

                return base.TagKey;

            }

        }

 

        /// <summary>

        /// When overridden in a derived class, binds data from the data source to the control.

        /// </summary>

        /// <param name="data">The <see cref="T:System.Collections.IEnumerable"/> list of data returned from a <see cref="M:System.Web.UI.WebControls.DataBoundControl.PerformSelect"/> method call.</param>

        /// <exception cref="T:System.ArgumentOutOfRangeException">

        /// The selected value is not in the list of avaliable values.

        /// </exception>

        protected override void PerformDataBinding(IEnumerable data)

        {

            base.PerformDataBinding(data);

 

            if (this.DesignMode)

            {

                this.SetText(string.IsNullOrEmpty(this.ID) ? "abc" : this.ID);

                return;

            }

 

            if (data != null && this.SelectedValue != null)

            {

                // Clear out the Text property

                this.ClearText();

 

                string formatString = this.DataTextFormatString.Length == 0 ? "{0}" : this.DataTextFormatString;

 

                // Get the DataTextFormatString field value for the FIRST record

                foreach (object obj in data)

                {

                    if (this.DesignMode)

                    {

                        this.SetText(string.Format(formatString, "Databound"));

                        return;

                    }

                    else

                    {

                        bool hasDataValueField = this.DataValueField.Length != 0;

                        object dataValue = hasDataValueField ? DataBinder.GetPropertyValue(obj, this.DataValueField) : obj;

                        if (this.SelectedValue.Equals(dataValue))

                        {

                            bool hasDataTextField = this.DataTextField.Length != 0;

                            if (hasDataTextField)

                                this.SetText(DataBinder.GetPropertyValue(obj, this.DataTextField, formatString));

                            else if (hasDataValueField)

                                this.SetText(DataBinder.GetPropertyValue(obj, this.DataValueField, formatString));

                            else

                                this.SetText(string.Format(formatString, obj.ToString()));

 

                            return;

                        }

                    }

                }

 

                throw new ArgumentOutOfRangeException("SelectedValue", string.Format("'{0}' has a SelectedValue which is invalid because it does not exist in the list of items.", this.ID));

            }

        }

 

        /// <summary>

        /// Adds HTML attributes and styles that need to be rendered to the specified <see cref="T:System.Web.UI.HtmlTextWriter"/> object.

        /// </summary>

        /// <param name="writer">An <see cref="T:System.Web.UI.HtmlTextWriter"/> that represents the output stream that renders HTML contents to the client.</param>

        protected override void AddAttributesToRender(HtmlTextWriter writer)

        {

            if (this.AssociatedControlID.Length != 0)

            {

                Control control = this.FindControl(this.AssociatedControlID);

                if (control == null && !this.DesignMode)

                    throw new HttpException(string.Format("The ReferenceLabel '{0}' cannot find associated control ID '{1}'.", this.ID, this.AssociatedControlID));

                else

                    writer.AddAttribute(HtmlTextWriterAttribute.For, control.ClientID);

            }

 

            base.AddAttributesToRender(writer);

        }

 

        /// <summary>

        /// Renders the items in the <see cref="T:System.Web.UI.WebControls.ListControl"/> control.

        /// </summary>

        /// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"/> that represents the output stream used to write content to a Web page.</param>

        protected override void RenderContents(HtmlTextWriter writer)

        {

            HttpUtility.HtmlEncode(this.Text, writer);

        }

 

        /// <summary>

        /// Sets the text in the view state.

        /// </summary>

        /// <param name="text">The text to be stored in the view state.</param>

        protected virtual void SetText(string text)

        {

            this.ViewState["Text"] = text;

        }

 

        /// <summary>

        /// Clears the text stored in the view state.

        /// </summary>

        protected virtual void ClearText()

        {

            this.ViewState.Remove("Text");

        }

    }

}

Limitations:

Due to the aim of reducing ViewState, only the initial selected text is stored in the ViewState. Changing the SelectedValue after the control has been data bound will not change the displayed text.