Thursday, January 31, 2008

My Windows Mobile does not sound alarms / my Windows Mobile alerts whenever it want to alert

Many of Windows Mobile users are suffering from different problems, related to clocks, alarms and reminders. This problem exists almost in all Windows Mobile systems (Windows Mobile 2003, WM5, WM6, etc).  Why this happens and how to take care on it?

There root of this problem is something called "Notification Queue". The main propose of it is to run tasks and activate alarms and reminders at scheduled times, particularly when the device is in standby or low power mode.  There are a lot of problems with this module - troubles with alarm and reminders, which not working, or, alternatively, playing not in time after device reboot.

There are some bugs, reported to Microsoft and one of topmost requests from the next version of Windows Mobile is to produce more reliable alarm clock. 

For some reason, there is very little information about working with notifications queue in internet. There is absolutely no information about it in MSDN. And a lot of misinformation all over the network. I gathered up all I can from anywhere and now, I know what the cause for problems with alarms, alerts, notifications and reminders in Windows Mobile systems. I also learned how to fix it.

The root problem of notification queue is duplicate entries, produced by different applications, such as clock, ActiveSync, Alert, missed calls notifies and more. Windows mobile has no tools to treat this problem.

I build such tool and called it AlarmFixWM. It scans your Windows Mobile system for duplicate entries in notification queue and eliminate them. All you have to do, is do download it, put it into one of directories inside your mobile device (no installation), then run and hit Scan button. The program will do all the rest.

image

If you are not suffering from problem, related to Windows Mobile alerts, do not use this application.

I'd be happy to hear your feedbacks (also, if you want to learn more about this problem, you can ask me). And don't forget to backup your device before using this program!

Are there other tools, doing the same work? Yes, there are two: MemMaid and SKTools. Both are commercial and doing much more (cleaning your device inside). If all you want, is to get rid of wrong or not occurred alarms, AlarmFixWM is all you need.

Download AlarmFixWM (12.1k) >>

Tuesday, January 29, 2008

Microsoft almost never paying their presenters, so why we're coming?

In most cases, presenters, participate in TechEd, DevAcademy, open houses or other public sessions, arranged by Microsoft, are not get paid. However, we're still coming and presenting. Preparation of even small session takes at least a couple of days and costs us a lot of money, but we're still coming and presenting. Why?

The answer is not simple. So, in order to make it clearer to me, I created decision chart, that helps me to answer "yes" or "no" for next request to attend an event as presenter. Here it comes

image

Let me explain it for you. My hour costs at about 100$. To present at small event, I should prepare in ratio of 1/3 - for one hour session, I have to work at least three hours + arrangements, travel time, accommodations etc. Other words, one small session should costs about 1000$. Can they pay me what I'm worth? Probably they can, but there are other factors - what am I earn for example.

If I'm interested within attendees, I can generate more revenue from business opportunities, then from one time payment. Thus I wont ask to be paid. But sometimes, I might me unable to get such revenue. In this case, I'm asking another question: maybe inviters really need my help and I can allow myself to publish some charity? In this case I'll attend too.

So should Microsoft pay their presenters? Probably it should, but there are other factors should be took into account.

See me at TechEd '08 in Eilat :)

Printing more then one page, creation in memory XPS document and DocumentViewer customization

Today, we'll answer number of questions, regarding DocumentViewer, XPSDocument, FlowDocument and more

First question: I'm trying to display FlowDocument, by using DocumentViewer and I'm getting "FlowDocument' object cannot be added to 'DocumentViewer'. DocumentViewer supports only FixedDocument or FixedDocumentSequence documents". What to do?

First answer: DocumentViewer supports only fixed document source (one, which implements IDocumentPaginatorSource - other words supports pagination). In order to do it, we have to convert FlowDocument into FixedDocument and we can do it, by using XpsDocument and it's GetFixedDocumentSequence() method to create the page sequence.

Second question: But I do not want to save anything, I want to do it in memory. What to do?

Second answer: First load your FlowDocument by using XamlReader into IDocumentPaginatorSource (that's what we'll need for DocumentViewer)

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">

    <Paragraph>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam urna augue, semper ut, condimentum et, pharetra ac, massa. Cras tellus lacus, tristique eget, tincidunt vitae, mattis at, eros. Quisque pretium, ante at porttitor accumsan, ipsum enim laoreet tellus, sit amet aliquet felis tortor et lorem. Nullam sodales viverra sapien. Morbi leo magna, dignissim a, sollicitudin at, lacinia posuere, dui. Sed vestibulum elit a ante. Vivamus pellentesque augue sit amet enim. Pellentesque dignissim, lectus at congue elementum, augue felis vulputate ante, eu bibendum dui mauris sed magna. Cras metus dui, ullamcorper id, fermentum ornare, hendrerit non, libero. Donec blandit lorem sit amet velit. Phasellus aliquam. In vel urna sit amet lorem molestie tristique. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla aliquam urna sit amet enim. Integer vulputate mauris non diam. Vestibulum ac mauris. Proin porttitor adipiscing nibh. Phasellus neque. Sed sollicitudin eros in diam. Quisque accumsan, neque non volutpat semper, lectus nunc porttitor libero, at pretium purus velit eget mauris.</Paragraph>

    <Paragraph>Sed ac mauris. Nulla eu augue ut est pellentesque blandit. Phasellus non quam ac neque suscipit vehicula. Donec mauris augue, pulvinar at, vestibulum quis, vulputate et, nunc. Sed ut pede. Praesent ut justo id justo nonummy porttitor. Vivamus vitae massa sit amet massa scelerisque aliquam. Nullam ligula justo, suscipit id, sollicitudin at, pretium a, lorem. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In hac habitasse platea dictumst. In quam dui, gravida quis, congue ac, rhoncus ac, mi. Donec mattis tempor orci. Mauris ullamcorper. Donec non sem vel tortor imperdiet euismod. Morbi nec eros. Maecenas quis turpis at lorem semper ullamcorper.</Paragraph>

</FlowDocument>

using (Stream io = Assembly.GetExecutingAssembly().GetManifestResourceStream("PagePrint.text.xaml"))
            {
                IDocumentPaginatorSource text = XamlReader.Load(io) as IDocumentPaginatorSource;
                io.Close();
            }

Now, let's create Xps document in memory and load our text into it

ms = new MemoryStream();
pkg = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite);

doc = new XpsDocument(pkg, CompressionOption.SuperFast);
XpsSerializationManager rsm = new XpsSerializationManager(new XpsPackagingPolicy(doc), false);
DocumentPaginator pgn = text.DocumentPaginator;
rsm.SaveAsXaml(pgn);
viewer.Document = doc.GetFixedDocumentSequence();

We got an exception: "XpsDocument URI is null. Use XpsDocument constructor that takes URI parameter." But we have no URI, we are working in memory!

Third question: What to do?

Third answer: All you have to do is to add another package with URI, that identifies our document and create XPS document, by using the new identifier. We'll add it into current code and now it'll looks as following:

ms = new MemoryStream();
pkg = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite);

string pack = "pack://temp.xps";
PackageStore.AddPackage(new Uri(pack), pkg);

doc = new XpsDocument(pkg, CompressionOption.SuperFast,pack);
XpsSerializationManager rsm = new XpsSerializationManager(new XpsPackagingPolicy(doc), false);
DocumentPaginator pgn = text.DocumentPaginator;
rsm.SaveAsXaml(pgn);
viewer.Document = doc.GetFixedDocumentSequence();

Well, now it works, but we still have another questions

Forth question: How to set the page size for my document?

Forth answer: You already have DocumentPaginator, why not to use it?

ms = new MemoryStream();
pkg = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite);

string pack = "pack://temp.xps";
PackageStore.AddPackage(new Uri(pack), pkg);

doc = new XpsDocument(pkg, CompressionOption.SuperFast,pack);
XpsSerializationManager rsm = new XpsSerializationManager(new XpsPackagingPolicy(doc), false);
DocumentPaginator pgn = text.DocumentPaginator;

pgn.PageSize = new Size(768, 676);

rsm.SaveAsXaml(pgn);
viewer.Document = doc.GetFixedDocumentSequence();

Well done. Now our page is 8"x6" (1 inch = 96px in default resolution). Now it almost ok, but I want to customize DocumentViewer, used to present our document

Fifth question: How to remove search field ("Type text to find...") or how to customize buttons?

Fifth answer: DocumentViewer is regular WPF control, thus in order to customize it, you should override it's default template

By default the controls looks

image

But if you'll remove <ContentControl Grid.Row="2" x:Name="PART_FindToolBarHost"/> line from the control template, you'll get rid of the search bar. Of couse, you can customize anything you want within the control template of any WPF control.

image

We done. Have a nice XPS/WPF programming.

Source code for this article

Monday, January 28, 2008

Weird bug in Windows Vista

Well, there are some (ghm) bugs in Windows Vista. Most of those bugs are not harmful for your system, however there are some, that ready are. Here the little bug, I experienced today. Follow those steps to repro (don't do it on files you need)

  • Select multiple files
  • Right click on those files and choose rename and change the name of one of those files
  • Hit enter
    • Expected result: all selected files renamed (name (0),name (1), name (2) etc)
    • Actual result: all selected files renamed (name (0),name (1), name (2) etc)
  • Hit Ctrl-Z (Undo)
    • Expected result: all renamed files undo to it's original names
    • Actual result: all renamed files undo to it's original names
  • Hit Ctrl-Y (Redo)
    • Expected result: all undid files redo to it's new names
    • Actual result: all files, except the first one, disappeared.

They are really disappear, they did not removed or deleted. They just disappear.

Workaround: Don't redo multiple rename action.

 

Have a nice day

Friday, January 25, 2008

RTFM - Not only software needs manual, kids need it too - How to care your child (visual instructions)

For all my friends, become fathers and mothers within last couple of months. Please, read it before using your kids!

kidcare kidcare (2) kidcare (3) kidcare (4) kidcare (5) kidcare (6) kidcare (7) kidcare (8) kidcare (9) kidcare (10) kidcare (11) kidcare (12) kidcare (13) kidcare (14) kidcare (15) kidcare (16) kidcare (17) kidcare (18) kidcare (19) kidcare (20) kidcare (21) kidcare (22) kidcare (23) kidcare (24) kidcare (25) kidcare (26) kidcare (27) kidcare (28)

Stop subclassing and using Helpers - start Extension Methods

How many classes, named Helper, you have on your hard disk? I counted, and I have 320. What is "Helper"? Helper - is static class, that consists of static methods, that provide simple services to your program. Good examples for such methods are

public static string FormatTime(TimeSpan time)
        {
            return time.Hours.ToString("00") + ":" + time.Minutes.ToString("00") + ":" + time.Seconds.ToString("00");
        }

or

public static byte[] ConvertObjectToByteArray(object obj)
        {
            byte[] _resp = null;
            BinaryFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                formatter.Serialize(ms, obj);
                _resp = ms.ToArray();
            }

            return _resp;
        }

or, even

public static byte[] Compress(byte[] buffer)
       {
           MemoryStream ms = new MemoryStream();
           GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true);
           zip.Write(buffer, 0, buffer.Length);
           zip.Close();
           ms.Position = 0;

           MemoryStream outStream = new MemoryStream();

           byte[] compressed = new byte[ms.Length];
           ms.Read(compressed, 0, compressed.Length);

           byte[] gzBuffer = new byte[compressed.Length + 4];
           Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
           Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
           return gzBuffer;
       }

Those stand-alone methods are in use all over the application and provide small, frequent services.

What are disadvantages of such approach?

  • Another class = wider maintenance
  • You never know where it in use (even after searching)
  • You should remember all services provided
  • Sometimes, you have a number of overloads for those methods in order to make it's using simpler.
  • If you are working on shared project, someone can harm all your project, by changing "something small" in Helper class.

Can we do something else? Yes, we can. We can subclass our objects and hide those methods inside it. This approach is even worse. In spite of easiness of intellisense, provided with this method, you'll have large number of almost the same classes with little changes. Also, we cannot do anything with sealed classes.

What to do? In C# 3.0 (not only WPF), Extension Methods were introduced. What is it? The same "Helper", with only one difference - this keyword before the first argument. So, when changing our code to following:

public static string FormatTime(this TimeSpan time)
        {
            return time.Hours.ToString("00") + ":" + time.Minutes.ToString("00") + ":" + time.Seconds.ToString("00");
        }

or

public static object ConvertByteArrayToObject(this byte[] data)
        {
            object[] _resp = null;

            BinaryFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream(data, 0, data.Length))
            {
                try
                {
                    object _tmp = formatter.Deserialize(ms);
                    _resp = _tmp as object[];
                }
                catch
                {
                    _resp = new object[1];
                }
            }

            return _resp;
        }

or, even

public static byte[] Decompress(this byte[] gzBuffer)
        {
            MemoryStream ms = new MemoryStream();
            int msgLength = BitConverter.ToInt32(gzBuffer, 0);
            ms.Write(gzBuffer, 4, gzBuffer.Length - 4);

            byte[] buffer = new byte[msgLength];

            ms.Position = 0;
            GZipStream zip = new GZipStream(ms, CompressionMode.Decompress);
            zip.Read(buffer, 0, buffer.Length);

            return buffer;
        }

We will able to use all those methods within regular classes of argument type. Full intellisense support and very easy syntax. Like this.

image

But, do not go to extreme with extension methods, 'cos you likely face with the problem, exists now with arrays and Linq - too much extensions. You'll never know what are the original class methods (except icons :)). See yourself

image

Have a nice day. I had not time (as always) to review this post before publishing :)

Thursday, January 24, 2008

SVG vs. Silverlight head-to-head fight

Adobe stops supporting SVG next year, thus there are some SVG consumers are looking for the replacement of this technology, by other, that will be supported. The only technology, can actually replace SVG is Silverlight. Yes, Flex, too, but it's too complicated to perform transitions. Today, we'll look into those two technologies and try to understand how to perform migration easily. Let's start from SVG (Adobe SVG 3.x) vs SL (Silverlight 1.0) syntax

SVG

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd">
<svg width="200" height="100">
</svg>

SL

<Canvas  xmlns="http://schemas.microsoft.com/client/2007"
  Width="200" Height="100">
</Canvas>

Looks pretty the same, no? At least, very similar. Let's see what's going with text.

SVG

<text x="10" y="15" font-size="12">
  Hello World!
  <tspan x="10" dy="1.6em" font-size="8">This is</tspan>
  <tspan x="10" dy="1.6em" font-size="20">SVG text</tspan>
</text>

SL

<TextBlock Canvas.Left="10" Canvas.Top="15" >
  <Run Text="Hello World!" FontSize="12"/>
  <LineBreak/>
  <Run Text="This is" FontSize="8"/>
  <LineBreak/>
  <Run Text="Silverlight text"  FontSize="20"/>
</TextBlock>

Similar too, but what's about rendering? From now and on, you'll need Silverlight 1.0 and SVG 3.x plugins in order to see working samples.

Let's look closer

image

And even more closer

image

Silverlight renders small and large text much better, then SVG do.

Our next station is splines and simple geometry.

SVG

<rect width="100" height="50" fill="blue" stroke="black"  stroke-width="3" x="0" y="0"/>

SL

<Rectangle Width="100" Height="50" Fill="Blue" Stroke="Black" StrokeThickness="3" Canvas.Left="0" Canvas.Top="150" />

That's look very similar. What's about lines?

SVG

<path fill="white" stroke="black" stroke-width="2" d="M20,140 Q100,20 100,140 Q100,220 180,140" />

SL

<Path Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2" Data="M20,140 Q100,20 100,140 Q100,220 180,140"/>

That's the same. Even coordinates and tangents are equal. So, how it renders?

image

Well. There are some differences here.

Never mind, let's go on into animations

SVG

<circle cx="200" cy="150" r="40" fill="red">
    <animate attributeName="cy" dur="5s" repeatCount="indefinite" keySplines="0.5 0.1 0.9 0.5;0.1 0.5 0.5 0.9" calcMode="spline" keyTimes="0;2.5;5" values="150;350;150"/>
  </circle>

SL

<Ellipse Width="80" Height="80" Fill="Red" Canvas.Left="160" Canvas.Top="-91" x:Name="ellipse">
    <Ellipse.Triggers>
        <EventTrigger RoutedEvent="Canvas.Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.Y)" RepeatBehavior="Forever">
                        <SplineDoubleKeyFrame KeyTime="00:00:02.5" Value="200" KeySpline="0.5 0.1 0.9 0.5"/>
                        <SplineDoubleKeyFrame KeyTime="00:00:05" Value="0" KeySpline="0.1 0.5 0.5 0.9"/>
                    </DoubleAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Ellipse.Triggers>
    <Ellipse.RenderTransform>
        <TransformGroup>
            <TranslateTransform/>
        </TransformGroup>
    </Ellipse.RenderTransform>
</Ellipse>

Here, it looks like a lot of differences, however, if you'll look into code, you'll see, that there are no difference between the methods. Even key splines are the same. Let's look deeper into code.

SVG SL
circle Ellipse
animate DoubleAnimationUsingKeyFrames
cx,cy Width, Height
attributeName TargetName+TargetProperty
dur KeyTime
repeatCount RepeatBehavior
keySplines KeySpline+KeySpline
calcMode SplineDoubleKeyFrame
keyTimes KeyTime+KeyTime
values (absolute) Value (relative)

 

That's all. After all, there are very similar methods and objects are in use. The only difference, that Silverlight is much more flexible, then SVG in animation. Let's see the result (if the ball is breaking on the edge, just reload internal page - this is load time issue)

So, after all if you know SVG, you can start developing Silverlight (don't go back :) ).

All this nice, but what's the problems? Well, there are some. In Silverlight 1.0, there is no Tile or Visual brushes, thus you can not create following effect (this is checker board)

SVG

<defs>
<pattern id="P01" width="10" height="10" patternUnits="userSpaceOnUse">
    <rect width="10" height="10" fill="#FFFFFF" stroke="#000000" stroke-width="0.1"/>
</pattern>
</defs>
<rect x="0" y="0" width="400" height="400" fill="url(#P01)"/>

But no worry, you probably, will have all you need and much more in Silverlight 2.0 :)

Have a nice day.

Tuesday, January 22, 2008

Don't show this again!

One of greatest and most informative message boxes, I ever see. Here comes the king. Well, it's from beta Expression product.

dontaskme

Monday, January 21, 2008

Clipboard and WPF as hooks and ImageSources

Challenge: create visual clipboard watcher, that displays and saves Bitmaps right after they arrives into the system clipboard by using WPF. Let's start.

First of all, we have to set hooks to detect clipboard changed events. .NET does not provide events, and does not listen to the clipboard changes, so, we have to deep into Win32 in order to archive the requirement. Let's see, once something arrives into the clipboard, we can see WM_DRAWCLIPBOARD message. It's not necessarily our data, so we have to change clipboard chain first, so, we should listen to WM_CHANGECBCHAIN and pass it into our application. But nothing will happen, if we will not use SetClipboardViewer(IntPtr) first. We already know, how to emulate WinProc in WPF. So, let's code it.

IntPtr viewerHandle = IntPtr.Zero;
IntPtr installedHandle = IntPtr.Zero;

const int WM_DRAWCLIPBOARD = 0x308;
const int WM_CHANGECBCHAIN = 0x30D;

[DllImport("user32.dll")]
private extern static IntPtr SetClipboardViewer(IntPtr hWnd);

[DllImport("user32.dll")]
private extern static int ChangeClipboardChain(IntPtr hWnd, IntPtr hWndNext);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private extern static int SendMessage(IntPtr hWnd,int wMsg,IntPtr wParam,IntPtr lParam);

Hook into WinProc

protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);
    HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
    if (hwndSource != null)
    {
        installedHandle = hwndSource.Handle;
        viewerHandle = SetClipboardViewer(installedHandle);
        hwndSource.AddHook(new HwndSourceHook(this.hwndSourceHook));
    }
}

And unhook after

protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
    ChangeClipboardChain(this.installedHandle, this.viewerHandle);
    int error = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
    e.Cancel = error != 0;

    base.OnClosing(e);
}
protected override void OnClosed(EventArgs e)
{
    this.viewerHandle = IntPtr.Zero;
    this.installedHandle = IntPtr.Zero;
    base.OnClosed(e);
}

Then choose and treat messages

IntPtr hwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    switch (msg)
    {
        case WM_CHANGECBCHAIN:
            this.viewerHandle = lParam;
            if (this.viewerHandle != IntPtr.Zero)
            {
                SendMessage(this.viewerHandle, msg, wParam, lParam);
            }

            break;

        case WM_DRAWCLIPBOARD:
            EventArgs clipChange = new EventArgs();
            OnClipboardChanged(clipChange);

            if (this.viewerHandle != IntPtr.Zero)
            {
                SendMessage(this.viewerHandle, msg, wParam, lParam);
            }

            break;

    }
    return IntPtr.Zero;
}

Now, we should receive the Bitmap from Clipboard and convert it into BitmapSource. How to do it? Simple, really. Thank's to WPF Imaging team

ImageSource = (System.Windows.Interop.InteropBitmap)Clipboard.GetData(DataFormats.Bitmap);

We have a nasty Clipboard bug, so let's make it nicer a bit.

try
{
  if (Clipboard.ContainsData(DataFormats.Bitmap))
   ImageSource = (System.Windows.Interop.InteropBitmap)Clipboard.GetData(DataFormats.Bitmap);
}
catch{}

Now, all we have to do is to save the result by using regular encoder.

using (FileStream fs = new FileStream(f.FileName, FileMode.Create, FileAccess.Write))
                {
                    JpegBitmapEncoder enc = new JpegBitmapEncoder();
                    enc.Frames.Add(BitmapFrame.Create(ImageSource));
                    enc.Save(fs);
                    fs.Close();
                    fs.Dispose();
                }

That's all, folks. Now, upon the application start, we begin listening to clipboard and if we'll detect bitmap inside it, we'll enable ApplicationCommands.SaveAs command and save it into the user's hard drive.

<StackPanel>
        <StackPanel.CommandBindings>
            <CommandBinding Command="ApplicationCommands.SaveAs" Executed="CommandBinding_Executed" CanExecute="CommandBinding_CanExecute"/>
        </StackPanel.CommandBindings>
        <Button Command="ApplicationCommands.SaveAs" CommandTarget="{Binding Path=ImageSource}" Content="{Binding Path=Command.Text,RelativeSource={RelativeSource Self} }"/>
        <Image Name="image" Source="{Binding Path=ImageSource}"/>
    </StackPanel>

Have a nice day and be good people.

Source code for this article.

Friday, January 18, 2008

Steve Jacobs in 60 seconds - presentation skills

At Macworld 2008, Steve Jacobs made 90 minutes keynotes. Probably, there is PR blood in his veins, however it's possible to stretch the whole 90 minutes keynotes into 60 seconds subset. Don't believe me? Look this video. This how you should present.

Microsoft .NET framework 3.5 beta exams

Do you want to be the first, who'll judge my work last summer? Participate 71-502 - Microsoft.NET Framework 3.5 - Windows Presentation Foundation beta exams. You can participate until 24-Jan here. Possible, that this exams will be even poorer, then 70-552, however, who knows? You tell us! Register at http://www.register.prometric.com/ClientInformation.asp. No guarantee of a seat, not avaliable in China, India and Pakistan.

If you do not want to pass WPF, you can participate beta of WCF or WF. Before taking those, read here and here. Also, you are more, then invited to feedback Gerry.

Good luck!

Wednesday, January 16, 2008

How to load unmanaged (native) resources from managed C# code

Let's say, that you have native assembly, that holds some resources -  strings, bitmaps, icons and images and you want to get them from your managed code. How to do it? First of all, let's see how those resources looks like

image

What we can see here, that we have one PNG resources with ID 209, one REGISTRY resource with ID 303 etc. So, let's extract them.

Looking in user32, we'll find two handy methods LoadImage and LoadBitmap. Both receives string names of the resources and handle to the loaded module, that holds those resources. You can not load the library by using Assembly class from reflection namespace, due to fact, that our module is native code. So, we should load it as datafile. How to do it?

kernel32 holds method, named LoadLibraryEx, that actually receives the path to our file and some flags. So, let's interop it

[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);

Now all we have to do is to load our file with LOAD_LIBRARY_AS_DATAFILE (0x00000002) flag.

IntPtr hMod = LoadLibraryEx(path, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE);

Now, we have a pointer to our module and we can begin to extract resources. But we do not know the names (there are not) of embedded resources. The only information we have is those IDs. Looking into small note in MSDN, we can assume, that it's possible to assume, that this method can receive MAKEINTRESOURCE macro, to convert resource ID into name, how to do it in C#? Simple.

Encoding.Default.GetString(BitConverter.GetBytes(rID))

Thus, we have write our own override to LoadBitmap, that receives C# int (long in C++). We can even use it with LoadImage enhanced method.

[DllImport("User32.dll")]
public static extern IntPtr LoadImage(IntPtr hInstance, int uID, uint type, int width, int height, int load);
[DllImport("User32.dll")]
public static extern IntPtr LoadBitmap(IntPtr hInstance, int uID);

However, this wont work, due to fact, that our resource is not Bitmap. It's PNG. What to do? We should load it as "other" resource. But first of all, we should find it and measure it's size. We'll use the same dirty trick to convert string name of the resource into it's ID.

[DllImport("kernel32.dll")]
static extern IntPtr FindResource(IntPtr hModule, int lpID, string lpType);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);
[DllImport("kernel32.dll", SetLastError = true)]
static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo);

Well, but what's the type of the resource? It's "PNG" for some reason :) So, using following should bring us the pointer into our resource and it's size.

IntPtr hMod = LoadLibraryEx(path, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE);
IntPtr hRes = FindResource(hMod, 209, "PNG");
uint size = SizeofResource(hMod, hRes);
IntPtr pt = LoadResource(hMod, hRes);

Well, now we have our pointer. Let's make Bitmap. Simple? Not so fast... Using Bitmap.FromHbitmap(pt) will throw exception, because of the type of resource. It is not hBitmap. It's PNG byte array. Let's copy it and create Bitmap from stream

byte[] bPtr = new byte[size];
Marshal.Copy(pt, bPtr, 0, (int)size);
using (MemoryStream m = new MemoryStream(bPtr))
  bmp = (Bitmap)Bitmap.FromStream(m);

Now it works. We have Bitmap, that actually PNG, stores in our native resource file. Next step is to extract string resources. The same way? No. IMHO, String is the best class ever in every programming language, thus, we have special method to extract string resources from unmanaged code.

[DllImport("User32.dll")]
static extern int LoadString(IntPtr hInstance, int uID, StringBuilder lpBuffer, int nBufferMax);

So, following code will bring us strings, we are looking for.

StringBuilder sb = new StringBuilder();
int ln = LoadString(hMod, 210, sb, 255);

string s = sb.ToString();

Well done, we're fininshed. Actually, this is not very straight forward to load native resources, however, even with small brain as mine, you can do it.

Monday, January 14, 2008

This is not joke. This is the real code, I got from one of offshore companies, I working with

I, probably, print it and put in my office...

if( (i==j).ToString().Length == 4) { ...DoSomething();...}
else if( (i==j).ToString().Length == 5) { .. DoSomethingElese();... }
else { throw new NotImplementedException(); }

Friday, January 11, 2008

Om Malik had a heart attack

GigaOm had a heart attack last week. Now, he's fine. Get well soon. via TechCrunch

om-small.png

Wednesday, January 09, 2008

How to merge help files to appear inside Visual Studio?

How many times after an installation of some SDK, you saw, that nothing has been merged into Visual Studio help. You press F1 and nothing happens? What to do? Actually, the answer is really stupid. You should go into Visual Studio Documentation (Programs->Visual Studio [number]->Visual Studio [number] documentation), go to Index and set filter by property to (unfiltered) and then look for collection manager->help

image

There you will find all help files installed in your system and now, you can merge (or unmerge) them manually by marking relevant checkboxes and clicking "Update VSCC" button.

This is really simple, but for me it looks a bit strange, that in order to do it, you should not go to any of options, but search into help context. However, this is the real live :)

Declaimer: this is not internal or private information of Microsoft Corporation. You can reference to online MSDN library to find small information pieces about this issue. Here one of such pieces (look for note section)