//***************************************************************************** // // Microsoft Windows Media // Copyright (C) Microsoft Corporation. All rights reserved. // // FileName: Drm.cpp // // Abstract: Implementation of class CDRM which handles DRM license // acquisition for protected content. // //***************************************************************************** // #include "stdafx.h" #include "nserror.h" #include "AudioPlay.h" #include "AudioDlg.h" #include #include #ifdef SUPPORT_DRM #include "DRM.h" #pragma warning( disable:4192 ) #import "shdocvw.dll" class __declspec(uuid("0002DF01-0000-0000-C000-000000000046")) InternetExplorer; struct __declspec(uuid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E")) IWebBrowser2; // // This function is used automate the internet browser for DRMv7 non-silent license acquisition // HRESULT OpenURLWithData( LPWSTR wszURL, BYTE* pbPostData ) { static const LPSTR POST_DATA_PREFIX = "nonsilent=1&challenge="; static const LPWSTR POST_HEADER_DATA = L"Content-Type: application/x-www-form-urlencoded\r\n"; HRESULT hr = S_OK; SHDocVw::IWebBrowser2* pWebBrowser = NULL; BSTR bstrURL = NULL; BSTR bstrHeader = NULL; VARIANT vtPostData = {0}; VARIANT vtEmpty; VARIANT vtHeader; int nPostDataSize; SAFEARRAY* saPostData = NULL; void* pvData; int nPostDataPrefixSize; if ( !wszURL ) return E_INVALIDARG; do { // // Create the web browser instance // hr = ::CoCreateInstance( __uuidof(InternetExplorer), NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, __uuidof(IWebBrowser2), reinterpret_cast(&pWebBrowser) ); if( FAILED(hr) ) { //Can't create instance of IE! return hr; } // // Convert URL to BSTR // bstrURL = SysAllocString( wszURL ); if ( !bstrURL ) { hr = E_OUTOFMEMORY; break; } // // Create a variant for the header information // bstrHeader = SysAllocString( POST_HEADER_DATA ); if ( !bstrHeader ) { hr = E_OUTOFMEMORY; break; } VariantInit( &vtEmpty ); VariantInit( &vtPostData ); VariantInit( &vtHeader ); V_VT( &vtHeader ) = VT_BSTR; V_BSTR( &vtHeader ) = bstrHeader; if ( pbPostData ) { // // Convert post data to a variant // nPostDataSize = strlen( (char*) pbPostData ); nPostDataPrefixSize = strlen( POST_DATA_PREFIX ); saPostData = SafeArrayCreateVector( VT_UI1, 0, nPostDataPrefixSize + nPostDataSize + 1 ); if( NULL == saPostData ) { hr = E_OUTOFMEMORY; break; } hr = SafeArrayAccessData( saPostData, &pvData ); if( FAILED(hr) ) { break; } // // Copy the prefix, then the data // CopyMemory( pvData, POST_DATA_PREFIX, nPostDataPrefixSize ); CopyMemory( ((LPBYTE)pvData) + nPostDataPrefixSize, pbPostData, nPostDataSize + 1 ); hr = SafeArrayUnaccessData( saPostData ); if( FAILED(hr) ) { break; } V_VT(&vtPostData) = VT_ARRAY | VT_UI1; V_ARRAY(&vtPostData) = saPostData; } try { // // Show the web browser // pWebBrowser->put_Visible ( (VARIANT_BOOL) TRUE ); // Ignore the hr - it's not really important either way // // Navigate to the requested URL // hr = pWebBrowser->Navigate( bstrURL, &vtEmpty, &vtEmpty, &vtPostData, &vtHeader ); if( FAILED(hr) ) { break; } } catch ( ... ) { // An exception was thrown calling the IE control! hr = E_FAIL; } } while ( FALSE ); SAFE_RELEASE( pWebBrowser ); SAFE_SYSFREESTRING( bstrURL ); SAFE_SYSFREESTRING( bstrHeader ); if( saPostData ) { SafeArrayDestroy( saPostData ); saPostData = NULL; } return hr; } //------------------------------------------------------------------------------ // Name: CDRM::CDRM() // Desc: Constructor. //------------------------------------------------------------------------------ CDRM::CDRM() { m_pParent = NULL; m_pDRMReader = NULL; m_pwszURL = NULL; m_statusDRM = NONE; m_pWMGetLicenseData = NULL; m_dwLastDRMVersion = 0; m_bDoNotConnectToUntrustedURL = FALSE; // if this is set to TRUE in the way, we will purposedly fail License Acquisition. } //------------------------------------------------------------------------------ // Name: CDRM::~CDRM() // Desc: Destructor. //------------------------------------------------------------------------------ CDRM::~CDRM() { Exit(); } //------------------------------------------------------------------------------ // Name: CDRM::Init() // Desc: Initializes some member variables. //------------------------------------------------------------------------------ HRESULT CDRM::Init( CAudioPlay* pParent, IWMReader* pReader, LPCWSTR pwszURL ) { if( ( NULL == pParent ) || ( NULL == pReader ) || ( NULL == pwszURL ) ) { return( E_INVALIDARG ); } m_bDoNotConnectToUntrustedURL = FALSE; m_pParent = pParent; m_pParent->AddRef(); m_pwszURL = ( LPWSTR )pwszURL; // // Query for IWMDRMReader interface // HRESULT hr = pReader->QueryInterface( IID_IWMDRMReader, ( void** )&m_pDRMReader ); if( FAILED( hr ) ) { //Did you remember to link to your stublib and unlink to wmvcore.lib? TCHAR tszErrMsg[256]; sprintf_s( tszErrMsg, ARRAYSIZE(tszErrMsg), _T( "Could not QI for IWMDRMReader (hr=%#X)" ), hr ); MessageBox( g_hwndDialog, tszErrMsg, ERROR_DIALOG_TITLE, MB_OK ); } return( hr ); } //------------------------------------------------------------------------------ // Name: CDRM::Exit() // Desc: Cleanup. //------------------------------------------------------------------------------ HRESULT CDRM::Exit() { SAFE_ARRAYDELETE( m_pWMGetLicenseData ); SAFE_RELEASE( m_pDRMReader ); SAFE_RELEASE( m_pParent ); m_pwszURL = NULL; m_statusDRM = NONE; return( S_OK ); } //------------------------------------------------------------------------------ // Name: CDRM::Cancel() // Desc: Cancel DRM operations. //------------------------------------------------------------------------------ HRESULT CDRM::Cancel() { // // If m_pDRMReader is NULL, either Init() has not been called or Exit() has // been called, and it indicates no DRM operation is being executed. // if( NULL == m_pDRMReader ) { return( S_FALSE ); } // // Cancel current operation // HRESULT hr = S_OK; switch( m_statusDRM ) { case NONSILENT: // // We cannot cancel this operation once the browser is brought up. // break; case SILENT: hr = m_pDRMReader->CancelLicenseAcquisition(); if( SUCCEEDED( hr ) ) { m_pParent->SetAsyncEvent( NS_S_DRM_ACQUIRE_CANCELLED ); } break; case INDIVIDUALIZE: hr = m_pDRMReader->CancelIndividualization(); if( SUCCEEDED( hr ) ) { m_pParent->SetAsyncEvent( NS_E_DRM_INDIVIDUALIZATION_INCOMPLETE ); } break; default: break; } return( hr ); } //------------------------------------------------------------------------------ // Name: CDRM::OnDRMStatus() // Desc: Handles DRM notifications in OnStatus. //------------------------------------------------------------------------------ HRESULT CDRM::OnDRMStatus( /* [in] */ WMT_STATUS Status, /* [in] */ HRESULT hr, /* [in] */ WMT_ATTR_DATATYPE dwType, /* [in] */ BYTE __RPC_FAR *pValue, /* [in] */ void __RPC_FAR *pvContext ) { if( NULL == m_pDRMReader ) { return( S_OK ); } HRESULT hRes = S_OK; DWORD cbWMGetLicenseDataSize; DWORD dwContinue; switch( Status ) { case WMT_NO_RIGHTS: // // This is a DRM v1 file that requires non-silent license acquisition. In this sample, // a browser window will be brought up and directed to the web site // from which a license can be acquired after filling in required info. // The user must click Play in order to play the file after // the license is acquired. // With v1 files, pValue is a WCHAR string containing the license acquisition URL. m_dwLastDRMVersion = 1; m_statusDRM = NONSILENT; SetCurrentStatus( ACQUIRINGLICENSE ); hRes = GetNonSilentLicense( pValue ); if( FAILED( hRes ) ) { m_pParent->SetAsyncEvent( hRes ); } else { m_pParent->SetAsyncEvent( NS_E_DRM_NO_RIGHTS ); } break; case WMT_NO_RIGHTS_EX: // // This event is fired only for DRM v7 files // pValue is a WM_GET_LICENSE_DATA structure // if( m_bDoNotConnectToUntrustedURL == TRUE ) { // // WRT the warning message displayed by WMT_LICENSEURL_SIGNATURE_STATE message // the user has previously chosen not to connect to license acquisition URL (silent or non silent) // SetCurrentStatus( CLOSED ); SetCurrentStatus( READY ); return E_FAIL; } m_dwLastDRMVersion = 7; m_statusDRM = SILENT; SetCurrentStatus( ACQUIRINGLICENSE ); // // Copy the WM_GET_LICENSE_DATA structure // cbWMGetLicenseDataSize = 0; SAFE_ARRAYDELETE( m_pWMGetLicenseData ); // // First, retrieve the size of the data to be copied // hRes = CopyWMGetLicenseData( (WM_GET_LICENSE_DATA*) pValue, NULL, &cbWMGetLicenseDataSize ); if ( FAILED( hRes ) ) { break; } // // Allocate the memory for the structure // m_pWMGetLicenseData = (WM_GET_LICENSE_DATA*) new BYTE[ cbWMGetLicenseDataSize ]; if ( !m_pWMGetLicenseData ) { hRes = E_OUTOFMEMORY; break; } // // Store the license data in case silent acquisition fails and // we need to try it non-silently using AcquireLastV7LicenseNonSilently // hRes = CopyWMGetLicenseData( (WM_GET_LICENSE_DATA*) pValue, m_pWMGetLicenseData, &cbWMGetLicenseDataSize ); if ( FAILED( hRes ) ) { break; } // // Acquire the license silently // hRes = m_pDRMReader->AcquireLicense( 1 ); if( FAILED( hRes ) ) { m_pParent->SetAsyncEvent( hRes ); } break; case WMT_ACQUIRE_LICENSE: // // This event is fired only for DRM v7 files after // an application has called AcquireLicense (for silent acquisition) // or MonitorLicenseAcquisition (for non-silent acquisition) // pValue is a WM_GET_LICENSE_DATA structure // hRes = HandleAcquireLicense( pValue ); if( FAILED( hRes ) ) { m_pParent->SetAsyncEvent( hRes ); } break; case WMT_NEEDS_INDIVIDUALIZATION: m_statusDRM = INDIVIDUALIZE; SetCurrentStatus( INDIVIDUALIZING ); // // Individualize the client. // hRes = m_pDRMReader->Individualize( 0 ); if( FAILED( hRes ) ) { m_pParent->SetAsyncEvent( hRes ); } break; case WMT_INDIVIDUALIZE: // // Individualize the client. // IMPORTANT!!! This operation will cause the user's system // to be modified. In your application you should // always let the user choose whether or not to individualize. // See the SDK documentation or the Microsoft Web site for more information. // hRes = HandleIndividualize( pValue ); if( FAILED( hRes ) ) { m_pParent->SetAsyncEvent( hRes ); } break; case WMT_LICENSEURL_SIGNATURE_STATE: switch((int)*pValue) { case WMT_DRMLA_UNTRUSTED: dwContinue = MessageBox( g_hwndDialog, _T( "A license is required to play this content, but the authenticity of the license acquisition URL can not be verified .\n\nTo obtain the license, a web connection will have to be made to the content provider's site with this untrusted URL. You might be required to register or pay a fee for the license -- it varies by provider.\n\nCAUTION: Web pages can contain elements that could be harmful to your computer. It is important to be certain that the content is from a trustworthy source before continuing.\n\nDo you want to continue acquiring the license?" ), ERROR_DIALOG_TITLE, MB_YESNO ); break; case WMT_DRMLA_TRUSTED: //Proceed silently break; case WMT_DRMLA_TAMPERED: dwContinue = MessageBox( g_hwndDialog, _T( "The license acquisition URL in this file has been tampered with. You are strongly advised not to navigate to this Web site. Navigate to this Web site anyway?" ), ERROR_DIALOG_TITLE, MB_YESNO ); break; default: dwContinue = MessageBox( g_hwndDialog, _T( "The license acquisition URL in this file is not signed and its validity cannot be guaranteed. Get a license anyway?" ), ERROR_DIALOG_TITLE, MB_YESNO ); break; } if(dwContinue == IDYES) m_bDoNotConnectToUntrustedURL = FALSE; //correct? or just fail silently? else m_bDoNotConnectToUntrustedURL = TRUE; //} break; default: break; } return( hr ); } //------------------------------------------------------------------------------ // Name: CDRM::HandleAcquireLicense() // Desc: Handles WMT_ACQUIRE_LICENSE notifications in OnDRMStatus. // This function is called in two cases: // (1) when silent acquisition succeeds using m_pDRMReader->AcquireLicense(1) // (2) when non-silent v7 acquisition succeeds if you call m_pDRMReader->MonitorLicenseAcquisition // Note: v1 licenses have no notification mechanism like this // //------------------------------------------------------------------------------ HRESULT CDRM::HandleAcquireLicense( BYTE *pValue ) { WM_GET_LICENSE_DATA* pLicenseData = ( WM_GET_LICENSE_DATA* )pValue; if( NS_S_DRM_LICENSE_ACQUIRED != pLicenseData->hr ) { return ( pLicenseData->hr ); } m_statusDRM = NONE; // // License Acquisition Complete // Reopen the reader // SetCurrentStatus( LICENSEACQUIRED ); return( m_pParent->ReopenReader( this ) ); } //------------------------------------------------------------------------------ // Name: CDRM::HandleIndividualize() // Desc: Handles WMT_INDIVIDUALIZE notifications in OnDRMStatus. // // Individualize the client. // IMPORTANT!!! This operation will cause the user's system // to be modified. In your application you should // always let the user choose whether or not to individualize. // See the SDK documentation or the Microsoft Web site for more information. // //------------------------------------------------------------------------------ HRESULT CDRM::HandleIndividualize( BYTE *pValue ) { WM_INDIVIDUALIZE_STATUS* pStatus = ( WM_INDIVIDUALIZE_STATUS* )pValue; // The WMT_INDIVIDUALIZE event will be sent to your application // repeatedly while the new component is downloading. // You can add code here to use the information in pStatus to // implement a progress bar or some other user interface that // informs the user of the status of the download operation. // if( INDI_SUCCEED != pStatus->enIndiStatus ) { return( pStatus->hr ); } m_statusDRM = NONE; // // Individualization Complete // Reopen the reader // SetCurrentStatus( INDIVIDUALIZED ); return( m_pParent->ReopenReader( this ) ); } //------------------------------------------------------------------------------ // Name: CDRM::GetNonSilentLicense() // Desc: Handles WMT_NO_RIGHTS notifications in OnDRMStatus. // This function does non-silent acquisition for v1 only. // v7 non-silent licenses are acquired using AcquireLastV7LicenseNonSilently //------------------------------------------------------------------------------ HRESULT CDRM::GetNonSilentLicense( BYTE *pValue ) { if( NULL == pValue ) { return( E_INVALIDARG ); } HRESULT hr = S_OK; LPTSTR ptszEscapedURL = NULL; LPTSTR ptszURL = NULL; TCHAR tszErrMsg[256]; DWORD cchURL; ZeroMemory( ( void* )tszErrMsg, sizeof( tszErrMsg ) ); do { // // m_pwszURL is the file we are trying to open. // It may be in the form of a local path. If it is, we // need to make it a URL by prepending "file://". We also // need to create escape sequences for certain characters if they // are present in the string. hr = MakeEscapedURL( m_pwszURL, &ptszEscapedURL ); if( FAILED( hr ) ) { break; } cchURL = _tcslen( ptszEscapedURL ) + wcslen( ( LPWSTR )pValue ) + 30; ptszURL = new TCHAR[ cchURL ]; if( NULL == ptszURL ) { _tcscpy_s( tszErrMsg, ARRAYSIZE(tszErrMsg), _T( "Insufficient memory" ) ); hr = HRESULT_FROM_WIN32( GetLastError() ); break; } // // Construct the complete HTTP string required for v1 license requests // _stprintf_s( ptszURL, cchURL, _T( "%ws&filename=%s&embedded=false" ), ( LPWSTR )pValue, ptszEscapedURL ); // // Launch this URL which will acquire the licence when the user fills all // the details asked at the site. // hr = LaunchURL( ptszURL ); if( FAILED( hr ) ) { _stprintf_s( tszErrMsg, ARRAYSIZE(tszErrMsg), _T( "Unable to launch the URL (Err=%#X)" ), hr ); break; } } while( FALSE ); delete[] ptszEscapedURL; delete[] ptszURL; if( FAILED( hr ) && ( _tcslen( tszErrMsg ) > 0 ) ) { MessageBox( g_hwndDialog, tszErrMsg, ERROR_DIALOG_TITLE, MB_OK ); } return( hr ); } //------------------------------------------------------------------------------ // Name: CDRM::MakeEscapedURL() // Desc: Put escape sequences in the file URL. //------------------------------------------------------------------------------ HRESULT CDRM::MakeEscapedURL( LPCWSTR pwszInURL, LPTSTR *ppszOutURL ) { if( ( NULL == pwszInURL ) || ( NULL == ppszOutURL ) ) { return( E_INVALIDARG ); } BOOL bNeedFilePrefix = FALSE; DWORD cEscapees = 0; DWORD cchOutURL = 0; DWORD cchToCopy = 0; LPCWSTR pwszTemp = NULL; LPTSTR pchNext = NULL; LPCWSTR pchToEscape = NULL; WCHAR chEscape; // // Check if we need to pre-pend "file://" to the output URL // bNeedFilePrefix = ( NULL == wcsstr( pwszInURL, L"://" ) ); // // Count how many characters need to be escaped // pwszTemp = pwszInURL; while( TRUE ) { pchToEscape = wcspbrk( pwszTemp, L" #$%&\\+,;=@[]^{}" ); if( NULL == pchToEscape ) { break; } cEscapees++; pwszTemp = pchToEscape + 1; } // // Allocate space for out URL // cchOutURL = wcslen( pwszInURL ) + ( 2 * cEscapees ) + 1; if( bNeedFilePrefix ) { cchOutURL += _tcslen( _T( "file://" ) ); } *ppszOutURL = new TCHAR[ cchOutURL ]; if( NULL == *ppszOutURL ) { MessageBox( g_hwndDialog, _T( "Insufficient memory" ), ERROR_DIALOG_TITLE, MB_OK ); return( HRESULT_FROM_WIN32( GetLastError() ) ); } // // Fill in the output URL // pwszTemp = pwszInURL; pchNext = *ppszOutURL; if( bNeedFilePrefix ) { _tcscpy_s( *ppszOutURL, cchOutURL, _T( "file://" ) ); pchNext += _tcslen( _T( "file://" ) ); } pchToEscape = NULL; while( TRUE ) { pchToEscape = wcspbrk( pwszTemp, L" #$%&\\+,;=@[]^{}" ); if( NULL == pchToEscape ) { // // Copy the rest of the input string and get out // _stprintf_s( pchNext, cchOutURL, _T( "%ws" ), pwszTemp ); break; } // // Copy all characters since the previous escapee // cchToCopy = pchToEscape - pwszTemp; chEscape = *pchToEscape; if( cchToCopy > 0 ) { _stprintf_s( pchNext, cchOutURL, _T("%ws"), pwszTemp ); pchNext += cchToCopy; } // // Expand this character into an escape code and move on // pchNext += _stprintf_s( pchNext, cchOutURL, _T( "%%%02x" ), chEscape ); pwszTemp = pchToEscape + 1; } return( S_OK ); } //------------------------------------------------------------------------------ // Name: CDRM::LaunchURL() // Desc: Opens a URL in the browser. // ptszURL contains the license acquisition URL from the content header, // our correctly formed file name, and the "&embedded=false" string //------------------------------------------------------------------------------ HRESULT CDRM::LaunchURL( LPCTSTR ptszURL ) { DWORD cchLaunchCommand = 0; HRESULT hr = S_OK; LPTSTR ptszParam = NULL; LPTSTR ptszLaunchCommand = NULL; PROCESS_INFORMATION ProcInfo; STARTUPINFO StartUp; TCHAR tszShellOpenCommand[ MAX_PATH * 2 ]; TCHAR tszApplicationName[ MAX_PATH * 2 ]; do { // // Find the appropriate command with which to launch URL // hr = GetShellOpenCommand( tszShellOpenCommand, sizeof( tszShellOpenCommand ), tszApplicationName, sizeof( tszApplicationName) ); if( FAILED( hr ) ) { break; } // // Build the appropriate command line by possibly substituting our URL parameter // First search the open command for "%1" or "%*" // ptszParam = _tcsstr( tszShellOpenCommand, _T( "\"%1\"" ) ); if( NULL == ptszParam ) { ptszParam = _tcsstr( tszShellOpenCommand, _T( "\"%*\"" ) ); } if( NULL != ptszParam ) { // // Substitute "%1" or "%*" with the URL // cchLaunchCommand = _tcslen( tszShellOpenCommand ) + _tcslen( ptszURL ) - 3; // +1 for NULL, -4 for "%1" or "%*" ptszLaunchCommand = new TCHAR[ cchLaunchCommand ]; *ptszParam = _T( '\0' ); _stprintf_s( ptszLaunchCommand, cchLaunchCommand, _T( "%s%s%s" ), tszShellOpenCommand, ptszURL, ptszParam + 4 ); } else { // // No "%1" or "%*", so simply append the URL to the open command // cchLaunchCommand = _tcslen( tszShellOpenCommand ) + _tcslen( ptszURL ) + 1 + 1; // 1 for space, 1 for NULL ptszLaunchCommand = new CHAR[ cchLaunchCommand ]; _stprintf_s( ptszLaunchCommand, cchLaunchCommand, _T( "%s %s" ), tszShellOpenCommand, ptszURL ); } // // Use CreateProcess to launch the browser. // ZeroMemory( ( LPVOID )&ProcInfo, sizeof( PROCESS_INFORMATION ) ); ZeroMemory( ( LPVOID )&StartUp, sizeof( STARTUPINFO ) ); StartUp.cb = sizeof(STARTUPINFO); if( !CreateProcess( tszApplicationName, ptszLaunchCommand, NULL, NULL, FALSE, 0, NULL, NULL, &StartUp, &ProcInfo ) ) { hr = HRESULT_FROM_WIN32( GetLastError() ); } else { // // CreateProcess succeeded and we do not need the handles to the thread // or the process, so close them now. // if( NULL != ProcInfo.hThread ) { CloseHandle( ProcInfo.hThread ); } if( NULL != ProcInfo.hProcess ) { CloseHandle( ProcInfo.hProcess ); } } } while( FALSE ); SAFE_ARRAYDELETE( ptszLaunchCommand ); return( hr ); } //------------------------------------------------------------------------------ // Name: CDRM::GetShellOpenCommand() // Desc: Find the command for the shell's open verb associated with HTTP protocol. //------------------------------------------------------------------------------ HRESULT CDRM::GetShellOpenCommand( LPTSTR ptszShellOpenCommand, DWORD cbShellOpenCommand, LPTSTR ptszApplicationName, DWORD cbApplicationName) { HKEY hKey = NULL; LONG lResult; // // Find the command for the shell's open verb associated with HTTP protocol // lResult = RegOpenKeyEx( HKEY_CLASSES_ROOT, _T( "http\\shell\\open\\command" ), 0, KEY_READ, &hKey ); if( ERROR_SUCCESS == lResult ) { lResult = RegQueryValueEx( hKey, NULL, 0, NULL, ( BYTE* )ptszShellOpenCommand, &cbShellOpenCommand ); } if( NULL != hKey ) { RegCloseKey( hKey ); } if( ERROR_SUCCESS != lResult ) { return( HRESULT_FROM_WIN32( lResult ) ); } // // Find the application name out of the open command, stripping quotes if necessary // TCHAR *pchFirst = ptszShellOpenCommand; TCHAR *pchNext = NULL; // // Strip out any leading space // while( _T( ' ' ) == *pchFirst ) { pchFirst++; } // // Strip out quotes // if( _T( '"' ) == *pchFirst ) { pchFirst++; pchNext = _tcschr( pchFirst, _T( '"' ) ); } else { pchNext = _tcschr( pchFirst + 1, _T( ' ' ) ); } if( NULL == pchNext ) { pchNext = ptszShellOpenCommand + _tcslen( ptszShellOpenCommand ); } _tcsncpy_s( ptszApplicationName, cbApplicationName, pchFirst, pchNext - pchFirst ); ptszApplicationName[ pchNext - pchFirst ] = _T( '\0' ); return( S_OK ); } //------------------------------------------------------------------------------ // Name: CDRM::CopyWMGetLicenseData() // Desc: Stores the WM_GET_LICENSE_DATA structure.for possible later use during // non-silent acquisition in AcquireLastV7LicenseNonSilently function //------------------------------------------------------------------------------ HRESULT CDRM::CopyWMGetLicenseData( WM_GET_LICENSE_DATA* pOriginalData, WM_GET_LICENSE_DATA* pDestData, DWORD* pcbDestSize ) { HRESULT hr = S_OK; DWORD pcbRequiredSize; INT nURLLength; INT nLocalFilenameLength; if ( !pOriginalData ) { return E_INVALIDARG; } if ( !pcbDestSize ) { return E_POINTER; } // // Do a little verification of the original data // if ( ( NULL == pOriginalData->wszURL ) || ( NULL == pOriginalData->wszLocalFilename ) || ( NULL == pOriginalData->pbPostData && pOriginalData->dwPostDataSize != 0 ) ) { return E_INVALIDARG; } // // Calculate the number of bytes required for the data // nURLLength = wcslen( pOriginalData->wszURL ); nLocalFilenameLength = wcslen( pOriginalData->wszLocalFilename ); pcbRequiredSize = sizeof( WM_GET_LICENSE_DATA ) + ( nURLLength + 1 ) * sizeof( WCHAR ) + ( nLocalFilenameLength + 1 ) * sizeof( WCHAR ) + pOriginalData->dwPostDataSize; // // Copy the structure, if there's enough space for it // if ( pDestData ) { if ( *pcbDestSize >= pcbRequiredSize ) { memcpy( pDestData, pOriginalData, sizeof( WM_GET_LICENSE_DATA ) ); pDestData->wszURL = (LPWSTR) ( ((BYTE*) pDestData) + sizeof( WM_GET_LICENSE_DATA ) ); pDestData->wszLocalFilename = pDestData->wszURL + nURLLength + 1; pDestData->pbPostData = (BYTE*) ( pDestData->wszLocalFilename + nLocalFilenameLength + 1 ); wcscpy_s( pDestData->wszURL, nURLLength, pOriginalData->wszURL ); wcscpy_s( pDestData->wszLocalFilename, nLocalFilenameLength, pOriginalData->wszLocalFilename ); memcpy( pDestData->pbPostData, pOriginalData->pbPostData, pOriginalData->dwPostDataSize ); } else { hr = E_INVALIDARG; // Buffer was too small } } // // Update the size required / copied // *pcbDestSize = pcbRequiredSize; return hr; } //------------------------------------------------------------------------------ // Name: CDRM::AcquireLastV7LicenseNonSilently() // Desc: Tries to acquire the license non-silently.after silent acquisition failed //------------------------------------------------------------------------------ HRESULT CDRM::AcquireLastV7LicenseNonSilently() { HRESULT hr; LPTSTR tszLocalURL = NULL; // // Check to make sure we have info for a v7 license acquisition // if ( !m_pWMGetLicenseData ) { return E_UNEXPECTED; } m_statusDRM = NONSILENT; do { hr = m_pDRMReader->MonitorLicenseAcquisition(); if( FAILED(hr) ) return hr; // // Launch the file in m_pWMGetLicenseData->wszLocalFilename, which will // redirect to the proper page for non-silent license acquisition // hr = OpenURLWithData( m_pWMGetLicenseData->wszURL, m_pWMGetLicenseData->pbPostData ); } while ( FALSE ); SAFE_ARRAYDELETE( tszLocalURL ); return hr; } //------------------------------------------------------------------------------ // Name: CDRM::GetLastDRMVersion() // Desc: Retrieves the value of m_dwLastDRMVersion. //------------------------------------------------------------------------------ DWORD CDRM::GetLastDRMVersion() { return m_dwLastDRMVersion; } #endif // SUPPORT_DRM