2025-11-28 00:35:46 +09:00

584 lines
17 KiB
C++

//<SnippetMusicBundle_cppConsumptionWholePage>
/*****************************************************************************
*
* File: MusicBundleConsumption.cpp
*
* Description:
* This sample is a simple application that might be used as a starting-point
* for an application that uses the Packaging API. This sample demonstrates
* the production and consumption of a music bundle package, which is a custom
* package file-format.
*
* The music bundle format is an example of a custom package file format and
* was designed specifically for this sample. See the MusicBundle.h header file
* for the music bundle specification.
*
* For the sake of simplicity, production data used for the sample is hard
* coded. In a fully-functional application, production data would be retrieved
* from the user of the application.
*
* ------------------------------------
*
* This file is part of the Microsoft Windows SDK Code Samples.
*
* Copyright (C) Microsoft Corporation. All rights reserved.
*
* This source code is intended only as a supplement to Microsoft
* Development Tools and/or on-line documentation. See these other
* materials for detailed information regarding Microsoft code samples.
*
* THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*****************************************************************************/
#include <stdio.h>
#include <windows.h>
#include <shlobj.h>
#include <msopc.h> // For Packaging APIs
#include <strsafe.h>
#include "util.h"
#include "MusicBundle.h"
//-------------------------------------
// Consumption helper methods.
///////////////////////////////////////////////////////////////////////////////
// Description:
// Reads a part from the Music Bundle, displays content to the console (if
// required), and writes the content to a file in the output directory.
///////////////////////////////////////////////////////////////////////////////
HRESULT
ReadPartFromBundle(
IOpcFactory *opcFactory,
IOpcRelationshipSet *relationshipSet,// Track relationship set.
IOpcPartSet *packagePartSet, // Set of all parts in the package.
LPCWSTR relationshipType, // Relationship type of relationship targeting the part.
LPCWSTR contentType, // Content type of the part.
LPCWSTR outputDirectory, // Part content is serialized as the content of a file in
// this directory.
LPCWSTR displayTitle = NULL, // Title to display with file contents. Optional; set to
// NULL if displaying content is not required.
IOpcPart **partRead = NULL // The part to be read. Optional; caller must release the
// object.
)
{
HRESULT hr = S_OK;
IOpcPart * part = NULL;
IOpcRelationship * relationship = NULL;
IStream * stream = NULL;
// Get relationships of the specified type.
hr = GetRelationshipByType(
relationshipSet,
relationshipType,
&relationship
);
if (SUCCEEDED(hr))
{
// Get the part targetted by the relationship.
hr = GetRelationshipTargetPart(
packagePartSet,
relationship,
contentType,
&part
);
}
if (SUCCEEDED(hr) && displayTitle)
{
// Get part content stream.
hr = part->GetContentStream(&stream);
if (SUCCEEDED(hr))
{
// Display the content to the console.
hr = DisplayStreamContent(displayTitle, stream);
}
}
if (SUCCEEDED(hr))
{
// Write the part content to a file in the output directory.
hr = WritePartContentToFile(opcFactory, outputDirectory, part);
}
if (SUCCEEDED(hr) && partRead != NULL)
{
// Return a point to the part that was read and written.
*partRead = part;
part = NULL;
}
// Release resources
if (part)
{
part->Release();
part = NULL;
}
if (relationship)
{
relationship->Release();
relationship = NULL;
}
if (stream)
{
stream->Release();
stream = NULL;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// Description:
// Method does the following:
// 1. Reads a specified Track part in the Music Bundle and writes the part to
// a file in the output directory.
// 2. Reads the Lyrics part for the Track part.
///////////////////////////////////////////////////////////////////////////////
HRESULT
ReadTrackAndLyricsFromBundle(
IOpcFactory *opcFactory,
IOpcPartSet *packagePartSet,// Set of all parts in the package.
IOpcPart *trackPart, // Track part to read.
LPCWSTR outputDirectory // Write part content to a file in this directory.
)
{
HRESULT hr = S_OK;
IOpcRelationshipSet * trackRelationshipSet = NULL;
// Write part content to a file in the output directory.
hr = WritePartContentToFile(opcFactory, outputDirectory, trackPart);
// Get the relationship set for the Track part.
if (SUCCEEDED(hr))
{
hr = trackPart->GetRelationshipSet(&trackRelationshipSet);
}
// Get Lyrics for track.
if (SUCCEEDED(hr))
{
hr = ReadPartFromBundle(
opcFactory,
trackRelationshipSet,
packagePartSet,
g_lyricsRelationshipType,
g_lyricsContentType,
outputDirectory,
L"Lyrics"
);
}
// Release resources
if (trackRelationshipSet)
{
trackRelationshipSet->Release();
trackRelationshipSet = NULL;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// Description:
// Enumerates and reads all the Track parts in the Track List
// relationship set by the relationship type
///////////////////////////////////////////////////////////////////////////////
HRESULT
EnumerateTracksFromBundle(
IOpcFactory *opcFactory,
IOpcRelationshipSet *trackListRelationshipSet,// Set of all relationships whose source
// is the Track List part.
IOpcPartSet *packagePartSet, // Set of all parts in the package.
LPCWSTR outputDirectory // Write part content to a file in this directory.
)
{
HRESULT hr = S_OK;
BOOL bNext = FALSE;
IOpcRelationshipEnumerator * relationshipEnumerator = NULL;
// Get enumerator of relationships in the set that are the track
// relationship type.
hr = trackListRelationshipSet->GetEnumeratorForType(
g_trackRelationshipType,
&relationshipEnumerator
);
// For each relationship in the enumerator, get the targetted Track part,
// read the part and read the Lyrics part linked to the current Track part.
if (SUCCEEDED(hr))
{
while (SUCCEEDED(hr = relationshipEnumerator->MoveNext(&bNext)) && bNext)
{
IOpcRelationship * trackRelationship = NULL;
IOpcPart * trackPart = NULL;
// Get current enumerator relationship.
hr = relationshipEnumerator->GetCurrent(&trackRelationship);
// Get the Track part targetted by the relationship.
if (SUCCEEDED(hr))
{
hr = GetRelationshipTargetPart(
packagePartSet,
trackRelationship,
g_trackContentType,
&trackPart
);
}
if (SUCCEEDED(hr))
{
// Read contents of the Track part and of the Lyrics part that
// is linked to the current Track part.
hr = ReadTrackAndLyricsFromBundle(
opcFactory,
packagePartSet,
trackPart,
outputDirectory
);
}
// Release resources
if (trackRelationship)
{
trackRelationship->Release();
trackRelationship = NULL;
}
if (trackPart)
{
trackPart->Release();
trackPart = NULL;
}
}
}
// Release resources
if (relationshipEnumerator)
{
relationshipEnumerator->Release();
relationshipEnumerator = NULL;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// Description:
// Method does the following:
// 1. Reads the Track List in the Music Bundle, displays it to
// the console.
// 2. Writes the part to a file in the output directory.
// 3. Enumerates the Track List relationships and reads all the
// Tracks in the Music Bundle.
///////////////////////////////////////////////////////////////////////////////
HRESULT
ReadTrackListFromBundle(
IOpcFactory *opcFactory,
IOpcRelationshipSet *packageRelationshipSet,// Package relationship set.
IOpcPartSet *packagePartSet, // Set of all parts in the package.
LPCWSTR outputDirectory // Write part content to a file in this directory.
)
{
HRESULT hr = S_OK;
IOpcPart * trackListPart = NULL;
IOpcRelationshipSet * trackListRelationshipSet = NULL;
// Find the Track List part by using the track list relationship type.
hr = ReadPartFromBundle(
opcFactory,
packageRelationshipSet,
packagePartSet,
g_trackListRelationshipType,
g_trackListContentType,
outputDirectory,
L"TrackList",
&trackListPart
);
if (SUCCEEDED(hr))
{
// Get the set of relationships whose source is the Track List part.
hr = trackListPart->GetRelationshipSet(&trackListRelationshipSet);
}
if (SUCCEEDED(hr))
{
// Enumerate tracks in the bundle.
hr = EnumerateTracksFromBundle(
opcFactory,
trackListRelationshipSet,
packagePartSet,
outputDirectory
);
}
// Release resources
if (trackListPart)
{
trackListPart->Release();
trackListPart = NULL;
}
if (trackListRelationshipSet)
{
trackListRelationshipSet->Release();
trackListRelationshipSet = NULL;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// Description:
// Reads the Album Art in the Music Bundle and writes the part
// to a file in the output directory
///////////////////////////////////////////////////////////////////////////////
HRESULT
ReadAlbumArtFromBundle(
IOpcFactory *opcFactory,
IOpcRelationshipSet *packageRelationshipSet,// Package relationship set.
IOpcPartSet *packagePartSet, // Set of all parts in the package.
LPCWSTR outputDirectory // Write part content to a file in this directory.
)
{
HRESULT hr = S_OK;
// Find the Album Art part by using the album art relationship type.
hr = ReadPartFromBundle(
opcFactory,
packageRelationshipSet,
packagePartSet,
g_albumArtRelationshipType,
g_albumArtContentType,
outputDirectory
);
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// Description:
// Reads the Album Website part displays its content in the console.
///////////////////////////////////////////////////////////////////////////////
HRESULT
ReadAlbumWebsiteFromBundle(
IOpcRelationshipSet *packageRelationshipSet // Package relationship set.
)
{
HRESULT hr = S_OK;
IOpcRelationship * opcRelationship = NULL;
OPC_URI_TARGET_MODE targetMode = OPC_URI_TARGET_MODE_INTERNAL;
IUri * targetUri = NULL;
BSTR targetUriString = NULL;
// Find the Album Website part by using the album website relationship type.
hr = GetRelationshipByType(
packageRelationshipSet,
g_albumWebsiteRelationshipType,
&opcRelationship
);
if (SUCCEEDED(hr))
{
// Get the target mode of the relationship; teh mode must be 'External'
// for the relationship to target an external absolute URL.
hr = opcRelationship->GetTargetMode(&targetMode);
}
if (SUCCEEDED(hr))
{
if (targetMode != OPC_URI_TARGET_MODE_EXTERNAL)
{
// The target mode was 'Internal'.
fwprintf(
stderr,
L"Invalid music bundle package: relationship with type %s must have External target mode.\n",
g_albumWebsiteRelationshipType
);
// Set the return code to an error.
hr = E_FAIL;
}
}
if (SUCCEEDED(hr))
{
// Get the target URI, which is the album website URL.
hr = opcRelationship->GetTargetUri(&targetUri);
}
if (SUCCEEDED(hr))
{
// Get the album website URL as a string.
hr = targetUri->GetAbsoluteUri(&targetUriString);
}
if (SUCCEEDED(hr))
{
// Display the album website URL.
wprintf(L"\n++++++ Album Website ++++++\n%s\n\n", targetUriString);
}
// Release resources
if (opcRelationship)
{
opcRelationship->Release();
opcRelationship = NULL;
}
if (targetUri)
{
targetUri->Release();
targetUri = NULL;
}
SysFreeString(targetUriString);
return hr;
}
//---------------------------------
// Function to consume the new music bundle.
// Exposed through MusicBundle.h.
//
///////////////////////////////////////////////////////////////////////////////
// Description:
// Deserializes the contents of a music bundle package, displays text from
// the Track List, Lyrics, Album Website parts. The method then serializes the
// contents of the parts to files in specified output directory.
///////////////////////////////////////////////////////////////////////////////
HRESULT
ConsumeMusicBundle(
LPCWSTR inputPackageName,// Name of music bundle.
LPCWSTR outputDirectory // Directory into which music bundle parts are written as files.
)
{
HRESULT hr = S_OK;
IOpcFactory * opcFactory = NULL;
IStream * packageStream = NULL;
IOpcPackage * opcPackage = NULL;
IOpcRelationshipSet * packageRelationshipSet = NULL;
IOpcPartSet * packagePartSet = NULL;
// Create a new factory.
hr = CoCreateInstance(
__uuidof(OpcFactory),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IOpcFactory),
(LPVOID*)&opcFactory
);
if (SUCCEEDED(hr))
{
// Open a read-only stream over the input package.
hr = opcFactory->CreateStreamOnFile(
inputPackageName,
OPC_STREAM_IO_READ, // Read-only.
NULL,
FILE_ATTRIBUTE_NORMAL,
&packageStream
);
}
if (SUCCEEDED(hr))
{
// Create a package object to represent the pacakge being read, allowing
// package components to be accessed through Packaging API objects.
hr = opcFactory->ReadPackageFromStream(
packageStream,
OPC_READ_DEFAULT, // Validate package component when it is accessed.
&opcPackage
);
}
if (SUCCEEDED(hr))
{
// Get relationship set of package relationships.
hr = opcPackage->GetRelationshipSet(&packageRelationshipSet);
}
if (SUCCEEDED(hr))
{
// Get the set of parts in the package that are not Relationships parts.
hr = opcPackage->GetPartSet(&packagePartSet);
}
// Read, display and unpack the music bundle.
if (SUCCEEDED(hr))
{
// Read and display album art.
hr = ReadAlbumArtFromBundle(
opcFactory,
packageRelationshipSet,
packagePartSet,
outputDirectory
);
}
if (SUCCEEDED(hr))
{
// Read and display album website.
hr = ReadAlbumWebsiteFromBundle(packageRelationshipSet);
}
if (SUCCEEDED(hr))
{
// Read and unpack as files in the output directory: the track list,
// tracks and lyrics. Display the track list and corresponding lyrics.
hr = ReadTrackListFromBundle(
opcFactory,
packageRelationshipSet,
packagePartSet,
outputDirectory
);
}
// Release resources
if (opcFactory)
{
opcFactory->Release();
opcFactory = NULL;
}
if (packageStream)
{
packageStream->Release();
packageStream = NULL;
}
if (opcPackage)
{
opcPackage->Release();
opcPackage = NULL;
}
if (packageRelationshipSet)
{
packageRelationshipSet->Release();
packageRelationshipSet = NULL;
}
if (packagePartSet)
{
packagePartSet->Release();
packagePartSet = NULL;
}
return hr;
}
//</SnippetMusicBundle_cppConsumptionWholePage>