Version 1.24
[libovr-mingw-w64-jolly.git] / Shim / OVR_CAPIShim.c
1 /************************************************************************************\r
2 \r
3 Filename    :   OVR_CAPIShim.c\r
4 Content     :   CAPI DLL user library\r
5 Created     :   November 20, 2014\r
6 Copyright   :   Copyright 2014-2016 Oculus VR, LLC All Rights reserved.\r
7 \r
8 Licensed under the Oculus VR Rift SDK License Version 3.3 (the "License");\r
9 you may not use the Oculus VR Rift SDK except in compliance with the License,\r
10 which is provided at the time of installation or download, or which\r
11 otherwise accompanies this software in either electronic or hard copy form.\r
12 \r
13 You may obtain a copy of the License at\r
14 \r
15 http://www.oculusvr.com/licenses/LICENSE-3.3\r
16 \r
17 Unless required by applicable law or agreed to in writing, the Oculus VR SDK\r
18 distributed under the License is distributed on an "AS IS" BASIS,\r
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
20 See the License for the specific language governing permissions and\r
21 limitations under the License.\r
22 \r
23 ************************************************************************************/\r
24 \r
25 #include "OVR_CAPI.h"\r
26 #include "OVR_Version.h"\r
27 #include "OVR_ErrorCode.h"\r
28 #include "OVR_CAPI_Prototypes.h"\r
29 #include <stdio.h>\r
30 #include <stdlib.h>\r
31 #include <stddef.h>\r
32 #include <stdint.h>\r
33 #include <string.h>\r
34 #include <ctype.h>\r
35 #include <assert.h>\r
36 \r
37 #if defined(_WIN32)\r
38 #if defined(_MSC_VER)\r
39 #pragma warning(push, 0)\r
40 #endif\r
41 #include <windows.h>\r
42 #if defined(_MSC_VER)\r
43 #pragma warning(pop)\r
44 #endif\r
45 \r
46 #include "../Include/OVR_CAPI_D3D.h"\r
47 #else\r
48 #if defined(__APPLE__)\r
49 #include <mach-o/dyld.h>\r
50 #include <sys/syslimits.h>\r
51 #include <libgen.h>\r
52 #include <pwd.h>\r
53 #include <unistd.h>\r
54 #endif\r
55 #include <dlfcn.h>\r
56 #include <sys/stat.h>\r
57 #include <unistd.h>\r
58 #endif\r
59 #include "../Include/OVR_CAPI_GL.h"\r
60 #include "../Include/OVR_CAPI_Vk.h"\r
61 \r
62 \r
63 #if defined(_MSC_VER)\r
64 #pragma warning(push)\r
65 #pragma warning(disable : 4996) // 'getenv': This function or variable may be unsafe.\r
66 #endif\r
67 \r
68 // clang-format off\r
69 static const uint8_t OculusSDKUniqueIdentifier[] = {\r
70   0x9E, 0xB2, 0x0B, 0x1A, 0xB7, 0x97, 0x09, 0x20, 0xE0, 0xFB, 0x83, 0xED, 0xF8, 0x33, 0x5A, 0xEB,\r
71   0x80, 0x4D, 0x8E, 0x92, 0x20, 0x69, 0x13, 0x56, 0xB4, 0xBB, 0xC4, 0x85, 0xA7, 0x9E, 0xA4, 0xFE,\r
72   OVR_MAJOR_VERSION, OVR_MINOR_VERSION, OVR_PATCH_VERSION\r
73 };\r
74 \r
75 // clang-format on\r
76 \r
77 static const uint8_t OculusSDKUniqueIdentifierXORResult = 0xcb;\r
78 \r
79 // -----------------------------------------------------------------------------------\r
80 // ***** OVR_ENABLE_DEVELOPER_SEARCH\r
81 //\r
82 // If defined then our shared library loading code searches for developer build\r
83 // directories.\r
84 //\r
85 #if !defined(OVR_ENABLE_DEVELOPER_SEARCH)\r
86 #endif\r
87 \r
88 // -----------------------------------------------------------------------------------\r
89 // ***** OVR_BUILD_DEBUG\r
90 //\r
91 // Defines OVR_BUILD_DEBUG when the compiler default debug preprocessor is set.\r
92 //\r
93 // If you want to control the behavior of these flags, then explicitly define\r
94 // either -DOVR_BUILD_RELEASE or -DOVR_BUILD_DEBUG in the compiler arguments.\r
95 \r
96 #if !defined(OVR_BUILD_DEBUG) && !defined(OVR_BUILD_RELEASE)\r
97 #if defined(_MSC_VER)\r
98 #if defined(_DEBUG)\r
99 #define OVR_BUILD_DEBUG\r
100 #endif\r
101 #else\r
102 #if defined(DEBUG)\r
103 #define OVR_BUILD_DEBUG\r
104 #endif\r
105 #endif\r
106 #endif\r
107 \r
108 //-----------------------------------------------------------------------------------\r
109 // ***** FilePathCharType, ModuleHandleType, ModuleFunctionType\r
110 //\r
111 #if defined(_WIN32) // We need to use wchar_t on Microsoft platforms, as that's the native file\r
112 // system character type.\r
113 #define FilePathCharType \\r
114   wchar_t // #define instead of typedef because debuggers (VC++, XCode) don't recognize typedef'd\r
115 // types as a string type.\r
116 typedef HMODULE ModuleHandleType;\r
117 typedef FARPROC ModuleFunctionType;\r
118 #else\r
119 #define FilePathCharType char\r
120 typedef void* ModuleHandleType;\r
121 typedef void* ModuleFunctionType;\r
122 #endif\r
123 \r
124 #define ModuleHandleTypeNull ((ModuleHandleType)NULL)\r
125 #define ModuleFunctionTypeNull ((ModuleFunctionType)NULL)\r
126 \r
127 //-----------------------------------------------------------------------------------\r
128 // ***** OVR_MAX_PATH\r
129 //\r
130 #if !defined(OVR_MAX_PATH)\r
131 #if defined(_WIN32)\r
132 #define OVR_MAX_PATH _MAX_PATH\r
133 #elif defined(__APPLE__)\r
134 #define OVR_MAX_PATH PATH_MAX\r
135 #else\r
136 #define OVR_MAX_PATH 1024\r
137 #endif\r
138 #endif\r
139 \r
140 #if !defined(OVR_DLSYM)\r
141 #if defined(_WIN32)\r
142 #define OVR_DLSYM(dlImage, name) GetProcAddress(dlImage, name)\r
143 #else\r
144 #define OVR_DLSYM(dlImage, name) dlsym(dlImage, name)\r
145 #endif\r
146 #endif\r
147 \r
148 static size_t OVR_strlcpy(char* dest, const char* src, size_t destsize) {\r
149   const char* s = src;\r
150   size_t n = destsize;\r
151 \r
152   if (n && --n) {\r
153     do {\r
154       if ((*dest++ = *s++) == 0)\r
155         break;\r
156     } while (--n);\r
157   }\r
158 \r
159   if (!n) {\r
160     if (destsize)\r
161       *dest = 0;\r
162     while (*s++) {\r
163     }\r
164   }\r
165 \r
166   return (size_t)((s - src) - 1);\r
167 }\r
168 \r
169 static size_t OVR_strlcat(char* dest, const char* src, size_t destsize) {\r
170   const size_t d = destsize ? strlen(dest) : 0;\r
171   const size_t s = strlen(src);\r
172   const size_t t = s + d;\r
173 \r
174   if (t < destsize)\r
175     memcpy(dest + d, src, (s + 1) * sizeof(*src));\r
176   else {\r
177     if (destsize) {\r
178       memcpy(dest + d, src, ((destsize - d) - 1) * sizeof(*src));\r
179       dest[destsize - 1] = 0;\r
180     }\r
181   }\r
182 \r
183   return t;\r
184 }\r
185 \r
186 #if defined(__APPLE__)\r
187 static ovrBool\r
188 OVR_strend(const char* pStr, const char* pFind, size_t strLength, size_t findLength) {\r
189   if (strLength == (size_t)-1)\r
190     strLength = strlen(pStr);\r
191   if (findLength == (size_t)-1)\r
192     findLength = strlen(pFind);\r
193   if (strLength >= findLength)\r
194     return (strcmp(pStr + strLength - findLength, pFind) == 0);\r
195   return ovrFalse;\r
196 }\r
197 \r
198 static ovrBool OVR_isBundleFolder(const char* filePath) {\r
199   static const char* extensionArray[] = {".app", ".bundle", ".framework", ".plugin", ".kext"};\r
200   size_t i;\r
201 \r
202   for (i = 0; i < sizeof(extensionArray) / sizeof(extensionArray[0]); i++) {\r
203     if (OVR_strend(filePath, extensionArray[i], (size_t)-1, (size_t)-1))\r
204       return ovrTrue;\r
205   }\r
206 \r
207   return ovrFalse;\r
208 }\r
209 #endif\r
210 \r
211 #if defined(OVR_ENABLE_DEVELOPER_SEARCH)\r
212 \r
213 // Returns true if the path begins with the given prefix.\r
214 // Doesn't support non-ASCII paths, else the return value may be incorrect.\r
215 static int OVR_PathStartsWith(const FilePathCharType* path, const char* prefix) {\r
216   while (*prefix) {\r
217     if (tolower((unsigned char)*path++) != tolower((unsigned char)*prefix++))\r
218       return ovrFalse;\r
219   }\r
220 \r
221   return ovrTrue;\r
222 }\r
223 \r
224 #endif\r
225 \r
226 static ovrBool OVR_GetCurrentWorkingDirectory(\r
227     FilePathCharType* directoryPath,\r
228     size_t directoryPathCapacity) {\r
229 #if defined(_WIN32)\r
230   DWORD dwSize = GetCurrentDirectoryW((DWORD)directoryPathCapacity, directoryPath);\r
231 \r
232   if ((dwSize > 0) &&\r
233       (directoryPathCapacity > 1)) // Test > 1 so we have room to possibly append a \ char.\r
234   {\r
235     size_t length = wcslen(directoryPath);\r
236 \r
237     if ((length == 0) ||\r
238         ((directoryPath[length - 1] != L'\\') && (directoryPath[length - 1] != L'/'))) {\r
239       directoryPath[length++] = L'\\';\r
240       directoryPath[length] = L'\0';\r
241     }\r
242 \r
243     return ovrTrue;\r
244   }\r
245 \r
246 #else\r
247   char* cwd = getcwd(directoryPath, directoryPathCapacity);\r
248 \r
249   if (cwd && directoryPath[0] &&\r
250       (directoryPathCapacity > 1)) // Test > 1 so we have room to possibly append a / char.\r
251   {\r
252     size_t length = strlen(directoryPath);\r
253 \r
254     if ((length == 0) || (directoryPath[length - 1] != '/')) {\r
255       directoryPath[length++] = '/';\r
256       directoryPath[length] = '\0';\r
257     }\r
258 \r
259     return ovrTrue;\r
260   }\r
261 #endif\r
262 \r
263   if (directoryPathCapacity > 0)\r
264     directoryPath[0] = '\0';\r
265 \r
266   return ovrFalse;\r
267 }\r
268 \r
269 // The appContainer argument is specific currently to only Macintosh. If true and the application is\r
270 // a .app bundle then it returns the\r
271 // location of the bundle and not the path to the executable within the bundle. Else return the path\r
272 // to the executable binary itself.\r
273 // The moduleHandle refers to the relevant dynamic (a.k.a. shared) library. The main executable is\r
274 // the main module, and each of the shared\r
275 // libraries is a module. This way you can specify that you want to know the directory of the given\r
276 // shared library, which may be different\r
277 // from the main executable. If the moduleHandle is NULL then the current application module is\r
278 // used.\r
279 static ovrBool OVR_GetCurrentApplicationDirectory(\r
280     FilePathCharType* directoryPath,\r
281     size_t directoryPathCapacity,\r
282     ovrBool appContainer,\r
283     ModuleHandleType moduleHandle) {\r
284 #if defined(_WIN32)\r
285   DWORD length = GetModuleFileNameW(moduleHandle, directoryPath, (DWORD)directoryPathCapacity);\r
286   DWORD pos;\r
287 \r
288   if ((length != 0) &&\r
289       (length <\r
290        (DWORD)directoryPathCapacity)) // If there wasn't an error and there was enough capacity...\r
291   {\r
292     for (pos = length; (pos > 0) && (directoryPath[pos] != '\\') && (directoryPath[pos] != '/');\r
293          --pos) {\r
294       if ((directoryPath[pos - 1] != '\\') && (directoryPath[pos - 1] != '/'))\r
295         directoryPath[pos - 1] = 0;\r
296     }\r
297 \r
298     return ovrTrue;\r
299   }\r
300 \r
301   (void)appContainer; // Not used on this platform.\r
302 \r
303 #elif defined(__APPLE__)\r
304   uint32_t directoryPathCapacity32 = (uint32_t)directoryPathCapacity;\r
305   int result = _NSGetExecutablePath(directoryPath, &directoryPathCapacity32);\r
306 \r
307   if (result == 0) // If success...\r
308   {\r
309     char realPath[OVR_MAX_PATH];\r
310 \r
311     if (realpath(directoryPath, realPath)) // realpath returns the canonicalized absolute file path.\r
312     {\r
313       size_t length = 0;\r
314 \r
315       if (appContainer) // If the caller wants the path to the containing bundle...\r
316       {\r
317         char containerPath[OVR_MAX_PATH];\r
318         ovrBool pathIsContainer;\r
319 \r
320         OVR_strlcpy(containerPath, realPath, sizeof(containerPath));\r
321         pathIsContainer = OVR_isBundleFolder(containerPath);\r
322 \r
323         while (!pathIsContainer && strncmp(containerPath, ".", OVR_MAX_PATH) &&\r
324                strncmp(containerPath, "/", OVR_MAX_PATH)) // While the container we're looking for\r
325         // is not found and while the path doesn't\r
326         // start with a . or /\r
327         {\r
328           OVR_strlcpy(containerPath, dirname(containerPath), sizeof(containerPath));\r
329           pathIsContainer = OVR_isBundleFolder(containerPath);\r
330         }\r
331 \r
332         if (pathIsContainer)\r
333           length = OVR_strlcpy(directoryPath, containerPath, directoryPathCapacity);\r
334       }\r
335 \r
336       if (length == 0) // If not set above in the appContainer block...\r
337         length = OVR_strlcpy(directoryPath, realPath, directoryPathCapacity);\r
338 \r
339       while (length-- && (directoryPath[length] != '/'))\r
340         directoryPath[length] =\r
341             '\0'; // Strip the file name from the file path, leaving a trailing / char.\r
342 \r
343       return ovrTrue;\r
344     }\r
345   }\r
346 \r
347   (void)moduleHandle; // Not used on this platform.\r
348 \r
349 #else\r
350   ssize_t length = readlink("/proc/self/exe", directoryPath, directoryPathCapacity);\r
351   ssize_t pos;\r
352 \r
353   if (length > 0) {\r
354     for (pos = length; (pos > 0) && (directoryPath[pos] != '/'); --pos) {\r
355       if (directoryPath[pos - 1] != '/')\r
356         directoryPath[pos - 1] = '\0';\r
357     }\r
358 \r
359     return ovrTrue;\r
360   }\r
361 \r
362   (void)appContainer; // Not used on this platform.\r
363   (void)moduleHandle;\r
364 #endif\r
365 \r
366   if (directoryPathCapacity > 0)\r
367     directoryPath[0] = '\0';\r
368 \r
369   return ovrFalse;\r
370 }\r
371 \r
372 #if defined(_WIN32) || defined(OVR_ENABLE_DEVELOPER_SEARCH) // Used only in these cases\r
373 \r
374 // Get the file path to the current module's (DLL or EXE) directory within the current process.\r
375 // Will be different from the process module handle if the current module is a DLL and is in a\r
376 // different directory than the EXE module.\r
377 // If successful then directoryPath will be valid and ovrTrue is returned, else directoryPath will\r
378 // be empty and ovrFalse is returned.\r
379 static ovrBool OVR_GetCurrentModuleDirectory(\r
380     FilePathCharType* directoryPath,\r
381     size_t directoryPathCapacity,\r
382     ovrBool appContainer) {\r
383 #if defined(_WIN32)\r
384   HMODULE hModule;\r
385   BOOL result = GetModuleHandleExW(\r
386       GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,\r
387       (LPCWSTR)(uintptr_t)OVR_GetCurrentModuleDirectory,\r
388       &hModule);\r
389   if (result)\r
390     OVR_GetCurrentApplicationDirectory(directoryPath, directoryPathCapacity, ovrTrue, hModule);\r
391   else\r
392     directoryPath[0] = 0;\r
393 \r
394   (void)appContainer;\r
395 \r
396   return directoryPath[0] ? ovrTrue : ovrFalse;\r
397 #else\r
398   return OVR_GetCurrentApplicationDirectory(\r
399       directoryPath, directoryPathCapacity, appContainer, NULL);\r
400 #endif\r
401 }\r
402 \r
403 #endif\r
404 \r
405 #if defined(_WIN32)\r
406 \r
407 #ifdef _MSC_VER\r
408 #pragma warning(push)\r
409 #pragma warning(disable : 4201)\r
410 #endif\r
411 \r
412 #include <softpub.h>\r
413 #include <wincrypt.h>\r
414 \r
415 #ifdef _MSC_VER\r
416 #pragma warning(pop)\r
417 #endif\r
418 \r
419 // Expected certificates:\r
420 #define ExpectedNumCertificates 3\r
421 typedef struct CertificateEntry_t {\r
422   const wchar_t* Issuer;\r
423   const wchar_t* Subject;\r
424 } CertificateEntry;\r
425 \r
426 CertificateEntry NewCertificateChain[ExpectedNumCertificates] = {\r
427     {L"DigiCert SHA2 Assured ID Code Signing CA", L"Oculus VR, LLC"},\r
428     {L"DigiCert Assured ID Root CA", L"DigiCert SHA2 Assured ID Code Signing CA"},\r
429     {L"DigiCert Assured ID Root CA", L"DigiCert Assured ID Root CA"},\r
430 };\r
431 \r
432 #define CertificateChainCount 1\r
433 CertificateEntry* AllowedCertificateChains[CertificateChainCount] = {NewCertificateChain};\r
434 \r
435 typedef WINCRYPT32API DWORD(WINAPI* PtrCertGetNameStringW)(\r
436     PCCERT_CONTEXT pCertContext,\r
437     DWORD dwType,\r
438     DWORD dwFlags,\r
439     void* pvTypePara,\r
440     LPWSTR pszNameString,\r
441     DWORD cchNameString);\r
442 typedef LONG(WINAPI* PtrWinVerifyTrust)(HWND hwnd, GUID* pgActionID, LPVOID pWVTData);\r
443 typedef CRYPT_PROVIDER_DATA*(WINAPI* PtrWTHelperProvDataFromStateData)(HANDLE hStateData);\r
444 typedef CRYPT_PROVIDER_SGNR*(WINAPI* PtrWTHelperGetProvSignerFromChain)(\r
445     CRYPT_PROVIDER_DATA* pProvData,\r
446     DWORD idxSigner,\r
447     BOOL fCounterSigner,\r
448     DWORD idxCounterSigner);\r
449 \r
450 PtrCertGetNameStringW m_PtrCertGetNameStringW = 0;\r
451 PtrWinVerifyTrust m_PtrWinVerifyTrust = 0;\r
452 PtrWTHelperProvDataFromStateData m_PtrWTHelperProvDataFromStateData = 0;\r
453 PtrWTHelperGetProvSignerFromChain m_PtrWTHelperGetProvSignerFromChain = 0;\r
454 \r
455 typedef enum ValidateCertificateContentsResult_ {\r
456   VCCRSuccess = 0,\r
457   VCCRErrorCertCount = -1,\r
458   VCCRErrorTrust = -2,\r
459   VCCRErrorValidation = -3\r
460 } ValidateCertificateContentsResult;\r
461 \r
462 static ValidateCertificateContentsResult ValidateCertificateContents(\r
463     CertificateEntry* chain,\r
464     CRYPT_PROVIDER_SGNR* cps) {\r
465   int certIndex;\r
466 \r
467   if (!cps || !cps->pasCertChain || cps->csCertChain != ExpectedNumCertificates) {\r
468     return VCCRErrorCertCount;\r
469   }\r
470 \r
471   for (certIndex = 0; certIndex < ExpectedNumCertificates; ++certIndex) {\r
472     CRYPT_PROVIDER_CERT* pCertData = &cps->pasCertChain[certIndex];\r
473     wchar_t subjectStr[400] = {0};\r
474     wchar_t issuerStr[400] = {0};\r
475 \r
476     if ((pCertData->fSelfSigned && !pCertData->fTrustedRoot) || pCertData->fTestCert) {\r
477       return VCCRErrorTrust;\r
478     }\r
479 \r
480     m_PtrCertGetNameStringW(\r
481         pCertData->pCert,\r
482         CERT_NAME_ATTR_TYPE,\r
483         0,\r
484         szOID_COMMON_NAME,\r
485         subjectStr,\r
486         ARRAYSIZE(subjectStr));\r
487 \r
488     m_PtrCertGetNameStringW(\r
489         pCertData->pCert,\r
490         CERT_NAME_ATTR_TYPE,\r
491         CERT_NAME_ISSUER_FLAG,\r
492         0,\r
493         issuerStr,\r
494         ARRAYSIZE(issuerStr));\r
495 \r
496     if (wcscmp(subjectStr, chain[certIndex].Subject) != 0 ||\r
497         wcscmp(issuerStr, chain[certIndex].Issuer) != 0) {\r
498       return VCCRErrorValidation;\r
499     }\r
500   }\r
501 \r
502   return VCCRSuccess;\r
503 }\r
504 \r
505 #define OVR_SIGNING_CONVERT_PTR(ftype, fptr, procaddr) \\r
506   {                                                    \\r
507     union {                                            \\r
508       ftype p1;                                        \\r
509       ModuleFunctionType p2;                           \\r
510     } u;                                               \\r
511     u.p2 = procaddr;                                   \\r
512     fptr = u.p1;                                       \\r
513   }\r
514 \r
515 static BOOL OVR_Win32_SignCheck(FilePathCharType* fullPath, HANDLE hFile) {\r
516   WINTRUST_FILE_INFO fileData;\r
517   WINTRUST_DATA wintrustData;\r
518   GUID actionGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;\r
519   LONG resultStatus;\r
520   BOOL verified = FALSE;\r
521   HMODULE libWinTrust = LoadLibraryW(L"wintrust");\r
522   HMODULE libCrypt32 = LoadLibraryW(L"crypt32");\r
523   if (libWinTrust == NULL || libCrypt32 == NULL) {\r
524     return FALSE;\r
525   }\r
526 \r
527   OVR_SIGNING_CONVERT_PTR(\r
528       PtrCertGetNameStringW,\r
529       m_PtrCertGetNameStringW,\r
530       GetProcAddress(libCrypt32, "CertGetNameStringW"));\r
531   OVR_SIGNING_CONVERT_PTR(\r
532       PtrWinVerifyTrust, m_PtrWinVerifyTrust, GetProcAddress(libWinTrust, "WinVerifyTrust"));\r
533   OVR_SIGNING_CONVERT_PTR(\r
534       PtrWTHelperProvDataFromStateData,\r
535       m_PtrWTHelperProvDataFromStateData,\r
536       GetProcAddress(libWinTrust, "WTHelperProvDataFromStateData"));\r
537   OVR_SIGNING_CONVERT_PTR(\r
538       PtrWTHelperGetProvSignerFromChain,\r
539       m_PtrWTHelperGetProvSignerFromChain,\r
540       GetProcAddress(libWinTrust, "WTHelperGetProvSignerFromChain"));\r
541 \r
542   if (m_PtrCertGetNameStringW == NULL || m_PtrWinVerifyTrust == NULL ||\r
543       m_PtrWTHelperProvDataFromStateData == NULL || m_PtrWTHelperGetProvSignerFromChain == NULL) {\r
544     return FALSE;\r
545   }\r
546 \r
547   if (hFile == INVALID_HANDLE_VALUE || fullPath == NULL) {\r
548     return FALSE;\r
549   }\r
550 \r
551   ZeroMemory(&fileData, sizeof(fileData));\r
552   fileData.cbStruct = sizeof(fileData);\r
553   fileData.pcwszFilePath = fullPath;\r
554   fileData.hFile = hFile;\r
555 \r
556   ZeroMemory(&wintrustData, sizeof(wintrustData));\r
557   wintrustData.cbStruct = sizeof(wintrustData);\r
558   wintrustData.pFile = &fileData;\r
559   wintrustData.dwUnionChoice = WTD_CHOICE_FILE; // Specify WINTRUST_FILE_INFO.\r
560   wintrustData.dwUIChoice = WTD_UI_NONE; // Do not display any UI.\r
561   wintrustData.dwUIContext = WTD_UICONTEXT_EXECUTE; // Hint that this is about app execution.\r
562   wintrustData.fdwRevocationChecks = WTD_REVOKE_NONE;\r
563   wintrustData.dwProvFlags = WTD_REVOCATION_CHECK_NONE;\r
564   wintrustData.dwStateAction = WTD_STATEACTION_VERIFY;\r
565   wintrustData.hWVTStateData = 0;\r
566 \r
567   resultStatus = m_PtrWinVerifyTrust(\r
568       (HWND)INVALID_HANDLE_VALUE, // Do not display any UI.\r
569       &actionGUID, // V2 verification\r
570       &wintrustData);\r
571 \r
572   if (resultStatus == ERROR_SUCCESS && wintrustData.hWVTStateData != 0 &&\r
573       wintrustData.hWVTStateData != INVALID_HANDLE_VALUE) {\r
574     CRYPT_PROVIDER_DATA* cpd = m_PtrWTHelperProvDataFromStateData(wintrustData.hWVTStateData);\r
575     if (cpd && cpd->csSigners == 1) {\r
576       CRYPT_PROVIDER_SGNR* cps = m_PtrWTHelperGetProvSignerFromChain(cpd, 0, FALSE, 0);\r
577       int chainIndex;\r
578       for (chainIndex = 0; chainIndex < CertificateChainCount; ++chainIndex) {\r
579         CertificateEntry* chain = AllowedCertificateChains[chainIndex];\r
580         if (VCCRSuccess == ValidateCertificateContents(chain, cps)) {\r
581           verified = TRUE;\r
582           break;\r
583         }\r
584       }\r
585     }\r
586   }\r
587 \r
588   wintrustData.dwStateAction = WTD_STATEACTION_CLOSE;\r
589 \r
590   m_PtrWinVerifyTrust(\r
591       (HWND)INVALID_HANDLE_VALUE, // Do not display any UI.\r
592       &actionGUID, // V2 verification\r
593       &wintrustData);\r
594 \r
595   return verified;\r
596 }\r
597 \r
598 #endif // #if defined(_WIN32)\r
599 \r
600 static ModuleHandleType OVR_OpenLibrary(const FilePathCharType* libraryPath, ovrResult* result) {\r
601 #if defined(_WIN32)\r
602   DWORD fullPathNameLen = 0;\r
603   FilePathCharType fullPath[MAX_PATH] = {0};\r
604   HANDLE hFilePinned = INVALID_HANDLE_VALUE;\r
605   ModuleHandleType hModule = 0;\r
606 \r
607   *result = ovrSuccess;\r
608 \r
609   fullPathNameLen = GetFullPathNameW(libraryPath, MAX_PATH, fullPath, 0);\r
610   if (fullPathNameLen <= 0 || fullPathNameLen >= MAX_PATH) {\r
611     *result = ovrError_LibPath;\r
612     return NULL;\r
613   }\r
614 \r
615   hFilePinned = CreateFileW(\r
616       fullPath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, 0);\r
617 \r
618   if (hFilePinned == INVALID_HANDLE_VALUE) {\r
619     *result = ovrError_LibPath;\r
620     return NULL;\r
621   }\r
622 \r
623   if (!OVR_Win32_SignCheck(fullPath, hFilePinned)) {\r
624     *result = ovrError_LibSignCheck;\r
625     CloseHandle(hFilePinned);\r
626     return NULL;\r
627   }\r
628 \r
629   hModule = LoadLibraryW(fullPath);\r
630 \r
631   CloseHandle(hFilePinned);\r
632 \r
633   if (hModule == NULL) {\r
634     *result = ovrError_LibLoad;\r
635   }\r
636 \r
637   return hModule;\r
638 #else\r
639   *result = ovrSuccess;\r
640 \r
641   // Don't bother trying to dlopen() a file that is not even there.\r
642   if (access(libraryPath, X_OK | R_OK) != 0) {\r
643     *result = ovrError_LibPath;\r
644     return NULL;\r
645   }\r
646 \r
647   dlerror(); // Clear any previous dlopen() errors\r
648 \r
649   // Use RTLD_NOW because we don't want unexpected stalls at runtime, and the library isn't very\r
650   // large.\r
651   // Use RTLD_LOCAL to avoid unilaterally exporting resolved symbols to the rest of this process.\r
652   void* lib = dlopen(libraryPath, RTLD_NOW | RTLD_LOCAL);\r
653 \r
654   if (!lib) {\r
655     fprintf(stderr, "ERROR: Can't load '%s':\n%s\n", libraryPath, dlerror());\r
656   }\r
657 \r
658   return lib;\r
659 #endif\r
660 }\r
661 \r
662 static void OVR_CloseLibrary(ModuleHandleType hLibrary) {\r
663   if (hLibrary) {\r
664 #if defined(_WIN32)\r
665     // We may need to consider what to do in the case that the library is in an exception state.\r
666     // In a Windows C++ DLL, all global objects (including static members of classes) will be\r
667     // constructed just\r
668     // before the calling of the DllMain with DLL_PROCESS_ATTACH and they will be destroyed just\r
669     // after\r
670     // the call of the DllMain with DLL_PROCESS_DETACH. We may need to intercept DLL_PROCESS_DETACH\r
671     // and\r
672     // have special handling for the case that the DLL is broken.\r
673     FreeLibrary(hLibrary);\r
674 #else\r
675     dlclose(hLibrary);\r
676 #endif\r
677   }\r
678 }\r
679 \r
680 // Returns a valid ModuleHandleType (e.g. Windows HMODULE) or returns ModuleHandleTypeNull (e.g.\r
681 // NULL).\r
682 // The caller is required to eventually call OVR_CloseLibrary on a valid return handle.\r
683 //\r
684 static ModuleHandleType OVR_FindLibraryPath(\r
685     int requestedProductVersion,\r
686     int requestedMajorVersion,\r
687     FilePathCharType* libraryPath,\r
688     size_t libraryPathCapacity,\r
689     ovrResult* result) {\r
690   ModuleHandleType moduleHandle;\r
691   int printfResult;\r
692   FilePathCharType developerDir[OVR_MAX_PATH] = {'\0'};\r
693 \r
694 #if defined(_MSC_VER)\r
695 #if defined(_WIN64)\r
696   const char* pBitDepth = "64";\r
697 #else\r
698   const char* pBitDepth = "32";\r
699 #endif\r
700 #elif defined(__APPLE__)\r
701 // For Apple platforms we are using a Universal Binary LibOVRRT dylib which has both 32 and 64 in\r
702 // it.\r
703 #else // Other Unix.\r
704 #if defined(__x86_64__)\r
705   const char* pBitDepth = "64";\r
706 #else\r
707   const char* pBitDepth = "32";\r
708 #endif\r
709 #endif\r
710 \r
711   (void)requestedProductVersion;\r
712 \r
713   *result = ovrError_LibLoad;\r
714   moduleHandle = ModuleHandleTypeNull;\r
715   if (libraryPathCapacity)\r
716     libraryPath[0] = '\0';\r
717 \r
718 // Note: OVR_ENABLE_DEVELOPER_SEARCH is deprecated in favor of the simpler LIBOVR_DLL_DIR, as the\r
719 // edge\r
720 // case uses of the former created some complications that may be best solved by simply using a\r
721 // LIBOVR_DLL_DIR\r
722 // environment variable which the user can set in their debugger or system environment variables.\r
723 #if (defined(_MSC_VER) || defined(_WIN32)) && !defined(OVR_FILE_PATH_SEPARATOR)\r
724 #define OVR_FILE_PATH_SEPARATOR "\\"\r
725 #else\r
726 #define OVR_FILE_PATH_SEPARATOR "/"\r
727 #endif\r
728 \r
729   {\r
730     const char* pLibOvrDllDir =\r
731         getenv("LIBOVR_DLL_DIR"); // Example value: /dev/OculusSDK/Main/LibOVR/Mac/Debug/\r
732 \r
733     if (pLibOvrDllDir) {\r
734       char developerDir8[OVR_MAX_PATH];\r
735       size_t length = OVR_strlcpy(\r
736           developerDir8,\r
737           pLibOvrDllDir,\r
738           sizeof(developerDir8)); // If missing a trailing path separator then append one.\r
739 \r
740       if ((length > 0) && (length < sizeof(developerDir8)) &&\r
741           (developerDir8[length - 1] != OVR_FILE_PATH_SEPARATOR[0])) {\r
742         length = OVR_strlcat(developerDir8, OVR_FILE_PATH_SEPARATOR, sizeof(developerDir8));\r
743 \r
744         if (length < sizeof(developerDir8)) {\r
745 #if defined(_WIN32)\r
746           size_t i;\r
747           for (i = 0; i <= length; ++i) // ASCII conversion of 8 to 16 bit text.\r
748             developerDir[i] = (FilePathCharType)(uint8_t)developerDir8[i];\r
749 #else\r
750           OVR_strlcpy(developerDir, developerDir8, sizeof(developerDir));\r
751 #endif\r
752         }\r
753       }\r
754     }\r
755   }\r
756 \r
757 // Support checking for a developer library location override via the OVR_SDK_ROOT environment\r
758 // variable.\r
759 // This pathway is deprecated in favor of using LIBOVR_DLL_DIR instead.\r
760 #if defined(OVR_ENABLE_DEVELOPER_SEARCH)\r
761   if (!developerDir[0]) // If not already set by LIBOVR_DLL_PATH...\r
762   {\r
763     // __FILE__ maps to <sdkRoot>/LibOVR/Src/OVR_CAPIShim.c\r
764     char sdkRoot[OVR_MAX_PATH];\r
765     char* pLibOVR;\r
766     size_t i;\r
767 \r
768     // We assume that __FILE__ returns a full path, which isn't the case for some compilers.\r
769     // Need to compile with /FC under VC++ for __FILE__ to expand to the full file path.\r
770     // NOTE: This needs to be fixed on Mac. __FILE__ is not expanded to full path under clang.\r
771     OVR_strlcpy(sdkRoot, __FILE__, sizeof(sdkRoot));\r
772     for (i = 0; sdkRoot[i]; ++i)\r
773       sdkRoot[i] = (char)tolower(sdkRoot[i]); // Microsoft doesn't maintain case.\r
774     pLibOVR = strstr(sdkRoot, "libovr");\r
775     if (pLibOVR && (pLibOVR > sdkRoot))\r
776       pLibOVR[-1] = '\0';\r
777     else\r
778       sdkRoot[0] = '\0';\r
779 \r
780     if (sdkRoot[0]) {\r
781       // We want to use a developer version of the library only if the application is also being\r
782       // executed from\r
783       // a developer location. Ideally we would do this by checking that the relative path from the\r
784       // executable to\r
785       // the shared library is the same at runtime as it was when the executable was first built,\r
786       // but we don't have\r
787       // an easy way to do that from here and it would require some runtime help from the\r
788       // application code.\r
789       // Instead we verify that the application is simply in the same developer tree that was was\r
790       // when built.\r
791       // We could put in some additional logic to make it very likely to know if the EXE is in its\r
792       // original location.\r
793       FilePathCharType modulePath[OVR_MAX_PATH];\r
794       const ovrBool pathMatch = OVR_GetCurrentModuleDirectory(modulePath, OVR_MAX_PATH, ovrTrue) &&\r
795           (OVR_PathStartsWith(modulePath, sdkRoot) == ovrTrue);\r
796       if (pathMatch == ovrFalse) {\r
797         sdkRoot[0] = '\0'; // The application module is not in the developer tree, so don't try to\r
798         // use the developer shared library.\r
799       }\r
800     }\r
801 \r
802     if (sdkRoot[0]) {\r
803 \r
804 #ifndef CONFIG_VARIANT\r
805 #define CONFIG_VARIANT\r
806 #endif\r
807 \r
808 #if defined(OVR_BUILD_DEBUG)\r
809       const char* pConfigDirName = "Debug" CONFIG_VARIANT;\r
810 #else\r
811       const char* pConfigDirName = "Release" CONFIG_VARIANT;\r
812 #endif\r
813 \r
814 #undef CONFIG_VARIANT\r
815 \r
816 #if defined(_MSC_VER)\r
817 #if defined(_WIN64)\r
818       const char* pArchDirName = "x64";\r
819 #else\r
820       const char* pArchDirName = "Win32";\r
821 #endif\r
822 #else\r
823 #if defined(__x86_64__)\r
824       const char* pArchDirName = "x86_64";\r
825 #else\r
826       const char* pArchDirName = "i386";\r
827 #endif\r
828 #endif\r
829 \r
830 #if defined(_MSC_VER) && (_MSC_VER == 1600)\r
831       const char* pCompilerVersion = "VS2010";\r
832 #elif defined(_MSC_VER) && (_MSC_VER == 1700)\r
833       const char* pCompilerVersion = "VS2012";\r
834 #elif defined(_MSC_VER) && (_MSC_VER == 1800)\r
835       const char* pCompilerVersion = "VS2013";\r
836 #elif defined(_MSC_VER) && (_MSC_VER >= 1900)\r
837       const char* pCompilerVersion = "VS2015";\r
838 #endif\r
839 \r
840 #if defined(_WIN32)\r
841       int count = swprintf_s(\r
842           developerDir,\r
843           OVR_MAX_PATH,\r
844           L"%hs\\LibOVR\\Lib\\Windows\\%hs\\%hs\\%hs\\",\r
845           sdkRoot,\r
846           pArchDirName,\r
847           pConfigDirName,\r
848           pCompilerVersion);\r
849 #elif defined(__APPLE__)\r
850       // Apple/XCode doesn't let you specify an arch in build paths, which is OK if we build a\r
851       // universal binary.\r
852       (void)pArchDirName;\r
853       int count =\r
854           snprintf(developerDir, OVR_MAX_PATH, "%s/LibOVR/Lib/Mac/%s/", sdkRoot, pConfigDirName);\r
855 #else\r
856       int count = snprintf(\r
857           developerDir,\r
858           OVR_MAX_PATH,\r
859           "%s/LibOVR/Lib/Linux/%s/%s/",\r
860           sdkRoot,\r
861           pArchDirName,\r
862           pConfigDirName);\r
863 #endif\r
864 \r
865       if ((count < 0) ||\r
866           (count >=\r
867            (int)OVR_MAX_PATH)) // If there was an error or capacity overflow... clear the string.\r
868       {\r
869         developerDir[0] = '\0';\r
870       }\r
871     }\r
872   }\r
873 #endif // OVR_ENABLE_DEVELOPER_SEARCH\r
874 \r
875   {\r
876 #if !defined(_WIN32)\r
877     FilePathCharType cwDir[OVR_MAX_PATH]; // Will be filled in below.\r
878     FilePathCharType appDir[OVR_MAX_PATH];\r
879 #endif\r
880     size_t i;\r
881 \r
882 #if defined(_WIN32)\r
883     // On Windows, only search the developer directory and the usual path\r
884     const FilePathCharType* directoryArray[2];\r
885     directoryArray[0] = developerDir; // Developer directory.\r
886     directoryArray[1] = L""; // No directory, which causes Windows to use the standard search\r
887     // strategy to find the DLL.\r
888 \r
889 #elif defined(__APPLE__)\r
890     // https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/dyld.1.html\r
891 \r
892     FilePathCharType homeDir[OVR_MAX_PATH];\r
893     FilePathCharType homeFrameworkDir[OVR_MAX_PATH];\r
894     const FilePathCharType* directoryArray[5];\r
895     size_t homeDirLength = 0;\r
896 \r
897     const char* pHome = getenv("HOME"); // Try getting the HOME environment variable.\r
898 \r
899     if (pHome) {\r
900       homeDirLength = OVR_strlcpy(homeDir, pHome, sizeof(homeDir));\r
901     } else {\r
902       // https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/getpwuid_r.3.html\r
903       const long pwBufferSize = sysconf(_SC_GETPW_R_SIZE_MAX);\r
904 \r
905       if (pwBufferSize != -1) {\r
906         char pwBuffer[pwBufferSize];\r
907         struct passwd pw;\r
908         struct passwd* pwResult = NULL;\r
909 \r
910         if ((getpwuid_r(getuid(), &pw, pwBuffer, pwBufferSize, &pwResult) == 0) && pwResult)\r
911           homeDirLength = OVR_strlcpy(homeDir, pw.pw_dir, sizeof(homeDir));\r
912       }\r
913     }\r
914 \r
915     if (homeDirLength) {\r
916       if (homeDir[homeDirLength - 1] == '/')\r
917         homeDir[homeDirLength - 1] = '\0';\r
918       OVR_strlcpy(homeFrameworkDir, homeDir, sizeof(homeFrameworkDir));\r
919       OVR_strlcat(homeFrameworkDir, "/Library/Frameworks/", sizeof(homeFrameworkDir));\r
920     } else {\r
921       homeFrameworkDir[0] = '\0';\r
922     }\r
923 \r
924     directoryArray[0] = cwDir;\r
925     directoryArray[1] = appDir;\r
926     directoryArray[2] = homeFrameworkDir; // ~/Library/Frameworks/\r
927     directoryArray[3] = "/Library/Frameworks/"; // DYLD_FALLBACK_FRAMEWORK_PATH\r
928     directoryArray[4] = developerDir; // Developer directory.\r
929 \r
930 #else\r
931 #define STR1(x) #x\r
932 #define STR(x) STR1(x)\r
933 #ifdef LIBDIR\r
934 #define TEST_LIB_DIR STR(LIBDIR) "/"\r
935 #else\r
936 #define TEST_LIB_DIR appDir\r
937 #endif\r
938 \r
939     const FilePathCharType* directoryArray[5];\r
940     directoryArray[0] = cwDir;\r
941     directoryArray[1] = TEST_LIB_DIR; // Directory specified by LIBDIR if defined.\r
942     directoryArray[2] = developerDir; // Developer directory.\r
943     directoryArray[3] = "/usr/local/lib/";\r
944     directoryArray[4] = "/usr/lib/";\r
945 #endif\r
946 \r
947 #if !defined(_WIN32)\r
948     OVR_GetCurrentWorkingDirectory(cwDir, sizeof(cwDir) / sizeof(cwDir[0]));\r
949     OVR_GetCurrentApplicationDirectory(appDir, sizeof(appDir) / sizeof(appDir[0]), ovrTrue, NULL);\r
950 #endif\r
951 \r
952     // Versioned file expectations.\r
953     //     Windows: LibOVRRT<BIT_DEPTH>_<PRODUCT_VERSION>_<MAJOR_VERSION>.dll\r
954     //     // Example: LibOVRRT64_1_1.dll -- LibOVRRT 64 bit, product 1, major version 1,\r
955     //     minor/patch/build numbers unspecified in the name.\r
956     //     Mac:\r
957     //     LibOVRRT_<PRODUCT_VERSION>.framework/Versions/<MAJOR_VERSION>/LibOVRRT_<PRODUCT_VERSION>\r
958     //     // We are not presently using the .framework bundle's Current directory to hold the\r
959     //     version number. This may change.\r
960     //     Linux:   libOVRRT<BIT_DEPTH>_<PRODUCT_VERSION>.so.<MAJOR_VERSION>\r
961     //     // The file on disk may contain a minor version number, but a symlink is used to map this\r
962     //     major-only version to it.\r
963 \r
964     // Since we are manually loading the LibOVR dynamic library, we need to look in various\r
965     // locations for a file\r
966     // that matches our requirements. The functionality required is somewhat similar to the\r
967     // operating system's\r
968     // dynamic loader functionality. Each OS has some differences in how this is handled.\r
969     // Future versions of this may iterate over all libOVRRT.so.* files in the directory and use the\r
970     // one that matches our requirements.\r
971     //\r
972     // We need to look for a library that matches the product version and major version of the\r
973     // caller's request,\r
974     // and that library needs to support a minor version that is >= the requested minor version.\r
975     // Currently we\r
976     // don't test the minor version here, as the library is named based only on the product and\r
977     // major version.\r
978     // Currently the minor version test is handled via the initialization of the library and the\r
979     // initialization\r
980     // fails if minor version cannot be supported by the library. The reason this is done during\r
981     // initialization\r
982     // is that the library can at runtime support multiple minor versions based on the user's\r
983     // request. To the\r
984     // external user, all that matters it that they call ovr_Initialize with a requested version and\r
985     // it succeeds\r
986     // or fails.\r
987     //\r
988     // The product version is something that is at a higher level than the major version, and is not\r
989     // something that's\r
990     // always seen in libraries (an example is the well-known LibXml2 library, in which the 2 is\r
991     // essentially the product version).\r
992 \r
993     for (i = 0; i < sizeof(directoryArray) / sizeof(directoryArray[0]); ++i) {\r
994 #if defined(_WIN32)\r
995       printfResult = swprintf(\r
996           libraryPath,\r
997           libraryPathCapacity,\r
998           L"%lsLibOVRRT%hs_%d.dll",\r
999           directoryArray[i],\r
1000           pBitDepth,\r
1001           requestedMajorVersion);\r
1002 \r
1003       if (*directoryArray[i] == 0) {\r
1004         int k;\r
1005         FilePathCharType foundPath[MAX_PATH] = {0};\r
1006         DWORD searchResult = SearchPathW(NULL, libraryPath, NULL, MAX_PATH, foundPath, NULL);\r
1007         if (searchResult <= 0 || searchResult >= libraryPathCapacity) {\r
1008           continue;\r
1009         }\r
1010         foundPath[MAX_PATH - 1] = 0;\r
1011         for (k = 0; k < MAX_PATH; ++k) {\r
1012           libraryPath[k] = foundPath[k];\r
1013         }\r
1014       }\r
1015 \r
1016 #elif defined(__APPLE__)\r
1017       // https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/VersionInformation.html\r
1018       // Macintosh application bundles have the option of embedding dependent frameworks within the\r
1019       // application\r
1020       // bundle itself. A problem with that is that it doesn't support vendor-supplied updates to\r
1021       // the framework.\r
1022       printfResult =\r
1023           snprintf(libraryPath, libraryPathCapacity, "%sLibOVRRT.dylib", directoryArray[i]);\r
1024 \r
1025 #else // Unix\r
1026       // Applications that depend on the OS (e.g. ld-linux / ldd) can rely on the library being in a\r
1027       // common location\r
1028       // such as /usr/lib or can rely on the -rpath linker option to embed a path for the OS to\r
1029       // check for the library,\r
1030       // or can rely on the LD_LIBRARY_PATH environment variable being set. It's generally not\r
1031       // recommended that applications\r
1032       // depend on LD_LIBRARY_PATH be globally modified, partly due to potentialy security issues.\r
1033       // Currently we check the current application directory, current working directory, and then\r
1034       // /usr/lib and possibly others.\r
1035       printfResult = snprintf(\r
1036           libraryPath,\r
1037           libraryPathCapacity,\r
1038           "%slibOVRRT%s.so.%d",\r
1039           directoryArray[i],\r
1040           pBitDepth,\r
1041           requestedMajorVersion);\r
1042 #endif\r
1043 \r
1044       if ((printfResult >= 0) && (printfResult < (int)libraryPathCapacity)) {\r
1045         moduleHandle = OVR_OpenLibrary(libraryPath, result);\r
1046         if (moduleHandle != ModuleHandleTypeNull)\r
1047           return moduleHandle;\r
1048       }\r
1049     }\r
1050   }\r
1051 \r
1052   return moduleHandle;\r
1053 }\r
1054 \r
1055 //-----------------------------------------------------------------------------------\r
1056 // ***** hLibOVR\r
1057 //\r
1058 // global handle to the LivOVR shared library.\r
1059 //\r
1060 static ModuleHandleType hLibOVR = NULL;\r
1061 \r
1062 // This function is currently unsupported.\r
1063 ModuleHandleType ovr_GetLibOVRRTHandle() {\r
1064   return hLibOVR;\r
1065 }\r
1066 \r
1067 //-----------------------------------------------------------------------------------\r
1068 // ***** Function declarations\r
1069 //\r
1070 \r
1071 //-----------------------------------------------------------------------------------\r
1072 // ***** OVR_DECLARE_IMPORT\r
1073 //\r
1074 // Creates a pointer and loader value union for each entry in OVR_LIST_APIS()\r
1075 //\r
1076 \r
1077 #define OVR_DECLARE_IMPORT(ReturnValue, FunctionName, OptionalVersion, Arguments) \\r
1078   union {                                                                         \\r
1079     ReturnValue(OVR_CDECL* Ptr) Arguments;                                        \\r
1080     ModuleFunctionType Symbol;                                                    \\r
1081   } FunctionName;\r
1082 \r
1083 #define OVR_IGNORE_IMPORT(ReturnValue, FunctionName, OptionalVersion, Arguments)\r
1084 \r
1085 //-----------------------------------------------------------------------------------\r
1086 // ***** API - a structure with each API entrypoint as a FunctionName.Ptr and FunctionName.Symbol\r
1087 // union\r
1088 //\r
1089 \r
1090 static struct { OVR_LIST_APIS(OVR_DECLARE_IMPORT, OVR_IGNORE_IMPORT) } API = {{NULL}};\r
1091 \r
1092 static void OVR_UnloadSharedLibrary() {\r
1093   memset(&API, 0, sizeof(API));\r
1094   if (hLibOVR)\r
1095     OVR_CloseLibrary(hLibOVR);\r
1096   hLibOVR = NULL;\r
1097 }\r
1098 \r
1099 static ovrResult OVR_LoadSharedLibrary(int requestedProductVersion, int requestedMajorVersion) {\r
1100   FilePathCharType filePath[OVR_MAX_PATH];\r
1101   const char* SymbolName = NULL;\r
1102   ovrResult result = ovrSuccess;\r
1103 \r
1104   if (hLibOVR)\r
1105     return result;\r
1106 \r
1107   hLibOVR = OVR_FindLibraryPath(\r
1108       requestedProductVersion,\r
1109       requestedMajorVersion,\r
1110       filePath,\r
1111       sizeof(filePath) / sizeof(filePath[0]),\r
1112       &result);\r
1113 \r
1114   if (!hLibOVR)\r
1115     return result;\r
1116 \r
1117   // Zero the API table just to be paranoid\r
1118   memset(&API, 0, sizeof(API));\r
1119 \r
1120 // Load the current API entrypoint using the catenated FunctionName and OptionalVersion\r
1121 #define OVR_GETFUNCTION(ReturnValue, FunctionName, OptionalVersion, Arguments) \\r
1122   SymbolName = #FunctionName #OptionalVersion;                                 \\r
1123   API.FunctionName.Symbol = OVR_DLSYM(hLibOVR, SymbolName);                    \\r
1124   if (!API.FunctionName.Symbol) {                                              \\r
1125     fprintf(stderr, "Unable to locate symbol: %s\n", SymbolName);              \\r
1126     result = ovrError_LibSymbols;                                              \\r
1127     goto FailedToLoadSymbol;                                                   \\r
1128   }\r
1129 \r
1130   OVR_LIST_APIS(OVR_GETFUNCTION, OVR_IGNORE_IMPORT)\r
1131 \r
1132 #undef OVR_GETFUNCTION\r
1133 \r
1134   return result;\r
1135 \r
1136 FailedToLoadSymbol:\r
1137   // Check SymbolName for the name of the API which failed to load\r
1138   OVR_UnloadSharedLibrary();\r
1139   return result;\r
1140 }\r
1141 \r
1142 // These defaults are also in CAPI.cpp\r
1143 static const ovrInitParams DefaultParams = {\r
1144     ovrInit_RequestVersion, // Flags\r
1145     OVR_MINOR_VERSION, // RequestedMinorVersion\r
1146     0, // LogCallback\r
1147     0, // UserData\r
1148     0, // ConnectionTimeoutSeconds\r
1149     OVR_ON64("") // pad0\r
1150 };\r
1151 \r
1152 // Don't put this on the heap\r
1153 static ovrErrorInfo LastInitializeErrorInfo = {ovrError_NotInitialized,\r
1154                                                "ovr_Initialize never called"};\r
1155 \r
1156 OVR_PUBLIC_FUNCTION(ovrResult) ovr_Initialize(const ovrInitParams* inputParams) {\r
1157   ovrResult result;\r
1158   ovrInitParams params;\r
1159 \r
1160   typedef void(OVR_CDECL * ovr_ReportClientInfoType)(\r
1161       unsigned int compilerVersion,\r
1162       int productVersion,\r
1163       int majorVersion,\r
1164       int minorVersion,\r
1165       int patchVersion,\r
1166       int buildNumber);\r
1167   ovr_ReportClientInfoType reportClientInfo;\r
1168 \r
1169   // Do something with our version signature hash to prevent\r
1170   // it from being optimized out. In this case, compute\r
1171   // a cheap CRC.\r
1172   uint8_t crc = 0;\r
1173   size_t i;\r
1174 \r
1175   for (i = 0; i < (sizeof(OculusSDKUniqueIdentifier) - 3);\r
1176        ++i) // Minus 3 because we have trailing OVR_MAJOR_VERSION, OVR_MINOR_VERSION,\r
1177   // OVR_PATCH_VERSION which vary per version.\r
1178   {\r
1179     crc ^= OculusSDKUniqueIdentifier[i];\r
1180   }\r
1181 \r
1182   assert(crc == OculusSDKUniqueIdentifierXORResult);\r
1183   if (crc != OculusSDKUniqueIdentifierXORResult) {\r
1184     return ovrError_Initialize;\r
1185   }\r
1186 \r
1187   if (!inputParams) {\r
1188     params = DefaultParams;\r
1189   } else {\r
1190     params = *inputParams;\r
1191 \r
1192     // If not requesting a particular minor version,\r
1193     if (!(params.Flags & ovrInit_RequestVersion)) {\r
1194       // Enable requesting the default minor version.\r
1195       params.Flags |= ovrInit_RequestVersion;\r
1196       params.RequestedMinorVersion = OVR_MINOR_VERSION;\r
1197     }\r
1198   }\r
1199 \r
1200   // Clear non-writable bits provided by client code.\r
1201   params.Flags &= ovrinit_WritableBits;\r
1202 \r
1203 \r
1204 \r
1205   // Error out if the requested minor version is less than our lowest deemed compatible version\r
1206   // denoted by OVR_MIN_REQUESTABLE_MINOR_VERSION.\r
1207   // Note: This code has to be in the shim as we want to enforce usage of the new API versions for\r
1208   // applications being recompiled while maintaining backwards compatibility with older apps\r
1209   if (params.RequestedMinorVersion < OVR_MIN_REQUESTABLE_MINOR_VERSION) {\r
1210     // Requested LibOVRRT version too low\r
1211     result = ovrError_LibVersion;\r
1212     return result;\r
1213   }\r
1214 \r
1215   // By design we ignore the build version in the library search.\r
1216   result = OVR_LoadSharedLibrary(OVR_PRODUCT_VERSION, OVR_MAJOR_VERSION);\r
1217   if (result != ovrSuccess)\r
1218     return result;\r
1219 \r
1220   result = API.ovr_Initialize.Ptr(&params);\r
1221 \r
1222   if (result != ovrSuccess) {\r
1223     // Stash the last initialization error for the shim to return if\r
1224     // ovr_GetLastErrorInfo is called after we unload the dll below\r
1225     if (API.ovr_GetLastErrorInfo.Ptr) {\r
1226       API.ovr_GetLastErrorInfo.Ptr(&LastInitializeErrorInfo);\r
1227     }\r
1228     OVR_UnloadSharedLibrary();\r
1229   }\r
1230 \r
1231   reportClientInfo =\r
1232       (ovr_ReportClientInfoType)(uintptr_t)OVR_DLSYM(hLibOVR, "ovr_ReportClientInfo");\r
1233 \r
1234   if (reportClientInfo) {\r
1235     unsigned int mscFullVer = 0;\r
1236 #if defined(_MSC_FULL_VER)\r
1237     mscFullVer = _MSC_FULL_VER;\r
1238 #endif // _MSC_FULL_VER\r
1239 \r
1240     reportClientInfo(\r
1241         mscFullVer,\r
1242         OVR_PRODUCT_VERSION,\r
1243         OVR_MAJOR_VERSION,\r
1244         OVR_MINOR_VERSION,\r
1245         OVR_PATCH_VERSION,\r
1246         OVR_BUILD_NUMBER);\r
1247   }\r
1248 \r
1249   return result;\r
1250 }\r
1251 \r
1252 OVR_PUBLIC_FUNCTION(void) ovr_Shutdown() {\r
1253   if (!API.ovr_Shutdown.Ptr)\r
1254     return;\r
1255   API.ovr_Shutdown.Ptr();\r
1256   OVR_UnloadSharedLibrary();\r
1257 }\r
1258 \r
1259 OVR_PUBLIC_FUNCTION(const char*) ovr_GetVersionString() {\r
1260   // We don't directly return the value of the DLL API.ovr_GetVersionString.Ptr call,\r
1261   // because that call returns a pointer to memory within the DLL. If the DLL goes\r
1262   // away then that pointer becomes invalid while the process may still be holding\r
1263   // onto it. So we save a local copy of it which is always valid.\r
1264   static char dllVersionStringLocal[32];\r
1265   const char* dllVersionString;\r
1266 \r
1267   if (!API.ovr_GetVersionString.Ptr)\r
1268     return "(Unable to load LibOVR)";\r
1269 \r
1270   dllVersionString = API.ovr_GetVersionString.Ptr(); // Guaranteed to always be valid.\r
1271   assert(dllVersionString != NULL);\r
1272   OVR_strlcpy(dllVersionStringLocal, dllVersionString, sizeof(dllVersionStringLocal));\r
1273 \r
1274   return dllVersionStringLocal;\r
1275 }\r
1276 \r
1277 OVR_PUBLIC_FUNCTION(void) ovr_GetLastErrorInfo(ovrErrorInfo* errorInfo) {\r
1278   if (!API.ovr_GetLastErrorInfo.Ptr) {\r
1279     *errorInfo = LastInitializeErrorInfo;\r
1280   } else\r
1281     API.ovr_GetLastErrorInfo.Ptr(errorInfo);\r
1282 }\r
1283 \r
1284 OVR_PUBLIC_FUNCTION(ovrHmdDesc) ovr_GetHmdDesc(ovrSession session) {\r
1285   if (!API.ovr_GetHmdDesc.Ptr) {\r
1286     ovrHmdDesc hmdDesc;\r
1287     memset(&hmdDesc, 0, sizeof(hmdDesc));\r
1288     hmdDesc.Type = ovrHmd_None;\r
1289     return hmdDesc;\r
1290   }\r
1291 \r
1292   return API.ovr_GetHmdDesc.Ptr(session);\r
1293 }\r
1294 \r
1295 OVR_PUBLIC_FUNCTION(unsigned int) ovr_GetTrackerCount(ovrSession session) {\r
1296   if (!API.ovr_GetTrackerCount.Ptr) {\r
1297     return 0;\r
1298   }\r
1299 \r
1300   return API.ovr_GetTrackerCount.Ptr(session);\r
1301 }\r
1302 \r
1303 OVR_PUBLIC_FUNCTION(ovrTrackerDesc)\r
1304 ovr_GetTrackerDesc(ovrSession session, unsigned int trackerDescIndex) {\r
1305   if (!API.ovr_GetTrackerDesc.Ptr) {\r
1306     ovrTrackerDesc trackerDesc;\r
1307     memset(&trackerDesc, 0, sizeof(trackerDesc));\r
1308     return trackerDesc;\r
1309   }\r
1310 \r
1311   return API.ovr_GetTrackerDesc.Ptr(session, trackerDescIndex);\r
1312 }\r
1313 \r
1314 OVR_PUBLIC_FUNCTION(ovrResult) ovr_Create(ovrSession* pSession, ovrGraphicsLuid* pLuid) {\r
1315   if (!API.ovr_Create.Ptr)\r
1316     return ovrError_NotInitialized;\r
1317   return API.ovr_Create.Ptr(pSession, pLuid);\r
1318 }\r
1319 \r
1320 OVR_PUBLIC_FUNCTION(void) ovr_Destroy(ovrSession session) {\r
1321   if (!API.ovr_Destroy.Ptr)\r
1322     return;\r
1323   API.ovr_Destroy.Ptr(session);\r
1324 }\r
1325 \r
1326 OVR_PUBLIC_FUNCTION(ovrResult)\r
1327 ovr_GetSessionStatus(ovrSession session, ovrSessionStatus* sessionStatus) {\r
1328   if (!API.ovr_GetSessionStatus.Ptr) {\r
1329     if (sessionStatus) {\r
1330       sessionStatus->IsVisible = ovrFalse;\r
1331       sessionStatus->HmdPresent = ovrFalse;\r
1332       sessionStatus->HmdMounted = ovrFalse;\r
1333       sessionStatus->ShouldQuit = ovrFalse;\r
1334       sessionStatus->DisplayLost = ovrFalse;\r
1335       sessionStatus->ShouldRecenter = ovrFalse;\r
1336       sessionStatus->HasInputFocus = ovrFalse;\r
1337       sessionStatus->OverlayPresent = ovrFalse;\r
1338       sessionStatus->DepthRequested = ovrFalse;\r
1339     }\r
1340 \r
1341     return ovrError_NotInitialized;\r
1342   }\r
1343 \r
1344   return API.ovr_GetSessionStatus.Ptr(session, sessionStatus);\r
1345 }\r
1346 \r
1347 \r
1348 OVR_PUBLIC_FUNCTION(ovrResult)\r
1349 ovr_IsExtensionSupported(ovrSession session, ovrExtensions extension, ovrBool* extensionSupported) {\r
1350   if (!API.ovr_IsExtensionSupported.Ptr)\r
1351     return ovrError_NotInitialized;\r
1352   return API.ovr_IsExtensionSupported.Ptr(session, extension, extensionSupported);\r
1353 }\r
1354 \r
1355 OVR_PUBLIC_FUNCTION(ovrResult)\r
1356 ovr_EnableExtension(ovrSession session, ovrExtensions extension) {\r
1357   if (!API.ovr_EnableExtension.Ptr)\r
1358     return ovrError_NotInitialized;\r
1359   return API.ovr_EnableExtension.Ptr(session, extension);\r
1360 }\r
1361 \r
1362 OVR_PUBLIC_FUNCTION(ovrResult)\r
1363 ovr_SetTrackingOriginType(ovrSession session, ovrTrackingOrigin origin) {\r
1364   if (!API.ovr_SetTrackingOriginType.Ptr)\r
1365     return ovrError_NotInitialized;\r
1366   return API.ovr_SetTrackingOriginType.Ptr(session, origin);\r
1367 }\r
1368 \r
1369 OVR_PUBLIC_FUNCTION(ovrTrackingOrigin) ovr_GetTrackingOriginType(ovrSession session) {\r
1370   if (!API.ovr_GetTrackingOriginType.Ptr)\r
1371     return ovrTrackingOrigin_EyeLevel;\r
1372   return API.ovr_GetTrackingOriginType.Ptr(session);\r
1373 }\r
1374 \r
1375 OVR_PUBLIC_FUNCTION(ovrResult) ovr_RecenterTrackingOrigin(ovrSession session) {\r
1376   if (!API.ovr_RecenterTrackingOrigin.Ptr)\r
1377     return ovrError_NotInitialized;\r
1378   return API.ovr_RecenterTrackingOrigin.Ptr(session);\r
1379 }\r
1380 \r
1381 OVR_PUBLIC_FUNCTION(ovrResult) ovr_SpecifyTrackingOrigin(ovrSession session, ovrPosef originPose) {\r
1382   if (!API.ovr_SpecifyTrackingOrigin.Ptr)\r
1383     return ovrError_NotInitialized;\r
1384   return API.ovr_SpecifyTrackingOrigin.Ptr(session, originPose);\r
1385 }\r
1386 \r
1387 OVR_PUBLIC_FUNCTION(void) ovr_ClearShouldRecenterFlag(ovrSession session) {\r
1388   if (!API.ovr_ClearShouldRecenterFlag.Ptr)\r
1389     return;\r
1390   API.ovr_ClearShouldRecenterFlag.Ptr(session);\r
1391 }\r
1392 \r
1393 OVR_PUBLIC_FUNCTION(ovrTrackingState)\r
1394 ovr_GetTrackingState(ovrSession session, double absTime, ovrBool latencyMarker) {\r
1395   if (!API.ovr_GetTrackingState.Ptr) {\r
1396     ovrTrackingState nullTrackingState;\r
1397     memset(&nullTrackingState, 0, sizeof(nullTrackingState));\r
1398     return nullTrackingState;\r
1399   }\r
1400 \r
1401   return API.ovr_GetTrackingState.Ptr(session, absTime, latencyMarker);\r
1402 }\r
1403 \r
1404 OVR_PUBLIC_FUNCTION(ovrResult)\r
1405 ovr_GetDevicePoses(\r
1406     ovrSession session,\r
1407     ovrTrackedDeviceType* deviceTypes,\r
1408     int deviceCount,\r
1409     double absTime,\r
1410     ovrPoseStatef* outDevicePoses) {\r
1411   if (!API.ovr_GetDevicePoses.Ptr)\r
1412     return ovrError_NotInitialized;\r
1413   return API.ovr_GetDevicePoses.Ptr(session, deviceTypes, deviceCount, absTime, outDevicePoses);\r
1414 }\r
1415 \r
1416 OVR_PUBLIC_FUNCTION(ovrTrackingState)\r
1417 ovr_GetTrackingStateWithSensorData(\r
1418     ovrSession session,\r
1419     double absTime,\r
1420     ovrBool latencyMarker,\r
1421     ovrSensorData* sensorData) {\r
1422   if (!API.ovr_GetTrackingStateWithSensorData.Ptr) {\r
1423     ovrTrackingState nullTrackingState;\r
1424     memset(&nullTrackingState, 0, sizeof(nullTrackingState));\r
1425     if (sensorData)\r
1426       memset(&sensorData, 0, sizeof(sensorData));\r
1427     return nullTrackingState;\r
1428   }\r
1429 \r
1430   return API.ovr_GetTrackingStateWithSensorData.Ptr(session, absTime, latencyMarker, sensorData);\r
1431 }\r
1432 \r
1433 OVR_PUBLIC_FUNCTION(ovrTrackerPose)\r
1434 ovr_GetTrackerPose(ovrSession session, unsigned int trackerPoseIndex) {\r
1435   if (!API.ovr_GetTrackerPose.Ptr) {\r
1436     ovrTrackerPose nullTrackerPose;\r
1437     memset(&nullTrackerPose, 0, sizeof(nullTrackerPose));\r
1438     return nullTrackerPose;\r
1439   }\r
1440 \r
1441   return API.ovr_GetTrackerPose.Ptr(session, trackerPoseIndex);\r
1442 }\r
1443 \r
1444 OVR_PUBLIC_FUNCTION(ovrResult)\r
1445 ovr_GetInputState(ovrSession session, ovrControllerType controllerType, ovrInputState* inputState) {\r
1446   if (!API.ovr_GetInputState.Ptr) {\r
1447     if (inputState)\r
1448       memset(inputState, 0, sizeof(ovrInputState));\r
1449     return ovrError_NotInitialized;\r
1450   }\r
1451   return API.ovr_GetInputState.Ptr(session, controllerType, inputState);\r
1452 }\r
1453 \r
1454 OVR_PUBLIC_FUNCTION(unsigned int) ovr_GetConnectedControllerTypes(ovrSession session) {\r
1455   if (!API.ovr_GetConnectedControllerTypes.Ptr) {\r
1456     return 0;\r
1457   }\r
1458   return API.ovr_GetConnectedControllerTypes.Ptr(session);\r
1459 }\r
1460 \r
1461 OVR_PUBLIC_FUNCTION(ovrTouchHapticsDesc)\r
1462 ovr_GetTouchHapticsDesc(ovrSession session, ovrControllerType controllerType) {\r
1463   if (!API.ovr_GetTouchHapticsDesc.Ptr) {\r
1464     ovrTouchHapticsDesc nullDesc;\r
1465     memset(&nullDesc, 0, sizeof(nullDesc));\r
1466     return nullDesc;\r
1467   }\r
1468 \r
1469   return API.ovr_GetTouchHapticsDesc.Ptr(session, controllerType);\r
1470 }\r
1471 \r
1472 OVR_PUBLIC_FUNCTION(ovrResult)\r
1473 ovr_SetControllerVibration(\r
1474     ovrSession session,\r
1475     ovrControllerType controllerType,\r
1476     float frequency,\r
1477     float amplitude) {\r
1478   if (!API.ovr_SetControllerVibration.Ptr)\r
1479     return ovrError_NotInitialized;\r
1480 \r
1481   return API.ovr_SetControllerVibration.Ptr(session, controllerType, frequency, amplitude);\r
1482 }\r
1483 \r
1484 OVR_PUBLIC_FUNCTION(ovrResult)\r
1485 ovr_SubmitControllerVibration(\r
1486     ovrSession session,\r
1487     ovrControllerType controllerType,\r
1488     const ovrHapticsBuffer* buffer) {\r
1489   if (!API.ovr_SubmitControllerVibration.Ptr)\r
1490     return ovrError_NotInitialized;\r
1491 \r
1492   return API.ovr_SubmitControllerVibration.Ptr(session, controllerType, buffer);\r
1493 }\r
1494 \r
1495 OVR_PUBLIC_FUNCTION(ovrResult)\r
1496 ovr_GetControllerVibrationState(\r
1497     ovrSession session,\r
1498     ovrControllerType controllerType,\r
1499     ovrHapticsPlaybackState* outState) {\r
1500   if (!API.ovr_GetControllerVibrationState.Ptr)\r
1501     return ovrError_NotInitialized;\r
1502 \r
1503   return API.ovr_GetControllerVibrationState.Ptr(session, controllerType, outState);\r
1504 }\r
1505 \r
1506 OVR_PUBLIC_FUNCTION(ovrResult)\r
1507 ovr_TestBoundary(\r
1508     ovrSession session,\r
1509     ovrTrackedDeviceType deviceBitmask,\r
1510     ovrBoundaryType singleBoundaryType,\r
1511     ovrBoundaryTestResult* outTestResult) {\r
1512   if (!API.ovr_TestBoundary.Ptr)\r
1513     return ovrError_NotInitialized;\r
1514 \r
1515   return API.ovr_TestBoundary.Ptr(session, deviceBitmask, singleBoundaryType, outTestResult);\r
1516 }\r
1517 \r
1518 OVR_PUBLIC_FUNCTION(ovrResult)\r
1519 ovr_TestBoundaryPoint(\r
1520     ovrSession session,\r
1521     const ovrVector3f* point,\r
1522     ovrBoundaryType singleBoundaryType,\r
1523     ovrBoundaryTestResult* outTestResult) {\r
1524   if (!API.ovr_TestBoundaryPoint.Ptr)\r
1525     return ovrError_NotInitialized;\r
1526 \r
1527   return API.ovr_TestBoundaryPoint.Ptr(session, point, singleBoundaryType, outTestResult);\r
1528 }\r
1529 \r
1530 OVR_PUBLIC_FUNCTION(ovrResult)\r
1531 ovr_SetBoundaryLookAndFeel(ovrSession session, const ovrBoundaryLookAndFeel* lookAndFeel) {\r
1532   if (!API.ovr_SetBoundaryLookAndFeel.Ptr)\r
1533     return ovrError_NotInitialized;\r
1534 \r
1535   return API.ovr_SetBoundaryLookAndFeel.Ptr(session, lookAndFeel);\r
1536 }\r
1537 \r
1538 OVR_PUBLIC_FUNCTION(ovrResult) ovr_ResetBoundaryLookAndFeel(ovrSession session) {\r
1539   if (!API.ovr_ResetBoundaryLookAndFeel.Ptr)\r
1540     return ovrError_NotInitialized;\r
1541 \r
1542   return API.ovr_ResetBoundaryLookAndFeel.Ptr(session);\r
1543 }\r
1544 \r
1545 OVR_PUBLIC_FUNCTION(ovrResult)\r
1546 ovr_GetBoundaryGeometry(\r
1547     ovrSession session,\r
1548     ovrBoundaryType singleBoundaryType,\r
1549     ovrVector3f* outFloorPoints,\r
1550     int* outFloorPointsCount) {\r
1551   if (!API.ovr_GetBoundaryGeometry.Ptr)\r
1552     return ovrError_NotInitialized;\r
1553 \r
1554   return API.ovr_GetBoundaryGeometry.Ptr(\r
1555       session, singleBoundaryType, outFloorPoints, outFloorPointsCount);\r
1556 }\r
1557 \r
1558 OVR_PUBLIC_FUNCTION(ovrResult)\r
1559 ovr_GetBoundaryDimensions(\r
1560     ovrSession session,\r
1561     ovrBoundaryType singleBoundaryType,\r
1562     ovrVector3f* outDimensions) {\r
1563   if (!API.ovr_GetBoundaryDimensions.Ptr)\r
1564     return ovrError_NotInitialized;\r
1565 \r
1566   return API.ovr_GetBoundaryDimensions.Ptr(session, singleBoundaryType, outDimensions);\r
1567 }\r
1568 \r
1569 OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetBoundaryVisible(ovrSession session, ovrBool* outIsVisible) {\r
1570   if (!API.ovr_GetBoundaryVisible.Ptr)\r
1571     return ovrError_NotInitialized;\r
1572 \r
1573   return API.ovr_GetBoundaryVisible.Ptr(session, outIsVisible);\r
1574 }\r
1575 \r
1576 OVR_PUBLIC_FUNCTION(ovrResult) ovr_RequestBoundaryVisible(ovrSession session, ovrBool visible) {\r
1577   if (!API.ovr_RequestBoundaryVisible.Ptr)\r
1578     return ovrError_NotInitialized;\r
1579 \r
1580   return API.ovr_RequestBoundaryVisible.Ptr(session, visible);\r
1581 }\r
1582 \r
1583 OVR_PUBLIC_FUNCTION(ovrSizei)\r
1584 ovr_GetFovTextureSize(\r
1585     ovrSession session,\r
1586     ovrEyeType eye,\r
1587     ovrFovPort fov,\r
1588     float pixelsPerDisplayPixel) {\r
1589   if (!API.ovr_GetFovTextureSize.Ptr) {\r
1590     ovrSizei nullSize;\r
1591     memset(&nullSize, 0, sizeof(nullSize));\r
1592     return nullSize;\r
1593   }\r
1594 \r
1595   return API.ovr_GetFovTextureSize.Ptr(session, eye, fov, pixelsPerDisplayPixel);\r
1596 }\r
1597 \r
1598 #if defined(_WIN32)\r
1599 OVR_PUBLIC_FUNCTION(ovrResult)\r
1600 ovr_CreateTextureSwapChainDX(\r
1601     ovrSession session,\r
1602     IUnknown* d3dPtr,\r
1603     const ovrTextureSwapChainDesc* desc,\r
1604     ovrTextureSwapChain* outTextureSet) {\r
1605   if (!API.ovr_CreateTextureSwapChainDX.Ptr)\r
1606     return ovrError_NotInitialized;\r
1607 \r
1608   return API.ovr_CreateTextureSwapChainDX.Ptr(session, d3dPtr, desc, outTextureSet);\r
1609 }\r
1610 \r
1611 OVR_PUBLIC_FUNCTION(ovrResult)\r
1612 ovr_CreateMirrorTextureDX(\r
1613     ovrSession session,\r
1614     IUnknown* d3dPtr,\r
1615     const ovrMirrorTextureDesc* desc,\r
1616     ovrMirrorTexture* outMirrorTexture) {\r
1617   if (!API.ovr_CreateMirrorTextureDX.Ptr)\r
1618     return ovrError_NotInitialized;\r
1619 \r
1620   return API.ovr_CreateMirrorTextureDX.Ptr(session, d3dPtr, desc, outMirrorTexture);\r
1621 }\r
1622 \r
1623 OVR_PUBLIC_FUNCTION(ovrResult)\r
1624 ovr_CreateMirrorTextureWithOptionsDX(\r
1625     ovrSession session,\r
1626     IUnknown* d3dPtr,\r
1627     const ovrMirrorTextureDesc* desc,\r
1628     ovrMirrorTexture* outMirrorTexture) {\r
1629   if (!API.ovr_CreateMirrorTextureWithOptionsDX.Ptr)\r
1630     return ovrError_NotInitialized;\r
1631 \r
1632   return API.ovr_CreateMirrorTextureWithOptionsDX.Ptr(session, d3dPtr, desc, outMirrorTexture);\r
1633 }\r
1634 \r
1635 OVR_PUBLIC_FUNCTION(ovrResult)\r
1636 ovr_GetTextureSwapChainBufferDX(\r
1637     ovrSession session,\r
1638     ovrTextureSwapChain chain,\r
1639     int index,\r
1640     IID iid,\r
1641     void** ppObject) {\r
1642   if (!API.ovr_GetTextureSwapChainBufferDX.Ptr)\r
1643     return ovrError_NotInitialized;\r
1644 \r
1645   return API.ovr_GetTextureSwapChainBufferDX.Ptr(session, chain, index, iid, ppObject);\r
1646 }\r
1647 \r
1648 OVR_PUBLIC_FUNCTION(ovrResult)\r
1649 ovr_GetMirrorTextureBufferDX(\r
1650     ovrSession session,\r
1651     ovrMirrorTexture mirror,\r
1652     IID iid,\r
1653     void** ppObject) {\r
1654   if (!API.ovr_GetMirrorTextureBufferDX.Ptr)\r
1655     return ovrError_NotInitialized;\r
1656 \r
1657   return API.ovr_GetMirrorTextureBufferDX.Ptr(session, mirror, iid, ppObject);\r
1658 }\r
1659 \r
1660 OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceOutWaveId(unsigned int* deviceOutId) {\r
1661   if (!API.ovr_GetAudioDeviceOutWaveId.Ptr)\r
1662     return ovrError_NotInitialized;\r
1663 \r
1664   return API.ovr_GetAudioDeviceOutWaveId.Ptr(deviceOutId);\r
1665 }\r
1666 \r
1667 OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceInWaveId(unsigned int* deviceInId) {\r
1668   if (!API.ovr_GetAudioDeviceInWaveId.Ptr)\r
1669     return ovrError_NotInitialized;\r
1670 \r
1671   return API.ovr_GetAudioDeviceInWaveId.Ptr(deviceInId);\r
1672 }\r
1673 \r
1674 OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceOutGuidStr(WCHAR* deviceOutStrBuffer) {\r
1675   if (!API.ovr_GetAudioDeviceOutGuidStr.Ptr)\r
1676     return ovrError_NotInitialized;\r
1677 \r
1678   return API.ovr_GetAudioDeviceOutGuidStr.Ptr(deviceOutStrBuffer);\r
1679 }\r
1680 \r
1681 OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceOutGuid(GUID* deviceOutGuid) {\r
1682   if (!API.ovr_GetAudioDeviceOutGuid.Ptr)\r
1683     return ovrError_NotInitialized;\r
1684 \r
1685   return API.ovr_GetAudioDeviceOutGuid.Ptr(deviceOutGuid);\r
1686 }\r
1687 \r
1688 OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceInGuidStr(WCHAR* deviceInStrBuffer) {\r
1689   if (!API.ovr_GetAudioDeviceInGuidStr.Ptr)\r
1690     return ovrError_NotInitialized;\r
1691 \r
1692   return API.ovr_GetAudioDeviceInGuidStr.Ptr(deviceInStrBuffer);\r
1693 }\r
1694 \r
1695 OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceInGuid(GUID* deviceInGuid) {\r
1696   if (!API.ovr_GetAudioDeviceInGuid.Ptr)\r
1697     return ovrError_NotInitialized;\r
1698 \r
1699   return API.ovr_GetAudioDeviceInGuid.Ptr(deviceInGuid);\r
1700 }\r
1701 \r
1702 #endif\r
1703 \r
1704 OVR_PUBLIC_FUNCTION(ovrResult)\r
1705 ovr_CreateTextureSwapChainGL(\r
1706     ovrSession session,\r
1707     const ovrTextureSwapChainDesc* desc,\r
1708     ovrTextureSwapChain* outTextureSet) {\r
1709   if (!API.ovr_CreateTextureSwapChainGL.Ptr)\r
1710     return ovrError_NotInitialized;\r
1711 \r
1712   return API.ovr_CreateTextureSwapChainGL.Ptr(session, desc, outTextureSet);\r
1713 }\r
1714 \r
1715 OVR_PUBLIC_FUNCTION(ovrResult)\r
1716 ovr_CreateMirrorTextureGL(\r
1717     ovrSession session,\r
1718     const ovrMirrorTextureDesc* desc,\r
1719     ovrMirrorTexture* outMirrorTexture) {\r
1720   if (!API.ovr_CreateMirrorTextureGL.Ptr)\r
1721     return ovrError_NotInitialized;\r
1722 \r
1723   return API.ovr_CreateMirrorTextureGL.Ptr(session, desc, outMirrorTexture);\r
1724 }\r
1725 \r
1726 OVR_PUBLIC_FUNCTION(ovrResult)\r
1727 ovr_CreateMirrorTextureWithOptionsGL(\r
1728     ovrSession session,\r
1729     const ovrMirrorTextureDesc* desc,\r
1730     ovrMirrorTexture* outMirrorTexture) {\r
1731   if (!API.ovr_CreateMirrorTextureWithOptionsGL.Ptr)\r
1732     return ovrError_NotInitialized;\r
1733 \r
1734   return API.ovr_CreateMirrorTextureWithOptionsGL.Ptr(session, desc, outMirrorTexture);\r
1735 }\r
1736 \r
1737 OVR_PUBLIC_FUNCTION(ovrResult)\r
1738 ovr_GetTextureSwapChainBufferGL(\r
1739     ovrSession session,\r
1740     ovrTextureSwapChain chain,\r
1741     int index,\r
1742     unsigned int* texId) {\r
1743   if (!API.ovr_GetTextureSwapChainBufferGL.Ptr)\r
1744     return ovrError_NotInitialized;\r
1745 \r
1746   return API.ovr_GetTextureSwapChainBufferGL.Ptr(session, chain, index, texId);\r
1747 }\r
1748 \r
1749 OVR_PUBLIC_FUNCTION(ovrResult)\r
1750 ovr_GetMirrorTextureBufferGL(ovrSession session, ovrMirrorTexture mirror, unsigned int* texId) {\r
1751   if (!API.ovr_GetMirrorTextureBufferGL.Ptr)\r
1752     return ovrError_NotInitialized;\r
1753 \r
1754   return API.ovr_GetMirrorTextureBufferGL.Ptr(session, mirror, texId);\r
1755 }\r
1756 \r
1757 #if !defined(OSX_UNIMPLEMENTED)\r
1758 OVR_PUBLIC_FUNCTION(ovrResult)\r
1759 ovr_GetInstanceExtensionsVk(\r
1760     ovrGraphicsLuid luid,\r
1761     char* extensionNames,\r
1762     uint32_t* inoutExtensionNamesSize) {\r
1763   if (!API.ovr_GetInstanceExtensionsVk.Ptr)\r
1764     return ovrError_NotInitialized;\r
1765 \r
1766   return API.ovr_GetInstanceExtensionsVk.Ptr(luid, extensionNames, inoutExtensionNamesSize);\r
1767 }\r
1768 \r
1769 OVR_PUBLIC_FUNCTION(ovrResult)\r
1770 ovr_GetDeviceExtensionsVk(\r
1771     ovrGraphicsLuid luid,\r
1772     char* extensionNames,\r
1773     uint32_t* inoutExtensionNamesSize) {\r
1774   if (!API.ovr_GetDeviceExtensionsVk.Ptr)\r
1775     return ovrError_NotInitialized;\r
1776 \r
1777   return API.ovr_GetDeviceExtensionsVk.Ptr(luid, extensionNames, inoutExtensionNamesSize);\r
1778 }\r
1779 \r
1780 OVR_PUBLIC_FUNCTION(ovrResult)\r
1781 ovr_GetSessionPhysicalDeviceVk(\r
1782     ovrSession session,\r
1783     ovrGraphicsLuid luid,\r
1784     VkInstance instance,\r
1785     VkPhysicalDevice* out_physicalDevice) {\r
1786   if (!API.ovr_GetSessionPhysicalDeviceVk.Ptr)\r
1787     return ovrError_NotInitialized;\r
1788 \r
1789   return API.ovr_GetSessionPhysicalDeviceVk.Ptr(session, luid, instance, out_physicalDevice);\r
1790 }\r
1791 \r
1792 OVR_PUBLIC_FUNCTION(ovrResult) ovr_SetSynchronizationQueueVk(ovrSession session, VkQueue queue) {\r
1793   if (!API.ovr_SetSynchronizationQueueVk.Ptr)\r
1794     return ovrError_NotInitialized;\r
1795 \r
1796   return API.ovr_SetSynchronizationQueueVk.Ptr(session, queue);\r
1797 }\r
1798 \r
1799 OVR_PUBLIC_FUNCTION(ovrResult)\r
1800 ovr_CreateTextureSwapChainVk(\r
1801     ovrSession session,\r
1802     VkDevice device,\r
1803     const ovrTextureSwapChainDesc* desc,\r
1804     ovrTextureSwapChain* out_TextureSwapChain) {\r
1805   if (!API.ovr_CreateTextureSwapChainVk.Ptr)\r
1806     return ovrError_NotInitialized;\r
1807 \r
1808   return API.ovr_CreateTextureSwapChainVk.Ptr(session, device, desc, out_TextureSwapChain);\r
1809 }\r
1810 \r
1811 OVR_PUBLIC_FUNCTION(ovrResult)\r
1812 ovr_GetTextureSwapChainBufferVk(\r
1813     ovrSession session,\r
1814     ovrTextureSwapChain chain,\r
1815     int index,\r
1816     VkImage* out_Image) {\r
1817   if (!API.ovr_GetTextureSwapChainBufferVk.Ptr)\r
1818     return ovrError_NotInitialized;\r
1819 \r
1820   return API.ovr_GetTextureSwapChainBufferVk.Ptr(session, chain, index, out_Image);\r
1821 }\r
1822 \r
1823 OVR_PUBLIC_FUNCTION(ovrResult)\r
1824 ovr_CreateMirrorTextureWithOptionsVk(\r
1825     ovrSession session,\r
1826     VkDevice device,\r
1827     const ovrMirrorTextureDesc* desc,\r
1828     ovrMirrorTexture* out_MirrorTexture) {\r
1829   if (!API.ovr_CreateMirrorTextureWithOptionsVk.Ptr)\r
1830     return ovrError_NotInitialized;\r
1831 \r
1832   return API.ovr_CreateMirrorTextureWithOptionsVk.Ptr(session, device, desc, out_MirrorTexture);\r
1833 }\r
1834 \r
1835 OVR_PUBLIC_FUNCTION(ovrResult)\r
1836 ovr_GetMirrorTextureBufferVk(\r
1837     ovrSession session,\r
1838     ovrMirrorTexture mirrorTexture,\r
1839     VkImage* out_Image) {\r
1840   if (!API.ovr_GetMirrorTextureBufferVk.Ptr)\r
1841     return ovrError_NotInitialized;\r
1842 \r
1843   return API.ovr_GetMirrorTextureBufferVk.Ptr(session, mirrorTexture, out_Image);\r
1844 }\r
1845 #endif // OSX_UNIMPLEMENTED\r
1846 \r
1847 OVR_PUBLIC_FUNCTION(ovrResult)\r
1848 ovr_GetTextureSwapChainLength(ovrSession session, ovrTextureSwapChain chain, int* length) {\r
1849   if (!API.ovr_GetTextureSwapChainLength.Ptr)\r
1850     return ovrError_NotInitialized;\r
1851 \r
1852   return API.ovr_GetTextureSwapChainLength.Ptr(session, chain, length);\r
1853 }\r
1854 \r
1855 OVR_PUBLIC_FUNCTION(ovrResult)\r
1856 ovr_GetTextureSwapChainCurrentIndex(\r
1857     ovrSession session,\r
1858     ovrTextureSwapChain chain,\r
1859     int* currentIndex) {\r
1860   if (!API.ovr_GetTextureSwapChainCurrentIndex.Ptr)\r
1861     return ovrError_NotInitialized;\r
1862 \r
1863   return API.ovr_GetTextureSwapChainCurrentIndex.Ptr(session, chain, currentIndex);\r
1864 }\r
1865 \r
1866 OVR_PUBLIC_FUNCTION(ovrResult)\r
1867 ovr_GetTextureSwapChainDesc(\r
1868     ovrSession session,\r
1869     ovrTextureSwapChain chain,\r
1870     ovrTextureSwapChainDesc* desc) {\r
1871   if (!API.ovr_GetTextureSwapChainDesc.Ptr)\r
1872     return ovrError_NotInitialized;\r
1873 \r
1874   return API.ovr_GetTextureSwapChainDesc.Ptr(session, chain, desc);\r
1875 }\r
1876 \r
1877 OVR_PUBLIC_FUNCTION(ovrResult)\r
1878 ovr_CommitTextureSwapChain(ovrSession session, ovrTextureSwapChain chain) {\r
1879   if (!API.ovr_CommitTextureSwapChain.Ptr)\r
1880     return ovrError_NotInitialized;\r
1881 \r
1882   return API.ovr_CommitTextureSwapChain.Ptr(session, chain);\r
1883 }\r
1884 \r
1885 OVR_PUBLIC_FUNCTION(void)\r
1886 ovr_DestroyTextureSwapChain(ovrSession session, ovrTextureSwapChain chain) {\r
1887   if (!API.ovr_DestroyTextureSwapChain.Ptr)\r
1888     return;\r
1889 \r
1890   API.ovr_DestroyTextureSwapChain.Ptr(session, chain);\r
1891 }\r
1892 \r
1893 OVR_PUBLIC_FUNCTION(void)\r
1894 ovr_DestroyMirrorTexture(ovrSession session, ovrMirrorTexture mirrorTexture) {\r
1895   if (!API.ovr_DestroyMirrorTexture.Ptr)\r
1896     return;\r
1897 \r
1898   API.ovr_DestroyMirrorTexture.Ptr(session, mirrorTexture);\r
1899 }\r
1900 \r
1901 OVR_PUBLIC_FUNCTION(ovrResult)\r
1902 ovr_WaitToBeginFrame(ovrSession session, long long frameIndex) {\r
1903   if (!API.ovr_WaitToBeginFrame.Ptr)\r
1904     return ovrError_NotInitialized;\r
1905 \r
1906   return API.ovr_WaitToBeginFrame.Ptr(session, frameIndex);\r
1907 }\r
1908 \r
1909 OVR_PUBLIC_FUNCTION(ovrResult)\r
1910 ovr_BeginFrame(ovrSession session, long long frameIndex) {\r
1911   if (!API.ovr_BeginFrame.Ptr)\r
1912     return ovrError_NotInitialized;\r
1913 \r
1914   return API.ovr_BeginFrame.Ptr(session, frameIndex);\r
1915 }\r
1916 \r
1917 OVR_PUBLIC_FUNCTION(ovrResult)\r
1918 ovr_EndFrame(\r
1919     ovrSession session,\r
1920     long long frameIndex,\r
1921     const ovrViewScaleDesc* viewScaleDesc,\r
1922     ovrLayerHeader const* const* layerPtrList,\r
1923     unsigned int layerCount) {\r
1924   if (!API.ovr_EndFrame.Ptr)\r
1925     return ovrError_NotInitialized;\r
1926 \r
1927   return API.ovr_EndFrame.Ptr(session, frameIndex, viewScaleDesc, layerPtrList, layerCount);\r
1928 }\r
1929 \r
1930 OVR_PUBLIC_FUNCTION(ovrResult)\r
1931 ovr_SubmitFrame(\r
1932     ovrSession session,\r
1933     long long frameIndex,\r
1934     const ovrViewScaleDesc* viewScaleDesc,\r
1935     ovrLayerHeader const* const* layerPtrList,\r
1936     unsigned int layerCount) {\r
1937   if (!API.ovr_SubmitFrame.Ptr)\r
1938     return ovrError_NotInitialized;\r
1939 \r
1940   return API.ovr_SubmitFrame.Ptr(session, frameIndex, viewScaleDesc, layerPtrList, layerCount);\r
1941 }\r
1942 \r
1943 OVR_PUBLIC_FUNCTION(ovrEyeRenderDesc)\r
1944 ovr_GetRenderDesc(ovrSession session, ovrEyeType eyeType, ovrFovPort fov) {\r
1945   if (!API.ovr_GetRenderDesc.Ptr) {\r
1946     ovrEyeRenderDesc nullEyeRenderDesc;\r
1947     memset(&nullEyeRenderDesc, 0, sizeof(nullEyeRenderDesc));\r
1948     return nullEyeRenderDesc;\r
1949   }\r
1950   return API.ovr_GetRenderDesc.Ptr(session, eyeType, fov);\r
1951 }\r
1952 \r
1953 OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetPerfStats(ovrSession session, ovrPerfStats* outPerfStats) {\r
1954   if (!API.ovr_GetPerfStats.Ptr)\r
1955     return ovrError_NotInitialized;\r
1956 \r
1957   return API.ovr_GetPerfStats.Ptr(session, outPerfStats);\r
1958 }\r
1959 \r
1960 OVR_PUBLIC_FUNCTION(ovrResult) ovr_ResetPerfStats(ovrSession session) {\r
1961   if (!API.ovr_ResetPerfStats.Ptr)\r
1962     return ovrError_NotInitialized;\r
1963 \r
1964   return API.ovr_ResetPerfStats.Ptr(session);\r
1965 }\r
1966 \r
1967 OVR_PUBLIC_FUNCTION(double) ovr_GetPredictedDisplayTime(ovrSession session, long long frameIndex) {\r
1968   if (!API.ovr_GetPredictedDisplayTime.Ptr)\r
1969     return 0.0;\r
1970 \r
1971   return API.ovr_GetPredictedDisplayTime.Ptr(session, frameIndex);\r
1972 }\r
1973 \r
1974 OVR_PUBLIC_FUNCTION(double) ovr_GetTimeInSeconds() {\r
1975   if (!API.ovr_GetTimeInSeconds.Ptr)\r
1976     return 0.;\r
1977   return API.ovr_GetTimeInSeconds.Ptr();\r
1978 }\r
1979 \r
1980 OVR_PUBLIC_FUNCTION(ovrBool)\r
1981 ovr_GetBool(ovrSession session, const char* propertyName, ovrBool defaultVal) {\r
1982   if (!API.ovr_GetBool.Ptr)\r
1983     return ovrFalse;\r
1984   return API.ovr_GetBool.Ptr(session, propertyName, defaultVal);\r
1985 }\r
1986 \r
1987 OVR_PUBLIC_FUNCTION(ovrBool)\r
1988 ovr_SetBool(ovrSession session, const char* propertyName, ovrBool value) {\r
1989   if (!API.ovr_SetBool.Ptr)\r
1990     return ovrFalse;\r
1991   return API.ovr_SetBool.Ptr(session, propertyName, value);\r
1992 }\r
1993 \r
1994 OVR_PUBLIC_FUNCTION(int) ovr_GetInt(ovrSession session, const char* propertyName, int defaultVal) {\r
1995   if (!API.ovr_GetInt.Ptr)\r
1996     return 0;\r
1997   return API.ovr_GetInt.Ptr(session, propertyName, defaultVal);\r
1998 }\r
1999 \r
2000 OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetInt(ovrSession session, const char* propertyName, int value) {\r
2001   if (!API.ovr_SetInt.Ptr)\r
2002     return ovrFalse;\r
2003   return API.ovr_SetInt.Ptr(session, propertyName, value);\r
2004 }\r
2005 \r
2006 OVR_PUBLIC_FUNCTION(float)\r
2007 ovr_GetFloat(ovrSession session, const char* propertyName, float defaultVal) {\r
2008   if (!API.ovr_GetFloat.Ptr)\r
2009     return 0.f;\r
2010   return API.ovr_GetFloat.Ptr(session, propertyName, defaultVal);\r
2011 }\r
2012 \r
2013 OVR_PUBLIC_FUNCTION(ovrBool)\r
2014 ovr_SetFloat(ovrSession session, const char* propertyName, float value) {\r
2015   if (!API.ovr_SetFloat.Ptr)\r
2016     return ovrFalse;\r
2017   return API.ovr_SetFloat.Ptr(session, propertyName, value);\r
2018 }\r
2019 \r
2020 OVR_PUBLIC_FUNCTION(unsigned int)\r
2021 ovr_GetFloatArray(\r
2022     ovrSession session,\r
2023     const char* propertyName,\r
2024     float values[],\r
2025     unsigned int arraySize) {\r
2026   if (!API.ovr_GetFloatArray.Ptr)\r
2027     return 0;\r
2028   return API.ovr_GetFloatArray.Ptr(session, propertyName, values, arraySize);\r
2029 }\r
2030 \r
2031 OVR_PUBLIC_FUNCTION(ovrBool)\r
2032 ovr_SetFloatArray(\r
2033     ovrSession session,\r
2034     const char* propertyName,\r
2035     const float values[],\r
2036     unsigned int arraySize) {\r
2037   if (!API.ovr_SetFloatArray.Ptr)\r
2038     return ovrFalse;\r
2039   return API.ovr_SetFloatArray.Ptr(session, propertyName, values, arraySize);\r
2040 }\r
2041 \r
2042 OVR_PUBLIC_FUNCTION(const char*)\r
2043 ovr_GetString(ovrSession session, const char* propertyName, const char* defaultVal) {\r
2044   if (!API.ovr_GetString.Ptr)\r
2045     return "(Unable to load LibOVR)";\r
2046   return API.ovr_GetString.Ptr(session, propertyName, defaultVal);\r
2047 }\r
2048 \r
2049 OVR_PUBLIC_FUNCTION(ovrBool)\r
2050 ovr_SetString(ovrSession session, const char* propertyName, const char* value) {\r
2051   if (!API.ovr_SetString.Ptr)\r
2052     return ovrFalse;\r
2053   return API.ovr_SetString.Ptr(session, propertyName, value);\r
2054 }\r
2055 \r
2056 OVR_PUBLIC_FUNCTION(int) ovr_TraceMessage(int level, const char* message) {\r
2057   if (!API.ovr_TraceMessage.Ptr)\r
2058     return -1;\r
2059 \r
2060   return API.ovr_TraceMessage.Ptr(level, message);\r
2061 }\r
2062 \r
2063 OVR_PUBLIC_FUNCTION(ovrResult) ovr_IdentifyClient(const char* identity) {\r
2064   if (!API.ovr_IdentifyClient.Ptr)\r
2065     return ovrError_NotInitialized;\r
2066 \r
2067   return API.ovr_IdentifyClient.Ptr(identity);\r
2068 }\r
2069 \r
2070 OVR_PUBLIC_FUNCTION(ovrResult) ovr_Lookup(const char* name, void** data) {\r
2071   if (!API.ovr_Lookup.Ptr)\r
2072     return ovrError_NotInitialized;\r
2073   return API.ovr_Lookup.Ptr(name, data);\r
2074 }\r
2075 \r
2076 OVR_PUBLIC_FUNCTION(ovrResult)\r
2077 ovr_GetExternalCameras(\r
2078     ovrSession session,\r
2079     ovrExternalCamera* outCameras,\r
2080     unsigned int* outCameraCount) {\r
2081   if (!API.ovr_GetExternalCameras.Ptr)\r
2082     return ovrError_NotInitialized;\r
2083   if (!outCameras || !outCameraCount)\r
2084     return ovrError_InvalidParameter;\r
2085 \r
2086   return API.ovr_GetExternalCameras.Ptr(session, outCameras, outCameraCount);\r
2087 }\r
2088 \r
2089 OVR_PUBLIC_FUNCTION(ovrResult)\r
2090 ovr_SetExternalCameraProperties(\r
2091     ovrSession session,\r
2092     const char* name,\r
2093     const ovrCameraIntrinsics* const intrinsics,\r
2094     const ovrCameraExtrinsics* const extrinsics) {\r
2095   if (!API.ovr_SetExternalCameraProperties.Ptr)\r
2096     return ovrError_NotInitialized;\r
2097   if (!name || (!intrinsics && !extrinsics))\r
2098     return ovrError_InvalidParameter;\r
2099 \r
2100   return API.ovr_SetExternalCameraProperties.Ptr(session, name, intrinsics, extrinsics);\r
2101 }\r
2102 #if defined(_MSC_VER)\r
2103 #pragma warning(pop)\r
2104 #endif\r