Delphi tips for Office toolbar,
ribbon tabs, popup menu and task panes

Add-in Express™
for Microsoft® Office and Delphi® VCL

Add-in Express Home > Add-in Express for Office and Delphi VCL > Online Guide > Office COM add-in tips

Tips and tricks

On this page you will find some tips and tricks that may find useful in your Office development.

Command bars & controls:

Debugging & deployment:

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 a new Add-in Express Command Bar instance to the add-in module 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.

Temporary or not?

According to the help reference for the Office object model contained within Office.DLL ( see Getting help on COM objects, properties and methods), temporary command bars and controls are removed by the host application when it is closed.

Normally, the developer has the following alternative: if command bars and controls are temporary, they are recreated whenever the add-in starts; if they are non-temporary, the installer removes those command bars and controls from the host. Looking from another angle, you will see that the real alternative is the time required for start-up against the time required for uninstalling the add-in (the host must be run to remove command bars).

Outlook and Word are two exceptions. It is strongly recommended that you use temporary command bars and controls in Outlook add-ins. If they are non-temporary, Add-in Express must run Outlook to remove them. Now imagine password-protected PST and multiple-profile scenarios.

In Word add-ins, we strongly advise making both command bars and controls non-temporary. Word removes temporary command bars. However, it does not remove temporary command bar controls, at least not all of them. When the add-in starts for the second time, Add-in Express finds such controls and just connects to them. In this way, it processes the user-moved-or-deleted-the-control scenario. Accordingly, the controls are missing in the UI.

Note that main and context menus are command bars. That is, in Word add-ins, custom controls added to these components must have Temporary = False as well. If you set Temporary to true for such controls, they will not be removed when you uninstall your add-in. That happens because Word has another peculiarity: it saves temporary controls when they are added to a built-in command bar. And all context menus are built-in command bars. To remove such controls, you will have to write some code or use a simple way: set Temporary to false for all controls, register the add-in on the affected PC, run Word. At this moment, the add-in finds this control and traces it from this moment on. Accordingly, when you unregister the add-in, the control is removed in a standard way.

CommandBar.SupportedApps

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

ControlTag 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.

However, pop-ups have an annoying feature: if an edit box or a combo box is added to a pop-up, their events are fired very oddly. Please don't regard this bug as that of Add-in Express.

Edits and combo boxes and the Change event

The Change event occurs only when the value is changed and the focus is moved off the combobox. This is by design.

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.

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>

See also How to find if Office 2010 64-bit is installed on the target machine

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).

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

GDIPLUS.DLL

This is the Microsoft Windows GDI+ library providing two-dimensional vector graphics, imaging, typography, etc. GDI+ improves on the Windows Graphics Device Interface (GDI) by adding new features and by optimizing existing features. It is required as a redistributable for COM Add-ins based on Add-in Express for VCL that run on the following operating systems: Microsoft Windows NT 4.0 SP6, Windows 2000, Windows 98, and Windows Millennium Edition (Windows Me).

This file must be located in the folder where your COM add-in is registered.

How to find if Office 64-bit is installed on the target machine

Remember that the 64-bit version of Office 2010, 2013 and 2016 can be installed on Windows 64-bit only. If Outlook is installed, then the value below exists in this registry key:

Outlook 2010 - 2016:
Key: HKLM\SOFTWARE\Microsoft\Office\{14 or 15}.0\Outlook\InstallRoot
Value name: Bitness
That value can be "x64" or "x86"; "x64" means Outlook 64-bit is installed.

If Outlook is not installed, you can check the following values in the following 64-bit registry key:

Excel, Word, PowerPoint 2010 - 2016:
Key: HKLM\Microsoft\Office\{14 or 15}.0\{application}\InstallRoot
Value name: Path
If that value exists, then the corresponding 64-bit application is installed.

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.

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.

COM Add-ins dialog

In Office 2010 - 2016 you click File Tab | Options and, on the Add-ins tab, choose COM Add-ins in the Manage dropdown and click Go.

In version 2007 of Word, Excel, PowerPoint and Access you click the Office Menu button, then click {Office application} options and choose the Add-ins tab. Now choose COM Add-ins in the Manage dropdown and click Go.

In all other Office applications, you need to add the COM Add-ins command to a toolbar or menu of your choice. To do so, follow the steps below:

  • 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.

In Office 2000-2003, this dialog shows add-in registered in HKCU only. In Office 2007 - 2016, HKLM-registered add-ins are shown as well.

New Items dialog

Add-in Express for Office and Delphi VCL adds several project templates to the Add-in Express VCL tab of the New Items dialog. To see the dialog, choose File | New | Other... in the menu.

New Items dialog

Whichever Add-in Express project template you choose, it starts the project wizard that allows specifying parameters of your project. The project wizard creates a new project and opens it in the Delphi IDE. The project contains an appropriate module. There are several designer types responsible for common tasks in customizing Office. Project-specific modules are the core components of Add-in Express. You can add any components onto the modules.

Don't use any Office object models in the OnCreate and OnDestroy events

Although the add-in module provides the OnCreate and OnDestroy events, using them is not recommended. The reason is simple: an instance of the module is created when you register/unregister the add-in. And there is no guarantee that the host application of your add-in will be loaded at that time.

How to get access to the add-in host applications

In the add-in module, Add-in Express wizards generate the <HostName> App properties. They return the Application object (of the OleVariant type) of the host application in which the add-in is currently running. To identify the host application, you can also use the HostType property of the module.

Excel workbooks

Sometimes you need to automate a given Excel workbook (template). You can do it with TadxExcelSheetModule that represents one worksheet of the workbook. For the module to recognize the workbook, you need to fill the following properties: Document, Worksheet, PropertyID, and PropertyValue. When you fill the PropertyID and PropertyValue properties, the design-time code of the module creates the property in the workbook and specifies its value.

A typical scenario of the module usage includes creating the workbook and designing it with MS Forms controls. Accordingly, in the IDE, you set up the PropertyID and PropertyValue properties, add Add-in Express MSForms control components to the module and bind them to the MS Forms controls on the worksheet. The module provides a full set of events available for the Excel Workbook class.

For the Add-in Express components available for the module see the following chapters: Command Bars: Toolbars, Menus, and Context Menus, Command Bar Controls, Built-in Control Connector, MSForms Controls, and Host Application Events.

Word documents

To automate a given Word document, you use the TadxWordDocumentModule. For the module to recognize the document, you need to fill the following properties: Document, PropertyID, and PropertyValue. When you fill the PropertyID and PropertyValue properties, the design-time code of the module creates the property in the document and specifies its value.

A typical scenario of the module usage includes creating a document and designing it with MS Forms controls. Accordingly, in the IDE, you set up PropertyID and PropertyValue properties, add Add-in Express MSForms control components to the module and bind them to the MS Forms controls on the document. The module provides a full set of events available for the Word Document class.

For the Add-in Express components available for the module see the following chapters: Command Bars: Toolbars, Menus, and Context Menus, Command Bar Controls, Built-in Control Connector, MSForms Controls, and Host Application Events. The module provides a full set of events available for a Word document.

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 an Office 2007 task pane shows up

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

Adding an Office 2007 task pane to an existing Add-in Express project

  • Add an instance of ActiveForm to the project (File | New | Other | ActiveX | Active Form)
  • 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 to the following:

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 TAddinModule and set its ControlProgID property to the ProgID of the ActiveForm - just select it from the dropdown list.
  • Remember about the Title property - the host application generates an exception if this property is left empty.
  • Clear the Target File Extension field in the project properties (Project | Options | Application).

Useful resources

If your questions are not answered here, please look for the code example on the How-To pages:

Excel Automation add-ins <<