/////////////////////////////////////////////////////////////////////////////// // // DRMUpdate.cpp : Contains application entry and functions for the DRMUpdate // sample. // // Copyright (c) Microsoft Corporation. All rights reserved. // /////////////////////////////////////////////////////////////////////////////// #include #include #include "DRMSampleUtils.h" #include /////////////////////////////////////////////////////////////////////////////// // Function Prototypes /////////////////////////////////////////////////////////////////////////////// HRESULT DisplaySecurityVersion(IWMDRMSecurity* pSecurity); HRESULT Individualize(IWMDRMSecurity* pSecurity, BOOL fForce, FILE* pLogFile); HRESULT TryOpenFile(wchar_t* FileName, FILE** ppFile); /////////////////////////////////////////////////////////////////////////////// // // Function: wmain // // Description: Application entry point. The DRMUpdate application is a simple, // command-line way to individualize the DRM component. DRMUpdate displays the // current security version, then performs individualization and displayes the // post-update security version. Status messages are displayed as they are // received. // // Parameters: The application take a single optional parameter, -force. If // set, the -force parameter causes the application to force individualization // instead of letting the DRM subsystem determine whether individualization is // required. // /////////////////////////////////////////////////////////////////////////////// void wmain(int argc, wchar_t **argv) { HRESULT hr = S_OK; BOOL fForce = FALSE; FILE* pFile = NULL; IWMDRMProvider* pProvider = NULL; IWMDRMSecurity* pSecurity = NULL; // Check the arguments. if (argc == 1) { // Invalid number of arguments. hr = E_INVALIDARG; } else if (argc == 2) { // If a valid call, there will be an output filename only. hr = TryOpenFile(argv[1], &pFile); } else if (argc == 3) { // The first argument should be the output filename. hr = TryOpenFile(argv[1], &pFile); // Check the second argument for the force flag. if (wcsstr(argv[2], L"-force") != NULL) { fForce = TRUE; } } else { // Invalid number of arguments. hr = E_INVALIDARG; } // Several branches of the argument checking above can set hr to // E_INVALIDARG. In all cases, this indicates that the passed arguments // were incorrect. Print a message to that effect. if (hr == E_INVALIDARG) { printf("Invalid command-line arguments. Use the following format:\n"); printf("DRMUpdate.exe [-force]\n"); printf("Where <> indicates vriable text and [] indicates an optional argument.\n"); } // Initialize DRM. if (SUCCEEDED(hr)) { hr = WMDRMStartup(); } // Create a DRM provider. if (SUCCEEDED(hr)) { hr = WMDRMCreateProvider(&pProvider); } // Create a security object. if (SUCCEEDED(hr)) { hr = pProvider->CreateObject(IID_IWMDRMSecurity, (void**)&pSecurity); } // Display the security version before updating. if (SUCCEEDED(hr)) { hr = DisplaySecurityVersion(pSecurity); } // Perform individualization. if (SUCCEEDED(hr)) { hr = Individualize(pSecurity, fForce, pFile); } // The security interface must be re-initialized in order to get an // accurate security version after indiv. if (SUCCEEDED(hr)) { SAFE_RELEASE(pSecurity); hr = pProvider->CreateObject(IID_IWMDRMSecurity, (void**)&pSecurity); } // Display the security version again now that an update happened. if (SUCCEEDED(hr)) { hr = DisplaySecurityVersion(pSecurity); } // Clean up. SAFE_RELEASE(pSecurity); SAFE_RELEASE(pProvider); SAFE_FILE_CLOSE(pFile); WMDRMShutdown(); } /////////////////////////////////////////////////////////////////////////////// // // Function: DisplaySecurityVersion // Description: Retrieves the current DRM security version and prints it to the // console. // Parameters: pSecurity - Security interface pointer. // /////////////////////////////////////////////////////////////////////////////// HRESULT DisplaySecurityVersion(IWMDRMSecurity* pSecurity) { HRESULT hr = S_OK; BSTR bstrVersion = NULL; // Get the security version. hr = pSecurity->GetSecurityVersion(&bstrVersion); if (SUCCEEDED(hr)) { printf("Security version = %S\n", bstrVersion); } // Release the string. if (bstrVersion != NULL) { SysFreeString(bstrVersion); } return hr; } /////////////////////////////////////////////////////////////////////////////// // // Function: Individualize // Description: Individualizes the DRM subsystem, reporting progress to the // specified log file. // Parameters: pSecurity - Security interface to use for individualization. // fForce - Flag indicating whether to force individualization. // pLogFile - Pointer to an opened file that will be overwritten // with the individualization event log. // /////////////////////////////////////////////////////////////////////////////// HRESULT Individualize(IWMDRMSecurity* pSecurity, BOOL fForce, FILE* pLogFile) { HRESULT hr = S_OK; IMFMediaEvent* pEvent = NULL; IUnknown* pCancelCookie = NULL; IWMDRMIndividualizationStatus* pIndivStatus = NULL; MediaEventType EventType = MEUnknown; HRESULT EventHR = E_FAIL; DWORD cEvents = 0; WM_INDIVIDUALIZE_STATUS IndivStatusStruct; // Intialize structures. ZeroMemory(&IndivStatusStruct, sizeof(IndivStatusStruct)); PROPVARIANT EventValue; DWORD dwFlags = 0; // Initialize the property variant. PropVariantInit(&EventValue); // Check input pointers. if (pSecurity == NULL || pLogFile == NULL) { return E_POINTER; } // Configure the flag for individualization. if (fForce == TRUE) { dwFlags = WMDRM_SECURITY_PERFORM_FORCE_INDIV; printf("Performing forced individualization.\n"); } else { dwFlags = WMDRM_SECURITY_PERFORM_INDIV; printf("Performing as-needed individualization.\n"); } // Write a header for the log file. fprintf(pLogFile, "Windows Media DRM Individualization Log\n\n"); // Start the security update. hr = pSecurity->PerformSecurityUpdate(dwFlags, &pCancelCookie); // Status loop. if (SUCCEEDED(hr)) { do { // Release the previous event (if there is one). SAFE_RELEASE(pEvent); SAFE_RELEASE(pIndivStatus); // Check for an event. hr = pSecurity->GetEvent(MF_EVENT_FLAG_NO_WAIT, &pEvent); // If an event was not found, wait a second and try again. if (FAILED(hr)) { printf("."); Sleep(1000); continue; } // Got an event. Increment the event count. cEvents ++; // Get the event type. if (SUCCEEDED(hr)) { hr = pEvent->GetType(&EventType); } if (SUCCEEDED(hr)) { // Display a message depending on the event. switch (EventType) { case MEWMDRMIndividualizationProgress: fprintf(pLogFile, "%d.) Received a progress event.\n", cEvents); hr = pEvent->GetValue(&EventValue); if (SUCCEEDED(hr)) { if (EventValue.vt == VT_UNKNOWN) { // Get the extended status interface. hr = EventValue.punkVal->QueryInterface( IID_IWMDRMIndividualizationStatus, (void**)&pIndivStatus); // If the interface can't be gotten, make a note in the log and continue. if (FAILED(hr)) { fprintf(pLogFile, " Unable to get the extended status interface.\n"); PropVariantClear(&EventValue); break; } // Get the status structure from the newly acquired interface. hr = pIndivStatus->GetStatus(&IndivStatusStruct); // If the structure can't be gotten, make a note in the log and continue. if (FAILED(hr)) { fprintf(pLogFile, " Unable to get the status structure.\n"); PropVariantClear(&EventValue); break; } ////////// // // Log the individualization status (all items for now). // The HRESULT. if (IndivStatusStruct.hr == S_OK) { fprintf(pLogFile, " hr = S_OK\n"); } else { fprintf(pLogFile, " hr = 0x%08X\n", IndivStatusStruct.hr); } // Current status of the overall individualization process. switch (IndivStatusStruct.enIndiStatus) { case INDI_BEGIN: fprintf(pLogFile, " Indiv Status = INDI_BEGIN\n"); break; case INDI_DOWNLOAD: fprintf(pLogFile, " Indiv Status = INDI_DOWNLOAD\n"); break; case INDI_INSTALL: fprintf(pLogFile, " Indiv Status = INDI_INSTALL\n"); break; case INDI_SUCCEED: fprintf(pLogFile, " Indiv Status = INDI_SUCCEED\n"); break; case INDI_FAIL: fprintf(pLogFile, " Indiv Status = INDI_FAIL\n"); break; case INDI_CANCEL: fprintf(pLogFile, " Indiv Status = INDI_CANCEL\n"); break; case INDI_UNDEFINED: fprintf(pLogFile, " Indiv Status = INDI_UNDEFINED\n"); break; default: fprintf(pLogFile, " Indiv Status = Invalid member.\n"); } // Individualization response URL. fprintf(pLogFile, " URL = %s\n", IndivStatusStruct.pszIndiRespUrl); // Number of HTTP requests (round-trip). fprintf(pLogFile, " HTTP Requests = %d\n", IndivStatusStruct.dwHTTPRequest); // HTTP status. switch (IndivStatusStruct.enHTTPStatus) { case HTTP_NOTINITIATED: fprintf(pLogFile, " HTTP Status = HTTP_NOTINITIATED.\n"); break; case HTTP_CONNECTING: fprintf(pLogFile, " HTTP Status = HTTP_CONNECTING.\n"); break; case HTTP_REQUESTING: fprintf(pLogFile, " HTTP Status = HTTP_REQUESTING.\n"); break; case HTTP_RECEIVING: fprintf(pLogFile, " HTTP Status = HTTP_RECEIVING.\n"); break; case HTTP_COMPLETED: fprintf(pLogFile, " HTTP Status = HTTP_COMPLETED.\n"); break; default: fprintf(pLogFile, " HTTP Status = Invalid member.\n"); } // HTTP progress. fprintf(pLogFile, " HTTP Progress = %d of %d bytes downloaded.\n\n", IndivStatusStruct.dwHTTPReadProgress, IndivStatusStruct.dwHTTPReadTotal); // ////////// // Clear the event value for the next iteration. PropVariantClear(&EventValue); } else { // All progress events should have a value of type // VT_UNKNOWN. Note this in the log and continue. fprintf(pLogFile, " Unexpected Value Type.\n"); PropVariantClear(&EventValue); break; } } break; case MEWMDRMIndividualizationCompleted: fprintf(pLogFile, "%d. Individualization completed.\n", cEvents); break; default: fprintf(pLogFile, "Received event number %d.\n", EventType); } } // Give up CPU time to stay out of a busy loop. Sleep(0); } while (EventType != MEWMDRMIndividualizationCompleted); // Print a newline character to the console so that subsequent events // will display properly. printf("\n"); } SAFE_RELEASE(pEvent); SAFE_RELEASE(pCancelCookie); return hr; } /////////////////////////////////////////////////////////////////////////////// // // Function: TryOpenFile // Description: Attempts to open a file. This function is used not only to open // a file for output, but also as a way of validating a filename entered by // the user. // Parameters: FileName - Name of the flie to open. // ppFile - Address of a variable that will hold the address of // the newly created file. // Remarks: If the file cannot be created, this function resturns E_INVALIDARG. // /////////////////////////////////////////////////////////////////////////////// HRESULT TryOpenFile(wchar_t* FileName, FILE** ppFile) { HRESULT hr = S_OK; if (_wfopen_s(ppFile, FileName, L"w") != 0) { hr = E_INVALIDARG; } return hr; }