Adding a Use License to the Compound File

[The AD RMS SDK leveraging functionality exposed by the client in Msdrm.dll is available for use in Windows Server 2008, Windows Vista, Windows Server 2008 R2, Windows 7, Windows Server 2012, and Windows 8. It may be altered or unavailable in subsequent versions. Instead, use Active Directory Rights Management Services SDK 2.1, which leverages functionality exposed by the client in Msipc.dll.]

After you have added a new issuance license to a file, you can acquire a use license for a requesting user and store it right in the document. That way, the user can view the document immediately, without making an additional call to a server for a use license.

The use license is stored as a new stream within the \009DRMTransform storage object that holds the signed issuance license. The new use license stream is given a unique name, beginning with "EUL-", so that it will not conflict with any other streams within the compound file. The data after "EUL-" is not particularly important, as long as it is unique and 27 or fewer WCHARs long (32 WCHARs – 1 for a terminating null WCHAR, – 4 for "EUL-"). In the following example, a random GUID is generated by using the NewGuid method of the .NET Framework Guid object, and then it is compressed by base32-encoding it.

AddEndUserLicense(WCHAR* wszEUL, 
              WCHAR*wszbase64ConsumerName,
              WCHAR*wszRmhFilePath, 
              WCHAR* EULClassID) // Unique ID created by application.
{
   int HeaderLen = 0;
   int EntryCount = 0;
   int EntryLength = 0;
   int RefComponentCount = 0;
   int RefComponentType = 0;
   int RefComponentLen = 0;
   int RefComponentPad = 0;
   int DataSpaceNameLen = 0;
   int DataSpaceNamePad = 0;
   int TotalLength = 0;

   LPWSTR RefComponent = NULL;
   LPWSTR DataSpaceName = NULL;

   WCHAR StorageName_DataSpaces[12]    =    L"*DataSpaces";
   WCHAR StorageName_DataSpaceInfo[14] =    L"DataSpaceInfo";
   WCHAR StorageName_TransformInfo[14] =    L"TransformInfo";
   WCHAR StorageName_DRMTransform[14]  =    L"*DRMTransform";
   WCHAR StreamName_DRMViewerContent[18] =  L"*DRMViewerContent";
   WCHAR StreamName_Version[8]         =    L"Version";
   WCHAR StreamName_DataSpaceMap[13]   =    L"DataSpaceMap";
   WCHAR StreamName_DRMDataSpace[14]   =    L"*DRMDataSpace";
   WCHAR StreamName_Primary[9]         =    L"*Primary";
 
  // Insert special characters into storage/stream names.
   short char_nine=9;
   short char_six=6;
   memcpy(StorageName_DataSpaces, &char_six, 2);
   memcpy(StorageName_DRMTransform, &char_nine, 2);
   memcpy(StreamName_DRMDataSpace, &char_nine, 2);
   memcpy(StreamName_Primary, &char_six, 2);

   // Storage and stream objects.
   IStorage *pStorage = NULL;
   IStorage *pDataSpaceStorage = NULL;
   IStorage *pTransformInfoStorage = NULL;
   IStorage *pDRMTransformStorage = NULL;
   IStream  *pStream = NULL;

   HRESULT hResult = NULL;
   ULONG bytesWritten = 0;
   BYTE *EncryptedBuffer = NULL;
   DWORD dwBufferSize = 0;
   BYTE *dataspacemap = NULL;
   LPSTR wszEUL64 = NULL;
   BYTE *eul_stream = NULL;
   LPSTR szRightsLabel = NULL;
   BYTE *drm_transform = NULL;

   VERSIONSTAMP version;
   version.ReaderVersionMajor  = 1;
   version.ReaderVersionMinor  = 0;
   version.UpdaterVersionMajor = 1;
   version.UpdaterVersionMinor = 0;
   version.WriterVersionMajor  = 1;
   version.WriterVersionMinor  = 0;


   // Open the previously created compound file.
   hResult = StgOpenStorageEx( 
              wszRmhFilePath,           // File name
              STGM_READWRITE|           // File access
                 STGM_SHARE_EXCLUSIVE, 
              STGFMT_STORAGE,           // Compound file
              0,                        // Required
              NULL,                     // Required
              0,                        // Required
              IID_IStorage,             // IStorage IID
              (void **)&pStorage);      // IStorage pointer

   // Navigate to \009DRMTransform storage space
   // to add a new stream to hold the use license.
   memcpy(StorageName_DataSpaces, &char_six,2);
   hResult = pStorage->OpenStorage(
              StorageName_DataSpaces,
              NULL,
              STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
              NULL,
              0,
              &pDataSpaceStorage);

   hResult = pDataSpaceStorage->OpenStorage( 
              StorageName_TransformInfo,
              NULL,
              STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
              NULL,
              0,
              &pTransformInfoStorage);

   memcpy(StorageName_DRMTransform, &char_nine,2);
   hResult = pTransformInfoStorage->OpenStorage(
              StorageName_DRMTransform,
              NULL,
              STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
              NULL,
              0,
              &pDRMTransformStorage);

   // Create a new, uniquely named stream to hold 
   // the use license.
   hResult = pDRMTransformStorage->CreateStream( 
              EULClassID,               // Required name
              STGM_READWRITE |          // File access
                 STGM_SHARE_EXCLUSIVE, 
              0,                        // Required
              0,                        // Required
              &pStream);                // IStream pointer

   // base64-encode the EUL.
   LPWSTR wszEUL64 = wszEUL;
   int b64usernamelen = (int)wcslen(wcsbase64ConsumerName);
   int licenselength = (int)wcslen(wszEUL64);

   int dwordalign = PaddingLength(b64usernamelen,sizeof(DWORD));
   int eulstreamLength = 8 + b64usernamelen + dwordalign;

   wszEUL64 = (CHAR *)HeapAlloc(
              GetProcessHeap(), 
              HEAP_ZERO_MEMORY, 
              wcslen(wszEUL64)+1);
   if ( NULL == wszEUL64 )
   {
      printf("Error (%s): E_OUTOFMEMORY\n", "HeapAlloc");
      goto e_Exit;
   }
   StringCchPrintf(wszEUL64, 
                   wcslen(wszEUL64)+1, 
                   "%S", 
                   wszEUL64);


   // Copy the data to a buffer.
   eul_stream = (BYTE *)HeapAlloc(
              GetProcessHeap(),
              0,
              eulstreamLength + licenselength + 4 +
                 PaddingLength(licenselength,sizeof(DWORD)));
   
   if ( NULL == eul_stream )
   {
      printf("Error (%s): E_OUTOFMEMORY\n", "HeapAlloc");
      goto e_Exit;
   }
   ZeroMemory(eul_stream, 
              eulstreamLength + licenselength + 4
             + PaddingLength(licenselength,sizeof(DWORD)));
   memcpy(eul_stream+0,
          &euIstreamLength,
          4);
   memcpy(eul_stream+4,
          &b64usernamelen,
          4);
   memcpy(eul_stream+8,
          wszbase64ConsumerName,
          b64usernamelen);
   memcpy(eul_stream+8+b64usernamelen+dwordalign,
          &licenselength,
          4);
   memcpy(eul_stream+12+b64usernamelen+dwordalign,
          wszEUL64,
          licenselength);

   // Copy buffer to the stream.
   hResult = pStream->Write(
                (void *)eul_stream,
                eulstreamLength+licenselength+4
                   +PaddingLength(licenselength,
                                  sizeof(DWORD)),
                &bytesWritten);
   CHECK_STG_ERROR("IStream::Write",hResult);

   // Save changes to container file.
   pStorage->Commit(STGC_DEFAULT);

e_Exit:
   // Clean up.
   if (pStorage != NULL)
      pStorage->Release();
   if (pDataSpaceStorage != NULL)
      pDataSpaceStorage->Release();
   if (pTransformInfoStorage != NULL)
      pTransformInfoStorage->Release();
   if (pDRMTransformStorage != NULL)
      pDRMTransformStorage->Release();
   if (pStream != NULL)
      pStream->Release();

   return hResult;
}

Adding an Issuance License to the Compound File

Creating a Compound File and Adding Protected Content

Understanding Compound Files