Implement some ActCtx functions for msvcr80.dll

This commit is contained in:
Luke Street 2025-10-05 15:52:38 -06:00
parent 5a2f8e2926
commit b87fb5e472
9 changed files with 437 additions and 1 deletions

View File

@ -221,6 +221,17 @@ if(BUILD_TESTING)
${CMAKE_CURRENT_SOURCE_DIR}/test/test_heap.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_actctx.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_actctx.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_actctx.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_actctx.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_overlapped_io.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
@ -310,6 +321,7 @@ if(BUILD_TESTING)
${WIBO_TEST_BIN_DIR}/test_resources.exe
${WIBO_TEST_BIN_DIR}/test_threading.exe
${WIBO_TEST_BIN_DIR}/test_heap.exe
${WIBO_TEST_BIN_DIR}/test_actctx.exe
${WIBO_TEST_BIN_DIR}/test_overlapped_io.exe
${WIBO_TEST_BIN_DIR}/test_time.exe
${WIBO_TEST_BIN_DIR}/test_virtualalloc.exe
@ -358,6 +370,12 @@ if(BUILD_TESTING)
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_actctx
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_actctx.exe)
set_tests_properties(wibo.test_actctx PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_overlapped_io
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_overlapped_io.exe)
set_tests_properties(wibo.test_overlapped_io PROPERTIES

View File

@ -246,6 +246,10 @@ void *resolveByName(const char *name) {
return (void *)kernel32::GetCurrentDirectoryA;
if (strcmp(name, "GetCurrentDirectoryW") == 0)
return (void *)kernel32::GetCurrentDirectoryW;
if (strcmp(name, "GetSystemWindowsDirectoryA") == 0)
return (void *)kernel32::GetSystemWindowsDirectoryA;
if (strcmp(name, "GetSystemWindowsDirectoryW") == 0)
return (void *)kernel32::GetSystemWindowsDirectoryW;
if (strcmp(name, "SetCurrentDirectoryA") == 0)
return (void *)kernel32::SetCurrentDirectoryA;
if (strcmp(name, "SetCurrentDirectoryW") == 0)
@ -264,6 +268,10 @@ void *resolveByName(const char *name) {
return (void *)kernel32::DecodePointer;
if (strcmp(name, "SetDllDirectoryA") == 0)
return (void *)kernel32::SetDllDirectoryA;
if (strcmp(name, "FindActCtxSectionStringA") == 0)
return (void *)kernel32::FindActCtxSectionStringA;
if (strcmp(name, "FindActCtxSectionStringW") == 0)
return (void *)kernel32::FindActCtxSectionStringW;
if (strcmp(name, "GetLongPathNameA") == 0)
return (void *)kernel32::GetLongPathNameA;
if (strcmp(name, "GetLongPathNameW") == 0)

View File

@ -312,7 +312,7 @@ BOOL WIN_FUNC HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) {
return FALSE;
}
if (!mi_heap_check_owned(record->heap, lpMem)) {
DEBUG_LOG("HeapFree: block %p not owned by heap %p\n", lpMem, record->heap);
DEBUG_LOG("-> INVALID_PARAMETER (not owned)\n");
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}

View File

@ -13,11 +13,13 @@
#include <cstdlib>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <limits>
#include <mimalloc.h>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
#include <sys/mman.h>
#include <sys/statvfs.h>
#include <system_error>
@ -298,7 +300,82 @@ constexpr DWORD kComputerNameRequiredSize = kComputerNameLength + 1;
constexpr const char kComputerNameAnsi[] = "COMPNAME";
const uint16_t kComputerNameWide[] = {u'C', u'O', u'M', u'P', u'N', u'A', u'M', u'E', 0};
struct DllRedirectionEntry {
std::string nameLower;
ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION dllData;
};
struct ActivationContext {
std::vector<DllRedirectionEntry> dllRedirections;
};
ActivationContext g_builtinActCtx;
ActivationContext *currentActivationContext() {
// TODO: hook into real activation context stack once we have it.
return &g_builtinActCtx;
}
} // namespace
void ensureDefaultActivationContext() {
static std::once_flag initFlag;
std::call_once(initFlag, [] {
ActivationContext *ctx = currentActivationContext();
auto addDll = [ctx](const std::string &name) {
DllRedirectionEntry entry;
entry.nameLower = stringToLower(name);
entry.dllData.Size = sizeof(entry.dllData);
entry.dllData.Flags = ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_OMITS_ASSEMBLY_ROOT;
entry.dllData.TotalPathLength = 0;
entry.dllData.PathSegmentCount = 0;
entry.dllData.PathSegmentOffset = 0;
ctx->dllRedirections.emplace_back(std::move(entry));
};
addDll("msvcr80.dll");
addDll("msvcp80.dll");
addDll("mfc80.dll");
addDll("mfc80u.dll");
addDll("msvcrt.dll");
});
}
constexpr const char kVc80ManifestName[] = "Microsoft.VC80.CRT.manifest";
void ensureVc80ManifestOnDisk(const DllRedirectionEntry &entry) {
static std::once_flag manifestOnce;
if (entry.nameLower != "msvcr80.dll") {
return;
}
std::call_once(manifestOnce, [] {
wibo::ModuleInfo *module = wibo::findLoadedModule("msvcr80.dll");
if (!module || module->resolvedPath.empty()) {
DEBUG_LOG("VC80 manifest: module not yet loaded, skipping creation\n");
return;
}
std::filesystem::path manifestPath = module->resolvedPath.parent_path() / kVc80ManifestName;
std::error_code ec;
if (std::filesystem::exists(manifestPath, ec)) {
return;
}
constexpr const char kManifestContents[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n"
" <assemblyIdentity type=\"win32\" name=\"Microsoft.VC80.CRT\" version=\"8.0.50727.762\" processorArchitecture=\"x86\" publicKeyToken=\"1fc8b3b9a1e18e3b\"/>\n"
" <file name=\"msvcr80.dll\"/>\n"
" <file name=\"msvcp80.dll\"/>\n"
" <file name=\"msvcm80.dll\"/>\n"
"</assembly>\n";
std::ofstream out(manifestPath, std::ios::binary);
if (!out) {
DEBUG_LOG("VC80 manifest: failed to create %s\n", manifestPath.string().c_str());
return;
}
out.write(kManifestContents, sizeof(kManifestContents) - 1);
if (!out) {
DEBUG_LOG("VC80 manifest: write error for %s\n", manifestPath.string().c_str());
}
});
}
namespace kernel32 {
@ -553,6 +630,90 @@ BOOL WIN_FUNC SetDllDirectoryA(LPCSTR lpPathName) {
return TRUE;
}
BOOL WIN_FUNC FindActCtxSectionStringA(DWORD dwFlags, const GUID *lpExtensionGuid, ULONG ulSectionId,
LPCSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData) {
DEBUG_LOG("FindActCtxSectionStringA(%#x, %p, %u, %s, %p)\n", dwFlags, lpExtensionGuid, ulSectionId,
lpStringToFind ? lpStringToFind : "<null>", ReturnedData);
std::vector<uint16_t> wideStorage;
if (lpStringToFind) {
size_t length = strlen(lpStringToFind);
wideStorage.resize(length + 1);
for (size_t i = 0; i <= length; ++i) {
wideStorage[i] = static_cast<uint8_t>(lpStringToFind[i]);
}
}
const uint16_t *widePtr = wideStorage.empty() ? nullptr : wideStorage.data();
return FindActCtxSectionStringW(dwFlags, lpExtensionGuid, ulSectionId,
reinterpret_cast<LPCWSTR>(widePtr), ReturnedData);
}
BOOL WIN_FUNC FindActCtxSectionStringW(DWORD dwFlags, const GUID *lpExtensionGuid, ULONG ulSectionId,
LPCWSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData) {
std::string lookup = lpStringToFind ? wideStringToString(lpStringToFind) : std::string();
DEBUG_LOG("FindActCtxSectionStringW(%#x, %p, %u, %s, %p)\n", dwFlags, lpExtensionGuid, ulSectionId,
lookup.c_str(), ReturnedData);
if (lpExtensionGuid) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
if (!ReturnedData) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
if (dwFlags & ~FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
ULONG originalSize = ReturnedData->cbSize;
if (originalSize < sizeof(ACTCTX_SECTION_KEYED_DATA)) {
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
ensureDefaultActivationContext();
ActivationContext *ctx = currentActivationContext();
const DllRedirectionEntry *matchedEntry = nullptr;
if (ulSectionId == ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION && !lookup.empty()) {
std::string lowerLookup = stringToLower(lookup);
for (const auto &entry : ctx->dllRedirections) {
if (entry.nameLower == lowerLookup) {
matchedEntry = &entry;
break;
}
}
}
size_t zeroSize = std::min(static_cast<size_t>(ReturnedData->cbSize), sizeof(*ReturnedData));
std::memset(ReturnedData, 0, zeroSize);
ReturnedData->cbSize = originalSize;
ReturnedData->ulDataFormatVersion = 1;
ReturnedData->ulFlags = ACTCTX_SECTION_KEYED_DATA_FLAG_FOUND_IN_ACTCTX;
if (dwFlags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX) {
ReturnedData->hActCtx = reinterpret_cast<HANDLE>(&g_builtinActCtx);
}
if (!matchedEntry) {
wibo::lastError = ERROR_SXS_KEY_NOT_FOUND;
return FALSE;
}
ensureVc80ManifestOnDisk(*matchedEntry);
ReturnedData->lpData = const_cast<ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION *>(&matchedEntry->dllData);
ReturnedData->ulLength = matchedEntry->dllData.Size;
ReturnedData->lpSectionBase = const_cast<ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION *>(&matchedEntry->dllData);
ReturnedData->ulSectionTotalLength = matchedEntry->dllData.Size;
ReturnedData->ulAssemblyRosterIndex = 1;
ReturnedData->AssemblyMetadata = {};
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
void tryMarkExecutable(void *mem) {
if (!mem) {
return;
@ -824,6 +985,27 @@ UINT WIN_FUNC GetWindowsDirectoryA(LPSTR lpBuffer, UINT uSize) {
return static_cast<UINT>(len);
}
UINT WIN_FUNC GetSystemWindowsDirectoryA(LPSTR lpBuffer, UINT uSize) {
DEBUG_LOG("GetSystemWindowsDirectoryA(%p, %u)\n", lpBuffer, uSize);
return GetWindowsDirectoryA(lpBuffer, uSize);
}
UINT WIN_FUNC GetSystemWindowsDirectoryW(LPWSTR lpBuffer, UINT uSize) {
DEBUG_LOG("GetSystemWindowsDirectoryW(%p, %u)\n", lpBuffer, uSize);
if (!lpBuffer) {
return 0;
}
const char *windowsDir = "C:\\Windows";
auto wide = stringToWideString(windowsDir);
UINT length = static_cast<UINT>(wide.size() - 1);
if (uSize < length + 1) {
return length + 1;
}
std::memcpy(lpBuffer, wide.data(), (length + 1) * sizeof(uint16_t));
return length;
}
DWORD WIN_FUNC GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetCurrentDirectoryA(%u, %p)\n", nBufferLength, lpBuffer);

View File

@ -4,6 +4,61 @@
#include <cstdarg>
struct GUID;
struct ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA {
PVOID lpInformation;
PVOID lpSectionBase;
ULONG ulSectionLength;
PVOID lpSectionGlobalData;
ULONG ulSectionGlobalDataLength;
};
struct ACTCTX_SECTION_KEYED_DATA {
ULONG cbSize;
ULONG ulDataFormatVersion;
PVOID lpData;
ULONG ulLength;
PVOID lpSectionGlobalData;
ULONG ulSectionGlobalDataLength;
PVOID lpSectionBase;
ULONG ulSectionTotalLength;
HANDLE hActCtx;
ULONG ulAssemblyRosterIndex;
ULONG ulFlags;
ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA AssemblyMetadata;
};
using PACTCTX_SECTION_KEYED_DATA = ACTCTX_SECTION_KEYED_DATA *;
using PCACTCTX_SECTION_KEYED_DATA = const ACTCTX_SECTION_KEYED_DATA *;
constexpr DWORD FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX = 0x00000001;
constexpr ULONG ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION = 1;
constexpr ULONG ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION = 2;
constexpr ULONG ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION = 3;
constexpr ULONG ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION = 7;
constexpr ULONG ACTCTX_SECTION_KEYED_DATA_FLAG_FOUND_IN_ACTCTX = 0x00000001;
constexpr ULONG ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_INCLUDES_BASE_NAME = 1;
constexpr ULONG ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_OMITS_ASSEMBLY_ROOT = 2;
constexpr ULONG ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_EXPAND = 4;
constexpr ULONG ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_SYSTEM_DEFAULT_REDIRECTED_SYSTEM32_DLL = 8;
struct ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION {
ULONG Size;
ULONG Flags;
ULONG TotalPathLength;
ULONG PathSegmentCount;
ULONG PathSegmentOffset;
};
struct ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_SEGMENT {
ULONG Length;
ULONG Offset;
};
namespace kernel32 {
BOOL WIN_FUNC IsBadReadPtr(LPCVOID lp, UINT_PTR ucb);
@ -21,6 +76,11 @@ PVOID WIN_FUNC EncodePointer(PVOID Ptr);
PVOID WIN_FUNC DecodePointer(PVOID Ptr);
BOOL WIN_FUNC SetDllDirectoryA(LPCSTR lpPathName);
BOOL WIN_FUNC FindActCtxSectionStringA(DWORD dwFlags, const GUID *lpExtensionGuid, ULONG ulSectionId,
LPCSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData);
BOOL WIN_FUNC FindActCtxSectionStringW(DWORD dwFlags, const GUID *lpExtensionGuid, ULONG ulSectionId,
LPCWSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData);
BOOL WIN_FUNC GetComputerNameA(LPSTR lpBuffer, LPDWORD nSize);
BOOL WIN_FUNC GetComputerNameW(LPWSTR lpBuffer, LPDWORD nSize);
@ -43,6 +103,8 @@ UINT WIN_FUNC GetSystemDirectoryW(LPWSTR lpBuffer, UINT uSize);
UINT WIN_FUNC GetSystemWow64DirectoryA(LPSTR lpBuffer, UINT uSize);
UINT WIN_FUNC GetSystemWow64DirectoryW(LPWSTR lpBuffer, UINT uSize);
UINT WIN_FUNC GetWindowsDirectoryA(LPSTR lpBuffer, UINT uSize);
UINT WIN_FUNC GetSystemWindowsDirectoryA(LPSTR lpBuffer, UINT uSize);
UINT WIN_FUNC GetSystemWindowsDirectoryW(LPWSTR lpBuffer, UINT uSize);
DWORD WIN_FUNC GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer);
DWORD WIN_FUNC GetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer);
int WIN_FUNC SetCurrentDirectoryA(LPCSTR lpPathName);

View File

@ -5,6 +5,14 @@
namespace user32 {
constexpr uint32_t RT_STRING_ID = 6;
constexpr uintptr_t kDefaultKeyboardLayout = 0x04090409;
constexpr int UOI_FLAGS = 1;
constexpr DWORD WSF_VISIBLE = 0x0001;
struct USEROBJECTFLAGS {
BOOL fInherit;
BOOL fReserved;
DWORD dwFlags;
};
int WIN_FUNC LoadStringA(void* hInstance, unsigned int uID, char* lpBuffer, int cchBufferMax) {
HOST_CONTEXT_GUARD();
@ -122,6 +130,48 @@ namespace user32 {
wibo::lastError = ERROR_SUCCESS;
return reinterpret_cast<HKL>(kDefaultKeyboardLayout);
}
HWINSTA WIN_FUNC GetProcessWindowStation() {
DEBUG_LOG("GetProcessWindowStation()\n");
static int kWindowStationStub;
wibo::lastError = ERROR_SUCCESS;
return reinterpret_cast<HWINSTA>(&kWindowStationStub);
}
BOOL WIN_FUNC GetUserObjectInformationA(HANDLE hObj, int nIndex, PVOID pvInfo, DWORD nLength,
LPDWORD lpnLengthNeeded) {
DEBUG_LOG("GetUserObjectInformationA(%p, %d, %p, %u, %p)\n", hObj, nIndex, pvInfo, nLength,
lpnLengthNeeded);
(void)hObj;
if (lpnLengthNeeded) {
*lpnLengthNeeded = sizeof(USEROBJECTFLAGS);
}
if (nIndex != UOI_FLAGS) {
wibo::lastError = ERROR_CALL_NOT_IMPLEMENTED;
return FALSE;
}
if (!pvInfo || nLength < sizeof(USEROBJECTFLAGS)) {
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
auto *flags = reinterpret_cast<USEROBJECTFLAGS *>(pvInfo);
flags->fInherit = FALSE;
flags->fReserved = FALSE;
flags->dwFlags = WSF_VISIBLE;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
HWND WIN_FUNC GetActiveWindow() {
DEBUG_LOG("GetActiveWindow()\n");
wibo::lastError = ERROR_SUCCESS;
return nullptr;
}
}
@ -130,6 +180,9 @@ static void *resolveByName(const char *name) {
if (strcmp(name, "LoadStringW") == 0) return (void *) user32::LoadStringW;
if (strcmp(name, "MessageBoxA") == 0) return (void *) user32::MessageBoxA;
if (strcmp(name, "GetKeyboardLayout") == 0) return (void *) user32::GetKeyboardLayout;
if (strcmp(name, "GetProcessWindowStation") == 0) return (void *) user32::GetProcessWindowStation;
if (strcmp(name, "GetUserObjectInformationA") == 0) return (void *) user32::GetUserObjectInformationA;
if (strcmp(name, "GetActiveWindow") == 0) return (void *) user32::GetActiveWindow;
return nullptr;
}

View File

@ -98,6 +98,8 @@ using REGSAM = DWORD;
using LSTATUS = LONG;
using LCID = DWORD;
using LCTYPE = DWORD;
using HWINSTA = HANDLE;
using HWND = HANDLE;
constexpr BOOL TRUE = 1;
constexpr BOOL FALSE = 0;

View File

@ -39,6 +39,7 @@
#define ERROR_NOT_OWNER 288
#define ERROR_TOO_MANY_POSTS 298
#define ERROR_SEM_TIMEOUT 121
#define ERROR_SXS_KEY_NOT_FOUND 14007
#define INVALID_SET_FILE_POINTER ((DWORD) - 1)
#define INVALID_HANDLE_VALUE ((HANDLE) - 1)

110
test/test_actctx.c Normal file
View File

@ -0,0 +1,110 @@
#include <windows.h>
#include "test_assert.h"
#ifndef ACTCTX_SECTION_KEYED_DATA_FLAG_FOUND_IN_ACTCTX
#define ACTCTX_SECTION_KEYED_DATA_FLAG_FOUND_IN_ACTCTX 0x00000001
#endif
#ifndef ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION
typedef struct _ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION {
ULONG Size;
ULONG Flags;
ULONG TotalPathLength;
ULONG PathSegmentCount;
ULONG PathSegmentOffset;
} ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION;
#endif
static BOOL isRunningUnderWine(void) {
HMODULE hNtdll = GetModuleHandleW(L"ntdll.dll");
return hNtdll != NULL && GetProcAddress(hNtdll, "wine_get_version") != NULL;
}
static void check_success_w(void) {
ACTCTX_SECTION_KEYED_DATA data = { 0 };
data.cbSize = sizeof(data);
SetLastError(0);
BOOL ok = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
L"msvcr80.dll", &data);
TEST_CHECK(ok);
TEST_CHECK_EQ(ERROR_SUCCESS, GetLastError());
TEST_CHECK_EQ(1u, data.ulDataFormatVersion);
TEST_CHECK((data.ulFlags & ACTCTX_SECTION_KEYED_DATA_FLAG_FOUND_IN_ACTCTX) != 0);
TEST_CHECK(data.lpData != NULL);
TEST_CHECK(data.ulLength >= sizeof(ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION));
TEST_CHECK(data.hActCtx == NULL);
TEST_CHECK_EQ(1u, data.ulAssemblyRosterIndex);
}
static void check_success_a(void) {
ACTCTX_SECTION_KEYED_DATA data = { 0 };
data.cbSize = sizeof(data);
SetLastError(0);
BOOL ok = FindActCtxSectionStringA(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
"msvcp80.dll", &data);
TEST_CHECK(ok);
TEST_CHECK_EQ(ERROR_SUCCESS, GetLastError());
TEST_CHECK((data.ulFlags & ACTCTX_SECTION_KEYED_DATA_FLAG_FOUND_IN_ACTCTX) != 0);
TEST_CHECK(data.lpData != NULL);
TEST_CHECK(data.hActCtx != NULL);
TEST_CHECK_EQ(1u, data.ulAssemblyRosterIndex);
}
static void check_invalid_parameters(void) {
ACTCTX_SECTION_KEYED_DATA data = { 0 };
data.cbSize = sizeof(data);
GUID fakeGuid = {0};
SetLastError(0);
BOOL ok = FindActCtxSectionStringW(0, &fakeGuid, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
L"msvcr80.dll", &data);
TEST_CHECK(!ok);
TEST_CHECK_EQ(ERROR_INVALID_PARAMETER, GetLastError());
ACTCTX_SECTION_KEYED_DATA sized = { 0 };
sized.cbSize = sizeof(data) - 4;
SetLastError(0);
ok = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
L"msvcr80.dll", &sized);
TEST_CHECK(!ok);
TEST_CHECK_EQ(ERROR_INSUFFICIENT_BUFFER, GetLastError());
ACTCTX_SECTION_KEYED_DATA flags = { 0 };
flags.cbSize = sizeof(flags);
SetLastError(0);
ok = FindActCtxSectionStringW(0x2, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
L"msvcr80.dll", &flags);
TEST_CHECK(!ok);
TEST_CHECK_EQ(ERROR_INVALID_PARAMETER, GetLastError());
}
static void check_missing_entries(void) {
ACTCTX_SECTION_KEYED_DATA data = { 0 };
data.cbSize = sizeof(data);
SetLastError(0);
BOOL ok = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
L"totally_missing.dll", &data);
TEST_CHECK(!ok);
TEST_CHECK_EQ(ERROR_SXS_KEY_NOT_FOUND, GetLastError());
ACTCTX_SECTION_KEYED_DATA wrongSection = { 0 };
wrongSection.cbSize = sizeof(wrongSection);
SetLastError(0);
ok = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION,
L"msvcr80.dll", &wrongSection);
TEST_CHECK(!ok);
TEST_CHECK_EQ(ERROR_SXS_KEY_NOT_FOUND, GetLastError());
}
int main(void) {
if (isRunningUnderWine()) {
printf("test_actctx: skipping under wine\n");
return 0;
}
check_success_w();
check_success_a();
check_invalid_parameters();
check_missing_entries();
return 0;
}