My favorites | English | Sign in

Google Desktop APIs (Labs)

Action API Developer Guide

Google Desktop Custom Actions allow plug-in developers to override the default actions when a user clicks on a specific UI item.

Example: samples/search/action_sample (in the SDK)

Contents

  1. Overview
    1. Getting Started
    2. Development Process Overview
  2. Custom Action Developer API
    1. Registering Custom Action Components
    2. Implementing and Handling Custom Actions

Overview

Getting Started

To implement Custom Actions and integrate your application with Google Desktop you will need, in addition to the information in this document:

  • Sufficient access to write a plug-in for your application and an installer for it.
  • Programming knowledge of the Microsoft Windows Component Object Model (COM).

Development Process Overview

To develop a Google Desktop Custom Action, start by downloading the SDK, in particular the GoogleDesktopActionAPI.idl file. We recommend developing your application with Microsoft Visual Studio.

You will then need to write code to:

  • Register your application with the Google Desktop (required).
  • Implement the required Custom Action interfaces.
  • Unregister your application with Google Desktop when your application uninstalls.

We recommend that you look over the sample code provided with the SDK. Please note that the sample code examples have their GUIDs hardcoded, so if you choose to reuse code from there you must change the interfaceIDs, classIDs, and libIDs to ones valid for your application.

Back to top

Custom Action Developer API

Registering Custom Action Components

Google Desktop will not accept unregistered components. Custom Action component registration is a one-time process done using the IGoogleDesktopRegistrar interface, and should be done during component installation. As part of the registration process, the component must provide its GUID as well as information about itself.

As part of its own uninstallation process, a component should unregister itself with Google Desktop.

Component Registration Interface Summary

The following summarizes the interface and its methods. All method return values are of type HRESULT.

interface IGoogleDesktopRegistrar: IDispatch

Note: Components are required to to call this interface to register themselves with Google Desktop before they can interact with any APIs or other provided services.

Note: The registration process consists of a call to StartComponentRegistration followed by individual registrations for various services obtained through GetRegistrationInterface and finished by a call to FinishComponentRegistration. For action components, the registration progid is "GoogleDesktop.ActionRegistration" and the interface is IGoogleDesktopRegisterCustomAction.

  • StartComponentRegistration: Must be invoked by any component to initiate the registration process.
    • Arguments:
      • BSTR component_guid_or_progid: The component's GUID or ProgID.
      • VARIANT component_description: A SAFEARRAY of pairs, where the first element is a descriptive parameter name and the second element is that parameter's value. The method expects only the following three required parameters, which should be given in this order.
        • "Title": Component title that will be displayed on the Google Desktop preferences page.
        • "Description": Component description that will be displayed on the Google Desktop preferences page.
        • "Icon": A string pointing to an ICON resource, of the form "c:\program files\boo\comp.dll,23". This icon may be used to indicate the component and its results on various Google Desktop pages.
    • Returns:
      • S_OK if successful.
      • E_COMPONENT_ALREADY_REGISTERED if this component has already been registered with Google Desktop.
      • Appropriate error on failure, such as an unregistered component classID or appID, component prohibited by policy, etc.

  • GetRegistrationInterface: Provides the requested type of registration interface.
    • Arguments:
      • BSTR registration_type: a stringified CLSID or a progid to the type of registration required.
      • [out, retval] IUnknown **registration_interface: provides the requested registration mechanism.
    • Returns:
      • S_OK if successful.
      • Appropriate error on failure.

  • FinishComponentRegistration: Must be invoked to finish the registration process.
    • Returns:
      • S_OK if successful.
      • Appropriate error on failure, such as an unregistered component classID or appID, component prohibited by policy, etc.

  • UnregisterComponent
    • Arguments:
      • BSTR component_guid_or_progid: the same GUID used when registering the component.
    • Returns:
      • S_OK if successful.
      • Appropriate error on failure.

Component Registration Code Template

The following template demonstrates how a component can register to handle the "Reply" action for emails. Note that this registration should only be done once, not every time the plug-in starts.

To register a component:

CComPtr<IGoogleDesktopRegistrar> spRegistrar;

HRESULT hr = spRegistrar.CoCreateInstance(CLSID_GoogleDesktopRegistrar);

if (SUCCEEDED(hr)) {
  ATLASSERT(spRegistrar != NULL);
  
  // Component description is 6 strings
  CComSafeArray<VARIANT> arr_descr(6);

  arr_descr.SetAt(0, CComVariant(L"Title"));
  arr_descr.SetAt(1, CComVariant(L"A sample action plug-in"));
  arr_descr.SetAt(2, CComVariant(L"Description"));
  arr_descr.SetAt(3, CComVariant(L"Implements sample custom actions"));
  arr_descr.SetAt(4, CComVariant(L"Icon"));
  arr_descr.SetAt(5, CComVariant(L",1"));

  // our CLSID in string format
  CComBSTR our_clsid(clsid);
  
  // Wrap description array in variant
  CComVariant descr(arr_descr.m_psa);

  // and register
  hr = spRegistrar->StartComponentRegistration(our_clsid, descr);
  if (FAILED(hr))
    return hr;

  // success, now register as a action component.
  // This two step registration allows the same plug-in to implement multiple
  // components
  CComPtr<IGoogleDesktopRegisterCustomAction> spRegistration;

  CComBSTR action_registrar_progid("GoogleDesktop.ActionRegistration");
  hr = spRegistrar->GetRegistrationInterface(action_registrar_progid,
    reinterpret_cast<IUnknown**>(&spRegistration));
  ATLASSERT(FAILED(hr) || spRegistration);

  if (SUCCEEDED(hr)) {
    CComVariant var;
    hr = spRegistration->RegisterAction(CComBSTR(CLSID_EmailActions), 
                  CComBSTR(ACTION_EMAIL_REPLY), CComVariant());

    if (SUCCEEDED(hr)) {
      hr = spRegistrar->FinishComponentRegistration();
    }
  }

To unregister a component:

CComPtr<IGoogleDesktopRegistrar> spRegistrar;
HRESULT hr;

hr = spRegistrar.CoCreateInstance(CLSID_GoogleDesktopRegistrar);

if (SUCCEEDED(hr)) { 
  // our CLSID in string format
  CComBSTR bstrClsid(clsid);
  hr = spRegistrar->UnregisterComponent(bstrClsid);
}

Back to top

Implementing and Handling Custom Actions

After a successful registration with Google Desktop, a component can use the Custom Action APIs to implement and override the default actions for specific user actions.

The Action API consists of a COM interface, which must be exposed by plug-ins wishing to implement custom actions. Whenever a custom action is rendered Google Desktop will query registered plug-ins about their interest in the action — whether to change the action title and whether to override or perform the default action. Please note that the custom action plug-ins will be loaded in a COM multi-threaded apartment.

interface IGoogleDesktopCustomAction: IUnknown
  • QueryInterest: Invoked when an action is being rendered to query for the plug-ins interest in the action.
    • Arguments:
      • ACTION_LOCATION location: The GUID identifier for the location where the action is being rendered (ACTION_LOCATION_ALL is a wildcard and currently the only supported location).
      • ACTION_ID action: The GUID for the action queried (e.g., ACTION_EMAIL_REPLY, ACTION_EMAIL_REPLY, ACTION_EMAIL_FORWARD).
      • BSTR query_string: The query string, if applicable and if allowed by the user's preferences. Note: we will not implement a preference to disallow this parameter in this iteration.
      • IUnknown * item: An interface to the item being rendered, most commonly a IGoogleDesktopNotifyEvent.
      • [in, out] BSTR * action_title: If the action is handled, this string will be displayed as the action title. On input this contains the default title for the current language.
      • [out] BSTR * action_cookie: A string which will be handed back to the object if the action is performed. This could be an item specific property (e.g., "uri", "cookie") or any string combination
      • [out] ActionHandling * handling: Specifies whether and how the action should be handled (e.g., ACTION_HANDLING_DEFAULT, ACTION_HANDLING_QUENCH, ACTION_HANDLING_OVERRIDE).
    • Returns:
      • S_OK in all cases.
      • An error return may result in the removal of the plug-in's registration for this action, or until Google Desktop is restarted.
  • HandleAction: Invoked when an action needs to be performed.
    • Arguments:
      • ACTION_LOCATION location: The identifier for the location where the action was rendered.
      • ACTION_ID action: The identifier for the action to perform.
      • BSTR query_string: The query string, if applicable and if allowed by the user's preferences.
      • IUnknown * item: An interface to the item who is rendered, most frequently this is IGoogleDesktopNotifyEvent. May be NULL in cases where it's not feasible to pass back the same instance as in QueryInterest.
      • BSTR action_cookie: The string cookie the plug-in provided in the call from QueryInterest.
    • Returns:
      • S_OK if successful.
      • Appropriate error on failure.

Action Code Template

The following template demonstrates how a component can implement the methods on the IGoogleDesktopCustomAction interface.

When QueryInterest is invoked for an email message the plug-in will override Forward and quench Reply.

/// IGoogleDesktopCustomAction
STDMETHOD(QueryInterest)( 
    /* [in] */ ACTION_LOCATION location,
    /* [in] */ ACTION_ID action,
    /* [in] */ BSTR query_string,
    /* [in] */ IUnknown *item,
    /* [out][in] */ BSTR *action_title,
    /* [out] */ BSTR *action_cookie,
    /* [out] */ ActionHandling *handling) {
    ATLASSERT(NULL != query_string);
    ATLASSERT(NULL != action_title && NULL != *action_title);
    ATLASSERT(NULL != action_cookie && NULL == *action_cookie);
    ATLASSERT(NULL != handling);
    
    /// Override Forward always, quench reply always
    if (IsEqualGUID(action, ACTION_EMAIL_FORWARD)) {
      ATLASSERT(NULL != item);
      *action_cookie = ::SysAllocString(L"Email Forward");
      *handling = ACTION_HANDLING_OVERRIDE;

    } else if (IsEqualGUID(action, ACTION_EMAIL_REPLY)) {
      *handling = ACTION_HANDLING_QUENCH;

    } else {
      /// unknown 
      ATLASSERT(false && "Unregistered action in QueryInterest");
      *handling = ACTION_HANDLING_DEFAULT;
    }

    return S_OK;
  }		

When HandleAction is invoked the plug-in will simply display a message box with the query and action strings.

/// IGoogleDesktopCustomAction
STDMETHOD(HandleAction)( 
  /* [in] */ ACTION_LOCATION location,
  /* [in] */ ACTION_ID action,
  /* [in] */ BSTR query_string,
  /* [in] */ IUnknown *item,
  /* [in] */ BSTR action_cookie) {
  /// Action processing displays a message box.
  CString str;
  str.Format(_T("Query: %ws, action: %ws"), query_string, action_cookie);
  MessageBox(NULL, str, _T("Action!"), MB_OK | MB_SERVICE_NOTIFICATION);

  return S_OK;
}

Back to top