Friday, 25 July 2008

Firefox 3, XAML, Silverlight (and Windows 2000 Pro)



Firefox 3, XAML, Silverlight (and Windows 2000 Pro) with Apache for local serving.

I got distracted because I am old ;-) and it works and I'm stuck with my tiny via TX series and that's fine. This machine "only" runs Windows 2000 + SP4 + loadsa patches, firewall, FF3. I wasn't expecting much Silverlight joy.

Installing Silverlight Beta 2 on Windows 2000 Pro

Download and install Silverlight 2 beta 2. I got an error message afer installation from the installer but just ignored it and restarted Firefox. Well, I kind ignored it and have yet to hit a problem. It worked! I could view XAML content on Win2K.x

Setting up Apache to Server XAML File

I used Apache to setup another local HTTP server for me. This one lives on 127.0.0.13 and will be used to server up files. My servers live at E:\servers\SomeServerName under this is public_html. In this case that server directory is called 1313.

Open Apache's conf\httpd.conf file and add a new host. If you want to name it edit %SYSTEMROOT%\System32\drivers\etc\hosts ...
<VirtualHost 127.0.0.13>
ServerAdmin wbmstr@1313.co.uk
ServerName 1313
DocumentRoot "E:/server/1313/public_html"
</VirtualHost>
Then add this to control access permissions on the folder ...
<Directory "E:/server/1313/public_html">
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
</Directory>
We will need to also edit Apache's mime.types file. To this add ...
text/xaml   xaml
This will set the Content-Type header to text/xaml when serving a file ending in the .xaml extension.

You may want to make sure that Listen is set to 80. If it isn't change port numbers elsewhere. You have several options.

Now you should restart Apache.

Now go to Firefox 3 and enter http://127.0.0.13/xaml.html

Not much yet. Let's put those files in place.
  1. The latest "Silverlight.js" from http://code.msdn.microsoft.com/silverlightjs
    Save this as E:\server\1313\public_html\Silverlight.js

  2. A .xaml file to try. XML version is important. There are many
    Save this as E:\server\1313\public_html\plugin.xaml
    <?xml version="1.0" encoding="utf-8"?>
    <Canvas xmlns="http://schemas.microsoft.com/client/2007">
    <TextBlock>Some text... don't ask me what will happen cos' I don't know...</TextBlock>
    </Canvas>

  3. An HTML file in which to host your Silverlight/XAML control.
    Save this as E:\server\1313\public_html\xaml.html
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title>My Silverlight Application</title>
    <!-- Helper files for initializing and creating the Silverlight plug-in -->
    <script type="text/javascript" src="Silverlight.js"></script>
    </head>
    <!--head and html tags omitted-->
    <body>
    <P>Expect silverlight below...</p>
    <div id="slPluginHost" >
    <script type="text/javascript">
    // Create a variable that references the HTML element that hosts the plug-in.
    var parentElement = document.getElementById("slPluginHost");

    Silverlight.createObjectEx(
    {
    source: 'plugin.xaml', // Source property value.
    parentElement:parentElement, // DOM reference to hosting DIV tag.
    id:'myPlugin', // Unique plug-in ID value.
    properties:
    { // Plug-in properties.
    width:'100%', // Width of rectangular region of plug-in, in pixels.
    height:'100%', // Height of rectangular region of plug-in, in pixels.
    background:'blue', // Background color of plug-in.
    framerate:'24', // MaxFrameRate property value.
    version:'2.0'
    },
    events:{
    onError:Silverlight.default_error_handler
    },
    initParams:null, // initParams property value -- user-settable string for information passing.
    context:null,
    }
    ); // Context value -- passed to Silverlight.js onLoad event handlers.
    </script>
    </div>
    </body>

  4. 4 - Install Firebug. It's as good as it gets at the moment.
Debugging

Debugging is primitive but useful and is enabled in the example xaml.html file.

The property onError is set to Silverlight.default_error_handler.

This function is part of Silverlight.js and will produce a Javascript alert dialogue when Silverlight detects an error.

To disable the debugging alert remove the onError handler.

Silverlight Beta 2 Support

NOTE. Support for Silverlight Beta 2 is slightly fuzzy. Whilst you can force support for Beta 2 by specifying a property within the properties member of the silverlight.createObjectEx call. Add
version:'2.0.30523'.
However, the HTML object created will have the type attribute type="application/x-silverlight-2-b2".

By looking in navigator.plugins with Firebug showed that both mime types application/x-silverlight and application/x-silverlight-2-b2 invoke version 2.0.30523.8 of npctrl.dll.

The only difference is that application/x-silverlight is bound to suffix .scr. Strange.

Signing off...

Thursday, 24 July 2008

ZFS, Sun and Flash Memory

Interesting approach from Sun. Being "Big Tin" manufacturers and wholesalers they have a rather different take on the Flash vs HD argument. Simply put Flash uses less power, has better bandwidth, much, much, much better latency and is in general more reliable BUT billions of writes could wear them out. Hard drives have WAY more storage per dollar/euro/pound/yen BUT there are many components that could fail.

So... which is cheaper? Sun don't view this is a simple $/Gb... They see it as "dollars per gigabyte served". Once you take into account power things change dramatically.

There's also talk of why ZFS fits this well (in a nutshell, ZFS is very good at spotting and routing around errors

Sun CEO Jonathan Schwartz Blog Entry "Anything But a Flash in the Pan"

Tuesday, 15 July 2008

Adding a Url Scheme to a Qt Application Running on Mac Os X and Win32

Introduction

What is a URL Scheme or Plugin Protocol?

When you write a web address it starts with "http:" or "https:". An FTP connection (within a browser) starts "ftp:" that part of the address is known as the "scheme".

Many applications create their own schemes so that data can be passed from the browser via an <a href="anewscheme:this_data_is_sent_to_the_native_application"> style link.

I went through the mill getting this to work (especially on the Mac). By comparison Windows is very simple to setup - just a few registry hacks. So, let's start there.

Windows

All one needs to do to in Windows is set the appropriate registry keys. Let's assume that we've installed our application at "C:\Program Files\Acme\MyAcmeProgram.exe"

We need to add the following keys to the registry, all in HKEY Class Root. I instruct NSIS to do this at installation time as it knows where the application is to be installed.

"HKCR\anewscheme" = "URL:BODiBEAT Protocol"
"HKCR\anewscheme\URL Protocol" = ""
"HKCR\anewscheme\Shell\Open\Command" = "C:\Program Files\Acme\MyAcmeProgram.exe "%1$""

NOTE, the "URL Protocol" key really is empty. It's simply a place marker

NOTE, the extra quotes around the %1 are essential especially if your URL contains commas, spaces or any other character that specifies a parameter separator on the command line.

Operation

When the user accesses a link with like "anewscheme:datagoeshere" the application is executed and the link itself is sent to the application as argv[1]. It's that simple. You may want to make your application single instance and pipe the given URL to the first instance of the application.


Mac Os X

For the Mac we have much more work to do. The first thing we will need to do is to install an AppleEvent handler in our "main" function like this...


OSErr err = AEInstallEventHandler(kInternetEventClass,
kAEGetURL,
NewAEEventHandlerUPP((AEEventHandlerProcPtr)macCallbackGetUrl),
(long) (&app),
false);

We also need to provide the function "macCallbackGetUrl"


// AppleEvent callback
static pascal OSErr macCallbackGetUrl(const AppleEvent* inEvent,
AppleEvent* outEvent,
long refCon)
{
OSErr err = noErr;
Size actualSize = 0;
DescType descType = typeChar;

if ((err = AESizeOfParam(inEvent, keyDirectObject, &descType, &actualSize)) == noErr)
{
if (0 != actualSize)
{
// make a buffer (Qt style)
QByteArray bUrl;
bUrl.resize(actualSize + 1);

err = AEGetParamPtr(inEvent,
keyDirectObject,
typeChar,
0,
bUrl.data(),
actualSize,
&actualSize);
// Grufty C cast... meh.
(CMyApplication*)(app)->appReceivedUrl(bUrl);
}
}

return noErr;
}

NOTE:"app" is whatever you want. Possibly the most convenient object to pass to the event handler is your QApplication derived application class.

We're NEARLY there! The very last thing we need to do is to invoke the Carbon event loop. However, Qt does this for you when you create a QApplication object (which you did in main just after setting up the Apple event handler right?)

To make this all compile and link properly we need to link against the Carbon framework. TO do this we need to add one extra line to our qmake .pro file when building for the Mac

mac:LIBS += -framework Carbon

To finish off we need to add some XML to Info.plist which is inside the app bundle. Use finder to open the package and in the "Contents" folder you'll find "Info.plist" - you can use the property edit to edit this - just double click.

However! There's a little trick you can use in your qmake .pro (or .pri) file. Qt installs a very minimal Info.plist in your app bundle. To override this and provide your own add the line

mac:QMAKE_INFO_PLIST = ./Info.plist

Another way to do this is to use "install" type "man install" for more info. This lets you add/delete files from a package at will and is very powerful.

Anyhoo. These are the keys that need adding...

 <key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>A New Scheme</string>
<key>CFBundleURLSchemes</key>
<array>
<string>anewscheme</string>
</array>
</dict>
</array>
<key>NSAppleScriptEnabled</key>
<true/>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
Operation

When the user access a "anewscheme:" URL an Apple Event is received in the callback function and we can pick out that data and process it anyway we like.

Epilogue

And that's all! Honest! L8rz, burnttoy