Code Repo    |     RSS
MD's Technical Sharing



Tuesday, June 29, 2010

.NET CF MessageInterceptor class fails to intercept incoming messages

If you're writing an SMS application that intercepts incoming text messages using the MessageInterceptor class and observe that your application does not work on a particular phone, below is a list of things to check:

1. Most new HTC Phones will choose HTC Messages (part of HTC Sense), and not Pocket Outlook, as the default messaging spplication. HTC Message does not implement the MessageInterceptor class. To overcome this problem, you'll need to set Pocket Outlook as the default messaging application by using this patch.

Note: You may not be able to send/receive MMS after installing the patch. To use MMS, please install the Arcsoft MMS client.

Update (19 July 2010): I have found a way to intercept incoming messages on affected HTC phones without installing any patch by using MAPI Rule. For more information, see this post.

2. Some phones have a specific registry key to manually enable MessageInterceptor. Check HKEY_LOCAL_MACHINE\Software\Microsoft\Inbox\Svc\SMS\Rules and look for a key branch that looks like a GUID, e.g. {1000BC1C-F4A3-4210-B197-4AEBF2CEE6F5} Open that key, set the default value to 0 and reboot the phone to allow message interception.

3. You may have conflicting message interceptor rules left-over from other applications. To fix this, go to HKey_Local_Machine\Software\Microsoft\Inbox\Rules\, delete all sub-entries and reboot the phone. To avoid this from happening in the future, always call Dispose() on a MessageInterceptor when you finish using it or when your application closes.

Reference:

1. http://social.msdn.microsoft.com/Forums/en/vssmartdevicesvbcs/thread/e56f6db2-70d6-43a9-b3f2-7d476aabfa7e

2. http://stackoverflow.com/questions/2138650/messageinterceptor-is-not-called-on-htc-hd2
Read More »

Thursday, June 24, 2010

Wikipedia in MobiPocket ebook (PRC) format

Following my previous post on a version of Wikipedia for Windows Mobile improved from the original  Pocket Wikipedia 1.0 version by free-soft.ro, I decided to find a MobiPocket (PRC) version, to read on my Blackberry phone, Unfotunately I could not find a usable version - many versions I found, including PRC, are incomplete, with images stripped off, and not suitable for mobile viewing. There is also an expensive Wikipedia software for most mobile platforms. TomeRaider also offers a few free versions of wikipedia (with images,  and compact without images around 50MB) of Wikipedia in its propietary format. As none of these suit my needs, I decided to go ahead with creating my own PRC version of Wikipedia.

The article database

I decided to use the same article database (Wikipedia.wi) as Pocket Wikipedia 1.0, which turns out to be the 2007 School Wikipedia selection. Although the source code was never released, the binary was not obfuscated and after a bit of decompiling using .NET Reflector, I was able to extract the articles and images from the 180MB SevenZip-compressed database. 

Building the PRC ebook

My first thought was to rely on the MobiPocket Creator user interface. However, its UI is terrible - there is no way to add multiple HTML/image files at a time, you have to add them one by one. Even if drag and drop is supported, the application stops responding when a lot of files are added. I then decided to create the OPF file myself, then feed it into mobigen or kindlegen in order to create the final PRC file.

The source code to extract the articles and create the OPF file was written in .NET and can be downloaded here. Once the OPF is created, as there are more than 5000 articles and 24,000 images, kindlegen/mobigen takes more than 15 minutes on a 3Ghz processor to create the final PRC file.

Some of the articles contain Unicode characters (for example, various currency symbols) but were extracted and saved in ASCII format. I have tried various methods in System.Text.Encoding to convert to Unicode before saving without success. The only resolution I found is to use UTFCast Express (freeware) to convert the HTML files to Unicode before feeding them into kindlegen/mobigen.

The product: Wikipedia on a 214MB PRC file

The final compressed PRC file can be downloaded here. It's a multi-part RAR file, so you will need to download both parts to the same directory and use WinRar to extract the PRC file.

PocketWikipedia.part1.rar

PocketWikipedia.part2.rar

It contains all articles and images as in the original version, with a subject list, and an index where the titles of all articles can be looked up. As the title list is generated automatically by guessing the few words of the article, there are cases where the title are not retrieved properly, which can be resolved by editing the index manually in the OPF file before calling kindlegen to generate the PRC file.

Due to the large file size, some desktop versions of MobiPocker ebook reader may fail to open the file due to a Win32 exception. Mobile versions, in particular Blackberry and Windows Mobile, seem to open the PRC file properly.

UPDATE (8 Oct 2010): A Vietnamese reader has used my instructions to create an improved version of the Wikipedia ebook in PRC format. The new version, which fixes some font problems and has improved search support, can be downloaded here and here. It's a multi-part RAR file, so you will need to download both parts to the same directory and use WinRar to extract the original PRC file.
Read More »

Saturday, June 19, 2010

SerializableDictionary and System.InvalidOperationException

I recently attempted to use Paul Welter's SerializableDictionary in one of my Windows Mobile projects, Everything seems to work well with no code motifications, until when I need to serialize a class containing 2 dictionaries:

public class AppConfig
{       
      public SerializableDictionary Dictionary1;
      public SerializableDictionary Dictionary2;    
}

Attempt to serialize the above class will fail with a System.InvalidOperationException: Two mapping for dictionary. Searching the web for the exact error message returns no useful result, except for a posting which described a similiar problem (Two mappings for SourceTree.DTO.InventoryItemCollection.) but did not provide a solution. The posting also explicitly mentioned that the error occurred only on .NET Compact Framework, and not on the full framework.

The root cause of the error is at the first few lines of the SerializableDictionary source code:

[XmlRoot("dictionary")]
public class SerializableDictionary
    : Dictionary, IXmlSerializable

With this declaration, when 2 SerializableDictionary stay in the same class (which will be serialized), there will perhaps be a conflict somewhere as both of them are set up to use the same XmlRoot element ("dictionary").

A workaround is not to define XmlRoot inside SerializableDictionary class, but to create another class inheriting from SerializableDictionary and define XmlRoot in this class:

//parent class: SerializableDictionary
public class SerializableDictionary
    : Dictionary, IXmlSerializable { .... }

//dictionary 1
[XmlRoot("SerializableDictionary1")]
public class SerializableDictionary1 : SerializableDictionary { }

//dictionary 2
[XmlRoot("SerializableDictionary2")]
public class SerializableDictionary2 : SerializableDictionary { }

//the class to be serialized
public class AppConfigNew
{       
      public SerializableDictionary1 Dictionary1;
      public SerializableDictionary2 Dictionary2;    
}

This requires a few more lines of code, but is the cleanest workaround I have found. Also, I have yet to figure out why the full framework does not have such a problem.
Read More »

Sunday, June 13, 2010

Extension method and VB.NET With construct

Recently I came across a codeproject article about extension methods in VB.NET, where one reader complained that he could not get it to work when using VB.NET's With construct. The comment by the reader is very long and contains irrelevant code, but the issue is valid. This post will demonstrate the issue and summarize some of my findings.

Suppose you have the following code:

Snippet #1:

    <System.Runtime.CompilerServices.Extension()>
    Public Sub ModifyString(ByRef source As String)
        source += " modified"
    End Sub

    Sub Main()
        Dim str As String = "original"
        str.ModifyString()
        Debug.WriteLine(str)
    End Sub 

When the code is run, you will get the value "original modified" as expected. Now change the extension method call to be inside a With construct:

Snippet #2:
 
    Sub Main()
        Dim str As String = "original"
        With str
            .ModifyString()
        End With
        Debug.WriteLine(str)
    End Sub

You will now get "original", e.g. the string "temp" is never modified! This is clearly a bug in the framework itself so no workaround is available. Neverthess, let's look at the IL code for the above 2 code samples.

Snippet #1 in IL (No 'With' is used):


         .method public static void Main() cil managed
        {
            .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
            .entrypoint
            .maxstack 1
            .locals init (
                [0] string str)
            L_0000: nop
            L_0001: ldstr "original"
            L_0006: stloc.0
            L_0007: ldloca.s str
            L_0009: call void ConsoleApplication1.Module1::ModifyString(string&)
            L_000e: nop
            L_000f: nop
            L_0010: ret
        }

Snippet #2 in IL ('With' is used):

         .method public static void Main() cil managed
        {
            .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
            .entrypoint
            .maxstack 1
            .locals init (
                [0] string str,
                [1] string str2)
            L_0000: nop
            L_0001: ldstr "original"
            L_0006: stloc.0
            L_0007: ldloc.0
           
L_0008: stloc.1
            L_0009: ldloca.s str2
            L_000b: call void ConsoleApplication1.Module1::ModifyString(string&)
            L_0010: nop
            L_0011: ldnull
           
L_0012: stloc.1
            L_0013: nop
            L_0014: ret
        }

The different is obvious when a text comparison tool such as ExamDiff is used. When a With construct is used, the compiler generates extra code to create a copy of the string variable (str is copied to str2) and pass it to the extension method ModifyString! So whatever changes made to the string have no effect on the original variable, in spite of the ByRef keywork to pass the string by reference. This explains why we get the original value of the string variable.

Now change the code to:

Snippet #3:

    Sub Main()
        Dim str As String = "original"
        With str
            str.ModifyString()
        End With
        Debug.WriteLine(str)
    End Sub

We still use the With construct, but instead of using shorthand to call the extension method, we explicitly refer to the string variable. Guess what, now you'll get the correct result "original modified"! Let's look at the IL code to see what happened:

Snippet #3 in IL:

         .method public static void Main() cil managed
        {
            .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
            .entrypoint
            .maxstack 1
            .locals init (
                [0] string str,
                [1] string str2)
            L_0000: nop
            L_0001: ldstr "original"
            L_0006: stloc.0
            L_0007: ldloc.0
           
L_0008: stloc.1
            L_0009: ldloca.s str
            L_000b: call void ConsoleApplication1.Module1::ModifyString(string&)
            L_0010: nop
            L_0011: ldnull
           
L_0012: stloc.1
            L_0013: nop
            L_0014: ret
        }

A copy of the original string variable (str2) is created as usual, but it was never used. Instead, the original string variable (str) is passed to the extension method. This explains why everything works as intended.

The conclusion is to never use With...End With together with extension method as you may get unexpected results. As for the solution, well, I'll leave it up to whoever designs the .NET framework...

UPDATE (17 June 2010): The issue was submitted to Microsoft Connect here. They acknowledge the issue, yet decided to do nothing, not even adding a compilation warning.
Read More »

Thursday, June 3, 2010

Error accessing VC80.idb during compilation of VC++ project

If you're getting the following error
Could not delete file ‘c:\project\obj\release\vc80.idb
Make sure that the file is not open by another process and is not write-protected.
while building large VS solution with many VC++ projects, in a random and inconsitent manner, most likely you have just hit another Visual Studio bug. VS, by default, attempts to build multiple projects concurrently on system with multiple processors, which may cause the above error if different projects share the same IDB (VC++ Minimum Rebuild Dependency) file.

There are several solutions for this, but the simplest one would be to tell VS not to build multiple projects concurrently. To do this, open Tools>Options>Projects and Solutions>Build and Run, and set the value of Maximum number of parallel project builds to 1. However, with this method, your solution will take longer to build.
Read More »