Finding the Core Properties part
This topic shows how to use the Packaging APIs to find the Core Properties part with a relationship type.
This topic contains the following sections.
Introduction
This code example shows the FindCorePropertiesPart
and FindPartByRelationshipType
functions, which are the primary functions for finding the Core Properties part in the Set Author Sample.
Both functions are declared in the opclib.h header file and defined in the opclib.cpp implementation file of the Set Author Sample. For the complete program, which can load, modify, and save a package, see the Set Author Sample.
Finding the Core Properties Part by its Relationship Type
The function in the following sections finds the Core Properties part by following the steps outlined in the Parts Overview. For each step, the code is accompanied by additional explanation to show how that step could be implemented.
The step that requires resolving the part name from the URI of a relationship's target is omitted from this topic but is shown in the Resolving a Part Name from a Relationship's Target URI topic.
Steps
Identify and define a constant for the relationship type to be used and for the content type of the part.
The content type can be used to ensure that part content is the expected content type, which is described in the package-format specification or the OPC.
To find the Core Properties part, both the core properties relationship type and the Core Properties part content type are required. Both of these are defined in the OPC, and their definitions are shown in the following table.
Info to find Core Properties part Definition from OPC core properties relationship type https://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties Core Properties part's content type application/vnd.openxmlformats-package.core-properties+xml Define a constant for the core properties relationship type:
// The relationship type (core-properties relationship type) of the // relationship targeting the Core Properties part, as defined by the OPC // (ECMA-376 Part 2). static const WCHAR g_corePropertiesRelationshipType[] = L"https://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
Define a constant for the Core Properties part's content type:
// The expected content type of the Core Properties part, as defined by the OPC // (ECMA-376 Part 2). static const WCHAR g_corePropertiesContentType[] = L"application/vnd.openxmlformats-package.core-properties+xml";
Access the package where the part to be found is stored.
This code example primarily uses two functions to find the Core Properties part:
FindCorePropertiesPart
andFindPartByRelationshipType
. To find a part, most of the work is done in the body of theFindPartByRelationshipType
function.The
FindCorePropertiesPart
function declaration from the opclib.h file:HRESULT FindCorePropertiesPart( IOpcPackage *package, IOpcPart **part );
The
FindCorePropertiesPart
function takes an IOpcPackage interface pointer representing the package and retrieves an IOpcPart interface pointer representing the Core Properties part. It finds the Core Properties part by wrapping a call toFindPartByRelationshipType
, and by passing in as input arguments the global variables that contain the relationship type and part content type that are needed to find the Core Properties part.The body of the
FindCorePropertiesPart
function:return FindPartByRelationshipType( package, g_corePropertiesRelationshipType, g_corePropertiesContentType, part );
In this example, the relationship type that is defined in
g_corePropertiesRelationshipType
identifies a relationship that targets the Core Properties part. TheFindPartByRelationshipType
function is used to find the Core Properties part in this example. It can also be used to find any part targeted by a package relationship if the relevant relationship type and, optionally, content type information is passed to the function.The
FindPartByRelationshipType
function declaration from the opclib.h file:HRESULT FindPartByRelationshipType( IOpcPackage *package, LPCWSTR relationshipType, LPCWSTR contentType, // optional IOpcPart **part );
Find the part. The body of the
FindPartByRelationshipType
function finds the part and is shown in the following code.Declare variables that will be used to find the part:
*part = NULL; // Enable checks against value of *part. IOpcRelationshipSet * packageRels = NULL; IOpcRelationshipEnumerator * packageRelsEnum = NULL; IOpcPartSet * partSet = NULL; BOOL hasNext = false;
Get the part set object, which contains the parts in the package (excluding Relationships parts):
HRESULT hr = package->GetPartSet(&partSet);
The part to be found is targeted by a package relationship; therefore, a pointer to the relationship set object that represents the Relationships part that stores package relationships must be retrieved.
Call the IOpcPackage::GetRelationshipSet method to retrieve a pointer to the relationship set object for package relationships:
if (SUCCEEDED(hr)) { // Get package relationships stored in the package's Relationships part. hr = package->GetRelationshipSet(&packageRels); }
Identify the relationships of the specified relationship type in the set.
Call the IOpcRelationshipSet::GetEnumeratorForType method to retrieve an enumerator of the interface pointers in the set that represent relationships of the specified relationship type:
if (SUCCEEDED(hr)) { // Get package relationships of the specified relationship type. hr = packageRels->GetEnumeratorForType( relationshipType, &packageRelsEnum ); }
[!Important]
If the package format designer described an expected number of relationships of the specified relationship type that are stored in a Relationships part the , check that the number of relationships retrieved conforms to that expectation. For information about the expected number of relationships for a specified relationship type, see the package format specification or the OPC.
To find the part, iterate through relationships of the specified relationship type.
Note
This example is limited to finding the first, arbitrary part that is the target of a relationship retrieved from the enumerator.
Define a loop to iterate through the enumerator of relationships:
if (SUCCEEDED(hr)) { // Move pointer to first package relationship. hr = packageRelsEnum->MoveNext(&hasNext); } // Find the first, arbitrary part that is the target of a relationship // of the specified type and has the specified content type, if a content // type is provided. Abandon search when an error is encountered, when // there are no more relationships in the enumerator, or when a part is // found. while (SUCCEEDED(hr) && hasNext && *part == NULL) { IOpcPartUri * partUri = NULL; IOpcRelationship * currentRel = NULL; BOOL partExists = FALSE; hr = packageRelsEnum->GetCurrent(&currentRel);
If the target of a relationship is a part, resolve the part name against the URI of the relationship's source:
if (SUCCEEDED(hr)) { // There was a relationship of the specified type. // Try to resolve the part name of the relationship's target. hr = ResolveTargetUriToPart(currentRel, &partUri); }
For an example that shows how to resolve a part name from the target URI of a relationship, see Resolving a Part Name from a Target URI.
Ensure that a part with the resolved part name exists in the package, as shown in the following code.
if (SUCCEEDED(hr)) { // Part name resolved. Check that a part with that part name // exists in the package. hr = partSet->PartExists(partUri, &partExists); }
Get the part.
Get the IOpcPart interface pointer to the part object that represents the part, as shown in the following code.
if (SUCCEEDED(hr) && partExists) { // A part with the resolved part name exists in the package, so // get a pointer to that part. LPWSTR currentContentType = NULL; IOpcPart * currentPart = NULL; hr = partSet->GetPart(partUri, &currentPart);
If an expected content type is defined for the part by the package designer or the OPC, ensure that the part has the correct content type. If the part has the expected content type, or if no expected content type is defined, the part has been found.
if (SUCCEEDED(hr) && contentType != NULL) { // Content type specified. // Get the content type of the part. hr = currentPart->GetContentType(&currentContentType); // Compare the content type of the part with the specified // content type. if (SUCCEEDED(hr) && 0 == wcscmp(contentType, currentContentType)) { // Part content type matches specified content type. // Part found. *part = currentPart; currentPart = NULL; } } if (SUCCEEDED(hr) && contentType == NULL) { // Content type not specified. // Part found. *part = currentPart; currentPart = NULL; } // Release resources CoTaskMemFree(static_cast<LPVOID>(currentContentType)); if (currentPart) { currentPart->Release(); currentPart = NULL; } }
Retrieve the next relationship represented in the set and close the loop.
// Get the next relationship of the specified type. if (SUCCEEDED(hr)) { hr = packageRelsEnum->MoveNext(&hasNext); } // Release resources if (partUri) { partUri->Release(); partUri = NULL; } if (currentRel) { currentRel->Release(); currentRel = NULL; } }
FindCorePropertiesPart
Code Details
The following code example shows the FindCorePropertiesPart
function definition in one convenient block, found in opclib.cpp.
The FindCorePropertiesPart
function definition:
HRESULT
FindCorePropertiesPart(
IOpcPackage *package,
IOpcPart **part
)
{
return FindPartByRelationshipType(
package,
g_corePropertiesRelationshipType,
g_corePropertiesContentType,
part
);
}
FindPartByRelationshipType
Code Details
The following shows the FindPartByRelationshipType
function definition, which is found in the opclib.cpp file, in one convenient block.
The FindPartByRelationshipType
function definition:
HRESULT
FindPartByRelationshipType(
IOpcPackage *package,
LPCWSTR relationshipType, // Relationship type used to find the part.
LPCWSTR contentType, // Expected content type of part (optional).
IOpcPart **part
)
{
*part = NULL; // Enable checks against value of *part.
IOpcRelationshipSet * packageRels = NULL;
IOpcRelationshipEnumerator * packageRelsEnum = NULL;
IOpcPartSet * partSet = NULL;
BOOL hasNext = false;
HRESULT hr = package->GetPartSet(&partSet);
if (SUCCEEDED(hr))
{
// Get package relationships stored in the package's Relationships part.
hr = package->GetRelationshipSet(&packageRels);
}
if (SUCCEEDED(hr))
{
// Get package relationships of the specified relationship type.
hr = packageRels->GetEnumeratorForType(
relationshipType,
&packageRelsEnum
);
}
// Note: Though not performed by this sample, it may be necessary to check
// that the number of retrieved relationships conforms to the expected
// number of relationships specified by the format designer or in the OPC.
if (SUCCEEDED(hr))
{
// Move pointer to first package relationship.
hr = packageRelsEnum->MoveNext(&hasNext);
}
// Find the first, arbitrary part that is the target of a relationship
// of the specified type and has the specified content type, if a content
// type is provided. Abandon search when an error is encountered, when
// there are no more relationships in the enumerator, or when a part is
// found.
while (SUCCEEDED(hr) && hasNext && *part == NULL)
{
IOpcPartUri * partUri = NULL;
IOpcRelationship * currentRel = NULL;
BOOL partExists = FALSE;
hr = packageRelsEnum->GetCurrent(&currentRel);
if (SUCCEEDED(hr))
{
// There was a relationship of the specified type.
// Try to resolve the part name of the relationship's target.
hr = ResolveTargetUriToPart(currentRel, &partUri);
}
if (SUCCEEDED(hr))
{
// Part name resolved. Check that a part with that part name
// exists in the package.
hr = partSet->PartExists(partUri, &partExists);
}
if (SUCCEEDED(hr) && partExists)
{
// A part with the resolved part name exists in the package, so
// get a pointer to that part.
LPWSTR currentContentType = NULL;
IOpcPart * currentPart = NULL;
hr = partSet->GetPart(partUri, &currentPart);
if (SUCCEEDED(hr) && contentType != NULL)
{
// Content type specified.
// Get the content type of the part.
hr = currentPart->GetContentType(&currentContentType);
// Compare the content type of the part with the specified
// content type.
if (SUCCEEDED(hr) &&
0 == wcscmp(contentType, currentContentType))
{
// Part content type matches specified content type.
// Part found.
*part = currentPart;
currentPart = NULL;
}
}
if (SUCCEEDED(hr) && contentType == NULL)
{
// Content type not specified.
// Part found.
*part = currentPart;
currentPart = NULL;
}
// Release resources
CoTaskMemFree(static_cast<LPVOID>(currentContentType));
if (currentPart)
{
currentPart->Release();
currentPart = NULL;
}
}
// Get the next relationship of the specified type.
if (SUCCEEDED(hr))
{
hr = packageRelsEnum->MoveNext(&hasNext);
}
// Release resources
if (partUri)
{
partUri->Release();
partUri = NULL;
}
if (currentRel)
{
currentRel->Release();
currentRel = NULL;
}
}
if (SUCCEEDED(hr) && *part == NULL)
{
// Loop complete without errors and no part found.
hr = E_FAIL;
}
// Release resources
if (packageRels)
{
packageRels->Release();
packageRels = NULL;
}
if (packageRelsEnum)
{
packageRelsEnum->Release();
packageRelsEnum = NULL;
}
if (partSet)
{
partSet->Release();
partSet = NULL;
}
return hr;
}
Disclaimer
Code examples are not intended to be complete and working programs. The code examples that are referenced on this page, for example, do not perform parameter checking, error checking, or error handling. Use these examples as a starting point, then add the code necessary to create a robust application. For more information about error handling in COM, see the Error Handling (COM) topic.
Related topics
-
Overviews
-
Reference