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
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.
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.
Back to Add-in Express VCL homepage

