Tips for building MS Office 2007 – 2000 toolbars,
ribbon tabs, popup menu and task panes in Delphi

Add-in Express
for Borland VCL


Add-in Express Home > Add-in Express VCL > Online Guide > COM add-in tips

Add-in Express VCL tips

How to build Office add-in in Delphi- video You might have an impression that developing add-ins is a very simple task. Please don't get too enthusiastic. Yes, Add-in Express for Delphi makes embedding your code into Office applications very easy, but you have to write applied code yourself, and we guess it might be something more intricate than a single call of ShowMessage.

Below you will find some tips for building Outlook command bars and popup menus, creating Office 2007 task panes and ribbon controls that may be helpful in your Office development in Delphi.

Terminology

In this Developer's Guide and in all our txt files we use the terminology suggested by Microsoft for all toolbars, their controls, and for all interfaces of Office Type Library. For example:

  • CommandBar is a toolbar or a menu bar;
  • CommandBar control is one of the following: a button, an edit box, a combo box, and a popup.
  • Pop-up can stand for a pop-up menu, a popup button on a command bar or a submenu on a menu bar.

Add-in Express VCL uses interfaces from the Office Type Library. So, please refer to the VBAOFF9.CHM (Office 2000) file and to the Office Type Library.

General tips:

Command bars & controls tips:

Getting help on COM objects, properties and methods

To get assistance with host applications’ objects, their properties and methods as well as help info, use the Object Browser. Go to the VBA environment (in the host application, choose menu Tools / Macro / Visual Basic Editor or just press Alt+F11), press F2, select the host application (also Office and MSForms) in the topmost combo and/or specify a search string in the search combo.

How to access the add-in host applications

Add-in Express allows accessing host applications through the add-in module's <HostName>App properties generated by the wizards. They return the Application object (of the OleVariant type) of the host application the add-in is currently running in. You use them to access, say, the current Excel list by calling ExcelApp.ActiveSheet or you can access an active explorer by calling OutlookApp.ActiveExplorer.

Unfortunately, we can't describe here in more detail how to work with all interfaces of the MS Office applications. The reason is simple - there are too many of them (you can count yourself: Excel, Word, Outlook, PowerPoint, Access, Project, FrontPage, MapPoint, Visio). So we recommend you using the VBA online help of Office applications. And remember about early binding and imported type libraries used by Add-in Express.

Also, to identify the host application, you can also use the HostType property of the module.

Registry entries

COM Add-ins registry entries are located in the following registry branches:

HKEY_CURRENT_USER\Software\Microsoft\Office\<OfficeApplication>\AddIns\<Add-in ProgID>
HKEY_CLASSES_ROOT\CLSID\<Add-in Express Project GUID>

Make command bar appear in some or all host applications

Use the CommandBar.SupportedAppsthis property to specify if the command bar will appear in some or all host applications supported by the add-in.

My add-in is always disconnected

If your Delphi add-in fires exceptions at the startup, the host application can block the add-in and move it to the Disabled Items list. To find the list, in the host application, go to "Help", then "About". At the bottom of the About dialog, there is the Disabled Items button. Check it to see if the add-in is listed there (if so, select it and click the enable button).

Update speed for an RTD server

Microsoft limits the minimal interval between updates to 2 seconds. There is a way to change this minimum value but Microsoft doesn't recommend doing this.

Sequence of events when a task pane shows

  AddinModule.OnTaskPaneBeforeCreate
  AddinModule.OnTaskPaneAfterCreate
  AddinModule.OnTaskPaneBeforeShow
  TaskPane.OnVisibleStateChange
  AddinModule.OnTaskPaneAfterShow

Adding a task pane to an existing Add-in Express project

Add an instance of ActiveForm to the project (File | New | Other | ActiveX | Active Form), then change its AxBorderStyle property to afbNone. Add the following declaration to the private section of the ActiveForm

procedure WMMouseActivate(var Message: TWMMouseActivate); 
message WM_MOUSEACTIVATE;

Change the method code as follows:


var
  FocusedWindow: HWND;
  CursorPos: TPoint;
begin
  inherited;
  FocusedWindow := Windows.GetFocus;
  if not SearchForHWND(Self, FocusedWindow) then begin
    Windows.GetCursorPos(CursorPos);
    FocusedWindow := WindowFromPoint(CursorPos);
    Windows.SetFocus(FocusedWindow);
    Message.Result := MA_ACTIVATE;
  end;

Add the following function used by the WMMouseActivate method (place it before the method):


function SearchForHWND(const AControl: TWinControl; Focused: HWND): boolean;
var
  i: Integer;
begin
  Result := (AControl.Handle = Focused);
  if not Result then
    for i := 0 to AControl.ControlCount - 1 do
      if AControl.Controls[i] is TWinControl then begin
        if TWinControl(AControl.Controls[i]).Handle = Focused then begin
          Result := True;
          Break;
        end
        else
          if TWinControl(AControl.Controls[i]).ControlCount > 0 then begin
            Result := SearchForHWND(TWinControl(AControl.Controls[i]), Focused);
            if Result then Break;
          end;
      end;
end;

Add and override the ActiveForm destructor using the following code:


destructor TMyTaskPane.Destroy;
var
  ParkingHandle: HWND;
begin
  ParkingHandle := FindWindowEx(0, 0, 'DAXParkingWindow', nil);
  if ParkingHandle <> 0 then
    SendMessage(ParkingHandle, WM_CLOSE, 0, 0);
  inherited Destroy;
end;

Now you add an item to the TaskPanes collection of AddinModule and set its ControlProgID property to the ProgID of the Active Form – just select it in the dropdown list. Don't forget about the Title property – the host application generates an exception if this property is left empty. Finally, clear the Target File Extension field in the project properties (Project | Options | Application). More about custom task panes.

Debugging add-ins

Unfortunately, the Delphi debugger is not able to debug DLLs when the path to these files is too long. To debug your add-ins, just indicate the root of one of the logical drives as the destination path (the Output Directory parameter) in the Project Options window. And remember to indicate the host application in "Run | Parameters".

Add the COM add-in command to a toolbar or menu

To add the COM Add-ins command to a toolbar or menu you do the following:

  • Open the host application (Outlook, Excel, Word, etc).
  • On the Tools menu, click Customize.
  • Click the Commands tab. 
  • In the Categories list, click the Tools category.
  • In the Commands list, click COM Add-Ins and drag it to a toolbar or menu of your choice.

Sharing Office 2007 ribbon controls across multiple add-ins

First off, you assign a string value to the TAddinModule.Namespace property. This makes Add-in Express to add two xmlns attributes to the customUI tag in the resulting xml markup:

  • xmlns:default="%ProgId of your add-in, say TAddinModule.COMAddInClassFactory.ProgID%",
  • xmlns:shared="%the value of the TAddinModule.Namespace property%".

Originally, all the Ribbon controls are located in the default namespace (id="%Ribbon control's id%" or idQ="default:%Ribbon control's id%") and you have full control over them via the callbacks provided by Add-in Express. When you specify the Namespace property, Add-in Express changes the markup to use idQ's instead of id's.

Then, in all the add-ins that should share a Ribbon control, for the control with the same Id (you can change the Id's to match), you set the Shared property to True. For the Ribbon control whose Shared property is True, Add-in Express changes its idQ to use the shared namespace (idQ="shared:%Ribbon control's id%") instead of the default one. Also, for such Ribbon controls, Add-in Express cuts out all the callbacks and replaces them with "static" versions of the attributes. Say, getVisible="GetVisible_CallBack" will be replaced with visible="%value%".

The shareable Ribbon controls are the following Ribbon container controls: 

  • Ribbon Tab - TadxRibbonTab
  • Ribbon Box - TadxRibbonBox
  • Ribbon Group - TadxRibbonGroup
  • Ribbon Button Group - TadxRibbonButtonGroup

When referring to a shared Ribbon control in the BeforeId and AfterId properties of another Ribbon control, you use the shared controls' idQ: %namespace abbreviation% + ':' + %control id%. The abbreviations of these namespaces are available in the adxDefaultNS and adxSharedNS constants ('default' and 'shared' string values).

Resulting Xml markup may look like this:


<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" 
          xmlns:default="MyOutlookAddin1.coMyOutlookAddin1" 
          xmlns:shared="MyNameSpace" [callbacks omitted]>
 <ribbon>
  <tabs>
   <tab idQ=" shared:adxRibbonTab1" visible="true" label="My Tab">
    <group idQ="default:adxRibbonGroup1" [callbacks omitted]>
     <button idQ="default:adxRibbonButton1" [callbacks omitted]/>
    </group>
   </tab>
  </tabs>
 </ribbon>
</customUI>

More about customizing Office 2007 Ribbon UI

ControlTag property vs. Tag property

Add-in Express identifies all its controls (command bar controls) through the use of the ControlTag property (the Tag property of the CommandBarControl interface). The value of this property is generated automatically and you don’t need to change it. For your own needs, use the Tag property instead.

Pop-ups

According to the Microsoft’s terminology, the term “pop-up” can be used for several controls: pop-up menu, pop-up button, and submenu. With Add-in Express you can create your own pop-up as an element of your controls command bar collection and add to it any control via the Controls property. But pop-ups have a feature that is very annoying: if an edit box or a combo box is added to a pop-up, their events are fired very oddly. Don’t regard this bug as that of Add-in Express. It seems to be intended by MS.

Edits and combo boxes and the Change event

The Change event appears only when the value was changed and the focus was shifted. This is also not our bug but MS guys’ “trick”.

Built-in controls and command bars

You can connect an Add-in Express command bar instance to any built-in command bar. For example, you can add your own controls to the "Standard" command bar or remove some controls from it. To do this just add to the add-in module a new Add-in Express Command Bar instance and specify the name of the built-in command bar you need via the CommandBarName property.

In addition, you can add any built-in controls to your own command bars. To do this just add an ADXCommandBarControl instance to the ADXCommandBar.Controls collection and specify the Id of the built-in control you need via the Id property.

Outlook command bar visibility rules

You can use the FolderName(s) and ItemTypes properties to bind your toolbars to certain Outlook folders. Your toolbar is shown for a folder:

  • If its full name (includes the folder path) is found in the FolderName or FolderNames properties.
  • Or, if the folder type is found in the ItemTypes property.

Removing custom command bars and controls

Add-in Express removes custom command bars and controls while add-in is uninstalled. However, this doesn’t apply to Outlook and Access add-ins. You should set the Temporary property of custom command bars (and controls) to true to notify the host application that it can remove them itself. If you need to remove a toolbar or button yourself, use the Tools | Customize dialog.

Registering with user privileges

When you use this option of the Add-in Express project wizard, all COM objects are registered in HKCU/Software/Classes instead of HKLM/Software/Classes. This allows registering COM objects with non-admin privileges.

To support this option, Add-in Express modifies the code of the <project name>.dpr file and creates a special <project name>.ini. When you deploy the project created with this option, you should place the <project name>.ini and <project name>.dll files in the same location.

Restrictions:

  • This works on Windows 2000+ only.
  • The TAddinModule.RegisterForAllUsers property is ignored if you use the Register with User Privileges option.
  • RTD Servers in EXE cannot be registered for the current user, so this option will be ignored if chosen.

When modifying existing projects, do the following:

  • Add the following code to the <project name>.dpr file:
...
uses
...
ComObj, Windows, adxAddIn,
...

type
  TDummyComServer = class(TObject)
  private
    procedure FactoryRegister(Factory: TComObjectFactory);
    procedure FactoryUnRegister(Factory: TComObjectFactory);
  end;

procedure TDummyComServer.FactoryRegister(Factory: TComObjectFactory);
begin
  UpdateFactory(Factory, True);
end;

procedure TDummyComServer.FactoryUnRegister(Factory: TComObjectFactory);
begin
  UpdateFactory(Factory, False);
end;

function DllRegisterServer: HResult;
begin
  Result := E_FAIL;
  try
    if CheckConfigSection() then begin
      RegisterToHKCU := True;
      with TDummyComServer.Create do
        try
          ComClassManager.ForEachFactory(ComServer, FactoryRegister);
        finally
          Free;
        end;
      Result := S_OK;
    end;
  except
  end;
  if Result <> S_OK then Result := ComServ.DllRegisterServer();
end;

function DllUnregisterServer: HResult;
begin
  Result := E_FAIL;
  try
    if CheckConfigSection() then begin
      RegisterToHKCU := True;
      with TDummyComServer.Create do
        try
          ComClassManager.ForEachFactory(ComServer, FactoryUnRegister);
        finally
          Free;
        end;
      Result := S_OK;
    end;
  except
  end;
  if Result <> S_OK then Result := ComServ.DllUnregisterServer();
end;

exports
...
  • Create the <project name>.ini file in the project directory and modify its contents as follows:

[Config]
Privileges=User

Final remark

If your questions are not answered here, please see the Delphi HOWTOs for Outlook, Excel, Word which are regularly updated.

Creating your first Office add-in in Delphi <<

>> Building Outlook plugins

Back to Add-in Express VCL homepage




Client login

 

Login 

Password 

 

Remember me

Forgot my password