1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #if defined(XP_WIN)
8 #include <d3d9.h> // needed to prevent re-definition of enums
9 #include <stdio.h>
10 #include <string>
11 #include <vector>
12 #include <windows.h>
13 
14 #include "opmapi.h"
15 #endif
16 
17 namespace mozilla {
18 namespace gmptest {
19 
20 #if defined(XP_WIN)
21 typedef HRESULT(STDAPICALLTYPE * OPMGetVideoOutputsFromHMONITORProc)
22           (HMONITOR, OPM_VIDEO_OUTPUT_SEMANTICS, ULONG*, IOPMVideoOutput***);
23 
24 static OPMGetVideoOutputsFromHMONITORProc sOPMGetVideoOutputsFromHMONITORProc = nullptr;
25 
EnumDisplayMonitorsCallback(HMONITOR hMonitor,HDC hdc,LPRECT lprc,LPARAM pData)26 static BOOL CALLBACK EnumDisplayMonitorsCallback(HMONITOR hMonitor, HDC hdc,
27                                                  LPRECT lprc, LPARAM pData)
28 {
29   std::vector<std::string>* failureMsgs = (std::vector<std::string>*)pData;
30 
31   MONITORINFOEXA miex;
32   ZeroMemory(&miex, sizeof(miex));
33   miex.cbSize = sizeof(miex);
34   if (!GetMonitorInfoA(hMonitor, &miex)) {
35     failureMsgs->push_back("FAIL GetMonitorInfoA call failed");
36   }
37 
38   ULONG numVideoOutputs = 0;
39   IOPMVideoOutput** opmVideoOutputArray = nullptr;
40   HRESULT hr = sOPMGetVideoOutputsFromHMONITORProc(hMonitor,
41                                                    OPM_VOS_OPM_SEMANTICS,
42                                                    &numVideoOutputs,
43                                                    &opmVideoOutputArray);
44   if (S_OK != hr) {
45     if (0x8007001f != hr && 0x80070032 != hr && 0xc02625e5 != hr) {
46       char msg[100];
47       sprintf(msg, "FAIL OPMGetVideoOutputsFromHMONITOR call failed: HRESULT=0x%08x", hr);
48       failureMsgs->push_back(msg);
49     }
50     return true;
51   }
52 
53   DISPLAY_DEVICEA dd;
54   ZeroMemory(&dd, sizeof(dd));
55   dd.cb = sizeof(dd);
56   if (!EnumDisplayDevicesA(miex.szDevice, 0, &dd, 1)) {
57     failureMsgs->push_back("FAIL EnumDisplayDevicesA call failed");
58   }
59 
60   for (ULONG i = 0; i < numVideoOutputs; ++i) {
61     OPM_RANDOM_NUMBER opmRandomNumber;
62     BYTE* certificate = nullptr;
63     ULONG certificateLength = 0;
64     hr = opmVideoOutputArray[i]->StartInitialization(&opmRandomNumber,
65                                                      &certificate,
66                                                      &certificateLength);
67     if (S_OK != hr) {
68       char msg[100];
69       sprintf(msg, "FAIL StartInitialization call failed: HRESULT=0x%08x", hr);
70       failureMsgs->push_back(msg);
71     }
72 
73     if (certificate) {
74       CoTaskMemFree(certificate);
75     }
76 
77     opmVideoOutputArray[i]->Release();
78   }
79 
80   if (opmVideoOutputArray) {
81     CoTaskMemFree(opmVideoOutputArray);
82   }
83 
84   return true;
85 }
86 #endif
87 
88 static void
RunOutputProtectionAPITests()89 RunOutputProtectionAPITests()
90 {
91 #if defined(XP_WIN)
92   // Get hold of OPMGetVideoOutputsFromHMONITOR function.
93   HMODULE hDvax2DLL = GetModuleHandleW(L"dxva2.dll");
94   if (!hDvax2DLL) {
95     FakeDecryptor::Message("FAIL GetModuleHandleW call failed for dxva2.dll");
96     return;
97   }
98 
99   sOPMGetVideoOutputsFromHMONITORProc = (OPMGetVideoOutputsFromHMONITORProc)
100     GetProcAddress(hDvax2DLL, "OPMGetVideoOutputsFromHMONITOR");
101   if (!sOPMGetVideoOutputsFromHMONITORProc) {
102     FakeDecryptor::Message("FAIL GetProcAddress call failed for OPMGetVideoOutputsFromHMONITOR");
103     return;
104   }
105 
106   // Test EnumDisplayMonitors.
107   // Other APIs are tested in the callback function.
108   std::vector<std::string> failureMsgs;
109   if (!EnumDisplayMonitors(NULL, NULL, EnumDisplayMonitorsCallback,
110                            (LPARAM) &failureMsgs)) {
111     FakeDecryptor::Message("FAIL EnumDisplayMonitors call failed");
112   }
113 
114   // Report any failures in the callback function.
115   for (size_t i = 0; i < failureMsgs.size(); i++) {
116     FakeDecryptor::Message(failureMsgs[i]);
117   }
118 #endif
119 }
120 
121 static void
TestOuputProtectionAPIs()122 TestOuputProtectionAPIs()
123 {
124   RunOutputProtectionAPITests();
125   FakeDecryptor::Message("OP tests completed");
126   return;
127 }
128 
129 } // namespace gmptest
130 } // namespace mozilla
131