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)
To implement Custom Actions and integrate your application with Google Desktop you will need, in addition to the information in this document:
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:
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.
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.
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.
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.
S_OK
if successful.
E_COMPONENT_ALREADY_REGISTERED
if this component has
already been registered with Google Desktop.
GetRegistrationInterface
: Provides the requested type
of registration interface.
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.
S_OK
if successful.
FinishComponentRegistration
: Must be invoked to finish
the registration process.
S_OK
if successful.
UnregisterComponent
BSTR component_guid_or_progid
: the same GUID used when
registering the component.
S_OK
if successful.
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); }
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.
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).S_OK
in all cases.
HandleAction
: Invoked when an action needs to be
performed.
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.S_OK
if successful.
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; }