Differences between the Native and Managed APIs

This topic describes the programming differences between the native-code Packaging API, introduced in Windows 7, and its managed-code System.IO.Packaging API counterpart.

This topic contains the following sections:

Introduction

The description of the programming differences between the native Packaging API and its managed System.IO.Packaging API counterpart that appears in this topic originally appeared as two Packaging Team blog posts: Comparing the OPC Managed-Code and Native-Code APIs, posted August 5th, 2009; and Comparing the OPC managed-code and native-code Part URI helper APIs, posted August 18th, 2009.

Who is Affected by the API Differences

If you are a developer who wants to transition your application to or from a native-code environment, you may need to make changes in your application code to adjust for differences between the two APIs.

The differences described in this topic can help you identify which blocks of application code may need to be reworked as a result of a code-base transition.

Comparing the Native Packaging API to its Managed Counterpart

Both the managed System.IO.Packaging API and the native Packaging API were designed to adhere to the ECMA-376 OpenXML, 1st Edition, Part 2: Open Packaging Conventions (OPC). The packages created by one API can be accessed by the other API.

The following table compares the native Packaging API implementation to the managed System.IO.Packaging API implementation for specific API features that have notable differences.

API Feature Native Packaging API Managed System.IO.Packaging API Comments
Zip encoding
Enables you to specify the Zip encoding when calling the WritePackageToStream method of the IOpcFactory interface to serialize package.
The default encoding is ZIP64.
Determines Zip encoding automatically.
The default encoding is ZIP32. If the package size exceeds ZIP32 limits, ZIP64 encoding is used.
This difference means that if you use the native Packaging API to specify ZIP32 encoding and your package exceeds ZIP32 size limits, the package will not be serialized and the method will return an error.
Editing in-place
No equivalent feature.
Changes must be saved as a new package, which can then be made to replace the original.
Enables saving changes to the original package.
Editing in-place using the native Packaging API would require opening two streams to package at the same time, or opening one read/write stream to the package, neither of which is supported.
Core Properties part interaction
No equivalent feature.
The Core Properties part can be read and edited by using the same procedures used to access any other part in the package.
Provides the PackageProperties class to enable reading and editing of the Core Properties part.
The Set Author Sample shows how to access and edit Core Properties part content by using the native Packaging API. The procedures used in the Set Author Sample are explained in greater detail in Finding the Core Properties Part and Modifying Part Content.
Pack URI support
Provides the CreatePartUri method of the IOpcFactory interface and the IOpcUri and IOpcPartUri interfaces, to support creating URIs that address parts (part names), the path component of the Pack URI scheme.
Provides the PackUriHelper class to support creating URIs that adhere to the Pack URI scheme and that can address both parts in a package and an entire package.
The Pack URI scheme is specified in Annex B. Pack URI of the OPC.
Because the native Packaging API only make use of part names, the API only support operations with this component of the Pack URI scheme.
For a more detailed comparison of Pack URI support, see Pack URI Comparison.
Accessing content within a package stored on a website
No equivalent feature.
Provides the PackWebRequest and PackWebResponse classes that enable access to content within a URI-addressable package that is stored on a website.
The System.IO.Packaging API classes are based on the managed-code WebRequest and WebResponse classes that support URI requests to access resources over the web.
Accessing a package without a Content Types stream
The call to the ReadPackageFromStream method of the IOpcFactory interface fails and returns an error code.
The native API considers a missing Content Types stream to be an error.
The call to the Package.Open method succeeds and the package is opened, but it is treated as an empty package.
Without the Content Types stream, parts in the package are not recognized as valid parts.
The behavior of each API differs when the Content Types stream is missing because the OPC specification is non-specific about how this situation should be handled.
Relationships part compression
Relationships parts use a default compression of OPC_COMPRESSION_NORMAL, which balances between size and performance concerns.
Relationships parts are compressed with the same compression as the source part; for the package Relationships part, no compression is used.
For more information about compression options used in the native Packaging API, see OPC_COMPRESSION_OPTIONS.
Treatment of Relationships parts
Treats Relationships parts as different from other parts and therefore does not allow direct access to Relationships parts.
For example, if you try to retrieve a Relationships part from the set of normal parts by calling the GetPart method of the IOpcPartSet interface, the method will return an error. Instead, Relationships parts can be accessed by calling the GetRelationshipSet method of the IOpcPart interface or the GetRelationshipSet method of the IOpcPackage interface.
Treats Relationships parts the same as other parts. All operations that are permitted on parts also work on Relationships parts.
For example, it enables the use of the Package.GetPart method with the part name of a Relationships part to get that part and its content.
The native Packaging API treats Relationships parts as distinct from other parts because they can behave differently from other parts. For example, a Relationships part cannot be the source of a relationship like a normal part.
Accessing the content stream of a Relationships part
Provides read-only access to a stream of Relationships part content by calling the GetRelationshipsContentStream method of the IOpcRelationshipSet interface.
To add or delete a relationship in the Relationships part, call the CreateRelationship or DeleteRelationship method of the IOpcRelationshipSet interface, respectively.
Provides read/write access to a stream of Relationships part content by calling the PackagePart.GetStream method.
The stream can be used to add, delete, or modify the relationships stored in the accessed Relationships part.
Read access to Relationships part content is provided by the native Packaging API solely for digital signature purposes.

Pack URI Comparison

In contrast to the centralized Pack URI support provided by the managed System.IO.Packaging API, the native Packaging API provides decentralized Pack URI support with the IOpcFactory::CreatePartUri method and the IOpcUri and IOpcPartUri interfaces.

Unlike the managed System.IO.Packaging API, the native Packaging API does not enable access to a package or its content as an external resource, and therefore supports part names to address part content only within the current package.

Despite these differences, both native and managed implementations adhere to the OPC.

The following table shows a detailed comparison of Pack URI support in the native Packaging API and managed System.IO.Packaging API.

Native Packaging API Managed System.IO.Packaging API Equivalence
IOpcFactory::CreatePartUri
PackUriHelper.CreatePartUri
See Detailed Comparison of IOpcFactory::CreatePartUri and PackUriHelper.CreatePartUri
IOpcFactory::CreatePackageRootUri
No equivalent API
None
IOpcUri::GetRelationshipsPartUri
PackUriHelper.GetRelationshipPartUri
Identical
IOpcUri::GetRelativeUri
PackUriHelper.GetRelativeUri
Identical
IOpcUri::CombinePartUri
PackUriHelper.ResolvePartUri
See Detailed Comparision of IOpcUri::CombinePartUri and PackUriHelper.ResolvePartUri
IOpcPartUri::ComparePartUri
PackUriHelper.ComparePartUri
Identical
IOpcPartUri::GetSourceUri
PackUriHelper.GetSourcePartUriFromRelationshipPartUri
Identical
IOpcPartUri::IsRelationshipsPartUri
PackUriHelper.IsRelationshipPartUri
Identical
No equivalent
PackUriHelper.Create
None
No equivalent
PackUriHelper.ComparePackUri
None
No equivalent
PackUriHelper.GetNormalizedPartUri
None
No equivalent
PackUriHelper.GetPackageUri
None
No equivalent
PackUriHelper.GetPartUri
None

Detailed Comparision of IOpcFactory::CreatePartUri and PackUriHelper.CreatePartUri

Both the native and managed implementations adhere to the OPC requirements for creating part names. While both implementations should also adhere to the requirements of RFC 3987: Internationalized Resource Identifiers (IRIs), the managed PackUriHelper.CreatePartUri class method violates those requirements if the input contains bad UTF-encoding.

In addition, the native IOpcFactory::CreatePartUri interface method differs from its managed counterpart because the interface method ensures that the part names it returns are valid.

The following table shows these differences by comparing the behavior of the native and managed implementations.

Input Native IOpcFactory::CreatePartUri Behavior Managed PackUriHelper.CreatePartUri Behavior
Begins with more than one forward slash.
Collapses multiple forward slashes to a single forward slash, and returns a valid part name.
Fails and throws an ArgumentException.
Contains empty segments (multiple forward slashes).
Collapses empty segments to a single forward slash, and returns a valid part name.
Does not collapse empty segments, and returns an invalid part name.
Contains bad UTF-8 encoding.
For example: %FC
Preserves encoding, and returns a valid part name.
For example: %FC would be unchanged in the output.
Changes to valid UTF-8 encoding, and returns a valid part name.
For example: %FC would be changed to %C3%BC in the output, which violates requirements of RFC 3987.
Contains a percent-encoded NULL (%00).
Fails and returns an E_UNEXPECTED error code.
Percent-encoded NULL is unchanged, and returns a valid part name.
Ends with a forward slash.
Removes trailing forward slash, and returns a valid part name.
Fails and throws an ArgumentException.

Note

Characters above 0x7F must be escaped using UTF-8.

Detailed Comparision of IOpcUri::CombinePartUri and PackUriHelper.ResolvePartUri

There are a significant behavioral differences between these native and managed implementations because they adhere to different sets of requirements.

The native IOpcUri::CombinePartUri interface method adheres to the requirements from both RFC 3987 and section A.3 of the OPC. As a result, the part names that are returned by this interface method are valid.

In contrast, the managed PackUriHelper.ResolvePartUri class method adheres to the requirements from RFC 3987 but not section A.3 of the OPC. As a result, the part names that are returned by this class method may be invalid.

The following table shows these differences by comparing the behavior of the native and managed implementations.

Input Native IOpcUri::CombinePartUri Behavior Managed PackUriHelper.ResolvePartUri Behavior
Begins with more than one forward slash.
Collapses multiple forward slashes to a single forward slash, and returns a valid part name.
Fails and throws an ArgumentException, which violates requirements of section A.3 OPC.
Contains empty segments (multiple forward slashes).
Collapses empty segments to a single forward slash, and returns a valid part name.
Does not collapse empty segments, which violates requirements of section A.3 OPC, and returns an invalid part name.
Contains bad UTF-8 encoding.
For example: %FC
Preserves encoding, and returns a valid part name.
For example: %FC would be unchanged in output.
Preserves encoding, and returns a valid part name.
For example: %FC would be unchanged in output.
Contains percent-encoded unreserved characters.
Un-encodes unreserved characters, and returns a valid part name.
Preserves encoding, which violates requirements of section A.3 OPC, and returns an invalid part name.
Contains a percent-encoded NULL (%00).
Fails and returns an E_UNEXPECTED error code.
Percent-encoded NULL is unchanged, and returns a valid part name.
Ends with a forward slash.
Removes trailing forward slash, and returns a valid part name.
Does not remove trailing forward slash, which violates requirements of section A.3 OPC, and returns an invalid part name.

Packaging API Programming Guide

Reference

Packaging API Reference

Packaging API Samples

Overviews

Getting Started with the Packaging API

Open Packaging Conventions Fundamentals

External

ECMA-376 OpenXML