Advanced C# splash screen

I once posted about how to make a splash screen with C#; yet it’s still a rectangle. While it’s true that you can replace my picture with something that have curvy edges, you’ll have aliased edges i.e. crooked and crude pixels around the edges.

Example of an aliased picture, the edges are not smooth and you can't see through the semitransparent parts

There’s a solution: alpha-blend the picture and you can see through the form; pixels with alpha value of neither 0 or 255 will be mixed appropriately with the background.

Alpha-blended picture. The edges are smoother and you can see through the form

To achieve this, you have to write your custom painting function with windows API, specifically this one

[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);

Which can be a daunting task. Luckily we have someone from Visual C# kicks did the hard work and released the source for public use! But that’s not the end of my story just yet. I wanted the splash screen to fades in and out. The timing part was easy, just a timer and several more lines of code and it’s done.

        enum Phases {
            FadeIn,
            Hold,
            FadeOut
        };
        Phases CurrentPhase = Phases.FadeIn;
        int FadeInStep = 0;
        const int FadeInLast = 20;
        int HoldStep = 0;
        const int HoldLast = 80;
        int FadeOutStep = 20;
        const int FadeOutLast = 0;
        const int OpacityMultiplier = 5;

        private void timerFade_Tick(object sender, EventArgs e)
        {
            if (CurrentPhase == Phases.FadeIn)
            {
                if (FadeInStep < FadeInLast)
                {
                    FadeInStep++;
                    this.Opacity = (OpacityMultiplier * FadeInStep) / 100.0;
                }
                else
                    CurrentPhase = Phases.Hold;
            }
            else if (CurrentPhase == Phases.Hold)
            {
                if (HoldStep < HoldLast)
                {
                    HoldStep++;
                    this.UpdateFormDisplay(this.BackgroundImage);
                }
                else
                    CurrentPhase = Phases.FadeOut;
            }
            else if (CurrentPhase == Phases.FadeOut)
            {
                {
                    FadeOutStep--;
                    this.Opacity = (OpacityMultiplier * FadeOutStep) / 100.0;
                }
                else
                    this.Close();
            }

I have even altered the custom paint code to utilize the form’s transparency factor

                //Set up blending options
                API.BLENDFUNCTION blend = new API.BLENDFUNCTION();
                blend.BlendOp = API.AC_SRC_OVER;
                blend.BlendFlags = 0;
                blend.SourceConstantAlpha = (byte)(255 * this.Opacity);
                blend.AlphaFormat = API.AC_SRC_ALPHA;

                API.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, this.BackColor.ToArgb(), ref blend, API.ULW_ALPHA);

But that didn’t work to my expectation! The form is fading in and out gradually but the alpha blending effect is lost.

Fugly!

After fiddling around, I figured out that the custom paint code somehow didn’t override all the necessary painting functions and the setter of this.Opacity call those functions every time it’s changed. Searching around the list of functions can be overridden I found nothing interesting

That function doesn't help...

So I created a new variable and leave the form’s default Opacity alone. After all, if I have adjusted transparency myself in the custom paint function, who needs .NET’s alpha-blend-incapable render? The code above becomes:

        double MyOpacity = 0;

            if (CurrentPhase == Phases.FadeIn)
            {
                if (FadeInStep < FadeInLast)
                {
                    FadeInStep++;
                    MyOpacity = (OpacityMultiplier * FadeInStep) / 100.0;
                    this.UpdateFormDisplay(this.BackgroundImage);
                }
                else
                    CurrentPhase = Phases.Hold;
            }
            else if (CurrentPhase == Phases.Hold)
            {
                if (HoldStep < HoldLast)                 {                     HoldStep++;                     this.UpdateFormDisplay(this.BackgroundImage);                 }                 else                     CurrentPhase = Phases.FadeOut;             }             else if (CurrentPhase == Phases.FadeOut)             {                 if (FadeOutStep > FadeOutLast)
                {
                    FadeOutStep--;
                    MyOpacity = (OpacityMultiplier * FadeOutStep) / 100.0;
                    this.UpdateFormDisplay(this.BackgroundImage);
                }
                else
                    this.Close();
            }
        }
                //Set up blending options
                API.BLENDFUNCTION blend = new API.BLENDFUNCTION();
                blend.BlendOp = API.AC_SRC_OVER;
                blend.BlendFlags = 0;
                blend.SourceConstantAlpha = (byte)(255 * MyOpacity);
                blend.AlphaFormat = API.AC_SRC_ALPHA;

                API.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, this.BackColor.ToArgb(), ref blend, API.ULW_ALPHA);

And Voilà!

Alpha blended splash against my blog in the background, you can see through the semi-transparent form

You can get the project, source code and complied binary here.

Life with Ubuntu

First, Happy new year to you and your family 🙂

I have been using Linux on a daily basis for several months now and so far life is quite comfortable. For the first time I can simply forget what people have been telling me  since day one –  “you always need antivirus protection”. Heh, how the hell viruses is gonna infect my computer when even I myself can’t modify the system files! Yes, it’s true that if enough people use it there will be some folks spend time to carve into each input box in the whole operating system to find exploits but considering the rate of Firefox adoption over IE, I’d say it may took decades before Linux can take over. This world is resistant to changes, even if it’s good.

Though the default Ubuntu distribution works out of the box and satisfy the needs of most user, it’s oriented to the naive, who doesn’t have the need for more complex configurations, say – multilingual inputs. That’s when Google comes in handy but it may take a while and some searching skills to find what you need. There’s many question and answer in the Ubuntu forums but they are not always anwered satisfactorily.

Below is a collection of what I have to Google for the past months.

Japanese input

I posted about Japanese on Windows back from last year but I don’t really need Japanese for Linux until now – when my HDD is somewhere in the middle of snowstorms in America and I’m working on a little USB flash drive. It kinda feels like a netbook except it’s faster 😛

Windows doesn’t differentiate between input language and keyboard layout –  it combines both into the IME environment. The result is hideous registry settings to configure what should be readily available. It’s a different thing on Kubuntu: the keyboard layout you can configure in System Settings > Regional & Language > Keyboard Layout is for your physical keyboard only, which means if tells the operating system if there’s something special about your keyboard, like is it laid out in Dvorak, does it have extra function keys, does it have the Japanese switch button etc. To input languages you have to use the input method (IME) which is what translates what you type on the keyboard to something else according to configuration. For example, the Vietnamese input method translates Tie61ng Viet65 into “Tiếng Việt” and the Japanese input method translate katakana into “カタカナ”. All this happens within an input framework. To put it simple, an input framework is a tool that let you switch between languages (This is not technically correct but you’ll know better when you have become familiar with it). Being an operating system of choices, there’s three framework for you to choose on Linux: UIM, SCIM and iBus with iBus being the future.

To install iBus, first add the following line to /etc/apt/sources.list

deb http://ppa.launchpad.net/ibus-dev/ibus-1.2-karmic/ubuntu karmic main #IBus 1.2 for Karmic

Then run

sudo apt-get install ibus ibus-gtk

Once iBus has been installed, you can install input languages, say Vietnamese and Japanese:

sudo apt-get install ibus-unikey ibus-anthy

You can activate iBus with

im-switch -s ibus

It requires a restart and then you are good to go! 🙂 Note that instead of using the command line apt-get, you can type “ibus” into the software installer to find the packages and install them.

You can see the language you want to type is not bound to any specific keyboard layout here – at the start of this post you can have Qwerty, Dvorak or Colemak – that doesn’t matter, you can use it to input the language you have installed!

References: ibus @ ubuntu vn, ibus project

Multilingual input with Opera 10

Opera is a great browser, many of the functionality that defines the modern browser is from opera – say tabbed browsing, integrated search function, modular design and many others. Should Opera be free from the start it could have overthrown IE as the most popular browser. Well, what’s history is history already 🙂

I use Opera on linux for the sake of simplicity – it provides all the functions I need without the need to install any fancy plugin (I’m talking about you, Firefox). It’s a surprise that I can’t use iBus to type Vietnamese in Opera when I first installed it :(.

I found out why: the default version you can download from Opera’s homepage is compiled with the Qt3 library while iBus works with Qt4 only. Luckily Opera is also compiled with Qt4 but you’ll need to cruise around some FTP servers to get it.  Click here to get version 10.10 for ubuntu/x86, which is the latest at the time of writing.

When 128MB isn’t enough or how to expand your Ubuntu installation on a USB stick

Kubuntu 9.10 comes with a new feature: make a USB stick bootable and persists your changes between sessions. At first you may think the default storage space of 128 MB could be enough but after some themes, customizations and application s (namely Firefox); 128MB is used up in no time.

Your Linux home is stored within an image file in the root of the drive – casper-rw. You can allow Linux to use a bigger share of your stick by expanding the file then imposes ext3 formatting on it with the following steps:

# dd if=/dev/zero bs=1M count=1024 >> casper-rw
# e2fsck -f casper-rw
# resize2fs -f casper-rw
# e2fsck -f casper-rw

1024 means 1024MB, change this to whatever size you want. Note that this capacity is added to your existing quota, so if you have 128MB already then after this command you have 1153MB for storage.

File managing – Norton Commander style

While Kubuntu have dolphin as a pretty good file manager, iallowsng you to split windows and drag the navigation dock around, it’s still get nowhere close the original NC feel (say tabbing, F3, F4 and F5). Of course Midnight Commander have been around since Linux was still stuck in the server rooms but what? A text mode program on the all cute KDE Oxygen? Does not sound right to me.

Good thing that there’s Krusader. It’s a bit old but seems to work fine. The menu bar, button bar and command line stays true to the tradition – I feel like home 🙂

Facebook block workaround (and no, it doesn’t involve DNS)

image1

The reason [Source]

It has been a bit hard to reach facebook lately. For some ISP like Viettel and FPT, a DNS change is all it takes to resolve facebook’s IP and restore access to the site. For some other, like EVN and VNPT, here’s what you got

image2

Changing DNS won’t work, which means the rats must have bitten something else. You are forced to use slower methods to overcome this, which could heavily impact your ability to play happy farm 🙁

That’s until I read that facebook still work with SSL (e.g when you replaces http in the address with https you are able to login), but it reverts to http the next time you click a link and you’ll have to do it again. This is especially annoying with games, which uses a lot of redirects to show their ads and stuff (damn, they are greedy).

And so I made something to do the hard work for me, so that I won’t miss the daily login bonuses :p. It’s utterly simple and a bit hard to use  but it does the job.

The code

Make a form that looks like this

image3

Write these to the form’s code

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

        /// <summary>
        /// Executes when a request is made, it will fix the protocol or anything in
        /// the address if the first check box is checked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
        {
            string Address = e.Url.ToString();
            // Facebook uses some complicated redirection method so we'lll have to ignore this
            if (Address.Contains("redirectiframe.html"))
                return;
            // If it's not from facebook or facebook's cache, just ignore it
            if (!Address.Contains("facebook") && !Address.Contains("fbcdn"))
                e.Cancel = true;
            else
                if (checkBox1.Checked && Address.Contains(textBox1.Text))
                {
                    e.Cancel = true;
                    webBrowser1.Navigate(Address.Replace(textBox1.Text, textBox2.Text));
                }
        }

        /// <summary>
        /// Load facebook on start
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            webBrowser1.Navigate("http://www.facebook.com");
        }

        /// <summary>
        /// Fixes link after the document is loaded, may break some pages
        /// and creates an endless loop on login so it's not enabled by default
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            if (checkBox2.Checked)
                webBrowser1.DocumentText = webBrowser1.DocumentText.Replace(textBox3.Text, textBox4.Text);
            toolStripTextBox1.Text = webBrowser1.Url.ToString();
        }

        /// <summary>
        /// The go button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            webBrowser1.Navigate(toolStripTextBox1.Text);
        }

        /// <summary>
        /// Show/hide options
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            groupBox1.Visible = !groupBox1.Visible;
        }

        /// <summary>
        /// Update load progress
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void webBrowser1_ProgressChanged(object sender, WebBrowserProgressChangedEventArgs e)
        {
            toolStripProgressBar1.Maximum = (int)e.MaximumProgress;
            toolStripProgressBar1.Value = (int)e.CurrentProgress;
        }
    }

Usage

Open options, check the first check box and you’ll be able to login, open applications and view photos. Should something breaks, try uncheck the check box and press Go to reload the page.

Choose no when IE asks you this, as images are loaded with http

image4

The second check box corrects the links and images on the page to https, only use this when images are not loading

Alternatively, you con use this to access facebook with its ip address. Try navigate to 69.63.184.143 and have it replace http://www.63.184.143 with https://69.63.184.143 (facebook removes the leftmost part before the first . and replaces it with www when you login)

Here’s the executable

Dvorak 日本語

While most of the stuff I type everyday can be expressed using Latin characters (e.g English and Vietnamese) so I can use Dvorak for them without the need for another keyboard layout. But sometimes I just need to type in a different kind of language, like, what’s the latest くるま model from トヨタ? 😛

The most convenient way to type that in windows is to use the Japanese IME, but the funny part turning on the IME after my Dvorak conversion is I HAVE TO USE QWERTY FOR JAPANESE. It’s easy to say, but it took me 5 friggin’ minutes to figure out why all I can type is あああ 😐

It’s just what happen when you use Windows: every basic function works just fine, but when you want to take it to the next level of customization, something bad happens.

Luckily, I don’t have to abandon my newly learned layout (which I’m getting a better accuracy rate than the old). There’s three ways to do that

Remap your system’s layout

This site show you how and have a nice chart. I found this site first on my search but this have a lot a side effects: First, you have to change your layout back to qwerty and then remap, which could create confusion when you are protecting your user account with passwords (there’s no way you can tell which keyboard layout is in use at the windows logon prompt – a fatal flaw in design I say). Second, this setting is effective system wide, which means non – Dvorak users will never have the chance to share that computer with you.

Remap the IME

Open the MS-IME’s Properties and press the advanced button, you’ll see a mapping table you can edit, just type the Dvorak combination in place of the qwerty ones already there and you can type Japanese, but what happen if you want one or two Romani character in between? This won’t work 😐

image

There’s nothing a hack won’t fix

There’s a setting in the registry that will let you change the keyboard mapping file for a specific IME and it’s buried in

HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlKeyboard Layouts

There you will find a bunch of hexadecimal keys, each correspond to a specific IME: Slovak, US, Dvorak, Japanese, Korean… you name it! The code for Japanese (MS-IME 2002) is E0010411, go there and change the value of “LayoutFile” from kbdjpn.dll (actually a qwerty map) to kbddv.dll (Dvorak map) and restart your computer (This is the only way to restart the IME).

If that didn’t work (Microsoft may as well hiding some other option which will override what you have just overridden somewhere else, oh well…), you may need to go to %systemroot%system32 and copy the kbddv.dll over kbdjpn.dll itself, then restart.

Yup, that’s what I did to get what I wanted – type 日本語 with ドヴォラック :P.

Web page interoperability with .NET browser controls

Everyone knows that the best way to manipulate or extract data from a hypertext page is to use JavaScript. The langue is built entirely to serve that purpose so it’s natural to think about it every time someone tell you to get an element’s text or skip unnecessary screens. Firefox’s XUL even relies on the language to control the entire application’s behavior.

That method does well most of the time but it requires that you have access to the JavaScript source and can modify the page, which is not the case in some situation:

  1. Rapidshare makes you wait for two minutes or so when you want to get some file from them for free. It’s better than before when you have to go past some feline CAPTCHA but you still have to click on the download button after the timer expire, which means you can’t click on a Rapidshare link and leave it to download itself. Will Rapidshare allow you to edit the download page to insert the JavaScript that will click the button for you? No!
  2. You want to capture stock value from your finance information agency’s web site and save it into an Excel file for later reference, what should you do? Ask Yahoo Finance to modify its web page to send some fancy XMLRequest to your server every time it updates? And even if they do so you’ll have to make a listening server for those request on your side.

Of course there are other solution to those problem other than coding it on your own. There’s an extension for Firefox called Skipscreen that will automatically download the Rapidshare file for you or you con hire a better information provider that have built-in analysis functions on their site for you.

But if you are a control freak like me and want to make sure everything work exactly as what it is intended for then crawling through thousands of line of Skipscreen’s source code can be a bit of a pain (mind you that JavaScript is neither a strong typed or object oriented language so have fun visualizing variables and objects in your head). About the stock, can you be sure that your provider doesn’t tail gate your order? (e.g. You decide to buy some interesting stock and order them to do so, they find that stock interesting too and buy the same stock before actually place your order so they get the better price)

With Internet Explorer (e.g. the default browser control)

It’s simple actually, just create a browser control, use it’s Navigate(url) method for the page you want. For demonstration, I’ll try to get time from the text box on this page.

image

Here’s the code:

            HtmlElement IEElement1 = webBrowser1.Document.GetElementById("clockspot");
            if (IEElement1 != null)
            {
                textBox1.Text += "ie text 1: " + IEElement1.GetAttribute("value") + "rn";
            }
            HtmlElementCollection IEElements = webBrowser1.Document.GetElementsByTagName("input");
            if (IEElements.Count > 0)
            {
                foreach (HtmlElement IEElement in IEElements)
                {
                    if (IEElement.Name == "clockspot")
                        textBox1.Text += "ie text 2: " + IEElements[0].GetAttribute("value") + "rn";
                }
            }

This shows two ways you con search for a text box on the page. The first is by element ID. Actually, the textbox only have the name attribute but since this is IE and we have hideous rule all around, it will return the text box you want. The second way is to get all <input> elements on the Pago and check their name attribute.

Once you have found the textbox, get its “value” attribute. This value is updated in real time (the clock on the page is updated with JavaScript dynamically)

image

Side note: Running browser control in standard compliance mode

The first time you test the C# browser control  when you have IE8 installed may make you disappointed – it does not pass. This is because by default, the control run in quirks mode (this can break a lot of stuff). To force it to render the page in standard mode you’ll have to edit the registry, add this value:

[HKEY_CURRENT_USERSoftwareMicrosoftInternet ExplorerMainFeatureControlFEATURE_NATIVE_DOCUMENT_MODE]
"MyApplication.exe"=dword:13880

Replace MyApplication with your application’s executable name. Also if you are debugging in Visual Studio, add MyApplication.vshost.exe too.

With Firefox… or more exactly, XUL runner

XUL runner is the engine behind Firefox, it renders everything from web pages to Firefox itself. Being a cross platform platform (confusing isn’t it?), it will provide you with more cross-platform flexibility and may even save you from having to recompile the code. The is – if Mono is going somewhere.

XUL runner doesn’t work with C# out of the box, you’ll have to download Skybound’s  component – GeckoFX for that. This will give you a nice drag-and-drop component on the toolbox, but you are not done yet!

The basic component only provide basic functions like navigate, get/set for element text. To work with values contained in specific types of element you’ll need an experimental feature – DOM manipulation, which can be downloaded from here.

Add it to the original GeckoFX project, recompile it with the appropriate XUL version (1.8 or 1.9 or 1.9.1) and then you can use the code below:

            GeckoElementCollection FFElements = geckoWebBrowser1.Document.GetElementsByName("clockspot");
            if (FFElements.Count > 0)
            {
                GeckoElement Element = FFElements[0];
                GeckoInputElement Input = new GeckoInputElement(Element.DomObject);
                textBox1.Text += "ff text: " + Input.Value + "rn";
            }

The first step is similar to what you do with the IE control: search for the element. When it’s found, convert it to an input element (GeckoInputElement), then you can get its value. This is also updated in real time.

Conclusion

Due to time constraints, this post can only cover the very basic. You can explore other feature of the controls yourself – try replacing the “get” with “set” for example. Applications is endless. You can now make Rapidshare furious, dominate the stock market or use the internet itself for your data mining project!

Web application testing framework

This is an update section and is added on 10/07/2010

If you happened to use the .net Framework and wanted to test your web application’s behaviour in browsers, you have WaitN. Perhaps a bit of code from its first page will best illustrate what it does

[Test] 
public void SearchForWatiNOnGoogle()
{
 using (var browser = new IE("http://www.google.com"))
 {
  browser.TextField(Find.ByName("q")).TypeText("WatiN");
  browser.Button(Find.ByName("btnG")).Click();
  
  Assert.IsTrue(browser.ContainsText("WatiN"));
 }
}