« October 2005 | Main | December 2005 »

November 2005

November 30, 2005

Embed movies in PowerPoint

There was something really special about Ryan Davis’ excellent ZenHacks talk at RubyConf 2005. It took me a while to figure out what was going on, but it initially looked to me like he was typing code into a command shell embedded in the middle of his Keynote slide deck. As it turned out, he was playing QuickTime movies from within his slide deck, which let him give the feel of a live coding session, but with better commentary since he didn’t have to think, talk and type at the same time.

I decided to try the same approach for my talk tonight. However, I quickly ran into a large number of technical blocking issues. Here’s a set of notes to help anyone else that’s trying to use this technique.

1) Camtasia rocks. I have a full license for Captivate but I think I’m going to pony up the cash for Camtasia as well. The main reason for the switch is the ability to create WMV files directly from Camtasia.

2) Your screen cast video will look really crappy if it is scaled. The main problem with PowerPoint is that it insists on scaling your video to whatever your output device resolutiion is. One way to get around this is to force the slide show resolution to a fixed resolution (I used 1024×768):

Next, you must force the size of your video clip to be a fixed size (7.8125” works for an 800×600 movie using the default PowerPoint slide sizes).

3). Setup your video to play automatically. This makes for a much more seamless experience when you land on a slide with a video. I had a really hard time making things work the way I wanted with SWF files generated by Captivate, which was a major reason why I’m considering ponying up the $$$ to buy Camtasia (it’s not cheap either, but a good deal cheaper than Captivate).

November 29, 2005

Matthew's Birthday Present

I just finished updating Matthew’s Birthday Present for the RTM release of .NET 2.0. I’ll be unveiling Matthew’s second birthday present at the Canada Technology Triangle .NET User Group meeting Wednesday, November 30, 2005.

It should be a really fun talk. You’ll see the culmination of several months of late night hacking. Among the things you will see are:

  • Indigo
  • Avalon
  • Managed C++
  • CIL
  • Ruby

With the exception of WWF, it will be pretty much a lap around WinFX, but done using Ruby :)

It looks like I’ll have quite the crowd there: 104 113 registered as of right now. Hope to see you there!

November 28, 2005

TorCamp

This was TorCamp weekend in Toronto. And what a weekend it was. For the longest time, it felt quite isolating to be a geek living in Toronto (at least relative to places like Seattle or San Francisco). Sure, there’s a vibrant .NET developer community in Toronto, but most of that community is focused on “corporate” apps, and far less on innovative uses of the technology (aka startups).

ObjectSharp was proud to be a sponsor of the initial run of the conference. I met a lot of really interesting folks at the event that I’m sure I’ll be having a lot more interesting follow-up conversations with in the near future. A big thanks goes out to David Crow for making this event happen.

Check out the flickr group for some images from the conference. I love the space that teehan+lax provided for hosting the conference.

The best thing about this conference was the cross-fertilization of ideas that can happen when you get a bunch of folks from different walks of life having informed conversations and debates. Reg Braithwaite gave a nice talk about the importance of context in applications ranging from search to advertising to project management(!). David Janes gave a very cool demo about metadata, microcontent, blogging, and greasemonkey. I met Albert Lai, whose company, BubbleShare is actually using Ruby and .NET to build their innovative photo sharing service. Lots of other interesting hallway conversations too numerous to recount here.

I spent some time talking to a small group of folks about bridging Ruby and the CLR (this wasn’t really the right crowd to be giving a talk like this to). It started out small, but eventually turned into a 1:1 conversation between myself and Mike Shaver of Mozilla about the difficulties of avoiding memory leaks in a process that is running multiple GC-based allocators based on his experience with Mono + Firefox. It’s definitely something that I need to spend some more time thinking about.

November 25, 2005

Indigo and Ruby: great together (well sort of)

If you look at the code that I wrote to call flickr using Indigo, you’ll notice that the flickr API call accepts a string and returns a string. This makes it trivial for me to interop with Ruby:


require 'RubyShim'
require 'builder'
require 'builder/xmlmarkup'
require 'rexml/document'

reference_file 'flickrlib.dll'

include FlickrLib
include Builder
include REXML

f = Flickr.new('83293ff34e3ab3d9935018480190319f')
puts f.Call('<method>flickr.people.findByEmail</method>
             <find_email>jlam@iunknown.com</find_email>')

# or if you prefer
xml = Builder::XmlMarkup.new
xml.method     "flickr.people.findByEmail" 
xml.find_email "jlam@iunknown.com" 

d = Document.new(f.Call(xml.target!))
puts d.elements['//username'].text

I’m not all that happy with sending mal-formed XML as an in-parameter, but it was a quick and easy hack to get it up and running.

Indigo and flickr: happy at last

In yesterday’s post about the Flickr bug I explained what was causing Indigo to be so unhappy. I spent some quality time with Google, and found the code samples from Doug Purdy’s PDC presentation on how to make Indigo initiate POX (Plain Old XML) style calls. Now, flickr should really fix their API, but this led to an interesting educational trip into the world of MessageEncoders in Indigo.

A MessageEncoder is responsible for marshaling a Message object to and from an Indigo transport. By writing my own MessageEncoder, I can set its MediaType property to text/xml, thereby ensuring that the Indigo plumbing accepts the mal-formed flickr response.

Once you write your own MessageEncoder, you have to inject it into the Indigo stack. To do this, you’ll need to implement a custom MessageEncoderFactory and a custom BindingElement. This is fill-in-the-form style programming – you just have to override a few mandatory methods and you’re good to go.

The really nice part of this exercise was how none of the rest of the code that I wrote yesterday had to change to make this happen. The only part that changed was replacing the reference to TextMessageEncodingBindingElement with my new FlickrEncodingBindingElement.

Here’s the source code for my implementation (cleaned up a bit from the code that I posted yesterday).

Thanks go out to Don Box, Yasser Shohoud and Kenny Wolf for pointing out the right way of making this happen.

November 24, 2005

Indigo and flickr: not happy together

Inspired by Mike Taulty’s A slightly different ‘hello, world’ for Indigo blog entry, I decided to create a low-level Indigo client that talks to flickr.

I wanted to understand how the Indigo plumbing worked, so I decided to forego the high-level APIs and write my code using nothing more than ChannelFactory, Message, IRequestChannel and friends. This code compiles and runs on the November CTP bits, so my code looks a bit different than Mike’s code on his blog. If you want to follow along, you’ll need the November CTP bits and the SDK, but be warned: the documentation has not stayed in sync with changes to the API. Reflector is your friend :)

It all started innocently enough. Here’s the original version of my code:


    ChannelFactory<IRequestChannel> factory;
    using (factory = new ChannelFactory<IRequestChannel>(
           CreateBinding(),
           new EndpointAddress("http://www.flickr.com/services/soap/"))) {
      using (IRequestChannel channel = factory.CreateChannel()) {
        StringReader body =
          new StringReader(@"<x:FlickrRequest xmlns:x='urn:flickr'>
                             <api_key>83293ff34e3ab3d9935018480190319f</api_key>
                             <format>soap2</format>
                             <method>flickr.test.echo</method>
                             <name>value</name>
                           </x:FlickrRequest>");
        XmlTextReader reader = new XmlTextReader(body);
        Message message      = Message.CreateMessage(MessageVersion.Soap12Addressing1, 
                               "*", reader);
        Message response     = channel.Request(message);
        XmlDictionaryReader responseReader = response.GetReaderAtBodyContents();
        Console.Write(responseReader.ReadOuterXml());
      }
    }

This code uses a ChannelFactory to create a request/response style channel to flickr. Next, I construct a Message object and inject some XML into the message body. The flickr API is really just a single method that takes an XML document and returns an XML document. See the documentation for more examples. Finally, I send my request Message via the channel, and it hands me back a response Message object that I serialize to the console. Simple enough, right?

That’s when the fun began. There’s a bug in flickr, and apparently, I’m not the first one to report this. The flickr SOAP API returns a content-type of text/xml for a SOAP 1.2 message body, whereas the spec clearly states that the content-type should be application/soap+xml. Indigo is not happy at all with this, and throws a ProtocolException and aborts further processing of the HTTP response.

The crux of the problem lies in the type of channel that I created using the ChannelFactory class. To understand how the channel is constructed, I have to show you the missing implementation of the CreateBinding method:


CustomBinding binding = new CustomBinding();
binding.Elements.Add(new TextMessageEncodingBindingElement(
  MessageVersion.Soap12Addressing1, Encoding.UTF8));
binding.Elements.Add(new HttpTransportBindingElement());
return binding;

Here, I tell the ChannelFactory to construct a channel that uses an HTTP transport, and a text-based XML serializer that will generate a SOAP 1.2 message that is text encoded as UTF-8. Indigo will also check to make sure that the response from the server is a SOAP 1.2 message and the content-type is application/soap+xml. To see this checking in action, try sending a SOAP 1.1 Message using this channel.

I spent some time spelunking around using Reflector, TextMessageEncoder.IsContentTypeSupported is where the ProtocolException gets thrown. Unfortunately, I couldn’t find a way to change the ContentType property of this object. This left only one other option that I could see: write a custom MessageEncoder.

More on how to do this tomorrow.

November 23, 2005

Synergy!

While looking for other people who have actually used SOAP to access the Flickr API, I discovered Synergy.

My life’s dream is complete: I have actually discovered a useful utility before Scott Hanselman! Marvel at how I can use the same keyboard and mouse on the same virtual desktop across three computers, one of which is my Powerbook!

All I have to do is roll the mouse to the desired screen, and the keyboard “focus” follows my mouse. Absolutely fantastic utility.

Avalon November CTP

I spent some time this afternoon dealing with the breaking changes in my toy Avalon application between the September WinFX CTP and the November WinFX CTP.

Karsten Januszewski has kindly released a draft of his upcoming article on the November CTP that is scheduled to appear on MSDN in December. Between that and the Avalon XSD schema, I was able to figure out how to port my application to the November CTP.

The biggest problem that I had was remembering that the syntax of a PropertyPath is based on a dot-delimited list of (type name.property name) tuples. You can also specify indexers for the list tuples.

In my app, I had a fairly complex property path that scrapes a property out of a 3D model:

(Viewport3D.Children)[0].(ModelVisual3D.Content).(Model3DGroup.Children)[2].(Model3D.Transform).(RotateTransform3D.Rotation)

There is a new Children element that hangs off of Viewport3D that tripped me up. The runtime exceptions that get thrown by the framework aren’t, um, helpful towards diagnosis of the problem. Spelunking via Intellisense was what helped me discover the new Children property (Karsten mentions it in his article as well).

November 11, 2005

Ruby in the Enterprise

Most of the work we do at ObjectSharp is your standard line of business application. If you ever tried to introduce Ruby into such an environment, you’re bound to run into some resistence.

At next week’s Architect’s Roundtable presentation, I’m going to present the case for Ruby in the Enterprise. It’s an interesting story about how we can learn from the past, the importance of platforms, and how to sell productivity to customers.

If you’re in the Toronto area, make sure you drop by to say hello!

Ruby, COM and the CLR

If you want to write code that interacts with windows (note the lowercase w) and COM, then your thread must live in its own single threaded apartment (STA). This poses a problem if you want to write some Windows Forms code in Ruby. Here’s the problem in a nutshell:

If you’re using my bridge, the CLR is delay-loaded; it loads when my bridge is loaded by the Ruby interpreter. Now Ruby doesn’t know anything about COM, so Ruby doesn’t turn on COM via a CoInitializeEx call at startup. So I should have a chance to turn on COM on behalf of Ruby (more on why this is bad later) when my bridge loads. One of the really nice things about using MC++ is that the compiler/libraries does a bunch of auto-magical startup code to hoist the CLR into memory when my bridge loads. This is where our problems begin.

In V1.0 and V1.1 of the CLR, the runtime theoretically didn’t turn on COM either (it actually did in a number of corner cases). This lets you write code like:

Thread::CurrentThread::ApartmentState = ApartmentState::STA;

However, under V2.0 of the CLR all threads automatically start in the MTA – which means that you can no longer write code like the line above. You can instruct the CLR at intialization time to have threads default to their own STA (via an app.config file or via an STAThread attribute on your application’s Main method), or you can intialize COM yourself before you initialize the CLR.

For a variety of reasons, if the CLR is delay-loaded, there really is no way to declaratively tell the CLR about your intentions with respect to COM. This leaves you with one other option: turn on COM yourself before the CLR loads.

Now how can you do this without hacking Ruby itself? Anson Tsao, and old friend of mine at Microsoft provided me with the answer as I was feverishly coding up my bridge in anticipation of its first internal review meeting.

I had an Avalon demo application that I was coding up for Matthew’s second year birthday and it was refusing to run because the calling thread was not an STA thread! Now, as anyone with a 2 year old knows, they can get rather upset when things don’t go their way :) But thankfully at the very last minute, Anson provided me with this hack:


void InitializedManagedRubyBridge() {
  ...
}

#pragma unmanaged
// Main entry point
__declspec(dllexport) void Init_RubyShim() {
  CoInitializeEx(0, COINIT_APARTMENTTHREADED);
  InitializeManagedRubyBridge();
}

Notice how I can mix unmanaged and managed code inside the same DLL! If I define my DLL entry point in unmanaged code, I can turn on COM and then jump into my managed code. The call to InitializeManagedRubyBridge() gets intercepted by MC++ libraries which in turn hoist the CLR into memory before calling my method.

This is a nice way to solve this problem. In a future post, I’ll point out how this doesn’t really solve this problem in all cases but likely solves this problem in most cases that users of my bridge will run across.

Photos

  • www.flickr.com
    This is a Flickr badge showing public photos from John Lam. Make your own badge here.

Recent Comments

Recent Posts

May 2008

Sun Mon Tue Wed Thu Fri Sat
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Blog powered by TypePad