Win32 API 日本語リファレンス
ホーム › Data.RightsManagement › DRMEncrypt

DRMEncrypt

関数
RMSの暗号化プロバイダーでデータを暗号化する。
DLLmsdrm.dll呼出規約winapi

シグネチャ

// msdrm.dll
#include <windows.h>

HRESULT DRMEncrypt(
    DWORD hCryptoProvider,
    DWORD iPosition,
    DWORD cNumInBytes,
    BYTE* pbInData,
    DWORD* pcNumOutBytes,
    BYTE* pbOutData
);

パラメーター

名前型方向説明
hCryptoProviderDWORDinDRMCreateEnablingBitsEncryptor 関数を使用して作成された AD RMS 暗号化オブジェクトのハンドル。
iPositionDWORDin

暗号化を開始するバッファー内の位置。0 はバッファー内の最初のブロック、1 は 2 番目のブロックに対応し、以降も同様です。

注 発行ライセンスの署名時に AES キーを使用する場合、iPosition は常に 0 に設定できます。
cNumInBytesDWORDin暗号化するバイト数。
pbInDataBYTE*inout暗号化するバイト列を格納したバッファーへのポインター。
pcNumOutBytesDWORD*inout暗号化されたバイト数。
pbOutDataBYTE*inout暗号化されたバイト列へのポインター。

戻り値の型: HRESULT

公式ドキュメント

データを暗号化します。

戻り値

関数が成功した場合、S_OK を返します。

関数が失敗した場合は、エラーを示す HRESULT 値を返します。一般的なエラーコードの一覧については、Common HRESULT Values を参照してください。

解説(Remarks)

暗号化されたコンテンツのメモリの割り当てと解放は、呼び出し元の関数の責任です。次のコードサンプルは Encrypting Content からの引用で、コンテンツをブロック単位で暗号化する方法を示しています。この例では暗号化するコンテンツのサイズがあらかじめ分かっており、事前にメモリを割り当てています。ただし、割り当てるバイト数を判別する必要がある場合は、最初の呼び出しの後に必要なバッファーサイズが pcNumOutBytes パラメーターに返されます。メモリを割り当て、pbOutData が新しいメモリを指すように設定して、関数をもう一度呼び出してください。


#include "EncryptingContent.h"

/*===================================================================
File:      Encryption_EncryptContent.cpp

THIS CODE AND INFORMATION IS 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.

Copyright (C) Microsoft.  All rights reserved.
===================================================================*/

/////////////////////////////////////////////////////////////////////
// The EncryptContent function encrypts content. In this example,
// the content to be encrypted is defined in the header file.
//   #define PLAINTEXT L"This is the content to be encrypted."
//
HRESULT EncryptContent(
          DRMENVHANDLE   hEnv,
          DRMHANDLE      hLib,
          PWSTR          pwszRAC,
          PWSTR          pwszGUID,
          DRMHANDLE      hIssuanceLic,
          PWSTR          pwszSignedIL,
          BYTE**         ppbEncrypted)

{
  ///////////////////////////////////////////////////////////////////
  // Declare variables:
  //   hr........................Return value                     
  //   pwszOwnerLicense..........License with OWNER right
  //   pwszOutFile...............Name of file for encrypted content
  //   pbEncrypted...............Buffer to hold encrypted content
  //   uiOwnerLicenseLength......Owner licensee length, in characters
  //   uiBlock...................Decryption block size (16 bytes)
  //   uiBytes...................Size, in bytes, of uiBlock
  //   uiPlainText...............Number of bytes in the plain text
  //   uiPadding.................Blank space added to plain text
  //   uiBuffer..................uiPlainText + uiPadding
  //   uiEncrypted...............Size, bytes, of encrypted content
  //   uiOffset..................Offset into encryption buffer
  //   pbPlainText...............Pointer to unencrypted content
  //   hBoundLicense.............Handle to license bound to OWNER
  //   hEP.......................Enabling principal for binding   
  //   hEBEncryptor..............Handle to encrypting object
  //   dwBytesWritten............WriteFile function bytes written 
  //   idNULL....................DRMID structure
  //   idContent.................Structure for binding a license
  //   idStandardEP..............Structure for enabling principal
  //   oParams...................Structure for binding a license
  //   eType.....................Structure for license encoding
  //   
  HRESULT       hr                     = E_FAIL;
  PWSTR         pwszOwnerLicense       = NULL;
  PWSTR         pwszOutFile            = L"EncryptedContent.bin";
  BYTE*         pbEncrypted            = NULL;
  UINT          uiOwnerLicenseLength   = 0;
  UINT          uiBlock                = 0;
  UINT          uiBytes                = 0;
  UINT          uiPlainText            = 0;
  UINT          uiBuffer               = 0;
  UINT          uiPadding              = 0;
  UINT          uiEncrypted            = 0;
  UINT          uiOffset               = 0;
  BYTE*         pbPlainText            = NULL;
  DRMHANDLE     hBoundLicense          = NULL; 
  DRMHANDLE     hEP                    = NULL; 
  DRMHANDLE     hEBEncryptor           = NULL;
  DWORD         dwBytesWritten         = 0;
  DRMID         idNULL;
  DRMID         idContent;
  DRMID         idStandardEP;
  DRMBOUNDLICENSEPARAMS oParams;
  DRMENCODINGTYPE eType;              

  wprintf(L"\r\nEntering EncryptContent.\r\n");
 
  // Validate the input parameters.
  if ( NULL==hEnv ||
       NULL==hLib ||
       NULL==pwszRAC ||
       NULL==pwszGUID ||
       NULL==hIssuanceLic ||
       NULL==pwszSignedIL ||
       NULL==ppbEncrypted)
       return E_INVALIDARG;

  // Create an enabling principal.
  SecureZeroMemory(&idNULL, sizeof(idNULL));
  SecureZeroMemory(&idStandardEP, sizeof(idStandardEP));
  idStandardEP.wszIDType = L"ASCII Tag"; 
  idStandardEP.wszID     = L"UDStdPlg Enabling Principal"; 

  hr = DRMCreateEnablingPrincipal ( 
          hEnv,                     // Secure environment handle 
          hLib,                     // Library handle 
          idStandardEP.wszID,       // Enabling principal type 
          &idNULL,                  // DRMID structure 
          pwszRAC,                  // Rights account certificate
          &hEP);                    // enabling principal handle 
  if(FAILED(hr)) return hr;
  wprintf(L"DRMCreateEnablingPrincipal: hEP %i \r\n", hEP);

  // Call DRMGetOwnerLicense to get a license to bind to. An owner
  // license contains the OWNER right which allows the user to
  // exercise all rights regardless of whether they have been
  // explicitly granted.
  //   - Call DRMGetOwnerLicense once to retrieve the length, in
  //     characters, of the owner license.
  //   - Allocate memory for the license.
  //   - Call DRMGetOwnerLicense again to retrieve the license.
  //   - You must release the memory before leaving this function.
  hr = DRMGetOwnerLicense( 
           hIssuanceLic,               // Issuance license handle
           &uiOwnerLicenseLength,      // License length
           NULL);                      // Not used
  if(FAILED(hr)) goto e_Exit;

  pwszOwnerLicense = new WCHAR[uiOwnerLicenseLength];
  if(NULL == pwszOwnerLicense)
  {
    hr = E_OUTOFMEMORY; 
    goto e_Exit; 
  }
  hr = DRMGetOwnerLicense( 
          hIssuanceLic, 
          &uiOwnerLicenseLength, 
          pwszOwnerLicense);
  if(FAILED(hr)) goto e_Exit;
  wprintf(L"DRMGetOwnerLicense (pwszOwnerLicense) succeeded.\r\n");

  // Bind the owner license to the OWNER right.
  SecureZeroMemory(&idContent, sizeof(idContent));
  idContent.wszIDType        = L"MS-GUID"; 
  idContent.wszID            = pwszGUID;

  SecureZeroMemory(&oParams, sizeof(oParams));
  oParams.hEnablingPrincipal = hEP; 
  oParams.wszRightsRequested = L"OWNER";
  oParams.wszRightsGroup     = L"Main-Rights"; 
  oParams.idResource         = idContent; 

  hr = DRMCreateBoundLicense ( 
          hEnv,                     // Secure environment handle 
          &oParams,                 // Additional license options 
          pwszOwnerLicense,         // Owner license 
          &hBoundLicense,           // Handle to the bound license 
          NULL );                   // Reserved
  if(FAILED(hr)) goto e_Exit;
  wprintf(L"DRMCreateBoundLicense: (hBoundLicense) succeeded.\r\n");

  // Create an encrypting object. 
  hr = DRMCreateEnablingBitsEncryptor( 
          hBoundLicense,              // Bound license handle
          oParams.wszRightsRequested, // Requested right
          NULL,                       // Reserved
          NULL,                       // Reserved
          &hEBEncryptor);             // Encrypting object handle
  if(FAILED(hr)) goto e_Exit;
  wprintf(L"DRMCreateEnablingBitsEncryptor succeeded.\r\n");

  // Retrieve the size, in bytes, of the memory block that must 
  // be passed to DRMEncrypt.
  uiBytes= sizeof(uiBlock);
  hr = DRMGetInfo(
          hEBEncryptor,               // Encrypting object handle
          g_wszQUERY_BLOCKSIZE,       // Attribute to query for
          &eType,                     // Type of encoding to apply
          &uiBytes,                   // Size of uiBlock variable
          (BYTE*)&uiBlock);           // Size of memory block
  if(FAILED(hr)) goto e_Exit;
  wprintf(L"DRMGetInfo: uiBlock = %u\r\n", uiBlock);

  // Determine the size of the buffer needed to store the
  // encrypted content. The buffer must be an even multiple of 
  // the buffer size used during the [typically] iterative 
  // encryption process. In this example, the plain text
  // is 72 bytes long and the encryption buffer is 16 bytes. 
  // However 72 % 16 = 8. The plain text must therefore be padded
  // to 80 bytes (80 % 16 = 0).
  uiPlainText = (UINT)(sizeof(WCHAR) * wcslen(PLAINTEXT));
  uiPadding = uiBlock - (uiPlainText % uiBlock);
  uiBuffer = uiPlainText + uiPadding;

  pbPlainText = new BYTE[uiBuffer];
  *ppbEncrypted = new BYTE[uiBuffer];

  SecureZeroMemory(pbPlainText, sizeof(pbPlainText));
  memcpy_s(
          pbPlainText,
          uiBuffer,
          (BYTE*)PLAINTEXT,
          uiPlainText);

  // Encrypt the plain text.
  for ( int j = 0; (UINT)j * uiBlock < uiBuffer; j++ )
  {
    hr = DRMEncrypt( 
          hEBEncryptor,               // Encrypting object handle
          j * uiBlock,                // Position in buffer
          uiBlock,                    // Number of bytes to encrypt
          pbPlainText + (j*uiBlock),  // Bytes to encrypt
          &uiEncrypted,               // Number of bytes encrypted
          NULL);                      // NULL on first call
    if(FAILED(hr)) goto e_Exit;

    hr = DRMEncrypt( 
          hEBEncryptor,               // Encrypting object handle 
          j * uiBlock,                // Position in buffer 
          uiBlock,                    // Number of bytes to encrypt
          pbPlainText + (j*uiBlock),  // Bytes to encrypt
          &uiEncrypted,               // Number of bytes encrypted
          *ppbEncrypted + uiOffset);  // Encrypted content
    if(FAILED(hr)) goto e_Exit;

    uiOffset += uiEncrypted;          // Increment the buffer offset
  }

  // Create a new file to write the encrypted content and issuance
  // license to.
  HANDLE hFile = CreateFile(
          pwszOutFile,                // File name
          GENERIC_WRITE,              // Access type
          0,                          // Require exclusive access
          NULL,                       // Default security attributes
          CREATE_ALWAYS,              // Allow write-only access
          0,                          // No file attributes or flags
          NULL);                      // No open file as template
  if(INVALID_HANDLE_VALUE == hFile)
  {
    hr = HRESULT_FROM_WIN32(GetLastError());
    goto e_Exit;
  }
  wprintf(L"CreateFile: hFile = %i\r\n", hFile);

  // Write the encrypted content and relevant data to the file.
  if(!WriteFile(hFile, 
                &uiBuffer, 
                sizeof(UINT), 
                &dwBytesWritten, 
                NULL))
    goto e_Exit;
  size_t uiIssuanceLicenseLgth = (UINT)(sizeof(WCHAR) * 
                                 wcslen(pwszSignedIL));
  if(!WriteFile(hFile, 
                &uiIssuanceLicenseLgth, 
                sizeof(size_t), 
                &dwBytesWritten, 
                NULL))
    goto e_Exit;
  if(!WriteFile(hFile, 
                *ppbEncrypted, 
                uiBuffer, 
                &dwBytesWritten, 
                NULL))
    goto e_Exit;
  if(!WriteFile(hFile, 
                pwszSignedIL, 
                uiIssuanceLicenseLgth, 
                &dwBytesWritten, 
                NULL))
    goto e_Exit;
  wprintf(L"Writing to file succeeded.\r\n");

e_Exit:

  if (INVALID_HANDLE_VALUE != hFile)
  {
    CloseHandle(hFile);
  }
  if (NULL != hEP)
  {
    hr = DRMCloseHandle(hEP);
    hEP = NULL;
  }
  if (NULL != hBoundLicense)
  {
    hr = DRMCloseHandle(hBoundLicense);
    hBoundLicense = NULL;
  }
  if (NULL != hEBEncryptor)
  {
    hr = DRMCloseHandle(hEBEncryptor);
    hEBEncryptor = NULL;
  }
  if (NULL != pwszOwnerLicense)
  {
    delete [] pwszOwnerLicense;
    pwszOwnerLicense = NULL;
  }

  wprintf(L"Leaving EncryptContent: hr = %x \r\n", hr);
  return hr;
}

次のコードサンプルは、暗号ブロック連鎖 (CBC) 暗号モードで AES アルゴリズムを使用してコンテンツを暗号化する方法を示しています。この機能は Windows 7 でのみ使用できます。


/*===================================================================
Functions:      PerformCbcEncryption and PerformCbcDecryption

THIS CODE AND INFORMATION IS 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.

Copyright (C) Microsoft.  All rights reserved.
===================================================================*/
#include "msdrm.h"
#include "msdrmgetinfo.h"

#define SZ_CBC_KEY_TYPE L"AES_CBC4K"
#define DW_WAIT_TIME 60000
#define SZ_ENABLING_PRINCIPAL_TYPE L"UDStdPlg Enabling Principal"
#define SZ_MAIN_RIGHTS_GROUP L"Main-Rights"
#define SZ_EDIT_RIGHT L"EDIT"
#define SZ_VIEW_RIGHT L"VIEW"

extern HRESULT __stdcall StatusCallback(DRM_STATUS_MSG msg,
                                        HRESULT hr,
                                        void* pvParam,
                                        void* pvContext);

//
// Struct to hold DRMGetSignedIssuanceLicense callback information
//
typedef struct Drm_Context
{
 HANDLE  hEvent;
 HRESULT hr;
 PWSTR   wszData;
} DRM_CONTEXT, *PDRM_CONTEXT;

//
// This helper function will perform steps required to get a bound
// license when provided the required information. It is listed
// here to demonstrate that this part of the CBC encryption and
// decryption flow is unchanged from the standard flow. In practice,
// since creating a new bound license for each encryption and
// decryption request is costly, you would instead obtain all
// requested rights at once in a comma-separated list and reuse
// a single bound license when possible.
//
inline HRESULT GetBoundLicense(__in DRMENVHANDLE hEnv,
                               __in PWCHAR pwszRac,
                               __in PWSTR pwszUseLicense,
                               __in PWSTR pwszRightsRequested,
                               __in DRMHANDLE hIssuanceLicense,
                               __out DRMHANDLE* phBoundLicense)
{
    HRESULT hr = S_OK;
    DRMHANDLE hEnablingPrincipal = NULL;
    DRMID idNULL(NULL, NULL);
    UINT uiContentId = 0;
    UINT uiContentIdType = 0;
    PWSTR pwszContentId = NULL;
    PWSTR pwszContentIdType = NULL;
    DRMID idContent;
    DRMBOUNDLICENSEPARAMS bParams;

    hr = DRMCreateEnablingPrincipal(
        hEnv,                       // Environment handle
        NULL,                       // No library specified
        SZ_ENABLING_PRINCIPAL_TYPE, // Enabling principal type
        &idNULL,                    // DRMID structure
        pwszRac,                    // Current user certificate / RAC
        &hEnablingPrincipal);       // Enabling principal handle
    if (FAILED(hr))
    {
        goto e_Exit;
    }

    // Obtain the sizes of the buffers needed for the
    // content ID and content ID type
    hr = DRMGetMetaData(
          hIssuanceLicense,        // Handle to the license
          &uiContentId,            // Content Id Length
          NULL,                    // Content Id
          &uiContentIdType,        // Content Id Type Length
          NULL,                    // Content Id Type
          NULL,                    // SKU ID Length
          NULL,                    // SKU ID
          NULL,                    // SKU ID Type Length
          NULL,                    // SKU ID Type
          NULL,                    // Content Type Length
          NULL,                    // Content Type
          NULL,                    // Content Name Length
          NULL);                   // Content Name
    if (FAILED(hr))
    {
        goto e_Exit;
    }

    pwszContentId = new WCHAR[uiContentId];
    if(NULL == pwszContentId) 
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }

    pwszContentIdType = new WCHAR[uiContentIdType];
    if(NULL == pwszContentIdType) 
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }

    // Obtain the content ID and content ID type
    hr = DRMGetMetaData(
          hIssuanceLicense,        // Handle to the license
          &uiContentId,            // Content Id Length
          pwszContentId,           // Content Id
          &uiContentIdType,        // Content Id Type Length
          pwszContentIdType,       // Content Id Type
          NULL,                    // SKU ID Length
          NULL,                    // SKU ID
          NULL,                    // SKU ID Type Length
          NULL,                    // SKU ID Type
          NULL,                    // Content Type Length
          NULL,                    // Content Type
          NULL,                    // Content Name Length
          NULL);                   // Content Name
    if (FAILED(hr))
    {
        goto e_Exit;
    }

    idContent.uVersion = 0;
    idContent.wszIDType = pwszContentIdType;
    idContent.wszID = pwszContentId;

    bParams.hEnablingPrincipal = hEnablingPrincipal;
    bParams.hSecureStore = NULL;
    bParams.wszRightsRequested = pwszRightsRequested;
    bParams.wszRightsGroup = SZ_MAIN_RIGHTS_GROUP;
    bParams.idResource = idContent;
    bParams.wszDefaultEnablingPrincipalCredentials = NULL;
    bParams.cAuthenticatorCount = 0;

    hr = DRMCreateBoundLicense(
        hEnv,                      // Environment handle
        &bParams,                  // Additional license options
        pwszUseLicense,            // Use license
        phBoundLicense,            // Bound license handle
        NULL);                     // Reserved

e_Exit:
    if (NULL != hEnablingPrincipal)
    {
        DRMCloseHandle(hEnablingPrincipal);
    }
    if (NULL != pwszContentId)
    {
        delete [] pwszContentId;
    }
    if (NULL != pwszContentIdType)
    {
        delete [] pwszContentIdType;
    }

    return hr;
}

/////////////////////////////////////////////////////////////////////
// The PerformCbcEncryption function performs CBC encryption on the
// given unencrypted data buffer and returns the encrypted data
// in a single, freshly allocated buffer. In practice, you may want
// to modify this function so that larger amounts of data are
// streamed in, rather than having the entire block processed (and
// memory allocated) all at once.
//
// Arguments:
//        pbDataToEncrypt         - [in]  Buffer containing the data
//                                        that is to be encrypted
//        uiUnencryptedDataLength - [in]  Length of the unencrypted
//                                        data (in bytes)
//        hEnv                    - [in]  Environment handle
//        hIssuanceLicense        - [in]  Handle to an issuance
//                                        license
//        pwszCLC                 - [in]  CLC of the publishing user
//        pwszRac                 - [in]  RAC of the publishing user
//        ppbEncryptedData        - [out] Buffer holding the newly
//                                        encrypted data
//        puiEncryptedDataLength  - [out] Length of the encrypted
//                                        data (in bytes)
HRESULT PerformCbcEncryption(__in BYTE* pbDataToEncrypt,
                             __in UINT uiUnencryptedDataLength,
                             __in DRMENVHANDLE hEnv,
                             __in DRMPUBHANDLE hIssuanceLicense,
                             __in PWSTR pwszCLC,
                             __in PWCHAR pwszRac,
                             __out PBYTE* ppbEncryptedData,
                             __out UINT* puiEncryptedDataLength)
{
    HRESULT hr = S_OK;              // Return code
    DRM_CONTEXT context;            // To hold callback information
    DWORD dwWaitResult = 0;         // Result of wait operation
    PWSTR pwszOwnerLicense = NULL;  // Owner use license
    UINT uiOwnerLicenseLength = 0;  // Size of the owner license
    DRMHANDLE hBoundLicense = NULL; // Bound license handle
    DRMHANDLE hEBEncryptor = NULL;  // Encryptor handle
    UINT uiBlockSize = 0;           // Size of each block to be
                                    // passed to DRMEncrypt
    UINT uiBlockSizeInfo = 0;       // Size of the uiBlockSize
                                    // variable
    DRMENCODINGTYPE encodingType;   // Encoding type for DRMGetInfo
    UINT uiPaddingSize = 0;         // Length of padding needed to
                                    // match block size
    UINT uiOffset = 0;              // Offset in encryption buffer

    // For our example, we will be using the "EDIT" right
    // during encryption
    const PWSTR pwszRightsRequested = SZ_EDIT_RIGHT;

    // Validate parameters
    if ((NULL == pbDataToEncrypt)
        || (NULL == hEnv)
        || (NULL == hIssuanceLicense)
        || (NULL == pwszCLC)
        || (NULL == pwszRac)
        || (NULL == ppbEncryptedData)
        || (NULL == puiEncryptedDataLength))
    {
        hr = E_INVALIDARG;
        goto e_Exit;
    }

    // Create an event for the callback function
    context.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
    if (NULL == context.hEvent)
    {
        hr = HRESULT_FROM_WIN32(::GetLastError());
        goto e_Exit;
    }
    context.wszData = NULL;

    hr = DRMGetSignedIssuanceLicense(
        hEnv,                         // Environment handle
        hIssuanceLicense,             // Issuance license handle
        (DRM_SIGN_OFFLINE             // Sign offline with a CLC
            | DRM_AUTO_GENERATE_KEY), // Generate a content key
        NULL,                         // No symmetric key specified
        0,                            // No length specified
        SZ_CBC_KEY_TYPE,              // CBC encryption key type
        pwszCLC,                      // Client licensor certificate
        &StatusCallback,              // Callback function
        NULL,                         // No licensing URL specified
        (void*)&context);             // Callback context parameter
    if (FAILED(hr))
    {
        goto e_Exit;
    }

    // Wait for callback to return
    dwWaitResult = ::WaitForSingleObject(context.hEvent,
                                         DW_WAIT_TIME);
    if (WAIT_OBJECT_0 != dwWaitResult)
    {
        hr = HRESULT_FROM_WIN32(::GetLastError());
        goto e_Exit;
    }
    else if (FAILED(context.hr))
    {
        hr = context.hr;
        goto e_Exit;
    }

    // Obtain the length of the owner license
    hr = DRMGetOwnerLicense(
        hIssuanceLicense,             // Issuance license handle
        &uiOwnerLicenseLength,        // Length of owner license
        NULL);                        // Query for license length
    if (FAILED(hr))
    {
        goto e_Exit;
    }

    pwszOwnerLicense = new WCHAR[uiOwnerLicenseLength];
    if (NULL == pwszOwnerLicense)
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }

    hr = DRMGetOwnerLicense(
        hIssuanceLicense,             // Issuance license handle
        &uiOwnerLicenseLength,        // Length of owner license
        pwszOwnerLicense);            // Owner use license
    if (FAILED(hr))
    {
        goto e_Exit;
    }

    // Proceed normally (as you would for non-CBC encryption) to
    // obtain the bound license
    hr = GetBoundLicense(hEnv,
                         pwszRac,
                         pwszOwnerLicense,
                         pwszRightsRequested,
                         hIssuanceLicense,
                         &hBoundLicense);
    if (FAILED(hr))
    {
        goto e_Exit;
    }

    hr = DRMCreateEnablingBitsEncryptor(
        hBoundLicense,                // Bound license handle
        pwszRightsRequested,          // Requested rights
        NULL,                         // Reserved
        NULL,                         // Reserved
        &hEBEncryptor);               // Encryptor handle
    if (FAILED(hr))
    {
        goto e_Exit;
    }

    // Determine the block size you need to pass to DRMEncrypt
    uiBlockSizeInfo = sizeof(uiBlockSize);
    hr = DRMGetInfo(
        hEBEncryptor,                 // Encryptor handle
        g_wszQUERY_BLOCKSIZE,         // Queried attribute
        &encodingType,                // Type of encoding to apply
        &uiBlockSizeInfo,             // Size of uiBlockSize variable
        (BYTE*)&uiBlockSize);         // Block size to use
    if (FAILED(hr))
    {
        goto e_Exit;
    }

    // Since the amount of data we encrypt must be a multiple of the
    // block size, we must determine the amount of padding we need
    // to add to our data and create a buffer of the appropriate
    // size (the size of our original data + padding)
    uiPaddingSize
        = uiBlockSize - (uiUnencryptedDataLength % uiBlockSize);
    *puiEncryptedDataLength
        = uiUnencryptedDataLength + uiPaddingSize;

    *ppbEncryptedData = new BYTE[*puiEncryptedDataLength];
    if (NULL == *ppbEncryptedData)
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }

    // Fill the padding area with zeros
    ::SecureZeroMemory((*ppbEncryptedData + uiUnencryptedDataLength),
                       uiPaddingSize);

    // In this example, we are encrypting our content with one call
    // to DRMEncrypt for each 4 KB block (4096 bytes). In practice,
    // you may want to reduce the number of calls by passing in
    // a quantity of data that is some larger multiple of 4096 bytes.
    for (int i = 0;
         ((UINT)i * uiBlockSize) < *puiEncryptedDataLength;
         i++)
    {
        UINT uiNumBytesEncrypted = 0;
        UINT uiBufferPosition = (i * uiBlockSize);

        hr = DRMEncrypt(
            // Encryptor handle
            hEBEncryptor,
            // Starting block number (1 block = uiBlockSize)
            i,
            // Number of bytes to encrypt
            uiBlockSize,
            // Starting location of bytes to encrypt
            (pbDataToEncrypt + uiBufferPosition),
            // Number of bytes encrypted
            &uiNumBytesEncrypted,
            // Starting location for encrypted content
            (*ppbEncryptedData + uiOffset));
        if (FAILED(hr))
        {
            goto e_Exit;
        }

        uiOffset += uiNumBytesEncrypted;
    }

e_Exit:
    if (NULL != context.hEvent)
    {
        ::CloseHandle(context.hEvent);
    }
    if (NULL != context.wszData)
    {
        delete [] context.wszData;
    }
    if (NULL != pwszOwnerLicense)
    {
        delete [] pwszOwnerLicense;
    }
    if (NULL != hBoundLicense)
    {
        DRMCloseHandle(hBoundLicense);
    }
    if (NULL != hEBEncryptor)
    {
        DRMCloseHandle(hEBEncryptor);
    }

    return hr;
}

/////////////////////////////////////////////////////////////////////
// The PerformCbcDecryption function performs decryption on the
// given CBC encrypted data buffer and returns the decrypted data
// in a single freshly allocated buffer. In practice, you may want
// to modify this function so that larger quantities of data are
// streamed in, rather than having the entire block processed (and
// memory allocated) all at once.
// Arguments:
//        pbEncryptedData         - [in]  Buffer containing the data
//                                        that is to be decrypted
//        uiEncryptedDataLength   - [in]  Length of the encrypted
//                                        data (in bytes)
//        hEnv                    - [in]  Environment handle
//        hIssuanceLicense        - [in]  Handle to an issuance
//                                        license
//        pwszUseLicense          - [in]  Use license
//        pwszRac                 - [in]  RAC of the publishing user
//        ppbDecryptedData        - [out] Buffer holding the newly
//                                        decrypted data
HRESULT PerformCbcDecryption(__in BYTE* pbEncryptedData,
                             __in UINT uiEncryptedDataLength,
                             __in DRMENVHANDLE hEnv,
                             __in DRMPUBHANDLE hIssuanceLicense,
                             __in PWSTR pwszUseLicense,
                             __in PWCHAR pwszRac,
                             __out PBYTE* ppbDecryptedData)
{
    HRESULT hr = S_OK;              // Return code
    DRMHANDLE hBoundLicense = NULL; // Bound license handle
    DRMHANDLE hEBDecryptor = NULL;  // Decryptor handle
    PWSTR pwszKeyType = NULL;       // Key type used
    UINT uiKeyTypeLength = 0;       // Length of pwszKeyType
    UINT uiBlockSize = 0;           // Size of each block to be
                                    // passed to DRMEncrypt
    UINT uiBlockSizeInfo = 0;       // Size of the uiBlockSize
                                    // variable
    DRMENCODINGTYPE encodingType;   // Encoding type for DRMGetInfo
    UINT uiPaddingSize = 0;         // Length of padding needed to
                                    // match block size
    UINT uiOffset = 0;              // Offset in encryption buffer

    // For the example, the "VIEW" right is used
    // during decryption
    const PWSTR pwszRightsRequested = SZ_VIEW_RIGHT;

    // Validate parameters
    if ((NULL == pbEncryptedData)
        || (NULL == hEnv)
        || (NULL == hIssuanceLicense)
        || (NULL == pwszUseLicense)
        || (NULL == pwszRac)
        || (NULL == ppbDecryptedData))
    {
        hr = E_INVALIDARG;
        goto e_Exit;
    }

    // Proceed normally (as you would for non-CBC decryption) to
    // obtain the bound license
    hr = GetBoundLicense(hEnv,
                         pwszRac,
                         pwszUseLicense,
                         pwszRightsRequested,
                         hIssuanceLicense,
                         &hBoundLicense);
    if (FAILED(hr))
    {
        goto e_Exit;
    }

    hr = DRMCreateEnablingBitsDecryptor(
        hBoundLicense,                // Bound license handle
        pwszRightsRequested,          // Requested rights
        NULL,                         // Reserved
        NULL,                         // Reserved
        &hEBDecryptor);               // Decryptor handle
    if (FAILED(hr))
    {
        goto e_Exit;
    }

    // Verify/Determine that CBC decryption is needed. In practice,
    // this may not be needed if you already know whether or not
    // the cipher mode used is CBC
    hr = DRMGetInfo(
        hEBDecryptor,                 // Decryptor handle
        g_wszQUERY_SYMMETRICKEYTYPE,  // Queried attribute
        &encodingType,                // Type of encoding to apply
        &uiKeyTypeLength,             // Size of key type variable
        NULL);                        // Query for length
    if (FAILED(hr))
    {
        goto e_Exit;
    }

    pwszKeyType = new WCHAR[uiKeyTypeLength];
    if (NULL == pwszKeyType)
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }

    hr = DRMGetInfo(
        hEBDecryptor,                 // Decryptor handle
        g_wszQUERY_SYMMETRICKEYTYPE,  // Queried attribute
        &encodingType,                // Type of encoding to apply
        &uiKeyTypeLength,             // Size of key type variable
        (BYTE*)pwszKeyType);          // Key type used
    if (FAILED(hr))
    {
        goto e_Exit;
    }

    if (!wcscmp(SZ_CBC_KEY_TYPE, pwszKeyType))
    {
        // Unexpected -- in practice, you may want to instead
        // handle decryption for this non-CBC key type
        hr = E_UNEXPECTED;
        goto e_Exit;
    }

    // Verify/Determine the block size you need to pass to DRMDecrypt
    uiBlockSizeInfo = sizeof(uiBlockSize);
    hr = DRMGetInfo(
        hEBDecryptor,                 // Decryptor handle
        g_wszQUERY_BLOCKSIZE,         // Queried attribute
        &encodingType,                // Type of encoding to apply
        &uiBlockSizeInfo,             // Size of uiBlockSize variable
        (BYTE*)&uiBlockSize);         // Block size to use
    if (FAILED(hr))
    {
        goto e_Exit;
    }

    *ppbDecryptedData = new BYTE[uiEncryptedDataLength];
    if (NULL == *ppbDecryptedData)
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }

    // In this example, the content is being decrypted with one call
    // to DRMDecrypt for each 4 KB block (4096 bytes). In practice,
    // you may want to reduce the number of calls by passing in
    // a quantity of data that is some larger multiple of 4096 bytes.
    for (int i = 0;
         ((UINT)i * uiBlockSize) < uiEncryptedDataLength;
         i++)
    {
        UINT uiNumBytesDecrypted = 0;
        UINT uiBufferPosition = (i * uiBlockSize);

        hr = DRMDecrypt(
            // Decryptor handle
            hEBDecryptor,
            // Starting block number (1 block = uiBlockSize)
            i,
            // Number of bytes to decrypt
            uiBlockSize,
            // Starting location of bytes to decrypt
            (pbEncryptedData + uiBufferPosition),
            // Number of bytes decrypted
            &uiNumBytesDecrypted,
            // Starting location for decrypted content
            (*ppbDecryptedData + uiOffset));
        if (FAILED(hr))
        {
            goto e_Exit;
        }

        uiOffset += uiNumBytesDecrypted;
    }

e_Exit:
    if (NULL != hBoundLicense)
    {
        DRMCloseHandle(hBoundLicense);
    }
    if (NULL != hEBDecryptor)
    {
        DRMCloseHandle(hEBDecryptor);
    }
    if (NULL != pwszKeyType)
    {
        delete [] pwszKeyType;
    }

    return hr;
}
出典・ライセンス: 上記「公式ドキュメント」の内容は Microsoft の Win32 API ドキュメント(MicrosoftDocs/sdk-api)を日本語に翻訳・改変したものです。© Microsoft Corporation. CC BY 4.0 で提供。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)

各言語での呼び出し定義

// msdrm.dll
#include <windows.h>

HRESULT DRMEncrypt(
    DWORD hCryptoProvider,
    DWORD iPosition,
    DWORD cNumInBytes,
    BYTE* pbInData,
    DWORD* pcNumOutBytes,
    BYTE* pbOutData
);
[DllImport("msdrm.dll", ExactSpelling = true)]
static extern int DRMEncrypt(
    uint hCryptoProvider,   // DWORD
    uint iPosition,   // DWORD
    uint cNumInBytes,   // DWORD
    IntPtr pbInData,   // BYTE* in/out
    ref uint pcNumOutBytes,   // DWORD* in/out
    IntPtr pbOutData   // BYTE* in/out
);
<DllImport("msdrm.dll", ExactSpelling:=True)>
Public Shared Function DRMEncrypt(
    hCryptoProvider As UInteger,   ' DWORD
    iPosition As UInteger,   ' DWORD
    cNumInBytes As UInteger,   ' DWORD
    pbInData As IntPtr,   ' BYTE* in/out
    ByRef pcNumOutBytes As UInteger,   ' DWORD* in/out
    pbOutData As IntPtr   ' BYTE* in/out
) As Integer
End Function
' hCryptoProvider : DWORD
' iPosition : DWORD
' cNumInBytes : DWORD
' pbInData : BYTE* in/out
' pcNumOutBytes : DWORD* in/out
' pbOutData : BYTE* in/out
Declare PtrSafe Function DRMEncrypt Lib "msdrm" ( _
    ByVal hCryptoProvider As Long, _
    ByVal iPosition As Long, _
    ByVal cNumInBytes As Long, _
    ByVal pbInData As LongPtr, _
    ByRef pcNumOutBytes As Long, _
    ByVal pbOutData As LongPtr) As Long
' VBA7前提(PtrSafe)。32bit Office では LongPtr→Long。Integer=16bit / Long=32bit / LongLong=64bit。
import ctypes
from ctypes import wintypes

DRMEncrypt = ctypes.windll.msdrm.DRMEncrypt
DRMEncrypt.restype = ctypes.c_int
DRMEncrypt.argtypes = [
    wintypes.DWORD,  # hCryptoProvider : DWORD
    wintypes.DWORD,  # iPosition : DWORD
    wintypes.DWORD,  # cNumInBytes : DWORD
    ctypes.POINTER(ctypes.c_ubyte),  # pbInData : BYTE* in/out
    ctypes.POINTER(wintypes.DWORD),  # pcNumOutBytes : DWORD* in/out
    ctypes.POINTER(ctypes.c_ubyte),  # pbOutData : BYTE* in/out
]
require 'fiddle'
require 'fiddle/import'

lib = Fiddle.dlopen('msdrm.dll')
DRMEncrypt = Fiddle::Function.new(
  lib['DRMEncrypt'],
  [
    -Fiddle::TYPE_INT,  # hCryptoProvider : DWORD
    -Fiddle::TYPE_INT,  # iPosition : DWORD
    -Fiddle::TYPE_INT,  # cNumInBytes : DWORD
    Fiddle::TYPE_VOIDP,  # pbInData : BYTE* in/out
    Fiddle::TYPE_VOIDP,  # pcNumOutBytes : DWORD* in/out
    Fiddle::TYPE_VOIDP,  # pbOutData : BYTE* in/out
  ],
  Fiddle::TYPE_INT)
#[link(name = "msdrm")]
extern "system" {
    fn DRMEncrypt(
        hCryptoProvider: u32,  // DWORD
        iPosition: u32,  // DWORD
        cNumInBytes: u32,  // DWORD
        pbInData: *mut u8,  // BYTE* in/out
        pcNumOutBytes: *mut u32,  // DWORD* in/out
        pbOutData: *mut u8  // BYTE* in/out
    ) -> i32;
}
// crates: windows-sys provides ready-made bindings for this API.
$sig = @"
[DllImport("msdrm.dll")]
public static extern int DRMEncrypt(uint hCryptoProvider, uint iPosition, uint cNumInBytes, IntPtr pbInData, ref uint pcNumOutBytes, IntPtr pbOutData);
"@
$api = Add-Type -MemberDefinition $sig -Name 'msdrm_DRMEncrypt' -Namespace Win32 -PassThru
# $api::DRMEncrypt(hCryptoProvider, iPosition, cNumInBytes, pbInData, pcNumOutBytes, pbOutData)
#uselib "msdrm.dll"
#func global DRMEncrypt "DRMEncrypt" sptr, sptr, sptr, sptr, sptr, sptr
; DRMEncrypt hCryptoProvider, iPosition, cNumInBytes, varptr(pbInData), varptr(pcNumOutBytes), varptr(pbOutData)   ; 戻り値は stat
; hCryptoProvider : DWORD -> "sptr"
; iPosition : DWORD -> "sptr"
; cNumInBytes : DWORD -> "sptr"
; pbInData : BYTE* in/out -> "sptr"
; pcNumOutBytes : DWORD* in/out -> "sptr"
; pbOutData : BYTE* in/out -> "sptr"
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。
出力引数:
#uselib "msdrm.dll"
#cfunc global DRMEncrypt "DRMEncrypt" int, int, int, var, var, var
; res = DRMEncrypt(hCryptoProvider, iPosition, cNumInBytes, pbInData, pcNumOutBytes, pbOutData)
; hCryptoProvider : DWORD -> "int"
; iPosition : DWORD -> "int"
; cNumInBytes : DWORD -> "int"
; pbInData : BYTE* in/out -> "var"
; pcNumOutBytes : DWORD* in/out -> "var"
; pbOutData : BYTE* in/out -> "var"
; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。
出力引数:
; HRESULT DRMEncrypt(DWORD hCryptoProvider, DWORD iPosition, DWORD cNumInBytes, BYTE* pbInData, DWORD* pcNumOutBytes, BYTE* pbOutData)
#uselib "msdrm.dll"
#cfunc global DRMEncrypt "DRMEncrypt" int, int, int, var, var, var
; res = DRMEncrypt(hCryptoProvider, iPosition, cNumInBytes, pbInData, pcNumOutBytes, pbOutData)
; hCryptoProvider : DWORD -> "int"
; iPosition : DWORD -> "int"
; cNumInBytes : DWORD -> "int"
; pbInData : BYTE* in/out -> "var"
; pcNumOutBytes : DWORD* in/out -> "var"
; pbOutData : BYTE* in/out -> "var"
; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。
import (
	"golang.org/x/sys/windows"
	"unsafe"
)

var (
	msdrm = windows.NewLazySystemDLL("msdrm.dll")
	procDRMEncrypt = msdrm.NewProc("DRMEncrypt")
)

// hCryptoProvider (DWORD), iPosition (DWORD), cNumInBytes (DWORD), pbInData (BYTE* in/out), pcNumOutBytes (DWORD* in/out), pbOutData (BYTE* in/out)
r1, _, err := procDRMEncrypt.Call(
	uintptr(hCryptoProvider),
	uintptr(iPosition),
	uintptr(cNumInBytes),
	uintptr(pbInData),
	uintptr(pcNumOutBytes),
	uintptr(pbOutData),
)
_ = err  // syscall.Errno (valid when the call sets last-error)
_ = r1   // HRESULT
function DRMEncrypt(
  hCryptoProvider: DWORD;   // DWORD
  iPosition: DWORD;   // DWORD
  cNumInBytes: DWORD;   // DWORD
  pbInData: Pointer;   // BYTE* in/out
  pcNumOutBytes: Pointer;   // DWORD* in/out
  pbOutData: Pointer   // BYTE* in/out
): Integer; stdcall;
  external 'msdrm.dll' name 'DRMEncrypt';
result := DllCall("msdrm\DRMEncrypt"
    , "UInt", hCryptoProvider   ; DWORD
    , "UInt", iPosition   ; DWORD
    , "UInt", cNumInBytes   ; DWORD
    , "Ptr", pbInData   ; BYTE* in/out
    , "Ptr", pcNumOutBytes   ; DWORD* in/out
    , "Ptr", pbOutData   ; BYTE* in/out
    , "Int")   ; return: HRESULT
●DRMEncrypt(hCryptoProvider, iPosition, cNumInBytes, pbInData, pcNumOutBytes, pbOutData) = DLL("msdrm.dll", "int DRMEncrypt(dword, dword, dword, void*, void*, void*)")
# 呼び出し: DRMEncrypt(hCryptoProvider, iPosition, cNumInBytes, pbInData, pcNumOutBytes, pbOutData)
# hCryptoProvider : DWORD -> "dword"
# iPosition : DWORD -> "dword"
# cNumInBytes : DWORD -> "dword"
# pbInData : BYTE* in/out -> "void*"
# pcNumOutBytes : DWORD* in/out -> "void*"
# pbOutData : BYTE* in/out -> "void*"
# なでしこ1は32bit・ANSI(Shift_JIS)。文字列=char*(ANSI)、ポインタ/ハンドル=void*(4byte)。
const std = @import("std");

extern "msdrm" fn DRMEncrypt(
    hCryptoProvider: u32, // DWORD
    iPosition: u32, // DWORD
    cNumInBytes: u32, // DWORD
    pbInData: [*c]u8, // BYTE* in/out
    pcNumOutBytes: [*c]u32, // DWORD* in/out
    pbOutData: [*c]u8 // BYTE* in/out
) callconv(std.os.windows.WINAPI) i32;
proc DRMEncrypt(
    hCryptoProvider: uint32,  # DWORD
    iPosition: uint32,  # DWORD
    cNumInBytes: uint32,  # DWORD
    pbInData: ptr uint8,  # BYTE* in/out
    pcNumOutBytes: ptr uint32,  # DWORD* in/out
    pbOutData: ptr uint8  # BYTE* in/out
): int32 {.importc: "DRMEncrypt", stdcall, dynlib: "msdrm.dll".}
pragma(lib, "msdrm");
extern(Windows)
int DRMEncrypt(
    uint hCryptoProvider,   // DWORD
    uint iPosition,   // DWORD
    uint cNumInBytes,   // DWORD
    ubyte* pbInData,   // BYTE* in/out
    uint* pcNumOutBytes,   // DWORD* in/out
    ubyte* pbOutData   // BYTE* in/out
);
ccall((:DRMEncrypt, "msdrm.dll"), stdcall, Int32,
      (UInt32, UInt32, UInt32, Ptr{UInt8}, Ptr{UInt32}, Ptr{UInt8}),
      hCryptoProvider, iPosition, cNumInBytes, pbInData, pcNumOutBytes, pbOutData)
# hCryptoProvider : DWORD -> UInt32
# iPosition : DWORD -> UInt32
# cNumInBytes : DWORD -> UInt32
# pbInData : BYTE* in/out -> Ptr{UInt8}
# pcNumOutBytes : DWORD* in/out -> Ptr{UInt32}
# pbOutData : BYTE* in/out -> Ptr{UInt8}
# stdcall は 32bit のみ意味を持つ(x64 では無視)。
local ffi = require("ffi")
ffi.cdef[[
int32_t DRMEncrypt(
    uint32_t hCryptoProvider,
    uint32_t iPosition,
    uint32_t cNumInBytes,
    uint8_t* pbInData,
    uint32_t* pcNumOutBytes,
    uint8_t* pbOutData);
]]
local msdrm = ffi.load("msdrm")
-- msdrm.DRMEncrypt(hCryptoProvider, iPosition, cNumInBytes, pbInData, pcNumOutBytes, pbOutData)
-- hCryptoProvider : DWORD
-- iPosition : DWORD
-- cNumInBytes : DWORD
-- pbInData : BYTE* in/out
-- pcNumOutBytes : DWORD* in/out
-- pbOutData : BYTE* in/out
-- 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
const koffi = require('koffi');
const lib = koffi.load('msdrm.dll');
const DRMEncrypt = lib.func('__stdcall', 'DRMEncrypt', 'int32_t', ['uint32_t', 'uint32_t', 'uint32_t', 'uint8_t *', 'uint32_t *', 'uint8_t *']);
// DRMEncrypt(hCryptoProvider, iPosition, cNumInBytes, pbInData, pcNumOutBytes, pbOutData)
// hCryptoProvider : DWORD -> 'uint32_t'
// iPosition : DWORD -> 'uint32_t'
// cNumInBytes : DWORD -> 'uint32_t'
// pbInData : BYTE* in/out -> 'uint8_t *'
// pcNumOutBytes : DWORD* in/out -> 'uint32_t *'
// pbOutData : BYTE* in/out -> 'uint8_t *'
// 出力ポインタは koffi.out(...) で包む。構造体は koffi.struct で定義。
const lib = Deno.dlopen("msdrm.dll", {
  DRMEncrypt: { parameters: ["u32", "u32", "u32", "pointer", "pointer", "pointer"], result: "i32" },
});
// lib.symbols.DRMEncrypt(hCryptoProvider, iPosition, cNumInBytes, pbInData, pcNumOutBytes, pbOutData)
// hCryptoProvider : DWORD -> "u32"
// iPosition : DWORD -> "u32"
// cNumInBytes : DWORD -> "u32"
// pbInData : BYTE* in/out -> "pointer"
// pcNumOutBytes : DWORD* in/out -> "pointer"
// pbOutData : BYTE* in/out -> "pointer"
// 文字列引数は "buffer"(NUL 終端のバイト列を Uint8Array で渡す)。
// 値渡し構造体は { struct: [ ...field types... ] } を使用。
<?php
$ffi = FFI::cdef(<<<C
int32_t DRMEncrypt(
    uint32_t hCryptoProvider,
    uint32_t iPosition,
    uint32_t cNumInBytes,
    uint8_t* pbInData,
    uint32_t* pcNumOutBytes,
    uint8_t* pbOutData);
C, "msdrm.dll");
// $ffi->DRMEncrypt(hCryptoProvider, iPosition, cNumInBytes, pbInData, pcNumOutBytes, pbOutData);
// hCryptoProvider : DWORD
// iPosition : DWORD
// cNumInBytes : DWORD
// pbInData : BYTE* in/out
// pcNumOutBytes : DWORD* in/out
// pbOutData : BYTE* in/out
// 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
// WINAPI(stdcall): x64 では呼出規約が統一されるため問題なし。x86 では __stdcall 対応のラッパが必要な場合あり。
import com.sun.jna.*;
import com.sun.jna.ptr.*;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;

public interface Msdrm extends StdCallLibrary {
    Msdrm INSTANCE = Native.load("msdrm", Msdrm.class);
    int DRMEncrypt(
        int hCryptoProvider,   // DWORD
        int iPosition,   // DWORD
        int cNumInBytes,   // DWORD
        byte[] pbInData,   // BYTE* in/out
        IntByReference pcNumOutBytes,   // DWORD* in/out
        byte[] pbOutData   // BYTE* in/out
    );
}
@[Link("msdrm")]
lib Libmsdrm
  fun DRMEncrypt = DRMEncrypt(
    hCryptoProvider : UInt32,   # DWORD
    iPosition : UInt32,   # DWORD
    cNumInBytes : UInt32,   # DWORD
    pbInData : UInt8*,   # BYTE* in/out
    pcNumOutBytes : UInt32*,   # DWORD* in/out
    pbOutData : UInt8*   # BYTE* in/out
  ) : Int32
end
# 構造体/GUID/enum は lib 内に対応する型定義が必要。
# 呼出規約: x64 は規約統一のため OK。x86(32bit)は WINAPI=stdcall だが Crystal の fun に stdcall 付与構文がなく非対応。
import 'dart:ffi';
import 'package:ffi/ffi.dart';

typedef DRMEncryptNative = Int32 Function(Uint32, Uint32, Uint32, Pointer<Uint8>, Pointer<Uint32>, Pointer<Uint8>);
typedef DRMEncryptDart = int Function(int, int, int, Pointer<Uint8>, Pointer<Uint32>, Pointer<Uint8>);
final DRMEncrypt = DynamicLibrary.open('msdrm.dll')
    .lookupFunction<DRMEncryptNative, DRMEncryptDart>('DRMEncrypt');
// hCryptoProvider : DWORD -> Uint32
// iPosition : DWORD -> Uint32
// cNumInBytes : DWORD -> Uint32
// pbInData : BYTE* in/out -> Pointer<Uint8>
// pcNumOutBytes : DWORD* in/out -> Pointer<Uint32>
// pbOutData : BYTE* in/out -> Pointer<Uint8>
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。
{$mode objfpc}{$H+}
function DRMEncrypt(
  hCryptoProvider: DWORD;   // DWORD
  iPosition: DWORD;   // DWORD
  cNumInBytes: DWORD;   // DWORD
  pbInData: Pointer;   // BYTE* in/out
  pcNumOutBytes: Pointer;   // DWORD* in/out
  pbOutData: Pointer   // BYTE* in/out
): Integer; stdcall;
  external 'msdrm.dll' name 'DRMEncrypt';
import Foreign
import Foreign.C.Types
import Foreign.C.String

foreign import stdcall safe "DRMEncrypt"
  c_DRMEncrypt :: Word32 -> Word32 -> Word32 -> Ptr Word8 -> Ptr Word32 -> Ptr Word8 -> IO Int32
-- hCryptoProvider : DWORD -> Word32
-- iPosition : DWORD -> Word32
-- cNumInBytes : DWORD -> Word32
-- pbInData : BYTE* in/out -> Ptr Word8
-- pcNumOutBytes : DWORD* in/out -> Ptr Word32
-- pbOutData : BYTE* in/out -> Ptr Word8
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。
open Ctypes
open Foreign

let drmencrypt =
  foreign "DRMEncrypt"
    (uint32_t @-> uint32_t @-> uint32_t @-> (ptr uint8_t) @-> (ptr uint32_t) @-> (ptr uint8_t) @-> returning int32_t)
(* hCryptoProvider : DWORD -> uint32_t *)
(* iPosition : DWORD -> uint32_t *)
(* cNumInBytes : DWORD -> uint32_t *)
(* pbInData : BYTE* in/out -> (ptr uint8_t) *)
(* pcNumOutBytes : DWORD* in/out -> (ptr uint32_t) *)
(* pbOutData : BYTE* in/out -> (ptr uint8_t) *)
(* foreign は cdecl 前提。x64 Windows では WINAPI と一致。構造体は ctypes structure を定義のこと。 *)
(cffi:define-foreign-library msdrm (t "msdrm.dll"))
(cffi:use-foreign-library msdrm)

(cffi:defcfun ("DRMEncrypt" drmencrypt :convention :stdcall) :int32
  (h-crypto-provider :uint32)   ; DWORD
  (i-position :uint32)   ; DWORD
  (c-num-in-bytes :uint32)   ; DWORD
  (pb-in-data :pointer)   ; BYTE* in/out
  (pc-num-out-bytes :pointer)   ; DWORD* in/out
  (pb-out-data :pointer))   ; BYTE* in/out
; isize/usize(INT_PTR/SIZE_T)は x64 前提で :int64/:uint64。x86 では :int32/:uint32。
use Win32::API;
my $DRMEncrypt = Win32::API::More->new('msdrm',
    'int DRMEncrypt(DWORD hCryptoProvider, DWORD iPosition, DWORD cNumInBytes, LPVOID pbInData, LPVOID pcNumOutBytes, LPVOID pbOutData)');
# my $ret = $DRMEncrypt->Call($hCryptoProvider, $iPosition, $cNumInBytes, $pbInData, $pcNumOutBytes, $pbOutData);
# hCryptoProvider : DWORD -> DWORD
# iPosition : DWORD -> DWORD
# cNumInBytes : DWORD -> DWORD
# pbInData : BYTE* in/out -> LPVOID
# pcNumOutBytes : DWORD* in/out -> LPVOID
# pbOutData : BYTE* in/out -> LPVOID
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。

関連項目

公式の関連項目