1 /* 2 * PROJECT: ReactOS apisets 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: Resolving the apiset to a ReactOS system dll 5 * COPYRIGHT: Copyright 2024 Mark Jansen <mark.jansen@reactos.org> 6 */ 7 8 #include <ndk/umtypes.h> 9 #include <ndk/rtlfuncs.h> 10 #include "apisetsp.h" 11 12 13 const ULONGLONG API_ = (ULONGLONG)0x2D004900500041; /// L"API-" 14 const ULONGLONG EXT_ = (ULONGLONG)0x2D005400580045; /// L"EXT-"; 15 16 WORD PrefixSize = sizeof(L"api-") - sizeof(WCHAR); 17 WORD ExtensionSize = sizeof(L".dll") - sizeof(WCHAR); 18 19 20 // The official prototype according to the Windows kit 8.1 is: 21 //NTSTATUS 22 //ApiSetResolveToHost ( 23 // _In_ PCAPI_SET_NAMESPACE_ARRAY Schema, 24 // _In_ PCUNICODE_STRING FileNameIn, 25 // _In_opt_ PCUNICODE_STRING ParentName, 26 // _Out_ PBOOLEAN Resolved, 27 // _Out_ PUNICODE_STRING HostBinary 28 // ); 29 30 31 NTSTATUS 32 ApiSetResolveToHost( 33 _In_ DWORD ApisetVersion, 34 _In_ PCUNICODE_STRING ApiToResolve, 35 _Out_ PBOOLEAN Resolved, 36 _Out_ PUNICODE_STRING Output 37 ) 38 { 39 if (ApiToResolve->Length < PrefixSize) 40 { 41 *Resolved = FALSE; 42 return STATUS_SUCCESS; 43 } 44 45 // Grab the first four chars from the string, converting the first 3 to uppercase 46 PWSTR ApiSetNameBuffer = ApiToResolve->Buffer; 47 ULONGLONG ApiSetNameBufferPrefix = ((ULONGLONG *)ApiSetNameBuffer)[0] & 0xFFFFFFDFFFDFFFDF; 48 // Check if it matches either 'api-' or 'ext-' 49 if (!(ApiSetNameBufferPrefix == API_ || ApiSetNameBufferPrefix == EXT_)) 50 { 51 *Resolved = FALSE; 52 return STATUS_SUCCESS; 53 } 54 55 // If there is an extension, cut it off (we store apisets without extension) 56 UNICODE_STRING Tmp = *ApiToResolve; 57 const WCHAR *Extension = Tmp.Buffer + (Tmp.Length - ExtensionSize) / sizeof(WCHAR); 58 if (!_wcsnicmp(Extension, L".dll", ExtensionSize / sizeof(WCHAR))) 59 Tmp.Length -= ExtensionSize; 60 61 // Binary search the apisets 62 // Ideally we should use bsearch here, but that drags in another dependency and we do not want that here. 63 LONG UBnd = g_ApisetsCount - 1; 64 LONG LBnd = 0; 65 while (LBnd <= UBnd) 66 { 67 LONG Index = (UBnd - LBnd) / 2 + LBnd; 68 69 LONG result = RtlCompareUnicodeString(&Tmp, &g_Apisets[Index].Name, TRUE); 70 if (result == 0) 71 { 72 // Check if this version is included 73 if (g_Apisets[Index].dwOsVersions & ApisetVersion) 74 { 75 // Return a static string (does not have to be freed) 76 *Resolved = TRUE; 77 *Output = g_Apisets[Index].Target; 78 } 79 return STATUS_SUCCESS; 80 } 81 else if (result < 0) 82 { 83 UBnd = Index - 1; 84 } 85 else 86 { 87 LBnd = Index + 1; 88 } 89 } 90 *Resolved = FALSE; 91 return STATUS_SUCCESS; 92 } 93