mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 18:13:03 +00:00
Rework apisets to use a table
This removes all fake apiset forwarders, and handles apisets inside ntdll. This is not 100% compatible with how windows does it, but it should be good enough for us.
This commit is contained in:
parent
116c0cd9a5
commit
24a56f89ab
246 changed files with 1910 additions and 9091 deletions
|
@ -207,8 +207,6 @@ macro(dir_to_num dir var)
|
|||
set(${var} 57)
|
||||
elseif(${dir} STREQUAL reactos/winsxs/x86_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.7601.23038_none_deadbeef)
|
||||
set(${var} 58)
|
||||
elseif(${dir} STREQUAL reactos/winsxs/x86_reactos.apisets_6595b64144ccf1df_1.0.0.0_none_deadbeef)
|
||||
set(${var} 59)
|
||||
elseif(${dir} STREQUAL reactos/bin/suppl)
|
||||
set(${var} 60)
|
||||
elseif(${dir} STREQUAL reactos/winsxs/x86_microsoft.windows.gdiplus_6595b64144ccf1df_1.0.14393.0_none_deadbeef)
|
||||
|
@ -229,8 +227,6 @@ macro(dir_to_num dir var)
|
|||
set(${var} 68)
|
||||
elseif(${dir} STREQUAL reactos/winsxs/amd64_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.7601.23038_none_deadbeef)
|
||||
set(${var} 69)
|
||||
elseif(${dir} STREQUAL reactos/winsxs/amd64_reactos.apisets_6595b64144ccf1df_1.0.0.0_none_deadbeef)
|
||||
set(${var} 70)
|
||||
elseif(${dir} STREQUAL reactos/winsxs/amd64_microsoft.windows.gdiplus_6595b64144ccf1df_1.0.14393.0_none_deadbeef)
|
||||
set(${var} 71)
|
||||
|
||||
|
@ -240,8 +236,6 @@ macro(dir_to_num dir var)
|
|||
set(${var} 73)
|
||||
elseif(${dir} STREQUAL reactos/winsxs/arm_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.7601.23038_none_deadbeef)
|
||||
set(${var} 74)
|
||||
elseif(${dir} STREQUAL reactos/winsxs/arm_reactos.apisets_6595b64144ccf1df_1.0.0.0_none_deadbeef)
|
||||
set(${var} 75)
|
||||
elseif(${dir} STREQUAL reactos/winsxs/arm_microsoft.windows.gdiplus_6595b64144ccf1df_1.0.14393.0_none_deadbeef)
|
||||
set(${var} 76)
|
||||
|
||||
|
@ -251,8 +245,6 @@ macro(dir_to_num dir var)
|
|||
set(${var} 78)
|
||||
elseif(${dir} STREQUAL reactos/winsxs/arm64_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.7601.23038_none_deadbeef)
|
||||
set(${var} 79)
|
||||
elseif(${dir} STREQUAL reactos/winsxs/arm64_reactos.apisets_6595b64144ccf1df_1.0.0.0_none_deadbeef)
|
||||
set(${var} 80)
|
||||
elseif(${dir} STREQUAL reactos/winsxs/arm64_microsoft.windows.gdiplus_6595b64144ccf1df_1.0.14393.0_none_deadbeef)
|
||||
set(${var} 81)
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ add_subdirectory(inflib)
|
|||
if(CMAKE_CROSSCOMPILING)
|
||||
|
||||
add_subdirectory(3rdparty)
|
||||
add_subdirectory(apisets)
|
||||
add_subdirectory(cicero)
|
||||
add_subdirectory(comsupp)
|
||||
add_subdirectory(conutils)
|
||||
|
|
13
sdk/lib/apisets/CMakeLists.txt
Normal file
13
sdk/lib/apisets/CMakeLists.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
|
||||
add_library(apisets
|
||||
apisets.c
|
||||
apisets.h
|
||||
apisetsp.h
|
||||
|
||||
# Generated file:
|
||||
apisets.table.c
|
||||
)
|
||||
|
||||
target_include_directories(apisets INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_compile_definitions(apisets PRIVATE _NTSYSTEM_)
|
||||
add_dependencies(apisets psdk)
|
92
sdk/lib/apisets/apisets.c
Normal file
92
sdk/lib/apisets/apisets.c
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* PROJECT: ReactOS apisets
|
||||
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
|
||||
* PURPOSE: Resolving the apiset to a ReactOS system dll
|
||||
* COPYRIGHT: Copyright 2024 Mark Jansen <mark.jansen@reactos.org>
|
||||
*/
|
||||
|
||||
#include <ndk/umtypes.h>
|
||||
#include <ndk/rtlfuncs.h>
|
||||
#include "apisetsp.h"
|
||||
|
||||
|
||||
const ULONGLONG API_ = (ULONGLONG)0x2D004900500041; /// L"API-"
|
||||
const ULONGLONG EXT_ = (ULONGLONG)0x2D005400580045; /// L"EXT-";
|
||||
|
||||
WORD PrefixSize = sizeof(L"api-") - sizeof(WCHAR);
|
||||
WORD ExtensionSize = sizeof(L".dll") - sizeof(WCHAR);
|
||||
|
||||
|
||||
// The official prototype according to the Windows kit 8.1 is:
|
||||
//NTSTATUS
|
||||
//ApiSetResolveToHost (
|
||||
// _In_ PCAPI_SET_NAMESPACE_ARRAY Schema,
|
||||
// _In_ PCUNICODE_STRING FileNameIn,
|
||||
// _In_opt_ PCUNICODE_STRING ParentName,
|
||||
// _Out_ PBOOLEAN Resolved,
|
||||
// _Out_ PUNICODE_STRING HostBinary
|
||||
// );
|
||||
|
||||
|
||||
NTSTATUS
|
||||
ApiSetResolveToHost(
|
||||
_In_ DWORD ApisetVersion,
|
||||
_In_ PCUNICODE_STRING ApiToResolve,
|
||||
_Out_ PBOOLEAN Resolved,
|
||||
_Out_ PUNICODE_STRING Output
|
||||
)
|
||||
{
|
||||
if (ApiToResolve->Length < PrefixSize)
|
||||
{
|
||||
*Resolved = FALSE;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Grab the first four chars from the string, converting the first 3 to uppercase
|
||||
PWSTR ApiSetNameBuffer = ApiToResolve->Buffer;
|
||||
ULONGLONG ApiSetNameBufferPrefix = ((ULONGLONG *)ApiSetNameBuffer)[0] & 0xFFFFFFDFFFDFFFDF;
|
||||
// Check if it matches either 'api-' or 'ext-'
|
||||
if (!(ApiSetNameBufferPrefix == API_ || ApiSetNameBufferPrefix == EXT_))
|
||||
{
|
||||
*Resolved = FALSE;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// If there is an extension, cut it off (we store apisets without extension)
|
||||
UNICODE_STRING Tmp = *ApiToResolve;
|
||||
const WCHAR *Extension = Tmp.Buffer + (Tmp.Length - ExtensionSize) / sizeof(WCHAR);
|
||||
if (!_wcsnicmp(Extension, L".dll", ExtensionSize / sizeof(WCHAR)))
|
||||
Tmp.Length -= ExtensionSize;
|
||||
|
||||
// Binary search the apisets
|
||||
// Ideally we should use bsearch here, but that drags in another dependency and we do not want that here.
|
||||
LONG UBnd = g_ApisetsCount - 1;
|
||||
LONG LBnd = 0;
|
||||
while (LBnd <= UBnd)
|
||||
{
|
||||
LONG Index = (UBnd - LBnd) / 2 + LBnd;
|
||||
|
||||
LONG result = RtlCompareUnicodeString(&Tmp, &g_Apisets[Index].Name, TRUE);
|
||||
if (result == 0)
|
||||
{
|
||||
// Check if this version is included
|
||||
if (g_Apisets[Index].dwOsVersions & ApisetVersion)
|
||||
{
|
||||
// Return a static string (does not have to be freed)
|
||||
*Resolved = TRUE;
|
||||
*Output = g_Apisets[Index].Target;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else if (result < 0)
|
||||
{
|
||||
UBnd = Index - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
LBnd = Index + 1;
|
||||
}
|
||||
}
|
||||
*Resolved = FALSE;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
31
sdk/lib/apisets/apisets.h
Normal file
31
sdk/lib/apisets/apisets.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* PROJECT: ReactOS apisets
|
||||
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
|
||||
* PURPOSE: Interface for resolving the apisets
|
||||
* COPYRIGHT: Copyright 2024 Mark Jansen <mark.jansen@reactos.org>
|
||||
*/
|
||||
#ifndef APISETS_H
|
||||
#define APISETS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
#define APISET_WIN7 (1 << 0)
|
||||
#define APISET_WIN8 (1 << 1)
|
||||
#define APISET_WIN81 (1 << 2)
|
||||
#define APISET_WIN10 (1 << 3)
|
||||
//#define APISET_WIN11 (1 << 4)
|
||||
|
||||
|
||||
NTSTATUS
|
||||
ApiSetResolveToHost(_In_ DWORD ApisetVersion, _In_ PCUNICODE_STRING ApiToResolve, _Out_ PBOOLEAN Resolved, _Out_ PUNICODE_STRING Output);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif // APISETS_H
|
1263
sdk/lib/apisets/apisets.table.c
Normal file
1263
sdk/lib/apisets/apisets.table.c
Normal file
File diff suppressed because it is too large
Load diff
25
sdk/lib/apisets/apisetsp.h
Normal file
25
sdk/lib/apisets/apisetsp.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef APISETSP_H
|
||||
#define APISETSP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "apisets.h"
|
||||
|
||||
typedef struct _ROS_APISET
|
||||
{
|
||||
const UNICODE_STRING Name;
|
||||
const UNICODE_STRING Target;
|
||||
DWORD dwOsVersions;
|
||||
} ROS_APISET;
|
||||
|
||||
extern const ROS_APISET g_Apisets[];
|
||||
extern const LONG g_ApisetsCount;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // APISETSP_H
|
150
sdk/lib/apisets/update.py
Normal file
150
sdk/lib/apisets/update.py
Normal file
|
@ -0,0 +1,150 @@
|
|||
'''
|
||||
PROJECT: ReactOS apisets
|
||||
LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
PURPOSE: Create apiset lookup table based on the data files of https://apisets.info
|
||||
COPYRIGHT: Copyright 2024 Mark Jansen <mark.jansen@reactos.org>
|
||||
'''
|
||||
|
||||
from pathlib import Path
|
||||
from dataclasses import dataclass, field
|
||||
import sys
|
||||
import json
|
||||
|
||||
# These are modules we do not have, so redirect them to ones we do have.
|
||||
REDIRECT_HOSTS = {
|
||||
'kernelbase.dll': 'kernel32.dll',
|
||||
'kernel.appcore.dll': 'kernel32.dll',
|
||||
'combase.dll': 'ole32.dll',
|
||||
'ucrtbase.dll': 'msvcrt.dll',
|
||||
'shcore.dll': 'shell32.dll',
|
||||
'winmmbase.dll': 'winmm.dll',
|
||||
'gdi32full.dll': 'gdi32.dll'
|
||||
}
|
||||
|
||||
OUTPUT_HEADER = """/*
|
||||
* PROJECT: ReactOS apisets
|
||||
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
|
||||
* PURPOSE: Autogenerated table of all apisets
|
||||
* COPYRIGHT: Copyright 2024 Mark Jansen <mark.jansen@reactos.org>
|
||||
*/
|
||||
|
||||
#include <ndk/umtypes.h>
|
||||
#include <ndk/rtlfuncs.h>
|
||||
#include "apisetsp.h"
|
||||
|
||||
const ROS_APISET g_Apisets[] = {
|
||||
"""
|
||||
|
||||
OUTPUT_FOOTER = """};
|
||||
|
||||
const LONG g_ApisetsCount = RTL_NUMBER_OF(g_Apisets);
|
||||
"""
|
||||
|
||||
def winver_to_name(version):
|
||||
major, minor, build, _ = map(int, version.split('.'))
|
||||
if (major, minor) == (6, 1):
|
||||
return 'APISET_WIN7'
|
||||
if (major, minor) == (6, 2):
|
||||
return 'APISET_WIN8'
|
||||
if (major, minor) == (6, 3):
|
||||
return 'APISET_WIN81'
|
||||
if (major, minor) == (10, 0):
|
||||
if build < 22000:
|
||||
return 'APISET_WIN10'
|
||||
return 'APISET_WIN11'
|
||||
assert False, (major, minor, build)
|
||||
|
||||
@dataclass
|
||||
class Apiset:
|
||||
name: str
|
||||
host: str
|
||||
versions: list[str] = field(default_factory=list)
|
||||
|
||||
def add_version(self, version):
|
||||
if version not in self.versions:
|
||||
self.versions.append(version)
|
||||
|
||||
def __str__(self):
|
||||
version_str = ' | '.join(self.versions)
|
||||
name = self.name
|
||||
assert name[-4:].lower() == '.dll'
|
||||
name = name[:-4]
|
||||
prefix, postfix = '', ''
|
||||
host = self.host
|
||||
if host == '':
|
||||
# Disable forwarders that have an empty host
|
||||
prefix = '// '
|
||||
else:
|
||||
# Check to see if there is any dll we want to swap (kernelbase -> kernel32)
|
||||
replace = REDIRECT_HOSTS.get(host.lower(), None)
|
||||
if replace:
|
||||
postfix = ' // ' + host
|
||||
host = replace
|
||||
return f' {prefix}{{ RTL_CONSTANT_STRING(L"{name}"), RTL_CONSTANT_STRING(L"{host}"), {version_str} }},{postfix}'
|
||||
|
||||
|
||||
class ApisetSchema:
|
||||
def __init__(self, file):
|
||||
self._data = json.load(file.open())
|
||||
self.version = winver_to_name(self._data['PE']['ProductVersion'])
|
||||
self._arch = self._data['PE']['Machine']
|
||||
|
||||
def apisets(self):
|
||||
for elem in self._data['namespaces']:
|
||||
name = elem['name']
|
||||
host = elem['host']
|
||||
yield Apiset(name, host)
|
||||
|
||||
|
||||
class CombinedSchemas:
|
||||
def __init__(self):
|
||||
self._apisets = {}
|
||||
|
||||
def add(self, schema: ApisetSchema):
|
||||
for apiset in schema.apisets():
|
||||
lowername = apiset.name.lower()
|
||||
if lowername not in self._apisets:
|
||||
self._apisets[lowername] = apiset
|
||||
else:
|
||||
apiset = self._apisets[lowername]
|
||||
apiset.add_version(schema.version)
|
||||
|
||||
def generate(self, output):
|
||||
for key in sorted(self._apisets):
|
||||
apiset = self._apisets[key]
|
||||
output.write(f'{apiset}\n'.encode('utf-8'))
|
||||
|
||||
|
||||
def process_apisetschemas(input_dir: Path, output_file):
|
||||
schemas = CombinedSchemas()
|
||||
|
||||
for schemafile in input_dir.glob('*.json'):
|
||||
schema = ApisetSchema(schemafile)
|
||||
# Skip Win11 for now
|
||||
if schema.version != 'APISET_WIN11':
|
||||
schemas.add(schema)
|
||||
|
||||
output_file.write(OUTPUT_HEADER.encode('utf-8'))
|
||||
schemas.generate(output_file)
|
||||
output_file.write(OUTPUT_FOOTER.encode('utf-8'))
|
||||
|
||||
|
||||
def usage():
|
||||
print('Usage: update.py <apisetschema folder>')
|
||||
print(' where <apisetschema folder> is the folder with all apisetschema json files')
|
||||
|
||||
def main(args):
|
||||
if len(args) < 1:
|
||||
return usage()
|
||||
|
||||
apisetschemas = Path(args[0])
|
||||
if not apisetschemas.is_dir():
|
||||
return usage()
|
||||
|
||||
output = Path(__file__).parent / 'apisets.table.c'
|
||||
|
||||
process_apisetschemas(apisetschemas, output.open('wb'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
|
@ -5100,15 +5100,7 @@ void actctx_init(PVOID* pOldShimData)
|
|||
ctx.lpResourceName = NULL;
|
||||
ctx.lpSource = buffer;
|
||||
RtlStringCchCopyW(buffer, RTL_NUMBER_OF(buffer), SharedUserData->NtSystemRoot);
|
||||
|
||||
if (RosGetProcessCompatVersion())
|
||||
{
|
||||
RtlStringCchCatW(buffer, RTL_NUMBER_OF(buffer), L"\\winsxs\\manifests\\forwardcompatible.manifest");
|
||||
}
|
||||
else
|
||||
{
|
||||
RtlStringCchCatW(buffer, RTL_NUMBER_OF(buffer), L"\\winsxs\\manifests\\systemcompatible.manifest");
|
||||
}
|
||||
RtlStringCchCatW(buffer, RTL_NUMBER_OF(buffer), L"\\winsxs\\manifests\\systemcompatible.manifest");
|
||||
|
||||
Status = RtlCreateActivationContext(0, (PVOID)&ctx, 0, NULL, NULL, &handle);
|
||||
if (NT_SUCCESS(Status))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue