You are on page 1of 52




2008 Adobe Systems Incorporated. All rights reserved.

Adobe InDesign CS4 Porting Guide
If this guide is distributed with software that includes an end user agreement, this guide, as well as the software described in it, is furnished under license and may be
used or copied only in accordance with the terms of such license. Except as permitted by any such license, no part of this guide may be reproduced, stored in a retrieval
system, or transmitted, in any form or by any means, electronic, mechanical, recording, or otherwise, without the prior written permission of Adobe Systems
Incorporated. Please note that the content in this guide is protected under copyright law even if it is not distributed with software that includes an end user license
The content of this guide is furnished for informational use only, is subject to change without notice, and should not be construed as a commitment by Adobe Systems
Incorporated. Adobe Systems Incorporated assumes no responsibility or liability for any errors or inaccuracies that may appear in the informational content
contained in this guide.
Please remember that existing artwork or images that you may want to include in your project may be protected under copyright law. The unauthorized incorporation
of such material into your new work could be a violation of the rights of the copyright owner. Please be sure to obtain any permission required from the copyright
Any references to company names in sample templates are for demonstration purposes only and are not intended to refer to any actual organization.
Adobe, the Adobe logo, Adobe Bridge, Creative Suite, InCopy, InDesign, Reader, and Version Cue are either registered trademarks or trademarks of Adobe Systems
Incorporated in the United States and/or other countries. Microsoft and Windows are either registered trademarks or trademarks of Microsoft Corporation in the
United States and/or other countries. Macintosh and Mac OS are trademarks of Apple Computer, Incorporated, registered in the United States and other countries.
All other trademarks are the property of their respective owners.
Adobe Systems Incorporated, 345 Park Avenue, San Jose, California 95110, USA. Notice to U.S. Government End Users. The Software and Documentation are
Commercial Items, as that term is defined at 48 C.F.R. 2.101, consisting of Commercial Computer Software and Commercial Computer Software
Documentation, as such terms are used in 48 C.F.R. 12.212 or 48 C.F.R. 227.7202, as applicable. Consistent with 48 C.F.R. 12.212 or 48 C.F.R. 227.7202-1
through 227.7202-4, as applicable, the Commercial Computer Software and Commercial Computer Software Documentation are being licensed to U.S. Government
end users (a) only as Commercial Items and (b) with only those rights as are granted to all other end users pursuant to the terms and conditions herein.
Unpublished-rights reserved under the copyright laws of the United States. Adobe Systems Incorporated, 345 Park Avenue, San Jose, CA 95110-2704, USA. For U.S.
Government End Users, Adobe agrees to comply with all applicable equal opportunity laws including, if appropriate, the provisions of Executive Order 11246, as
amended, Section 402 of the Vietnam Era Veterans Readjustment Assistance Act of 1974 (38 USC 4212), and Section 503 of the Rehabilitation Act of 1973, as
amended, and the regulations at 41 CFR Parts 60-1 through 60-60, 60-250, and 60-741. The affirmative action clause and regulations contained in the preceding
sentence shall be incorporated by reference.


Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Before you begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Notation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Key concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Major Changes in CS4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Links Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Summary of changes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
What is a link in InDesign? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Frequently asked questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Porting CS3 links to the CS4 links architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
doScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
IScriptRunner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
IScriptEngine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
IScriptProvider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
IScriptErrorUtils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
IScriptEventData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Metadata resource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
RepresentScriptProvider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Text-attribute scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
TypeDef and TypeDefType . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Changes to Support Rotated Spreads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
A new enumerator for commonly referenced coordinate systems . . . . . . . . . . . . . . . . . . 32
ISpread::GetPagesBounds and ILayoutUtils::GetIntersectingPageUID . . . . . . . . . . . . . . . . 33
IShape::GetPaintedBBox and GetPrintedBBOx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
IMasterSpreadUtils::AppendMasterPageItems. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
IDrawMgr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
gSession Removed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
User Interface APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Workspace preference reading/writing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Palette management. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Document management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36


General Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
SDK folder structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
MLocaleIds.h and WLocaleIds.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Replace gSession with GetExecutionContextSession() . . . . . . . . . . . . . . . . . . . . . . . . . 40
Bring resource definitions up-to-date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
PMString constructor change . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Replace IScriptEventData::SetReturnData. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Utility APIs are accessed only through kUtilsBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
XCode Warning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Porting Recipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
IDFile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
IImportManager. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
IInCopyBridgeCmdSuite. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
ISnippetExport. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
IStaticTextAttributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
IStyleGroupListControlData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
ITextColumnSizer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
kInvalidUIDRef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
PMString . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Style matching. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
XML parser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Custom story thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
kHyperlinkTextMarkerBoss and kHyperlinkTextSourceEndMarkerBoss deprecated . . . . . . . 49
ISnippetExportSuite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Miscellaneous changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

Adobe InDesign CS4 Porting Guide

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

This document describes changes to plug-in code and development environments caused by
changes in the public API and other aspects of the SDK for the Adobe InDesign CS4 family of

Before you begin

Before you begin, do the following:
1. Read the introductory sections of this document, including Terminology on page 5.
2. Ensure your development environment meets the requirements to compile application
plug-ins. For Windows, you need Microsoft Visual C++ 8.0. For Mac OS, you need Apple
Xcode 2.4.1. For more information, see Required components on page 6.
3. Install the SDK, including the documentation. There are two valuable porting resources in
<SDK>/docs/references/: the .chm file containing all SDK documentation, and the APIAdvisor, APIAdvisorID5_vs_ID6.html. On Windows, you probably will use the built-in
Microsoft HTML Help viewer to view the CHM version of the SDK documentation. On
Mac OS, you can either decompress the TAR file and then use your browser to view the
HTML, or use a CHM viewer.
4. You should have a basic understanding of concepts related to links, scripting, and spreads,
and the InDesign API in general.


SDK root folder <SDK> refers to your local installed SDK root folder. The actual file path
of the root depends on the operating system.

Menu names For example, Tools > Options refers to the Options menu item in the Tools

Computer input or output, including source code, is presented in a monospace font. For
> sh
Cannot find specified file


API Application Programming Interface.

Adobe InDesign CS4 Porting Guide

Adobe InDesign CS4 Porting Guide


Application InDesign CS4, unless otherwise specified.

Applications Members of the InDesign CS4 family of applications (Adobe InDesign CS4,
Adobe InCopy CS4, and Adobe InDesign CS4 Server).

ODF OpenDoc Development Framework, a cross-platform software effort, initiated by

Apple and IBM, which defines an object-oriented extension of the Apple Rez language to
specify user-interface resources.

ODFRC OpenDoc Development Framework Resource Compiler, the compiler for framework resource .fr files. This is included with the SDK.

SDK Software development kit for the application.

Key concepts
SDK organization
The InDesign CS4 SDK inherits its folder structure from the InDesign CS3 SDK with a few
modifications as outlined in SDK folder structure on page 39.

Development environment
Table 1 lists the components required to build SDK plug-ins.
TABLE 1 Required components
Required component


Windows or Mac OS:

Applications: InDesign CS4,
InCopy CS4, InDesign CS4 Server

We recommend you have both the debug and

release applications. The debug application is
instrumented to detect bugs and is essential to
successful plug-in development.

OpenDoc Development
Framework Resource Compiler

Included with the InDesign SDK.

Adobe Reader 6.0 or later

For viewing PDF documents.

256 MB memory (minimum), 512

MB memory (recommended)
Pentium III or equivalent
(minimum), Pentium 4 or
equivalent (recommended)
Windows XP with Service Pack 2
Visual C++ 8

A component of Visual Studio 2005.

Adobe InDesign CS4 Porting Guide

Major Changes in CS4

Required component


Windows HTML Help (included

with Windows)

For viewing compiled HTML documentation


Mac OS:
G3 processor (minimum), G4
processor (recommended)
Mac OS 10.4 or later
Xcode 2.4.1
Apple Safari

To view the HTML version of the SDK reference

documentation in the sdkdocs.tar.gz file, you
must use a Web browser that understands long
Mac OS filenames. Current versions of Navigator
and Internet Explorer do not support long Mac
OS filenames in local href links.

CHM viewer

To view compiled HTML documentation

(index.chm) on Mac OS, you must use a CHM
viewer for Mac OS. Two such viewers are xCHM
(an open-source application found at and CHM
Viewer (a shareware application found at

Major Changes in CS4

The major CS4 modifications to the InDesign API include the following:

Links Architecture Restructuring See Links Architecture on page 8.

Scripting Undo See Scripting on page 24.

Rotated spreads See Changes to Support Rotated Spreads on page 32.

gSession removal See gSession Removed on page 35.

User Interface See User Interface APIs on page 36.

There also are changes that affect all plug-ins but do not involve a major feature change. These
are described in General Changes on page 39.

Adobe InDesign CS4 Porting Guide

Adobe InDesign CS4 Porting Guide

Links Architecture

Links Architecture
Datalink is re-engineered in CS4. The core mechanisms for storing and maintaining links was
replaced with new code. All pre-CS4 main datalink interfaces, like IDataLink and ICoreFilename, are deprecated.

Summary of changes
The new link architecture in CS4 offers the following advantages:

Removes the assumptions that all links are file-based, so we can support links to URLs,
databases, etc.

Provides three new link types import only, export only, and bi-directional.

Improves performance by providing asynchronous link-state updates.

Allows third-party developers to create custom links much more easily.

Improves the user experience by updating the Links UI panel.

What is a link in InDesign?

When you place a graphic file in an InDesign publication, InDesign does not include the
graphic file in the publication. Instead, it creates a page item to host the graphic object and
establishes a link between the page item and the graphic file. What you see on screen is a lowresolution proxy image of the graphic. A link helps InDesign avoid redundantly storing large
amounts of data in the publication, and it enables us to automatically update page items when
the external file is modified.
To see the link information associated with the page item, you need to display the Links UI
panel. If the current selected page item has an associated link, its link information is highlighted in the Links UI panel. The link information includes where the linked file comes from
and the links status.
When a user uses the default InDesign menu item File > Place..., the InDesign File Chooser
dialog appears, and when the user selects a file from the InDesign Place dialog, kImportAndLoadPlaceGunCmdBoss is processed. kImportAndLoadPlaceGunCmdBoss requires its client
to set up a command data-interface IImportResourceCmdData. IImportResourceCmdData
can store the UID of a link resource or a URI (Uniform Resource Identifier) that is a reference
to the link resource. The URI is used in a kImportResourceCmdBoss to create a link resource
from an URI. Internally, kImportResourceCmdBoss calls ILinkFacade::CreateResource to create the link resource from an URI, which in turn uses kLinkResourceCreateCmdBoss. Finally,
ILinkManager::CreateResource() is used to create the resource (kLinkResourceBoss) using the
InDesign link client ID.

A link client ID identifies a link client, You should use the same link client ID when
creating the link resource and the link. If you use kIDLinkClientID, the link shows up
in the Links UI panel. If you do not want to have your links in the Links UI panel, use
an ID other than kIDLinkClientID when you create the link and link resource.

Adobe InDesign CS4 Porting Guide

Links Architecture

The ILinkManager will query a resource handler based on the URIs scheme. The first resource
handler that knows how to handle (import, export, and resolve) the particular URI scheme is
used to import the resource. The resource handler is asked to supply a resources read stream,
and it is given to an import provider that knows how to import the particular file format. Once
the file is imported, a series of checks is performed to determine if a link is wanted before a link
is created. For example, by default, a text file always is embedded, not linked, unless it is an
Adobe InCopy file. Figure 1 illustrate the sequence of how the link and link resource are created during the processing of a kImportAndLoadPlaceGunCmdBoss.

Adobe InDesign CS4 Porting Guide

Adobe InDesign CS4 Porting Guide

Links Architecture

Link creation duing a kImportAndLoadPlaceGunCmdBoss

Create link resource

esource with the URI

Does link
oss) exist?



Check link resource state
Check using



link state is managed by
ILinkState on the link object
boss such as kTextStoryBoss.
If a link is wanted,
ILinkState::SetIsLinkWanted is
used to set the status.

available & a
valid read stream
is available



Link Resource queries

an IPMStream for read
from an

Determine if link is wanted

for the text le

Set link is wanted

ag to true


If the link


Is it InCopy

Set link is wanted

ag to
nkTextFiles on
doc's workspace


Identify an import
provider that knows
how to handle the le
format, and give it the
stream for import.

Import to an
existing page

Is link



Set link is wanted

ag to the P.I's old


Create link using





Is the import le
a text le?


Adobe InDesign CS4 Porting Guide

Links Architecture

What if you do not store your graphics as desktop files? For example, many workflows store
their assets in a database. The CS4 link architecture supports generalized, abstract links: it
allows data to come from a file, URL, database record, or any external or internal source that
can be read or written via a stream. In the remainder of this document, we refer to the resource
data as a link resource. Link resources are referenced using an abstract URI.

What is a link?
A link establishes a relationship between a linked resource and a link object. When an image is
placed in an InDesign publication, a link is created between the image file and the page item
that contains the image. Think of a link as a bridge that connects a source to a destination: on
one side is the link resource (the source), and we call the other, destination side the link object.
A link object should be an InDesign object, but it is not limited to a page item; it can be an
XML element, swatch, style set, chunk of text, etc.

Types of links
InDesign supports three types of links:

Import-only link This is represented by kImportLinkBoss, which maintains an import

association between an object and a linked resource. If the linked resource changes, the
object can be updated via an import.

Export-only link This is represented by kExportLinkBoss, which maintains an export

association between an object and a linked resource. If the object changes, the linked asset
can be updated via an export

Bi-directional link This is represented by kBidirectionalLinkBoss, which maintains a bidirectional association between an object and a linked resource. If the object changes, the
linked resource can be updated via an export. If the linked resource changes, the object can
be updated via an import. A bi-directional link requires conflict-resolution handling in the
case when both the object and the linked asset change.


There also is a kChildLinkBoss, whose purpose is to allow placing an InDesign

publication which may contains links. In this case, the links in the placed document
become a child link. You cannot update a child link directly; you must open the original
document to update the links it contains.

A link is created and maintained by ILinkManager. All the overridden ILinkManager::CreateLink methods create a link between a given link object and linked resource.

The ILink interface

All three link bosses aggregate a key interface, ILink, which establishes a relationship between a
link resource and a link object. A link resource is represented by kLinkResourceBoss, which
aggregates the ILinkResource interface. ILinkResource has methods to access and maintain a
linked resource. A link object is any boss that aggregates the ILinkObject interface. There is an
ILinkManager that manages linked resources and links
Figure 2 shows the relationship between a linked resource and linked object.

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

Links Architecture

Links object model




Linked resource and ILinkResourceHandler

A linked resource is referenced by a URI. According to the URI specification, a URI consists of
a hierarchical sequence of five components, referred to as the scheme, authority, path, query,
and fragment. For URI format syntax, see the specification (
There is an InDesign class, URI, which can be used to construct and parse a well formed URI.
The link architecture classifies link resources based on the link resources scheme from its URI.
All link resources of the same type must share the same scheme in their URIs. There should be
a link-resource handler (represented by ILinkResourceHandler) for each type of scheme available in InDesign. For example, most traditional InDesign datalinks are file-based links; i.e., the
link is between a page item and an external file established though a Place action. The link
resources for these type of links are the external file, and all their URIs have the scheme of
file; i.e., their URIs all look like file://path_to_file. During import (through Place), a
resource handler that knows how to handle URIs with a file scheme is used to create a
resource read stream, and the stream is given to an import provider that knows how to handle
the particular file format to import the resource.
What makes up a resource handler? A resource handler implements the ILinkResourceHandler
interface and is aggregated by a generic InDesign boss class. The convention to invoke a
resource handler is through a service-provider boss that supports the kLinkResourceService
service ID. In this service-provider boss, an ILinkResourceFactory should be aggregated. The
ILinkResourceFactory indicates what kind of URI scheme the resource handler can handle
through its GetSchemes method, and ILinkResourceFactory::QueryHandler returns an
instance of the handler upon request, based on a URI. For example, the CustomDataLink SDK
sample allows you to place assets specified in a CSV file. Since only CustomDataLink knows
how data is stored in the CSV file, it must implement a resource handler for assets from the
CSV. CustomDataLink defines its own URI that can uniquely identify any asset in the CSV.
CustomDataLinks resource handler knows how to retrieve data from the CSV based on the
URI. The URI defined in CustomDataLink has its own scheme, CSVLink, and its URI looks
something like this:

The resource handler in CustomDataLink declares it knows how to handle resources whose
URI scheme is CSVLink. When CustomDataLinks client asks to place a resource from the CSV,
CustomDataLink processes a kImportAndLoadPlaceGunCmdBoss by giving the command a
IImportResourceCmdData that consists of an URI to the resource client specified. kImportAndLoadPlaceGunCmdBoss does all the ground work for an import action; when it comes
time to import the real resource, it sends the URI to the link manager. The link manager que-


Adobe InDesign CS4 Porting Guide

Links Architecture

ries all the service providers that support kLinkResourceService, to see if anyone can handle a
URI scheme of CSVLink. Since CustomDataLink implements one, it is chosen to import the
data from the URI. The CustomDataLinks implementation of ILinkResourceHandler defines
methods like CreateResourceReadStream(), which returns an IPMStream to the resource to
which the selected CSV record points. Since CustomDataLink knows how to access the CSV,
given its own URI, it knows exactly what record its client is requesting and handles the request.
Table 2 lists the URI schemes handled by a default InDesign resource handler.
TABLE 2 InDesign URI schemes and their resource handler



Used when InDesign Place... is used to import file


For handling assets from Version Cue.


Used in assignment link

If you provide you own resource handler, you should implement your own Place dialog and
add it under your own Place menu.

Link object
A link object is any boss that aggregates the ILinkObject interface. ILinkObject is a proxy used
to represent the item in an InDesign publication being linked to; for example, a page item,
XML element, or range of text. Depending on the type of link associated with the item,
ILinkObject specifies how the item is imported, exported, or resolved. A link (ILink) stores the
UID of the link object with which it is associated, and the link object can be retrieved from the
ILink::GetObject() method. Normally, if your link object is a regular page item, it has an
ILinkObject with kPageItemLinkObjectImpl as its default implementation. kPageItemLinkObjectImpl specifies kPageItemUpdateLinkServiceProviderBoss as its import provider. When the
link needs an update, kPageItemUpdateLinkServiceProviderBoss is used to update the link.
Internally, kPageItemUpdateLinkServiceProviderBosss IUpdateLinkService implementation
(kPageItemUpdateLinkServiceImpl) processes a kReimportCmdBoss to update the link. Eventually, kReimportCmdBoss uses the link resources resource handler to provide a data stream to
the resource, just like the initial Place.
Table 3 lists the InDesign bosses that aggregates an ILinkObject by default.
TABLE 3 Default InDesign bosses that aggregates ILinkObject
Boss name












Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

Links Architecture

Boss name

















kJBXLinkObjectBoss also has kJBXLinkObjectImpl.

If you are trying to create a link on an object not listed in Table 3, make sure you aggregate
ILinkObject to the objects boss. The SDK sample ExtendedLink illustrates this situation, where
a link object is derived from kXMLLinkObjectReferenceBoss.

Link manager
There is a link manager, represented by ILinkManager, in every InDesign document (kDocBoss). ILinkManager is used to create and delete links and link resources. ILinkManager also
provides many ways to query links and link resources.
To query links through ILinkManager, first you should construct a LinkQuery object.
LinkQuery is a class that allows you to easily specify what you want the ILinkManager to
search for and pass the LinkQuery object to the ILinkManager::QueryLinks method. ILinkManager returns the query result in a ILinkManager::QueryResult, which is a std::vector that
contains the UID of the links. Once you have the UID of a link, you can query its ILink interface.
ILinkManager also uses the link client ID as a filter when it returns the LinkQuery result. If you
specify a client ID, ILinkManager::QueryLinks returns the link with the same client ID. This is
convenient if you used a unique client ID to identify your link and link resource: you can easily
query all your links with an empty LinkQuery and your client ID.
To query a link resource through ILinkManager, construct a LinkResourceQuery object.
LinkResourceQuery is similar to LinkQuery, in that it allows you to specify the criteria (such as
resource URI scheme) to look for when ILinkManager searches for a link resource in a document. Once you construct a LinkResourceQuery, you then pass it to ILinkManager::QueryResources for the query. ILinkManager also returns the query result in a

Link status
For every link resource handler made available in the link architecture through the kLinkResourceService service provider, you should provide an implementation of ILinkResourceStateUpdater, which provides the link manager with link-resource status information. There are
times when link manager will ask each link resource to provide a status update; for example,


Adobe InDesign CS4 Porting Guide

Links Architecture

when the application resumes from background to foreground. ILinkManager calls ILinkResourceStateUpdater::UpdateResourceStateAsync. ILinkResourceStateUpdater should be aggregated on the boss where ILinkResourceHandler is aggregated. In Linked resource and
ILinkResourceHandler on page 12, we discuss how ILinkResourceHandler normally is instantiated through the ILinkResourceFactory. ILinkResourceFactory has a method called QueryStateUpdater, which is used to instantiate a status updater for the URI scheme supported by the
same ILinkResourceFactory.
ILinkManager may call for a link-resource status report synchronously or asynchronously,
depending on the situation; therefore ILinkResourceStateUpdater declares two update methods: UpdateResourceStateSync and UpdateResourceStateAsync. In UpdateResourceStateSync,
the status update should be completed on the return of the function. In UpdateResourceStateAsync, it is expected that status update is done in the background or during idle time.
Both ILinkResourceStateUpdater::UpdateResourceStateSync and ILinkResourceStateUpdater::UpdateResourceStateAsync are passed in an UIDRef of a link resource (kLinkResourceBoss). ILinkResource stores resource-status information like resource state
(ILinkResource::ResourceState), modification time, and size.
Also, there is a stamp (of type ResourceStamp, which is essentially a WideString) stored in
ILinkResource. You can use the ResourceStamp to construct any custom stamp you need for
status-update purposes. ILinkResource has declared get/set methods for maintaining these
resource attributes.
In UpdateResourceStateSync/UpdateResourceStateAsync, a comparison should be made
between the link-resource object passed in and the external link resource (available from the
URI, which can be queried through the link-resource object). If you decide the link is out of
date, a kLinkResourceStateUpdateCmdBoss should be processed. This causes the link resource
to be updated with the new status data. The corresponding link (ILink) also maintains a
linked-resource modification state, which is set to ILink::kResourceModified, indicating the
link resource was modified since the last update. If the link is displayed in the Links UI panel,
the status shows it is out of date, and the Update Link option becomes available; this allows the
user to manually update the link on demand.

Each ILinkResourceStateUpdater implementation may have its own policy to decide

what should be regarded as a status change. For example, InDesigns
ILinkResourceStateUpdater for URI scheme file uses the files modification date and
file size as its criteria.

There are several approaches you can take to accomplish link-state updates. For example, Version Cue links are updating via a push approach. Version Cue notifies InDesign whenever the
state of a Version Cue link changes. File links use a pull approach to update link states, by getting current information from the file system. The SDK ExtLink sample uses an idle-taskbased solution. It is important to consider the case where there are many links in a document.
When the link architecture asks for a link-status update, it asks all links to provide updates;
therefore, the performance issue is critical and deserves a good implementation strategy.

Link update
When a link status is outdated, a link-update action becomes available. If the link information
is available on the Links UI panel, a contextual-menu item, Update Link, is enabled when a

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

Links Architecture

link is selected in the panel. When the Update Link menu action is selected on an import
link, kLinkUpdateCmdBoss is processed; this queries the ILink on the kImportLinkBoss and
calls its ILink::Update() method. Inside the ILink::Update(), it queries its associated link object
(ILinkObject) to see if there is an import provider available for the link object through the
ILinkObject::GetImportProvider(). If there is one, that import provider is used to re-import
the link resource; otherwise, ILinkObject::Import() is called. In ILinkObject::GetImportProvider(), you can specify a update-link service-provider boss that implements IUpdateLinkService or kInvalidClass. In the later case, you should then implement ILinkObject::Import. For
example, if the link object is a kPageItemLinkObjectImpl, it defines an kPageItemUpdateLinkServiceProviderBoss in its GetImportProvider, which is used to update the link. kPageItemUpdateLinkServiceProviderBoss processes a kReimportCmdBoss, which asks the link-resource
handler to create a read stream from the resource for import purposes.
What if your link object is not a page-item type, or you do not want to (or cannot) use kReimportCmdBoss to update your link? In these cases, you must implement your own link object
that will use your own IUpdateLinkService or ILinkObject::Import.

Link Notification
When a link or link resource is added, deleted, or changed, a lazy notification is sent on the
protocol of IID_ILINK or IID_ILINKRESOURCE (depending on what was changed). The
UID of the link or link resource is sent in the notification via the notification cookie, LazyNotificationData. Using LazyNotificationData::BreakoutChanges, you can determine which items
(UIDs) were added, deleted, or changed.
There is another lazy notification sent via the IID_ILINKDATA_CHANGED protocol. This
occurs not only when a link or link resource is added, deleted, or changed, but also when a
links link resource is changed. The notification cookie is passed in a type called ILinkManager::ChangeData, a wrapper of UID, which tells you what kind of UID is referenced.
You need not send any links-related notification from your plug-inthe links manager takes
care of that.

Data conversion for pre-CS4 link objects

To open a pre-CS4 document that contains an old data-link object, you need a phase 2 converter. In the converter, you can iterate through all the old data-link objects and convert them
to new ones. To allow you to iterate through the old links, some of the old data-links API was
retained in the InDesign CS4 code base; however, you should use it only for data conversion,
because most of the architecture code that supports the old data-links API was removed.
To get a list of old data-link objects, use the old ILinksManager available on the kDocBoss.
ILinksManager::GetNthLinkUID returns the UID of the old data-link boss object; this probably is the boss that aggregated the old IDataLink. For example, the InDesign CS3 SDK sample
CustomDataLink defines a boss object called kCusDtLnkAliasedDataLinkBoss, based on
kDataLinkBoss, that aggregates IDataLink. When a CS3 publication saved with data links that
were created by CustomDataLink is opened in CS4, the new CustomDataLink samples phase 2
converter uses ILinksManager::GetNthLinkUID to return the UIDs of kCusDtLnkAliasedDataLinkBoss objects saved in the document.


Adobe InDesign CS4 Porting Guide

Links Architecture

Once you have access to the old data-link object, you should try to convert the link using the
new link architecture. That is, an ILink should be instantiated to connect an ILinkResource and
an ILinkObject. You should be able to figure out the link resource for the old link through the
old IDataLink. The kDataLinkBoss also aggregates an ILinkObjectReference, which is a reference to the InDesign object, such as a page item, with which the link is associated. Link
object on page 13 discusses objects that have aggregated an ILinkObject beginning in CS4; in
such cases, the UID of the InDesign object should be used as the link object associated with the
The ILink and ILinkResource created from the old kDataLinkBoss should be initiated with the
data saved in IDataLink from the same boss. Both ILink and ILinkResource have a method
called CopyAttributes, which can be used to copy the data from the old kDataLinkBoss. For
conversion purposes, you can aggregate an ILink and ILinkResource in your old data-link boss.
Then, you initialize ILink and ILinkResource with the data from IDataLink. Finally, you call
the ILink::CopyAttributes, and ILinkResource::CopyAttributes, passing in the UIDRef of the
old data-link boss. In this way, the new ILink and ILinkResource are initialized properly.
Note that you still need a schema-based null converter.

Links panel extensibility

You can add your own column into the Links panel (through a service-provider boss with
kLinkInfoServiceImpl as IK2ServiceProvider) and provide your own ILinkInfoProvider implementation. The column will be available in the Links panels option dialog for the user to turn
on or off. Providing an ILinkInfoProvider implementation can be as easy as providing static
information, or you can indicate that the information needs to be updated dynamically based
on certain protocols notification. You can elect to listen to any command-notification protocol
in ILinkInfoProvider and update your information when the command notifies your subscribed protocol. For a simple ILinkInfoProvider implementation, see the CustomDataLink
sample in the SDK.

Frequently asked questions

Does the links architecture support the ability to programmatically alter
links notifications to support a push scenario versus pull/polling?
To provide a links manager with your link-resource status, implement ILinkResourceStateUpdater as described in Link status on page 14. The links sybsystem does not care when you
provide the update, and it does not enforce any update request; it is entirely up to you to implement your own update-timing strategy. The ExtLink SDK sample provides a links subsystem
through a manual menu action; it updates only when user decides to do so. It is the most primitive form of push scenario: the plug-in does not have any idle task polling the database for
the latest information; instead, it waits for the user to tell it to grab the latest status from the

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

Links Architecture

Does the links architecture support the ability to support a permissionsbased, bi-directional, update solution?
Bi-directional linking is supported. ExtLink SDK sample uses bi-directional linking to update
database content with data from an InDesign linked object. You must manage the access right
to the update, as there is no built-in mechanism for that purpose. One way to achieve this is
through the suppressed user interface, enabling the feature only for a specific user.

Can I programmatically define conditional links?

Suppose you have an image with both low-resolution and high-resolution versions. You want
to have the ability to define a link to alternate images, depending on whether the high-resolution image is available. The easiest way to achieve this workflow is to define a custom URI that
has paths to both images. The URI is opaque, the links subsystem cares about only the scheme
part of the URI, and each scheme is tied to a link-resource handler. In your link resource, you
must parse the URI to get the paths to both versions of the image (link resources). Then, you
also will build the logic for determining when to use each image in the link resource (and the
link-resource state updater). For example, you might have a flag in the database for each highresolution image, to indicate if it is ready to publish. In your link-resource handler, you would
check that flag, to see if you should import the low- or high-resolution image.

Is the InDesign links user interface customizable?

You can add your own column into the links user interface and provide your own information
in that column. For details, see Links panel extensibility on page 17.

How can I search and create/define custom sorts for the links user
CS4 does not support the search and custom-sort functions for the links user interface.

Can I define how links are displayed in the links user interface, so I can
provide a hierarchical view of my links?
There is no easy way to achieve this in CS4. Only parent/children links are grouped together.
An example of this is a placed InDesign file which has links in it. These links show up as child
links in the Links panel, and its parent, the InDesign file that is placed, is shown as the top-level
node in the links user interface. In theory, you can manage the user interface by manipulating
the links model; in reality, this is very complicated.

Porting CS3 links to the CS4 links architecture

This section describes how to port a CS3 CustomDataLink to CS4. It should provide some help
in porting your own custom data links.

How things worked in CS3

In CS3, a kCusDtLnkAliasedDataLinkBoss, which is based on kDataLinkBoss, provided major
functionality for the CSV link for the sample. The boss aggregated an IStringData interface
(with ID IID_ICUSDTLNKUNIQUEKEYSTRINGDATA), which stored a unique identifier


Adobe InDesign CS4 Porting Guide

Links Architecture

key for the asset stored in the database; in this case, a CSV file. When the user tried to place an
asset from the CSV file, CustomDataLink formed a unique identifier key based on the users
selection, instantiated a kCusDtLnkAliasedDataLinkBoss object, and initialized the IDataLink
on the object with the unique keys information. IDataLink used the NameInfo class to identify
a link, so CustomDataLink formed a NameInfo based on the unique key. If the unique key
really referenced a file, it got the file path and used it to populate NameInfo; otherwise, it populated the NameInfos filename with the unique key, and the volume name was set to 0. This is
fine, because the IDataLink implementation, CusDtLnkAliasedDataLink, knows how the
NameInfo is formatted, so it can provide operations like Combine and CompareBaseName.
CusDtLnkAliasedDataLink also implemented IDataLink::GetCurrentState, which provided
link-status information to the old links manager. kCusDtLnkAliasedDataLinkBoss also aggregated ILinkedStream, which created an IPMStream read stream from the linked asset when
requested. It primarily used the unique key stored in the kCusDtLnkAliasedDataLinkBoss to
get access to the file the key references. Finally, kCusDtLnkAliasedDataLinkBoss also aggregated IDataLinkAction, which provided functions for most of the contextual menu in the old
Links Panel when a link was right-clicked. To place the file selected by the user, CustomDataLink processed kImportAndLoadPlaceGunCmdBoss, whose command-data interface,
IImportFileCmdData, took an IDataLink pointer that was created from the unique identifier
CustomDataLink also implemented IUpdateLinkService with kCusDtLnkUpdateLinkServiceImpl, which was called by the old links manager when the link was out of date and the user
requested an update on the link. Essentially, it re-imported the linked resource, created a new
kCusDtLnkAliasedDataLinkBoss, and re-initialized the IDataLink. Also, to support copying
and pasting of the page item with the custom data link, CustomDataLink implemented an
IReferenceConverter, which added or embedded the link to the copied page item.

Converting from CS3 to CS4

First, you need to devise a URI to replace the unique key stored in the
unique identifier key on the database alias-database-1.csv was defined as something like this:

In CS4, the unique identifier is defined as an URI as follows:


When the user tries to place an asset from the CSV file, the new CustomDataLink forms a URI,
then processes a kImportAndLoadPlaceGunCmdBoss. Notice that the kImportAndLoadPlaceGunCmdBoss now aggregates an IImportResourceCmdData as its command-data interface
instead of IImportFileCmdData. IImportResourceCmdData takes a URI as an input parameter,
and that is all you need to do to process kImportAndLoadPlaceGunCmdBoss. As discussed in
What is a link in InDesign? on page 8, when it is time to import the resource during the processing of kImportAndLoadPlaceGunCmdBoss, a link-resource handler that knows how to
handle the type of URI scheme of the resource the user is trying to place is queried to provide a
resource read stream for the import provider that is doing the import. Since CustomDataLink
is the client that creates the scheme CSVLink, it needs to provide a link-resource handler
(ILinkResourceHandler), which is implemented and aggregated by the kCusDtLnkLinkRe-

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

Links Architecture

sourceHandlerBoss. Most of the methods in the ILinkResourceHandler are passed in a URI as

a parameter. As the creator/owner of the URI scheme CSVLink, CustomDataLink can decide
what to return as the short/long name of the resource, it would know how to open the resource
as a read stream given its URI, and it can decide if it wants to allow the typical datalink action
such as Edit Original and how it should be done.
ILinkResourceHandler::CreateResourceReadStream basically replaces the deprecated ILinkedStream. The only difference is that ILinkedStream was aggregated on a kDataLinkBoss, so it
accessed the link resource through the reference stored in IDataLink or whatever data interface
its plug-in chose to carry. ILinkResourceHandler::CreateResourceReadStream, on the other
hand, is passed in a URI, which represents the reference to the link resource currently being
asked for the resource stream.
In CS3, IDataLink::GetCurrentState provided link status. Its functionality was ported to
ILinkResourceStateUpdater, and it was implemented using an idle task. Link status on
page 14 provides details on how ILinkResourceStateUpdater should be implemented.
IDataLinkAction is now aggregated on the kImportLinkBoss. Normally, you should not have to
override the kImportLinkBoss; thus, you should not have to override the IDataLinkAction.
Besides, the IDataLinkAction was stripped to contain only GoToLink action. Much of the original IDataLinkAction methods were moved to ILinkResourceHandler, or the actions were provided automatically. For example, to embed a link, you only need to enable the embed action in
the ILinkResourceHandler::CanEmbedResource; the link architecture does the rest for you
when the embed action is requested. You still need to implement your own action, such as EditOriginal or RevealResource.
Finally, in CS4, IUpdateLinkService and IReferenceConverter are not needed for CustomDataLink, because the architecture takes care of this automatically. IReferenceConverter is
needed only when you have your own customized link boss; i.e., your link boss is not one of the
three types of links (e.g., kImportLinkBoss) specified in Types of links on page 11; in this
case, you must implement your own IReferenceConvert to support copy and paste operations
of your links. Customization of the link boss, however, should never be necessary.
In summary, the old way of implementing your own kDataLinkBoss-based custom data-link
boss is no longer supported. You should implement a resource-handler boss that aggregates an
ILinkResourceHandler and ILinkResourceStateUpdater, and provide a ILinkResourceFactory
to instantiate the handler on demand, as described in the procedure below.
To provide your own type of links support, follow these steps:
1. Define how your resource can be represented by a URI. You will need your own URI
scheme to identify the type of resource for which you will provide support.
2. Implement a link-resource handler that knows how to import the type of resource you
defined in your URI.
3. Provide a link-resource state-updater service provider that reports back to the link manager
the current state of a link resource.
4. Provide a phase 2 converter, if you have custom data-link data for a pre-CS4 InDesign publication and you want your user to be able to convert those links to CS4-compatible links.


Adobe InDesign CS4 Porting Guide

Links Architecture

Table 4 provides a high level comparison of links-related tasks in InDesign CS3 and CS4.
TABLE 4 Comparison of common link tasks in InDesign CS3 and CS4



Support your own

type of link

Create your own data-link

boss based on
kDataLinkBoss, which
implements IDataLink,
ILinkedStream, and

Provide an ILinkResourceHandler that knows how to handle

a particular URI scheme. It knows how to open a read stream
from the link resource, for import purposes. Most
IDataLinkAction functionalities are provided by the new link
architecture; some (like EditResource) were moved to

Provide link status

to the links


Implement ILinkResourceStateUpdater, which should queue

an LinkResourceStatePacket for processing in an idle time,
on completion of the packet. Process an
kLinkResourceStateUpdateCmdBoss if the resource state has

Support updating
a link from the
Links UI panel

Implement an
IUpdateLinkService service

If your link object is a page-item type and your

ILinkResourceHandler::CreateResourceReadStream returns
a stream that is ready to import into the page item, you do
not need to do anything: kReimportCmdBoss is processed
for you, and your
ILinkResourceHandler::CreateResourceReadStream is used
to supply an IPMStream to the resource. There are situations
when you might still need to implement an
IUpdateLinkService; for details, see Link update on
page 15.

Support copy and

paste of a page
item that has your
own type of link

Implement a
IReferenceConverter, which
adds or embeds a link in the
new page item.

You do nothing. The new links architecture takes care of

copying the links to the new page item.

CS3 links-related APIs deprecated in CS4

Table 5 lists CS3 links-related APIs that are deprecated in CS4. You might still see these APIs in
the SDK, but they exist only for conversion purposes; their core functionalities were removed
from the InDesign code base.
TABLE 5 InDesign CS3 APIs that are deprecated in CS4
Deprecated API



Do not assume the link always is to a file.


See Porting CS3 links to the CS4 links architecture on

page 18.


The main helper class you should use is ILinkFacade,

although there is not a 1:1 mapping between the two APIs.

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

Links Architecture

Deprecated API



This was used mainly to get to the associated kDataLinkBoss

from a page item. In CS4, use


If you want to allow the Edit Original menu to b e available in

the Links UI panel., return true in
ILinkResourceHandler::CanEditResource and implement


This was used mainly to get to the associated page item from a
kDataLinkBoss. In CS4, use ILink::GetObject.


This was replaced by ILinkManager.


This may be needed for backward compatibility.


This was moved from kDataLinkHelperBoss to

kImportLinkBoss. During an update link, it queries the
service provider that supports IUpdateLinkService, to handle
link update.

Porting recipes for links-related code

This following sections present several recipes for porting links-related code to CS4.

Porting recipe: ILinkFacade

ILinkFacade is a high-level API for dealing with links, link resources, and link objects. It has
methods to create, delete, update, and re-link a link. Also, it has methods to create link
resources and update resource state. Use ILinkFacade whenever possible.

Porting recipe: Getting to the associated InDesign link object like page item from a link
Given an IDataLink, query the ILinkObjectReference on the kDataLinkBoss and call ILinkObjectReference::GetUID.
Given an ILink, use ILink::GetObject to return the UID of the object.

Porting recipe: Getting to a link from a page item

Used IDataLinkReference as the bridge between a page item and an IDataLink:
// assume childHierarchy is an IHierarchy InterfacePtr<IDataLinkReference>
dataLinkReference(childHierarchy, UseDefaultIID());
if(!dataLinkReference) {
PMString datalinkPath("UNDEFINED");
IDataBase* db = docRef.GetDataBase();


Adobe InDesign CS4 Porting Guide

Links Architecture

UID itemUID = dataLinkReference->GetUID();

InterfacePtr<IDataLink> dataLink(db, itemUID, UseDefaultIID());
if(!dataLink) {
PMString* namePtr = dataLink->GetFullName();

Use ILinkManager::QueryLinksByObjectUID to get to ILink. It returns the result in an ILinkManager::QueryResult, which is a UID vector that holds the ILink UID. For details, see Link
manager on page 14.
InterfacePtr<IHierarchy> childHierarchy(frameHierarchy->QueryChild(0));
// If we're on a placed image we should have a data link to source item
InterfacePtr<ILinkObject> iLinkObject(childHierarchy,UseDefaultIID());
// get the link for this object
IDataBase* iDataBase = ::GetDataBase(childHierarchy);
InterfacePtr<ILinkManager> iLinkManager(iDataBase,iDataBase>GetRootUID(),UseDefaultIID());
ILinkManager::QueryResult linkQueryResult;
if (iLinkManager->QueryLinksByObjectUID(::GetUID(childHierarchy), linkQueryResult))
ASSERT_MSG(linkQueryResult.size()==1,"Only expecting single link with this
ILinkManager::QueryResult::const_iterator iter = linkQueryResult.begin();
InterfacePtr<ILink> iLink (iDataBase, *iter,UseDefaultIID());
if (iLink!=nil)
InterfacePtr<ILinkResource> iLinkResource(iLinkManager>QueryResourceByUID(iLink->GetResource()));
ASSERT_MSG(iLinkResource,"CHMLFiltHelper::addGraphicFrameDescription - Link
with no associated asset?");
PMString datalinkPath = iLinkResource->GetLongName();

Porting recipe: Updating a link

UID newDataLinkUID;
InterfacePtr<IUpdateLink> update((IUpdateLink *)::CreateObject(kDataLinkHelperBoss,
if ( !update)
// assume dl is a valid IDataLink
ErrorCode result = update->DoUpdateLink(dl, &newDataLinkUID) ;

Use ILinkFacade::UpdateLinks, which processes (or schedules) a kLinkUpdateCmdBoss. You
need to pass in the UID of a kImportLinkBoss.

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide


New for CS4 is the ability to undo an entire script in one step. A script typically contains many
undoable operations - one for each script request. For CS4, all of these operations can be stored
and undone as a single undo operation. This feature is accessed from IScriptRunner and from
the doScript method of the scripting DOM.
This feature also provides the ability to access the error code for individual scripting requests,
as defined in RepresentScriptProvider. The sections below explain the modified scriptingrelated APIs surrounding these new features, along with other changes to improve the scripting

The doScript method of the scripting DOM has two additional parameters:

undoMode defines how the script is to be undone.

undoName defines the undo menu item for the script.

Possible values for undoMode are defined by the undoMode enumType, including:

scriptRequest This is the default value. An undo history entry is added for every script
transaction that occurs within your script. After executing the example script below, the
Edit menu holds an item corresponding to the last script transaction that occurred within
myScript.jsx. If that transaction creates a new rectangle, for example, the undo menu item is
Undo Add New Item.
app.doScript( File("C:\\myScript.jsx"), ScriptLanguage.JAVASCRIPT, undefined,

entireScript One undo history entry is added for your entire script. The name of the entry
is defined by the undoName parameter. If undoName is undefined, Script is used by
default. After executing the example script below, the Edit menu holds the item Undo my
app.doScript( File("C:\\myScript.jsx"), ScriptLanguage.JAVASCRIPT, undefined,
UndoModes.entireScript, "my script");

autoUndo No undo history entry is added for the script. Instead, all script transactions
within the script are attached to the preceding history entry and undone when that entry is
undone. After executing the example script below, the Edit menu holds the item Undo Add
New Item for the rectangles.add transaction. No item is added for doScript.
app.activeDocument.rectangles.add(undefined, undefined, undefined,
{geometricBounds:[10, 10, 20, 20], contentType:ContentType.graphicType});
app.doScript( File("C:\\myScript.jsx"), ScriptLanguage.JAVASCRIPT, undefined,


Adobe InDesign CS4 Porting Guide


IScriptRunner provides the C++ API functionality for running a script. In CS4, this functionality includes the new entireScript undo functionality. When this new feature was implemented,
the parameter lists of the methods in IScriptRunner got too long. To solve this problem, a new
RunScriptParameter class was developed to contain parameters related to running a script. For
virtual ErrorCode RunFile(const IDFile& idFile, bool16 showErrorAlert = kTrue,
bool16 invokeDebugger = kFalse) = 0;
Call to RunFile:
ErrorCode err = scriptRunner->RunFile(scriptFile, kFalse, kTrue);

virtual ErrorCode RunFile(const IDFile& idFile, const RunScriptParams& params) = 0;
Call to RunFile:
RunScriptParams params( scriptRunner);
ErrorCode err = scriptRunner->RunFile(scriptFile, params);

CS4 introduces a new scripting interface, IScriptEngine. As its name suggests, IScriptEngine
provides support for engine-specific information within the scripting architecture. For example, several methods that were on the IScriptManager interface for CS3 were moved to







In addition, the IScriptPreferences and IScriptRunner interfaces were moved from the IScriptManager boss to the IScriptEngine boss. In practice, most scripting clients have only one
engine. These clients will be able to aggregate IScriptEngine with their existing IScriptManager
boss and use a default implementation of IScriptEngine intended for single-engine clients.
The main beneficiary of these changes will be the JavaScript client, which supports an arbitrary
number of engines. In CA3, all engines inherit identical preferences, including the active
scripting DOM version. That means if one engine sets the current scripting DOM version to
4.0, the scripts running in all JavaScript engines suddenly will be executed against the Firedrake DOM. With the CS4 change, each engine has its own DOM version. Prior to CS4, there
was no way to determine which engine initiated a scripting request. The biggest problem with
this was that when an engine executed a DoScript request, the sub-script was processed in the

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide


default (main) engine instead of the originating engine. For CS4, the RequestContext class is
updated to include a pointer to the IScriptEngine for the engine that initiated the request; thus,
a DoScript request is processed in the engine that initiated it.
With this change, it is conceivable that versioned scripts may break in the case where script A
executes script B in a different engine (i.e., by calling DoScript). In CS3, if script A changes the
current scripting DOM version in engine A, script B inherits that change in engine B. In CS4,
engine B and, thus, script B no longer inherit that change; script B executes against the scripting DOM version in engine B.
Furthermore, in CS3, the preferences for the JavaScript, AppleScript, and VBScript engines
were all tied together; that is, changing the current scripting DOM version in AppleScript also
affected JavaScripts and VBScripts (and vice versa for all combinations). In CS4, the engines for
these clients each have separate preferences. This change in behavior (from application-wide to
engine-specific) also includes the preference for user interaction level (that is, whether alerts
and dialogs are displayed during script execution); however, the enable redraw preference
remains a global setting.

Previously, CScriptProvider overloaded the HandleEvent, AccessProperty, and AccessProperties methods. Subclasses were forced to override these methods, but generally only one of the
overloads. This resulted in hidden virtual functions, which generate an error when the relevant
flag is turned on in XCode.
In CS4, the versions of HandleEvent and AccessProperty that accepted a list of objects were
renamed to HandleEventOnObjects and AccessPropertyOnObjects, and the version of
AccessProperties that accepted a list of objects was removed. These methods also were
renamed in classes that implement IScriptProvider (e.g., CScriptProvider) and those that
inherit from CScriptProvider.
virtual ErrorCode HandleEvent(ScriptID eventID, IScriptEventData* data,
const ScriptList& scriptList);
virtual ErrorCode HandleEvent(ScriptID eventID, IScriptEventData* data,
IScript* script);
virtual ErrorCode AccessProperty(ScriptID propID, IScriptEventData* data,
const ScriptList& scriptList);
virtual ErrorCode AccessProperty(ScriptID propID, IScriptEventData* data,
IScript* script);
virtual ErrorCode AccessProperties(IScriptEventData* data,
const ScriptList& scriptList);
virtual ErrorCode AccessProperties(IScriptEventData* data,
IScript* script);

virtual ErrorCode HandleEventOnObjects(ScriptID eventID, IScriptEventData* data,
const ScriptList& scriptList);
virtual ErrorCode HandleEvent(
ScriptID eventID, IScriptEventData* data, IScript* script);


Adobe InDesign CS4 Porting Guide


virtual ErrorCode AccessPropertyOnObjects(ScriptID propID, IScriptEventData* data,

const ScriptList& scriptList);
virtual ErrorCode AccessProperty(ScriptID propID, IScriptEventData* data,
IScript* script);
virtual ErrorCode AccessProperties(IScriptEventData* data,
IScript* script);

Typical CS3 code looked like this:

ErrorCode MyScriptProvider::HandleEvent(ScriptID eventID, IScriptEventData* data,
const ScriptList& scriptList)
if (eventID.Get() == e_Delete)
return DeleteErrors();
return CScriptProvider::HandleEvent(eventID, data, scriptList);

The CS3 code above now causes the following compiler error:
Error C2664: 'CScriptProvider::HandleEvent' : cannot convert parameter 3 from
'const ScriptList' to 'IScript *'
No user-defined-conversion operator available that can perform this
conversion, or the operator cannot be called

To fix this, write your CS4 code as follows:

ErrorCode MyScriptProvider::HandleEventOnObjects(ScriptID eventID,
IScriptEventData* data, const ScriptList& scriptList)
if (eventID.Get() == e_Delete)
return DeleteErrors();
return CScriptProvider::HandleEventOnObjects(eventID, data, scriptList);

Both the name of the subclass method and the call to the base-class method must be
changed to maintain the desired overridden virtual function behavior.

All script providers that returned kReadOnlyPropertyError in CS3 should now use the SetReadOnlyPropertyErrorData API instead. The following example is from the BasicShape SDK
sample, in BscShpScriptProvider::AccessParentStory().
if (data->IsPropertyPut())
return kReadOnlyPropertyError;

if (data->IsPropertyPut())

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide


return Utils<IScriptErrorUtils>()->SetReadOnlyPropertyErrorData( data,


As part of the change to give INX (and other scripting clients) access to the error code for every
script request (e.g., each individual property when doing a get or set of multiple properties), the
APIs in IScriptEventData related to return data were revised.
These changes will require edits in every script provider. The highest impact change is the
requirement to call IScriptEventData::AppendReturnData() with multiple parameters, in place
of IScriptEventData::SetReturnData() with a single parameter, to return a result from a scripting request. (The methods were renamed to enforce the change via the compiler and clarify the
implementationappend and replace rather than set.)
Previously, the return data comprised a list of return values (K2Vector<ScriptData>) accessed
via one method IScriptEventData::GetReturnData(). One error code and error string were
available via the IScriptError interface on the same boss. (For certain requests to get/set multiple properties at once, it was possible to retrieve a list of error codes through IScriptRequestHandler, but there was no way to tell which properties generated which results.)
Now, the return data comprises a list of ScriptReturnData objects. The declaration of this fairly
straightforward class is available at <SDK>/source/public/includes/ScriptReturnData.h. These
objects record the request (property/event) ID, return value, error code, and error string. For
reasons of compiler enforcement, performance, and precision, the method to retrieve the
return data was replaced with separate IScriptEventData::GetNumReturnData(), GetNthReturnData(), and GetAllReturnData() APIs. Furthermore, all return-data APIs take a target
parameter corresponding to the object in the scripting DOM on which the request was processed.
Therefore, it is now possible to determine which requests were processed on which targets with
which results. (Note: The IScriptError interface remains as a way to pass back a single, overall
error code and error string from the IScriptRequestHandler to scripting clients that do not care
about the new functionality.)
CS3 IScriptEventData API:
virtual void ClearReturnData() = 0 ;



const ScriptData* data ) = 0

const ScriptData& data ) = 0
IScript* object ) = 0 ;
const ScriptList& objectList
const ScriptListData& data )

) = 0 ;
= 0 ;

virtual const ScriptListData& GetReturnData() const = 0;

CS4 IScriptEventData API:

virtual void ClearReturnData( const IScript* target) = 0;
virtual void ClearReturnData( const ScriptList& targets) = 0;


Adobe InDesign CS4 Porting Guide


virtual void AppendReturnData( const IScript* target, const ScriptID requestID,

const ErrorCode errorCode) = 0;
virtual void AppendReturnData( const ScriptList& targets, const ScriptID requestID,
const ErrorCode errorCode) = 0;
virtual void AppendReturnData( const IScript* target, const ScriptID requestID,
const ScriptData& returnValue) = 0;
virtual void AppendReturnData( const ScriptList& targets, const ScriptID requestID,
const ScriptData& returnValue) = 0;
virtual void AppendReturnData( const IScript* target, const ScriptReturnData& data)
= 0;
virtual void AppendReturnData( const ScriptList& targets, const ScriptReturnData&
data) = 0;
virtual void ReplaceReturnData( const IScript* target, const ScriptReturnDataList&
data) = 0;
virtual void ReplaceReturnData( const ScriptList& targets, const
ScriptReturnDataList& data) = 0;
virtual void AppendReturnData( const IScript* target, const ScriptReturnDataList&
data) = 0;
virtual void AppendReturnData( const ScriptList& targets, const
ScriptReturnDataList& data) = 0;
virtual uint32 GetNumReturnData( const IScript* target ) const = 0;
virtual uint32 GetNumReturnData( const ScriptList& targets ) const = 0;
virtual ScriptReturnData GetNthReturnData( const IScript* target, uint32 n ) const
= 0;
virtual ScriptReturnData GetNthReturnData( const ScriptList& targets, uint32 n )
const = 0;
virtual ScriptReturnDataList GetAllReturnData( const IScript* target ) const = 0;
virtual ScriptReturnDataList GetAllReturnData( const ScriptList& targets ) const =

API usage for CS3:

ErrorCode MyScriptProvider::AccessProperty(ScriptID propID,
IScriptEventData* data, IScript* parent)
ScriptData scriptData;

API usage for CS4:

ErrorCode MyScriptProvider::AccessProperty(ScriptID propID,
IScriptEventData* data, IScript* parent)
ScriptData scriptData;
data->AppendReturnData( parent, propID, scriptData ) ;

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide


Metadata resource
Metadata resources are used to add arbitrary information to elements in the scripting DOM.
INX uses them extensively to customize the handling of various objects during import and
export. They also are used to control type information, to support properties on the
find/change objects for scripting clients.
Adding a ScriptElementID to metadata scripting resources makes it possible to version the
metadata resources included in a DOM based on the client. For example, we can indicate that
the INX client does not want certain metadata included in its DOMs. The addition of the
ScriptElementID requires all existing metadata scripting resources to add this field.
Below is an example from the TransparencyEffect sample plug-in (
m_INXSnippetAttrImportState, Int32Value(e_SetElementAttributes),

m_INXSnippetAttrImportState, Int32Value(e_SetElementAttributes),

CS4 gives scripting clients the ability to access the error code for every script request. The RepresentScriptProvider base class was modified to clarify expectations about how the methods'
implementations should return data and error codes. This change affects every subclass of RepresentScriptProvider. Note that two of these methods are pure virtual functions, so the compiler will enforce the change in existing implementations. Also, the compiler will catch the
AppendAllObjects method if the hidden virtual functions warning is enabled.
virtual int32 GetNumObjects( IScriptEventData* data, IScript* parent) = 0;
virtual ErrorCode AppendNthObject( IScriptEventData* data, IScript* parent,
int32 n, ScriptList& objectList) = 0;
virtual ErrorCode AppendAllObjects( IScriptEventData* data, IScript* parent,
ScriptList& objectList);


Adobe InDesign CS4 Porting Guide


virtual int32 GetNumObjects( const IScriptEventData* data, IScript* parent) = 0;
virtual ErrorCode AppendNthObject( const IScriptEventData* data, IScript* parent,
int32 n, ScriptList& objectList) = 0;
virtual ErrorCode AppendAllObjects( const IScriptEventData* data, IScript* parent,
ScriptList& objectList);

Text-attribute scripting
Script-provider implementations that get and set text attributes should use the new TextAttrScriptUtility class. This ensures consistent handling of text attributes across scripting objects.
Use of TextAttrScriptUtility is demonstrated in the BasicTextAdornment samples script provider (BscTAScriptProvider.cpp). Notice that this code implements the PreAccessProperty and
PostAccessProperty methods that use a TextAttrScriptUtility instance to access and modify text
Before moving to this code, the BasicTextAdornment sample used an ITextAttributeSuite to get
and set text attributes. This worked for scripting and INX, but it failed for IDML, because it
uses a new type of scripting object. Using the TextAttrScriptUtility class fixes that problem.

TypeDef and TypeDefType

A new feature added to the scripting resources is a TypeDef element and corresponding TypeDefType. A TypeDef resource defines a synonym for another type. A TypeDef type may be
used wherever a type is required, by using a TypeDefType declaration; for example, the storage
type of a property resource or the return type or parameter types of an event resource.
Two TypeDefs in the core DOM corresponding to user-interface colors in InDesign and
InCopy were re-implemented using this technique. The new TypeDefs are shown below.
"InDesign UI color type",
"Properties or parameters using the InDesign UI Colors enumeration use this to
specify the type as either one of the enumerated UI colors or a list of
RGB values for a custom color.",
RealMinMaxArrayType(3, 0, 255),
EnumType( kUIColorsEnumScriptElement )
"InCopy UI color type",
"Properties or parameters using the InCopy UI Colors enumeration use this to
specify the type as either one of the enumerated UI colors or a list of

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

Changes to Support Rotated Spreads

RGB values for a custom color."

RealMinMaxArrayType(3, 0, 255),
EnumType( kInCopyUIColorsEnumScriptElement )

Because these types were re-implemented, the following old #defines were removed from
#define UIColorType TypeDefType(kInDesignUIColorTypeDefScriptElement)
#define UIColorDefaultType(def)
TypeDefDefaultType(kInDesignUIColorTypeDefScriptElement) EnumValue(def){}
#define InCopyUIColorType TypeDefType( kInCopyUIColorTypeDefScriptElement)

The old #define constants that were used in properties and events were replaced with the new
TypeDefs. For example:
"watermark font color",
"Watermark font color for a document",

// changed for CS4

Changes to Support Rotated Spreads

Rotated spread is a new CS4 feature. A spread can be rotated in increments of 90 degrees. This
allows for easier design of calendars, packaging, annuals reports, and other content that
requires placement of text and imagery that is not right-side-up relative to the rest of the document. Users no longer need to temporarily rotate frames or their monitors. To support this feature, some APIs need to be changed; they are summarized in this section.

A new enumerator for commonly referenced coordinate systems

In CS3, enumerators for three commonly referenced coordinate systems were added to TransformTypes.h:

These named values are used throughout the transform and geometry API stacks. They are of
type Transform::CoordinateSpace. Here, pasteboard coordinates is the single coordinate system used to draw every spread on the floor within a layout window. It often is used as the
common ancestor of all page items on a spread. This was a mistake. Instead, spread coordinates


Adobe InDesign CS4 Porting Guide

Changes to Support Rotated Spreads

could have been used in most cases and must be used in some cases in the presence of rotated
spreads. Pasteboard coordinates really is of interest only to the layout control view.
In CS4, a new enumerator is added to TransformTypes.h:

The companion change to scripting is to add spread coordinates (en_SpreadCoordinates) to

the allowable coordinate systems used by the transform and resize script events.

No function signature needed to change as a result of this addition.

ISpread::GetPagesBounds and ILayoutUtils::GetIntersectingPageUID

PBPMRect ISpread::GetPagesBounds();

PMRect ISpread::GetPagesBounds( Transform::CoordinateSpace coords =

The legal values for coords are the default PasteboardCoordinates() and SpreadCoordinates().
Its return type is changed to PMRect from PBPMRect. Actually, these are the same C++ type.
The PB in the name was just suggestive to clients that the return value was in pasteboard
coordinates. If you pass in default parameter, the function returns exactly the same data to all
unmodified existing callers.
A similar change was made to ILayoutUtils::GetIntersectingPageUID.
ILayoutUtils::GetIntersectingPageUID(... const PMRect& itemBounds, ....)

ILayoutUtils::GetIntersectingPageUID(... const PMRect& itemBounds, ....,
Transform::CoordinateSpace s = Transform::PasteboardCoordinates())

IShape::GetPaintedBBox and GetPrintedBBOx

Similar to ISpread::GetPagesBounds and ILayoutUtils::GetIntersectingPageUID on page 33,
the following IShape methods now return bounds in coordinate space specified by the caller.
PMRect GetPaintedBBox(const PMMatrix& m);
PMRect GetPrintedBBox(const PMMatrix& m);

PMRect GetPaintedBBox(const PMMatrix& m, Transform::CoordinateSpace coords =
PMRect GetPrintedBBox(const PMMatrix& m, Transform::CoordinateSpace coords =

The legal values for coords are the default PasteboardCoordinates() or SpreadCoordinates().
The previous behavior matches the new default, so previously correct code remains correct.

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

Changes to Support Rotated Spreads

The previous behavior returns PMRects in pasteboard coordinates modified by the matrix m.
For example, if m were the pasteboard to view matrix, the result would be in view coordinates.
The new behavior allows one to optionally specify m relative to spread coordinates. For example, if m were the identity matrix and coords were SpreadCoordinates(), the resulting PMRects
would be in spread coordinates.

The meaning of the pageBounds parameter to IMasterSpreadUtils::AppendMasterPageItems
has been changed, so the PMRects are provided in spread coordinates rather than pasteboard
coordinates. A typical caller of this function would have to make a change when asking for the
page bounds from IGeometryFacade using Transform::SpreadCoordinates() rather than Transform::PasteboardCoordinates().

For the draw manager's filter mechanism to be general enough for rotated spreads, the filter
rectangles passed to IDrawMgr::BeginFilter need to be able to be specified in coordinate systems other than view coordinates.
void BeginFilter( const PMRect& r);

void BeginFilter( const PMRect& r, const PMMatrix& m = PMMatrix());

where m, if provided, is the view-to-filter space transformation. Usually, this is the view-tospread matrix, provided by the default value; therefore, you old code probably will continue to
work without any change.
The member function IDrawMgr::GetFilter also changes from:
PMRect GetFilter();

IDrawMgr::FilterInfo GetFilter();

struct FilterInfo{
PMRect fFilterRect;
PMMatrix fFilterTransform;

Among other things, this fixes problems where master page items with transparency get drawn
twice, hence too dark.


Adobe InDesign CS4 Porting Guide

gSession Removed

gSession Removed
Beginning in CS4, InDesign is moving toward a multi-threading environment. Multi-threading
will not be complete until a future release, but in preparation, there have been minor changes to
the CS4 API. Namely, global and static variables were removed.
One of the most visible and widely used globals was gSession, a pointer of type ISession on the
session boss. The session boss aggregates multiple interfaces (such as workspace, application,
and preferences). In the multi-threading environment, there are multiple session objects, one
for each concurrent thread, so a single session global will no longer do.
Each thread of execution now has its own execution context (environment). Your code should
not make any assumptions about the context in which it runs, so your code must now access
the session pointer by using the global GetExecutionContextSession() method.
InterfacePtr<IApplication> app(gSession->QueryApplication());
InterfacePtr<IApplication> app(GetExecutionContextSession()->QueryApplication());

In most places, a simple find/replace for gSession with GetExecutionContextSession() should

suffice, but keep in mind the following:

GetExecutionContextSession() has more overhead than de-referencing a pointer (gSession). In most cases, this overhead will not make any difference in the execution time. In
some cases, including drawing code and frequently called observers, it can make a difference if GetExecutionContextSession() is called carelessly.

When determining where it is necessary to optimize the number of calls to GetExecutionContextSession(), we recommend you use a profiler.

GetExecutionContextSession() can return nil in some extreme cases (very early on startup
or very late on shutdown). This should not affect you, but if you have code that you want to
execute very early on startup or very late on shutdown, check to make sure you have a valid
session before using it.

You could use the following are replacement techniques:


If the call to GetExecutionContextSession() happens in a function that is called often (like a

loop), see what you are querying the session for (workspace, preferences, database, etc.) and
pass that as a parameter to the function. This eliminates the repetitive call to GetExecutionContextSession().

Do not cache the session pointer in a class static variable. This would prevent the code from
running concurrently in multiple threads. If possible, refrain from using statics.

You can and should store the result of GetExecutionContextSession() in a variable inside
your function, if the function queries the session for multiple things (like workspace, the
application, command processor, and error state). For example:
void Foo() {
// Use a regular variable. DO NOT use a static.
ISession* session = GetExecutionContextSession();

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

User Interface APIs

InterfacePtr<IApplication> theApp(session->QueryApplication());
InterfacePtr<IWorkspace> ws(session->QueryWorkspace());
InterfacePtr<IFoo> myFoo(session->QueryFoo());

User Interface APIs

This section discusses the impact of user-interface changes on third-party developers.
When you first launch InDesign CS4, you will notice a new look to the document windows and
application. All Creative Suite 4 applications have similar changes, as a result of adopting a new
Adobe common user interface. The common user interface is provided by an internal library
called OWL. The transition from InDesigns own user interface to the common user interface
provided by OWL will take time. It began in CS3 with the use of palette windows. In CS4, the
new application container presents the most significant visual change to users.

Workspace preference reading/writing

OWL takes over workspace reading/writing; however, the old way of using InDesign APIs,
such as BasePanelSAXHandler and BasePanelXMLGenerator, is still supported.

Palette management
PaletteRef.h and PaletteRefUtils.h have detailed information about the palette hierarchy. Everything you see in the InDesign application workspace is an object hosted inside the palette
The CS3 Tab group cluster is no longer a valid object in the palette hierarchy; instead there is a
new, floating-dock object to host a palette and a document. As a result PaletteRefUtils::NewTabGroupClusterPalette and PaletteRefUtils::IsTabGroupCluster are obsolete;
instead, PaletteRefUtils::NewFloatingTabGroupContainerPalette and PaletteRefUtils::IsFloatingTabbedPaletteDock are used.
Floating palette docks can contain multiple tab panes, whereas the cluster was the pane, so
code that walks the widget hierarchy must change. Also, in CS3, tab panes were always docked,
but in CS4, tab panes can live in the new floating docks.

Document management
In InDesign CS3, a document is hosted in an layout window, represented by kDocumentWindowBoss. The IWindow in the CS3 kDocumentWindowBoss actually uses the system window
to host the document. In CS4, kLayoutWindowBoss is deprecated; instead, a kDocumentPresentationBoss is used to host a document, and IDocumentPresentation replaces IWindow as
the new key interface for views onto documents.


Adobe InDesign CS4 Porting Guide

User Interface APIs

IWindow is not completed deprecated; rather, is not used mainly in the document
window. It continues to serve as the main interface for things like kDialogWindowBoss,
which represents a dialog window.

See Table 6 for a list of API changes related to document windows.

TABLE 6 API changes related to document windows




































The following sections include porting recipes related to document windows.

Finding the front document window

IWindow* frontDocWindow = Utils<IWindowUtils>()->GetFrontDocWindow(); // or
IWindow* frontmostDocWindow = Utils<IWindowUtils>()->GetFrontDocWindow(document);
// or GetFrontDocLayerWindow(document);

IDocumentPresentation* frontDocPresentation = Utils<IDocumentUIUtils>()>GetActivePresentation();

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

User Interface APIs

IDocumentPresentation* frontmostDocPresentation = Utils<IDocumentUIUtils>()>GetFrontPresentationForDocument(document);

Document-window list iteration

The document presentation list IPresentationList replaces the document window list IWindowList, used to aggregated on kDocBoss.
InterfacePtr<IWindowList> winList(document, UseDefaultIID());
if (winList && winList.WindowCount() > 0)
for (int32 i = 0; i <= winList.WindowCount(); i++)
InterfacePtr<IControlView> containerView(winList->GetNthWindow(i),

InterfacePtr<IPresentationList> presList(document, UseDefaultIID());
if (presList && presList.size() > 0)
for (IPresentationList::iterator iter = presList.begin(); iter != presList.end();
InterfacePtr<IControlView> containerView(*iter, UseDefaultIID()); ...

Iterating all layout windows in front-to-back order

With multiple panes, multiple tab groups, and multiple docs per group, what front to back
means gets confusing. By using IDocumentUIUtils::FindPresentationsForDocument() with the
refer criteria, you can get some semblance of front-to-back ordering. You will get the active
document first, then the front-most documents in tab groups (in no particular order), followed
by the remaining documents (not the front document in their tab group). The following shows
an example:
PresentationSequence plist;
FindPresentation_Criteria require = nil; // no requirement = all presentations
FindPresentation_PreferCriteria prefer;
Utils<IDocumentUIUtils>()->FindPresentationsForDocument(nil, plist, require,
if (!plist.empty())
for (PresentationSequence::iterator iter = plist.begin(); iter != plist.end();
// do something with presentation here:
IDocumentPresentation* pres =_*iter;


Adobe InDesign CS4 Porting Guide

General Changes

Document-subject-window list notification

When a document presentation is opened or closed, the IID_IPRESENTATIONLIST interface
with kPresentationOpenedMessage and kPresentationClosedMessage messages is broadcast.
This replaces the IID_IWINDOWLIST interface with kWindowAddedMessage and kWindowRemovedMessage messages used in CS3.

General Changes
This section lists some of the changes we recommend you make to your existing CS3 project
before you start working on specific porting tasks.

SDK folder structure

Update include paths
There was some reorganization of the SDKs source folder for CS4. Specifically, the widgetbin
and publiclib folders were moved from /source/public/components/ to /source/public/libs/. As
a result, you must update your plug-ins project configuration files. Simply modify the include
paths to use the new /source/public/libs/ folder.
If your plug-in uses the configuration files supplied in the SDK, you need to make sure you are
using CS4 config files. On Windows, there are two config files: SDKCPPOptions.rsp and
SDKODFRCOptions.rsp. To update to the CS4 Windows config files, no action is necessary, as
their names have not changed. On Mac OS, the config file is plugin.sdk.xcconfig. On Mac OS,
the config file name has changed from plugin.xcconfig to plugin.sdk.xcconfig.
To update your plug-ins XCode project on Mac OS, follow these steps:
1. Add plugin.sdk.xcconfig from <SDK>/build/mac/prj to the project's xcconfig group.
2. Remove plugin.xcconfig from the project's xcconfig group or from wherever you originally
added plugin.xcconfig.
3. Click on the project under Group & Files to select it, then click Info, and select the Build
tab. In the Based on: pop up, select plugin.sdk

MLocaleIds.h and WLocaleIds.h

In CS4, the public, platform-specific, locale-identifier header files, WLocaleIds.h and MLocaleIds.h, are deprecated and consolidated into a single header file, PMLocaleIds.h. No source
code should include the platform-specific headers. Doing so now generates a compiler error
notifying the user to include the proper PMLocaleIds.h header.
This was done to ensure that both platforms (Windows and Mac OS) share the same values for
locale identifiers; previously, they did not.

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

General Changes

Replace gSession with GetExecutionContextSession()

You should do a global search and replace gSession with GetExecutionContextSession().
Chances are you are using gSession in some of your code. For more information about the
gSession change, see gSession Removed on page 35.

Bring resource definitions up-to-date

There are a few resource-declaration changes to some often used resources. Table 7 summarizes the changes. You should modify your .fr file if you use one of the resources in the table.
TABLE 7 ODFRC resource change summary


Widget interface or
resource with new


Widgets affected



A new integer was added

at the end to indicate if
Ampersands should be
converted to underline
character. See
on page 43.


Add a new convert

ampersands attribute (either
kTrue, or kFalse) in the
StaticTextAttributes portion
of every affected widgets and
their derivatives.


The constant used to

represent the view
resizable attribute has


Change the integer that

represents the views
resizable attribute from
notResizable to
kNotResizable and from
isResizable to kIsResizable.

KitList and

The constant used to

represent the view
resizable attribute has

Change the integer that

represents the views
resizable attribute from
notResizable to
kNotResizable and from
isResizable to kIsResizable.

Adobe InDesign CS4 Porting Guide

General Changes

Widget interface or
resource with new



ActionIDData and
were added to the
definition of

Widgets affected


Add an ActionID of an extra

menu item to add to the
bottom of this style dropdown list. Add
kInvalidActionID if there is
no extra menu item. The list
of observers to attach when
showing this style widget
typically includes
VER when ActionIDData
contains a nonkInvalidActionID value. This
also could also be empty.

PMString constructor change

In CS4, several PMString API were removed. The one you most likely will run into while porting is the removal of the translate parameter to the constructor, as detailed below. For more
detail about the changes to PMString, see PMString on page 45.
CS3 constructor:
PMString(ConstCString string, PMString::StringEncoding encoding,
TranslationSpecifier translate = kNeedsTranslate);

CS4 constructor:
PMString(ConstCString string, PMString::StringEncoding encoding);

For most cases in CS3, you probably created a PMString object like this:
PMString someString("SomeString", -1, PMString::kNoTranslate);

You can port it to CS4 using:

PMString someString("Root", PMString::kUnknownEncoding);

Replace IScriptEventData::SetReturnData
The APIs in IScriptEventData related to return data were modified to allow access to the error
code for every script request. Part of this change involves replacing IScriptEventData::SetReturnData with IScriptEventData::AppendReturnData. For details, see IScriptEventData on
page 28.

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

Porting Recipes

Utility APIs are accessed only through kUtilsBoss

This is more of a clean-up change, since most utilities were like this since the prior release;
however, the old way of accessing a utility method directly will not work any more. If you were
calling a utility method like this:

You should now call it through the Utils template:


This also means you need to change your header include for the utility from:
include "SomeUtils.h"

#include "ISomeUtils.h"

One implication of this change is that the often used inline, GetFrontDocument(), which is
defined in LayoutUIUtils.h, is no longer available Use Utils<ILayoutUIUtils>()->GetFrontDocument() instead.
PathUtils.h, PageItemUtils.h, and EncodingUtils.h are utilities used in the SDK. To work in
CS4, they needed to be ported using the above strategy.

XCode Warning
If you declare a variable with the same name more than once in the same scope, Xcode now will
warn: warning: declaration of 'myVar' shadows a member of 'this'. Rename the variable, or re-use
it if possible.

Porting Recipes
This section describes what changes are required to client code as a result of changes in the
InDesign CS4 API. If your code uses an affected API, follow these procedures to change your
code as required.

The following APIs were removed from IDFile:
CString GrabCString();
ConstCString GrabCString() const;
WString GrabWString();

For CS4, you can get a CString for the files path using this code:

For CS4, you can get a WString for the files path using this code:


Adobe InDesign CS4 Porting Guide

Porting Recipes


IImportManager::DoImportDialog() now requires the caller to supply a dialog for import. In
most cases (for regular file import), unless you are handling a specific type of resource for
import, you can provide the default file dialog in this manner:
InterfacePtr<IImportCore> iImportCore(importManager,IID_IIMPORTCORE);
InterfacePtr<IPlaceDialog> iPlaceDialog(iImportCore->QueryPlaceFileDialog());

Note that importManager used above can be obtained through IK2ServiceRegistry, with the ID
The IImportManager::DoImportDialog() returns a list of URIs for import, as opposed to SysFileList. URI uniquely identifies a resource for import. If you know the URI represents a file,
and SysFileList is required for your situation, you can use IURIUtils::URIListToSysFileList to
convert the URIList to SysFileList.

For CS4, the IInCopyBridgeCmdSuite public interface was removed and replaced with a new,
ILiveEditFacade public interface. Rather than creating your own instance of the IInCopyBridgeCmdSuite, you can now use the ILiveEditFacade to check in/out. For an example, see the
incopyfileactions sample (InCopyDocUtils.cpp).

The ISnippetExport interface was modified to accommodate IDML export. The major change
is that the ExportToStream methods were changed to ExportXMLElements and ExportPageItems. For details, see ISnippetExport.h.

The static-text widget was modified to allow/disallow automatic conversion of ampersands to
underlines. Two new, pure virtual methods were added to the IStaticTextAttributes interface
(see IStaticTextAttributes.h):
virtual void SetConvertAmpersandsToUnderline(bool16 convertAmpersands) = 0;
virtual bool16 GetConvertAmpersandsToUnderline() = 0;

A new field, fConvertAmpersandsToUnderline, was added to the StaticTextAttributes type

type StaticTextAttributes : Interface (IID = IID_ISTATICTEXTATTRIBUTES)
// fAlignment
// ellipsize ...
// fConvertAmpersandsToUnderline

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

Porting Recipes

To port existing StaticTextWidgets, add the new fConvertAmpersandsToUnderline field to the

static text-resource definition in your .fr file. Use kTrue to convert ampersands to underlines
(old default), or use kFalse to not convert. Here is an example:
// CControlView properties
kBscL10NStaticTextWidgetID, // widget ID
// StaticTextAttributes properties
// Alignment
kDontEllipsize, // Ellipsize style
// ==> ADDED for CS4 to convert ampersands

A misspelled method name was corrected in the IStyleGroupListControlData interface. The
old method name (with Child misspelled) was:
virtual void AppendChlidTypeIID(const PMIID& childType) = 0;

This was changed to:

virtual void AppendChildTypeIID(const PMIID& childType) = 0;

The API functionality remains the same. To use the new API, simply change the spelling to the
new version.

The APIs for navigating MultiColumnTextFrame were changed. Of note is that the ITextColumnSizer class no longer has a method named GetLastFrameIndex. To check that a frame that
is being linked from is not the last one in its frame list, use IMultiColumnTextFrame::GetIsLastMCF instead of comparing ItextColumnSizer::GetLastFrameIndex() to the total frame

kInvalidUIDRef is now defined in UIDRef.h. Prior versions of the InDesign API allowed separate definitions of this constant; for example:
#ifndef kInvalidUIDRef
#define kInvalidUIDRef UIDRef(nil, kInvalidUID)

To avoid the possibility of getting multiply defined compile errors for kInvalidUIDRef,
replace your definition with:
#include "UIDRef.h".


Adobe InDesign CS4 Porting Guide

Porting Recipes

Many APIs are continuing to move from PMString to WideString. To port your code to use
WideString, it is common to simply create a WideString by passing the PMString to the constructor:
PMString myOldString;

Also, some clean-up work was done to PMString. This involved removing the APIs listed

The constructor using translation parameter no longer uses a translation specifier. For CS4,
remove the TranslationSpecificer parameter if it is kNoTranslate. If it is kAutoTranslate,
remove encoding and pass kTranslateDuringCall. If it is kNeedsTranslate (keep in mind
that if nothing was passed, this was the default), remove kNeedsTranslate and the encoding
PMString(ConstCString string, PMString::StringEncoding encoding,
TranslationSpecifier translate = kNeedsTranslate);
PMString(ConstCString string, PMString::StringEncoding encoding);
CS3 usage:
PMString someString("SomeString", -1, PMString::kNoTranslate);
CS4 usage:
PMString someString("Root", PMString::kUnknownEncoding);

Translation enums kNeedsTranslate, kAutoTranslate, and kNoTranslate were removed. In

CS3, these enums were passed to the translation constructor to define how to translate the
string. This enums are no longer needed in CS4.
To replace kNeedsTranslate:
Use constructor without encoding, or call SetKey.
To replace kAutoTranslate:
Use constructor without encoding and pass kTranslateDuringCall.
To replace kNoTranslate:
Remove if using constructor. As long as encoding is passed to the
constructor, the string is marked as no translate. If calling SetCString,
pass encoding and string will be set to no translate.

Constructor specifying a character buffer, size, and encoding The encoding parameter was
removed. In CS4, use encoding only when you get the string as a platform string. At that
time, you can specify encoding.
Removed CS3 API:
PMString(const UTF16TextChar * string, int32 nDblBytes,
StringEncoding encoding);
PMString(const UTF16TextChar * string, int32 nDblBytes);

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

Porting Recipes

Constructor using ConstPString parameter To port to CS4, use the default constructor,
then use SetPString to assign the value of the string.
Removed CS3 API:
explicit PMString(ConstPString p);
PString pItsName = (PString) resPtr;
PMString itsName(pItsName);
PMString itsName;
PString pItsName = (PString) resPtr;
itsName.SetPString (pItsName, PMString::kUnknownEncoding);

GrabPString When porting, first see if this API is used for a Mac OS API call, then see if
there is a new version of the Mac OS API that takes a CFString. If not, use GetPString.
Removed CS3 APIs:
PString GrabPString(void);
ConstPString GrabPString(void) const;
err = FSMakeFSSpec(tSpec.vRefNum, tSpec.parID, tmpName.GrabPString(),
Str255 pstrTmpName;
tmpName.GetPString(pstrTmpName, 255);
err = FSMakeFSSpec(tSpec.vRefNum, tSpec.parID, pstrTmpName, &fSpec);

GetByteIndexFromCharPos and GetCharPosFromByteIndex If this is for a Windows API

call, you might already have a bug. Windows uses the Unicode API, and indexes should be
character indexes, so you should remove this call and use the CharCounter or index
directly. If this is used for a Mac OS API call, see if there is a new one that takes a character
Removed CS3 APIs:
int32 GetByteIndexFromCharPos(CharCounter charIndex) const;
CharCounter GetCharPosFromByteIndex(int32 byteIndex) const;

SubWString Replace calls to SubWString with Substring.

Removed CS3 API:
PMString* SubWString(int32 pos, int32 count = kMaxInt32) const;
PMString* Substring(CharCounter pos, CharCo unter count = kMaxInt32) const;

GrabCString Replace calls to GrabCString with GetCString or GetPlatformString().c_str().

Removed CS3 APIs:
CString GrabCString(void);
CS4 usage:
Trace("myTrace(%s)", myPMString.GetPlatformString().c_str());


Adobe InDesign CS4 Porting Guide

Porting Recipes

Shrink Replace calls to Shrink with reserve (inherited from UnicodeSavvyString).

Removed CS3 API:
void Shrink(bool16 maxshrink = kFalse);

SetHexChar Replace calls to SetHexChar with SetXString, passing count = 1.

Removed CS3 API:
void SetHexChar(const uchar x, PMString::StringEncoding encoding =
convertedString.SetXString((textchar*)&commaTextChar, 1);

Style matching
IStyleSyncService and ISelectivelyLoadStyleCmdData were modified to allow you to set and
get the style-matching strategy. A new enum, StyleMatchingStrategyEnum, was added to StyleClashResolutionTypes, and two pure virtual methods were added to IStyleSyncService and ISelectivelyLoadStyleCmdData.
virtual void SetStyleMatchingStrategy(
StyleClashResolutionTypes::StyleMatchingStrategyEnum styleMatchingStrategy)=0;
virtual StyleClashResolutionTypes::StyleMatchingStrategyEnum
GetStyleMatchingStrategy() const = 0;

To add the style-matching strategy code to your implementation of IStyleSyncService or ISelectivelyLoadStyleCmdData, follow these steps:
1. Add a private data member (fUseStyleMatchingStrategy) to store a StyleClashResolutionTypes::StyleMatchingStrategyEnum.
2. Add SetStyleMatchingStrategy(), and set fUseStyleMatchingStrategy to the parameter value.
3. Add GetStyleMatchingStrategy(), and return fUseStyleMatchingStrategy.
4. Initialize fUseStyleMatchingStrategy in your constructor.
For example:
class MyStyleSyncService : public CPMUnknown<IStyleSyncService>
MyStyleSyncService(IPMUnknown* boss) :
virtual void SetStyleMatchingStrategy(
StyleClashResolutionTypes::StyleMatchingStrategyEnum styleMatchingStrategy)
{ fUseStyleMatchingStrategy = styleMatchingStrategy; }
virtual StyleClashResolutionTypes::StyleMatchingStrategyEnum
GetStyleMatchingStrategy () const

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

Porting Recipes

{ return fUseStyleMatchingStrategy;}

XML parser
The underlying XML parser library was changed from AXEParser to a new parser called Expat.
This new parser also uses SAX (Simple API for XML), so no changes to our parser interface,
ISAXContentHandler, were required; however, some parser options on ISAXParserOptions are
no longer available. The following methods in ISAXParserOptions were removed:

IsNamespacePrefixesFeatureEnabled() and SetNamespacePrefixesFeature() This allowed

users to decide whether namespace prefixes are preserved. In Expat, namespace prefixes
always are preserved.

IsValidationFeatureEnabled() and SetValidationFeature() this allowed users to validate

the XML file against a DTD. Expat does not have validation functionality. A workaround is
to import the XML file into InDesign, then use the DTD validation support (IXMLValidator) in InDesign.

IsAutoValidationFeatureEnabled() and SetAutoValidationFeature() When both the validation option and this option were enabled, the parser validated the document if it contained a DTD. Again, a workaround is to import the XML file into InDesign, then use the
DTD validation support (IXMLValidator) in InDesign.

IsWarnCaseXMLDECLFeatureEnabled() and SetWarnCaseXMLDECLFeature() When

this was enabled, an incorrect case in the XML declaration was treated as a warning but not
an error. This option was a workaround for XML files that contained an incorrect case in
the XML declaration. These files are not well formed XML files, and they should no longer
be used.

IsWarnCaseDTDFeatureEnabled() and SetWarnCaseDTDFeature() Like the previous

option, this allowed the parser to treat an incorrect case in the DOCTYPE declaration as a
warning. Again, XML files that are not well formed should be fixed or not used.

IsValidateDTDEnabled() and SetValidateDTD() This allowed users to check the syntax of

the DTD in an XML file. A workaround is to import the XML file into InDesign or load the
DTD using XMLLoadDTDCmd.

Custom story thread

If you implement a custom story thread and owned item for a feature like the HiddenText sample, there are some new methods in ITextStoryThread and ITextParcelListData that you need to
be aware of:


ITextStoryThread::QueryParent should return the IScript object that is considered to be the

parent of any TextObject in the thread. If your story thread is not a host to a generic, textscript object like words or lines, you do not need to return anything; otherwise, you should

Adobe InDesign CS4 Porting Guide

Porting Recipes

query the IScript interface that may be aggregated on the same boss as the ITextStoryThread, and return the interface pointer of the IScript.

ITextStoryThread::GetAdjustedTextStart should return the adjusted thread start/end for the

specified scripting context. Some implementations do not support making the full range of
the StoryThread available to scripting and this method allows them to clip off the beginning
and/or end of the thread. This adjusted range will limit the natural extensions that take
place for scripting objects like words, lines, and paragraphs, that occur beyond a subrange
of the thread. For most of the implementation, you will be passed in an int32* that is the
adjusted span. Pass this into ITextStoryThread::GetTextStart to get the index of the adjusted
text start.

ITextParcelListData::GetIsRightToLeft should be true or false, indicating (especially at the

end of a line) whether to attach the caret to the right side of the left character or the left side
of the right character.

kHyperlinkTextMarkerBoss and kHyperlinkTextSourceEndMarkerBoss

These two bosses are no longer valid, owned item bosses, as a result of the re-write of the
hyperlink feature. We no longer track hyperlink text sources by marker pairs; instead, they are
tracked by a new strand, TextRangeListStrand. The only marker we need now is for the hyperlinktext destination, which is represented as kHyperlinkTextDestinationMarkerBoss. For
hyperlink text sources, if you have a text index (range) and want to find out if the index (range)
is contained in a hyperlink text-source range, you may call IHyperlinkUtils::IsRangeContainedByAHyperlink. If you want to find out whether a text range contains any hyperlink text
sources, use IHyperlinkUtils::GetRangesContainedHyperlinks.

ISnippetExportSuite::DoExport now requires you to pass in an INXOptions, An INXOptions
can be initialized with an INXStyle, which is defined in INXOptions.h. Also, there is an
IID_ISNIPPETPREFERENCES on the session workspace, which indicates whether the INXOptions should be in traditional or expanded style as a fallback option. For an example of the
use of IID_ISNIPPETPREFERENCES, see SnpManipulateXMLSelection::ExportXMLSnippetFromSelection.

Miscellaneous changes

IPageItemUtils::QuerySpread no longer exists. Use IPasteboardUtils::QuerySpread instead.

Text::GetParcelContentBounds was moved to ITextUtils.

IXMLTagList::GetTag now asks for a WideString instead of PMString. Wrap the old
PMString in a WideString.

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

Porting Recipes


Adobe InDesign CS4 Porting Guide

Porting Recipes

Adobe InDesign CS4 Porting Guide


Adobe InDesign CS4 Porting Guide

Porting Recipes