My favorites | English | Sign in

Sign up for Google I/O 2010 today!

Google Desktop APIs (Labs)

Going Beyond Script: Developing Hybrid Desktop Gadgets

This article was written and submitted by an external developer. The Google Desktop Team thanks Krzysztof Olczyk for his time and expertise.


Krzysztof Olczyk, Google Desktop Developer
September 2007

Introduction

The Google Desktop API makes it easy to write powerful, attractive gadgets using XML and JavaScript. However, it may happen that your gadget requires more refined and specific functionality that is not provided by the API.

Fortunately, gadget developers are not restricted to only the objects and functions available in the API. Functionality can be extended easily by writing a DLL library that encapsulates native code inside an ActiveX automation object. This article will show you how to start creating a hybrid gadget employing programming tools such as Microsoft Visual Studio 2005 or CodeGear Delphi (previously known as Borland Delphi).

After reading this article, you will be capable of developing advanced hybrid gadgets with the same ease and confidence you have in developing traditional script-based gadgets.

I will also provide you with a complete example of an ActiveX module written in CodeGear Delphi.

How do I start?

Let us begin by explaining what a hybrid gadget is. From the perspective of the end-user, it is not possible to distinguish between a standard gadget and a hybrid one. Both are packaged in a .gg file and can be installed by double-clicking the file or using the "Add gadgets" dialog. Indeed, they are the same except for the fact that after declaring your object in the manifest, you can create it in your code as if it was a standard JavaScript object: hybrid gadgets contain one or more DLL files that implement ActiveX automation objects. You may feel a bit uneasy now if you are not familiar with ActiveX technology, but you shouldn't worry. It does not have to be a difficult task, especially if you choose the right tools.

Moreover, you don't have to be concerned with any burdensome ActiveX deployment, i.e. registration of a type library. All you need to do is to add a tag to the manifest file (gadget.gmanifest) informing Google Desktop that your gadget is a hybrid, and that you have a DLL library with an ActiveX object embedded. If you take a look at the manifest file of any hybrid gadget, you will see something similar to the following:

<gadget minimumGoogleDesktopVersion="5.1.0.0">
  <about>
    <name>&GADGET_NAME;</name>
    <description>&GADGET_DESCRIPTION;</description>

    <aboutText>&GADGET_ABOUT_TEXT;</aboutText>
    <smallIcon>plugin_small.gif</smallIcon>
    <icon>plugin_large.gif</icon>
    <version>0.7.0.0</version>

    <author>John Smith</author>
    <authorWebsite>http://whatacute.site.com<authorWebsite>
    <id>ABBEDEE1-2EC5-4EAE-BD1A-8BE8B4D191E2</id>
    <copyright>Copyright (c) 2012 J.Smith </copyright>

    <authorEmail>contact@me.com</authorEmail>
  </about>
  <install>
    <object name="HybridHello" clsid="973FCA8C-DEA0-46EC-B228-3218B0D7B1C2" src="hybridhello.dll"/>
  </install>

</gadget>
Note that the ActiveX object is declared using an <object> tag inside the <install> section. You have to specify a name for the object, which will be used to identify it in the JavaScript code. You also specify the unique identifier of your class (IDEs generate this for you) and the filename of the DLL library.

After declaring your object in the manifest, you can create it in your code as if it was a standard JavaScript object:

var myhybridstuff;
   
myhybridstuff = new HybridHello();
myhybridstuff.SayHello(":D");

Create the ActiveX library

In order to start developing ActiveX libraries, you need to use one of the development environments that support ActiveX programming. Some examples of such suites are:

Later, I'll go over the basics of creating a project in Microsoft Visual Studio, which is powerful but may be more difficult because it uses C++. I'll also demonstrate TurboDelphi, which uses Pascal and is typically easier to use.

Quick guide to Microsoft Visual Studio 2005

ATL wizard - first screen shot
Figure 1: Creating a project in Visual Studio 2005

The hybrid module can be developed using Visual Studio 2005, which is probably the most popular development suite Microsoft offers. The Visual Studio approach requires coding in C++ and the use of ATL, Microsoft's toolkit library for ActiveX development.

The first thing to do is to start a new ATL project in Visual C++ using a wizard. You don't have to tweak any settings apart from the name of the project. Figure 1 depicts the wizard dialog window where you specify the type of project to create, in this case an ATL project.

Once you have finished with the project wizard, you can remove one of the generated project files, the one that ends in PS, e.g. HybridHelloPS. Now, you can proceed to create a class that is going to be instantiated in JavaScript code. Again, there is a wizard to help us with this task located in the Project | Add class.. menu. For a hybrid gadget, the class type should be ATL simple object.

After creating a class, you must manually introduce a change required by Google Desktop. The modification is to set the version of your class to 0xffff.0xffff. This is done in the header file where you implement your class (for instance, HelloWorld.h):

class ATL_NO_VTABLE CHelloWorld :
  public CComObjectRootEx<CComSingleThreadModel>,
  public CComCoClass<CHelloWorld, &CLSID_HelloWorld>,
  public IDispatchImpl<IHelloWorld, &IID_IHelloWorld, 
    &LIBID_HybridHelloLib,
    /*wMajor =*/ 0xffff, /*wMinor =*/ 0xffff>

Make sure that the parameters wMajor and wMinor are both 0xffff.

After the class is created, you can add new methods or properties in Class View by selecting the main interface of your class (IHybridHello for example) and invoking the Add method or Add property wizard. In the wizard, you may specify the data type of the property or arguments in the case of a method. You will find more information about data types below.

ATL wizard - adding new method
Figure 2: Adding new method

Assume you have created a class called HelloWorld. Then, one of the methods may look like this:

// CHelloWorld

STDMETHODIMP CHelloWorld::SayHello(BSTR str)
{
  CComBSTR msg;

  msg.Append("Hello World ");
  msg.Append(str);

  MessageBoxW(0, msg, L"Hello", 0);

  return S_OK;
}

Once compiled, the library can be used in your gadget as shown in the first section.

To discover the class identifier in order to specify it in the manifest file, open the .IDL file and search for your COM class (coclass). You will encounter a piece of code similar to the following:

  [a
    uuid(C4D3C406-20E7-47D7-8BC7-0BFDE34DB16E),
    helpstring("HelloWorld Class")
  ]
  coclass HelloWorld
  {
    [adefault] interface IHelloWorld;
  };

The value in uuid() is the one you are looking for.

Quick guide to CodeGear TurboDelphi

If you don't like programming in C++ and prefer the more human-friendly Pascal, you probably should use Turbo Delphi. Fortunately, even the free version—Turbo Delphi Explorer—supports ActiveX development.

Delphi - Creating automation object
Figure 3: Creating a class in Delphi

Type library in Delphi
Figure 4: Editing type library in Delphi

The first thing to do is to create a new project - ActiveX library. Delphi will create the template of the new library for you. As in Visual Studio, you need to create a new class, i.e. use the wizard to create an Automation Object (Figure 3).

After you choose a name for your class, Delphi will generate a code template and open the Type Library Editor. Here, you can add or modify the properties and methods for the main interface of your class.

It is necessary to change the version of your COM object in the type library, otherwise Google Desktop will not be able to instantiate your class. Set the Version parameter of your class and main interface to 65535.65535 (i.e. 0xffff.0xffff in hexadecimal notation, see Figure 4).

Now you can start writing your code. For every function or property, Delphi creates a template in the unit file. The function SayHello would look like the following:

procedure THelloWorld.SayHello(const Str: WideString);
begin
  ShowMessage('Hello world, ' + Str);

end;
Once compiled, you can use the library in your gadget as shown in the first section. Make sure that you specify a correct unique identifier in the manifest file. Note: Use the identifier found in the GUID field for the CoClass, not the one for the interface.

What data type should I choose for properties?

When you start outlining your ActiveX object, either using wizards in Visual Studio or in Type Library Editor in Delphi, you may get confused by the number of possible OLE types you can use for your properties or function arguments. Below, is a summary of various OLE types and how they should be used:

Strings

If you want to pass a text string from your script, the best option to choose is the standard OLE type used for strings - BSTR. It is recognized and supported by JScript. In ATL, there is a helper class CComBSTR for managing BSTRs, while in Delphi, the built-in type WideString is compatible with BSTR.

Numerals

You should use the LONG data type in passing numerical values to ActiveX objects. It is equivalent to int in C++ and Integer in Pascal.

Objects

In the communication between your script and the native code, you are not limited to primitive data types. You may also return an object to the script, as long as it implements the IDispatch interface. Such an object may be used like a normal JavaScript object, except when you want to dynamically add new properties to the returned object; in this case, you'll need your object to implement IDispatchEx. It also works the other way around; you may accept a JavaScript object in your hybrid code. What will be passed is a pointer to IDispatch interface.

In order to read/write a property or execute a method, you need to invoke the pair of GetIDsOfNames and Invoke methods of the IDispatch interface, all documented in MSDN. You can find an example of retrieving property value of a JScript object in one of the posts in my blog as well.

You don't have to do as much work in Delphi. If you assign a reference to IDispatch to a variable of type Variant, you can deal with the JScript object as if it was a normal Delphi object. Assume we have the following code in JavaScript:

var myobj = new Object();
myobj.someparam = "Hello";

hybr.Foo(myobj);

Then the function Foo would be defined as follows:
procedure THybridClass.Foo(Obj: IDispatch);
var
  vObj: variant;
begin
  vObj := Obj;
  ShowMessage(vObj.someparam);

end;

Arrays

Passing arrays between JavaScript (in particular JScript) code and an ActiveX object is quite problematic. The concept of an array in JScript is quite different from the one present in ActiveX technologies. Architects of JScript claim there is no easy way to convert between them and their suggestion is to not use arrays as method arguments or properties at all. However, in the case of a hybrid gadget, it is known that the array will be used exclusively in a JScript script. Like everything in JScript, an array is an object and has properties and methods. The elements of an array can be implemented in the same manner as if they were the properties of an object. In fact, there is no difference between the code arr.elem and arr[a"elem"] in JScript. Therefore, we can pass an array to the ActiveX object as an IDispatch reference and query for array elements using GetIDsOfNames and Invoke methods of IDispatch. Additionally, methods pop and push may be used to avoid querying for every element if their keys are not known. I have discussed exhaustively the topic of processing JScript arrays in my programming blog.

Conclusion

In this article I have outlined the topic of developing hybrid gadgets, a powerful concept in gadget development. Being able to develop hybrid gadgets dramatically increases your possibilities and removes constraints. I encourage you to download the sample I have developed recently in Delphi. In the sample, I use a built-in class in the Delphi library to provide the user with a color selection window. It is the same technique used in my gdAmp gadget and is good way to see how hybrid gadgets are developed.

Resources

Author Bio

Krzysztof Olczyk

Krzysztof Olczyk is a computer science student from Poland and is passionately interested in software development (more precisely technologies like ActiveX, .NET, Java, scripting, and recently, creating Google Desktop gadgets). Krzysztof studies at Technical University of Lodz, Poland and spent one-year studying as an exchange student at Technical University of Valencia, Spain.
He is the author of popular Google Gadgets like MultiDesktop and MiniExplorer.
Computer Science is not his only hobby: he is known to be an addict of good rock music and cannot imagine life without music. He enjoys composing music and playing guitar. Sometimes, he likes to read a good book, like those written by Paulo Coehlo. Be sure to visit his homepage containing his projects and his programming blog.

Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License.