Fooling around with the Office Assistant

I seem to have a special bond with ancient stuff. I were doing Pascal when C++ and WinForm was at their prime. Now I’m toying with a discontinued Microsoft Office feature. I just can’t help it, I have to work with Office 2003 around the clock since the upper IT management takes about a decade to certify a new software as “compatible”. Well, working for a big corporation has its pros and cons and we all have to cope with them.

I don’t feel the Office assistant intrusive though, it certainly doesn’t get in your way if you turn it off, but oh well, only when you know how. (Which, sadly, is not the case for many computer users). And I don’t think we can just let the woman take it from us. Gdzie jest czcionka? 😉

When I was in 7th grade or something. I read an article on PCWorld Vietnam about how to manipulate the Office Assistant. I diligently typed the code (in VBA) character-by-character without even understanding them :P. Nevertheless, the result was really satisfying, I were able to make the cat  (Links, an office assistant character) jump through hoops (literally).

Okay, enough trivia! I don’t remember any function from back then so I’ll have to start over. I have done various applications inter-operating with Microsoft Office’s VBA before, so I guess it would be an easy task. I added the Microsoft Excel’s object library to my  C# project and search for “assistant”. Lucky me, something popped up.

Assistant class in object browser

As you may see, it’s a child of the application class so you’ll have to start an Office application first. I chose Excel because it’s the application I have been working with the most. For aesthetics reasons, I tried to hide the Application’s window but that will hide the assistant too :(.  Apart from that, thanks to the well-built COM interface, initialize and display the assistant is easy.

using Microsoft.Office.Interop.Excel;
...
ApplicationClass Test = new ApplicationClass();
Test.Assistant.On = true;
Test.Assistant.Visible = true;

In case you are wondering, ApplicationClass is used to control Excel. All the possible action of “Assistant” is neatly listed within an enum so I just have to convert those to text and list them for the user to choose. No button-to-button editing for each action required!

 foreach (string TypeName in Enum.GetNames(typeof(Microsoft.Office.Core.MsoAnimationType)))
 {
     listBox1.Items.Add(TypeName);
 }

Because you can only see the Office Assistant when the host Office application has focus, I made a timer so the assistant will do the same action over and over, so the user can switch to the relevant application.

        private void timer1_Tick(object sender, EventArgs e)
        {
            Microsoft.Office.Core.MsoAnimationType[] Temp = (Microsoft.Office.Core.MsoAnimationType[])Enum.GetValues(typeof(Microsoft.Office.Core.MsoAnimationType));
            if (listBox1.SelectedIndex >= 0)
            {
                Test.Assistant.Animation = Temp[listBox1.SelectedIndex];
                Test.Visible = true;
            }
        }

"Get techy" with Rocky :p

You can also make the assistant say stuff you want:

 private void button1_Click(object sender, EventArgs e)
 // I created a button and a TextBox
 // When you enter some text into the TextBox and click the button, the
 // assistant will make a speech balloon with the text in it
 {
   timer1.Enabled = false;
   MessageBox.Show("Switch to Excel after clicking OK");
   System.Threading.Thread.Sleep(2000);
   Microsoft.Office.Core.Balloon Speech = Test.Assistant.NewBalloon;
   Speech.Heading = "Test balloon";
   Speech.Text = textBox1.Text;

   Speech.Mode = Microsoft.Office.Core.MsoModeType.msoModeModal;
   Speech.Show();
   timer1.Enabled = true;
 }

Bark!

So if you are still stuck with Office 2003 and wanted to play around with it a bit, here’s the compiled application (requires .NET 2.0 and Microsoft Office 2003 installed) and for those who want the code, here it is.

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"));
 }
}

Local browsing with CoolIris

UPDATE: You can simply use CoolIris 1.10 for the same purpsose

Full-Screen, 3D — Cooliris transforms your browser into a lightning fast, cinematic way to browse online photos and videos. Our “3D Wall” lets you fly through thousands of items in the blink of an eye on an infinitely expandable wall. To enjoy Cooliris on Google Images, Facebook, YouTube, Flickr, and hundreds of other sites, click the Cooliris icon that appears when you mouse over media on the supported site. Or enjoy Cooliris anytime by clicking the browser toolbar icon. See http://www.cooliris.com/product for details.

I was looking for an app that let me browse through my image gallery Apple style – PhotoFlip™, but there seems to be none, unless I download Safari :-/. I don’t want a new browser right now, so I turned to the next best thing: CoolIris. Somehow I vividly recall this is a project started from Microsoft Research but I can’t find any trace of Microsoft there. Maybe the Cooliris team doesn’t like Microsoft in the end. 😛

Well, at least I expected it to be able to automatically detect links to picture on a page and then let me view them. It supported Flickr and Google Images off-screen loading, which is much more complicated than a list.

What a shame it doesn’t.

I’m not the only person looking for a “standalone CoolIris” to view my files, the CoolIris forum is filled with similar requests but the best response they can give is “wait” and an “CoolIris Lite” in which the effect is much simple and you seems to have to add files manually.

No problem, I can fix that.

I tried the “quick” option from the developer’s site but that turned out to be the more complicated option since I have to generate both the expression and the gallery for it to work, so I tried the full option: I created a C# application that will read files from the directory you want, write two files “media.htm” and “media.rss” to the output directory.

  • Media.htm contains one picture to activate the CoolIris icon on the toolbar, links to media.rss.
  • Media.rss is the feed that lists the files which will let CoolIris know the full list of images.

The core part of the application follows

            // Read jpg and jpeg from target directory
            string[] Files = Directory.GetFiles(textBox1.Text, "*.jp*");
            // Prepare the feed
            StreamWriter writer = new StreamWriter(textBox2.Text + "media.rss");
            writer.WriteLine("<?xml version="1.0" encoding="UTF-8" standalone="yes"?>");
            writer.WriteLine("<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss" xmlns:atom="http://www.w3.org/2005/Atom">");
            writer.WriteLine("<channel>");
            writer.WriteLine("<title>Generated photos</title>");
	        writer.WriteLine("<link>file:///" + textBox2.Text.Replace("\","/") + "</link>");
            writer.WriteLine("<description>Photos from my trip to Africa.</description>");
            int Counter = 1;
            foreach (string FileName in Files)
            {
                FileInfo Item = new FileInfo(FileName);
                writer.WriteLine("<item>");
                writer.WriteLine("		<title>" + Item.Name + "</title>");
                writer.WriteLine("		<link>" + "file:///" + FileName.Replace("\","/") + "</link>");
                writer.WriteLine("		<guid>img " + Counter.ToString() + "</guid>");
                writer.WriteLine("		<media:description>" + Item.Name + "</media:description>");
                writer.WriteLine("		<media:thumbnail url="file:///" + FileName.Replace("\","/") + "" />");
                writer.WriteLine("		<media:content url="file:///" + FileName.Replace("\","/") + "" type="image/jpeg" />");
                writer.WriteLine("	</item>");
                writer.WriteLine("");
            }
            writer.WriteLine("</channel>");
            writer.WriteLine("</rss>");
            writer.Close();
            //Prepare the HTML file
            writer = new StreamWriter(textBox2.Text + "media.htm");
            writer.WriteLine("<html>");
            writer.WriteLine("  <head>");
            writer.WriteLine("    <link rel="alternate" href="media.rss" type="application/rss+xml" title="" id="gallery" />");
            writer.WriteLine("  </head>");
            writer.WriteLine("  <body>");
            foreach (string FileName in Files)
            {
                FileInfo Item = new FileInfo(FileName);
                writer.WriteLine("<a href="" + "file:///" + FileName.Replace("\", "/") + "">");
                writer.WriteLine("<img alt="[Image]" src="" + "file:///" + FileName.Replace("\", "/") + "" class="photo">");
                writer.WriteLine("</a>");
                break;
            }
            writer.WriteLine("  </body>");
            writer.WriteLine("<html>");
            writer.Close();
            //Open the HTML file with the default browser, hopefully it's the one with CoolIris installed
            System.Diagnostics.Process.Start(textBox2.Text + "media.htm");

localcooliris1

Application interface

Fill in the directory containing the pictures you want to view in the first text box, the second could be your temp directory. Click generate to generate the files mentioned above and open them in your default browser, click the CoolIris to activate CoolIris (this extra step is required because I don’t know how to call CoolIris on a file directly; the “Launch CoolIris” application seems to open Cooliris.com only).

I also made a command line interface with which you can call the app with 2 parameters. The first will go to “Directory” and the second to “Output”. If you run the app this way it will generate, open the file and then close itself.

localcooliris2
Result

Download the application

Requirements:

  • .NET Framework 2.0
  • CoolIris enabled browser

Mikrypto

Splash screen

Splash screen

Is the name of my latest school project in cryptography; possibly the fastest project ever: only 10 hours from concept to realization with all the functionality in place. It would be great if I were in the mood to document it. But unfortunately that is not the case right now. Other than some problem with XML Serialization (specifically serialization order control and serialize to stream), the project went smoothly. The version below is a little more polished than the version I turned in.

So what does this do? In short: It let you encrypt files and send to friends who also used this application. Upon account creation, you are given a key pair (which you can access using the export function); you are free to give your key to others and vice versa. If you want to send a file to someone, just encrypt the files choosing that one as the recipient, send the file to (s) he, the receiver logins to his/her account, hit decrypt and BOOM! Files appear!

Though the process is simple, way too simple that you don’t even have to enter a password to encrypt files, it is still not cryptographically feasible for anyone to decrypt the encrypted file. Even you, the one who encoded that file(s) to send wouldn’t be able to decode it without knowing the recipient’s account detail.

If that sounds interesting, give it a try

(If you are confused, read the Vietnamese usage instruction in the PDF file)