Index: winetests/apphelp/CMakeLists.txt =================================================================== --- winetests/apphelp/CMakeLists.txt (revision 0) +++ winetests/apphelp/CMakeLists.txt (working copy) @@ -0,0 +1,10 @@ + +list(APPEND SOURCE + testlist.c + layerapi.c + ) + +add_executable(apphelp_winetest ${SOURCE}) +set_module_type(apphelp_winetest win32cui) +add_importlibs(apphelp_winetest advapi32 msvcrt kernel32 ntdll) +add_cd_file(TARGET apphelp_winetest DESTINATION reactos/bin FOR all) Index: winetests/apphelp/layerapi.c =================================================================== --- winetests/apphelp/layerapi.c (revision 0) +++ winetests/apphelp/layerapi.c (working copy) @@ -0,0 +1,780 @@ +/* + * Copyright 2015 Mark Jansen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#define WIN32_NO_STATUS +#include +#include +#ifdef __REACTOS__ +#include +#else +#include +#endif +#include +#include + +#include "wine/test.h" + + +#define GPLK_USER 1 +#define GPLK_MACHINE 2 +#define MAX_LAYER_LENGTH 256 +#define LAYER_APPLY_TO_SYSTEM_EXES 1 + + +static HMODULE hdll; +static BOOL(WINAPI *pAllowPermLayer)(PCWSTR path); +static BOOL(WINAPI *pSdbSetPermLayerKeys)(PCWSTR wszPath, PCWSTR wszLayers, BOOL bMachine); +static BOOL(WINAPI *pSdbGetPermLayerKeys)(PCWSTR wszPath, PWSTR pwszLayers, PDWORD pdwBytes, DWORD dwFlags); +static BOOL(WINAPI *pSetPermLayerState)(PCWSTR wszPath, PCWSTR wszLayer, DWORD dwFlags, BOOL bMachine, BOOL bEnable); + + +/* Helper function to disable Wow64 redirection on an os that reports it being enabled. */ +static DWORD g_QueryFlag = 0xffffffff; +static DWORD QueryFlag(void) +{ + if (g_QueryFlag == 0xffffffff) + { + ULONG_PTR pbi = { 0 }; + NTSTATUS hr = NtQueryInformationProcess(NtCurrentProcess(), ProcessWow64Information, &pbi, sizeof(pbi), NULL); + g_QueryFlag = (SUCCEEDED(hr) && pbi != 0) ? KEY_WOW64_64KEY : 0; + } + return g_QueryFlag; +} + +/* Helper function to prepare the registry key with a value. */ +static BOOL setLayerValue(BOOL bMachine, const char* valueName, const char* value) +{ + HKEY key = NULL; + LSTATUS lstatus = RegCreateKeyExA(bMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers", 0, NULL, 0, QueryFlag() | KEY_SET_VALUE, NULL, &key, NULL); + if (lstatus == ERROR_SUCCESS) + { + if (value) + lstatus = RegSetValueExA(key, valueName, 0, REG_SZ, (const BYTE*)value, strlen(value)+1); + else + { + lstatus = RegDeleteValueA(key, valueName); + lstatus = (lstatus == ERROR_FILE_NOT_FOUND ? ERROR_SUCCESS : lstatus); + } + } + RegCloseKey(key); + return lstatus == ERROR_SUCCESS; +} + + +static void expect_LayerValue_imp(BOOL bMachine, const char* valueName, const char* value) +{ + HKEY key = NULL; + LSTATUS lstatus = RegCreateKeyExA(bMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers", 0, NULL, 0, QueryFlag() | KEY_QUERY_VALUE, NULL, &key, NULL); + winetest_ok(lstatus == ERROR_SUCCESS, "Expected to be able to open a registry key\n"); + if (lstatus == ERROR_SUCCESS) + { + char data[512] = { 0 }; + DWORD dwType = 0; + DWORD dwDataLen = sizeof(data); + lstatus = RegQueryValueExA(key, valueName, NULL, &dwType, (LPBYTE)data, &dwDataLen); + if (value) + { + winetest_ok(lstatus == ERROR_SUCCESS, "Expected to get a valid value, err: %u\n", lstatus); + if (lstatus == ERROR_SUCCESS) + { + winetest_ok(dwType == REG_SZ, "Expected the type to be REG_SZ, was: %u\n", dwType); + winetest_ok(!strcmp(data, value), "Expected the data to be: '%s', was: '%s'\n", value, data); + } + } + else + { + winetest_ok(lstatus == ERROR_FILE_NOT_FOUND, "Expected not to find the value %s\n", valueName); + } + } + RegCloseKey(key); +} + +void expect_Sdb_imp(PCSTR path, DWORD type, BOOL result, DWORD lenResult, PCSTR stringResult) +{ + WCHAR pathW[MAX_PATH], buffer[MAX_LAYER_LENGTH] = { 0 }; + char resultBuffer[MAX_LAYER_LENGTH] = { 0 }; + DWORD dwBufSize = sizeof(buffer); + + /* In case of a failure, the buffer size is not touched. */ + if (lenResult == 0xffffffff) + lenResult = dwBufSize; + + MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, MAX_PATH); + + winetest_ok(pSdbGetPermLayerKeys(pathW, buffer, &dwBufSize, type) == result, "Expected pSdbGetPermLayerKeys to %s\n", (result ? "succeed" : "fail")); + winetest_ok(dwBufSize == lenResult, "Expected dwBufSize to be %u, was %u\n", lenResult, dwBufSize); + if (result) + { + winetest_ok(lstrlenW(buffer) * 2 + 2 == lenResult, "Expected lstrlenW(buffer)*2+2 to be %u, was %u\n", lenResult, lstrlenW(buffer) * 2 + 2); + } + WideCharToMultiByte(CP_ACP, 0, buffer, -1, resultBuffer, sizeof(resultBuffer), NULL, NULL); + winetest_ok(!strcmp(stringResult, resultBuffer), "Expected the result to be '%s', was '%s'\n", stringResult, resultBuffer); +} + + +/* In case of a failure, let the location be from where the function was invoked, not inside the function itself. */ +#define expect_Sdb (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_Sdb_imp +#define expect_LayerValue (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_LayerValue_imp + + +BOOL wrapAllowPermLayer(const char* str) +{ + WCHAR buf[100]; + MultiByteToWideChar(CP_ACP, 0, str, -1, buf, 100); + return pAllowPermLayer(buf); +} + +/* Brute forcing all ascii chars in the first 2 places seems to indicate that all it cares for is: + - Second char has to be a ':' + if it's not a ':', display a diagnostic message (and a different one for '\\'). + - First char does not really matter, as long as it's not on a DRIVE_REMOTE (but, according to the logging this is meant to check for a CDROM drive...) +*/ +static void test_AllowPermLayer(void) +{ + char buf[20]; + char tmp1; + UINT drivetype = 0; + ok(pAllowPermLayer(NULL) == FALSE, "Expected AllowPermLayer to fail for NULL\n"); + ok(wrapAllowPermLayer("-:"), "Expected AllowPermLayer to succeed\n"); + ok(wrapAllowPermLayer("@:"), "Expected AllowPermLayer to succeed\n"); + ok(wrapAllowPermLayer("4:"), "Expected AllowPermLayer to succeed\n"); + ok(wrapAllowPermLayer("*:"), "Expected AllowPermLayer to succeed\n"); + ok(wrapAllowPermLayer("*a") == FALSE, "Expected AllowPermLayer to fail\n"); + ok(wrapAllowPermLayer("*\\") == FALSE, "Expected AllowPermLayer to fail\n"); + for (tmp1 = 'a'; tmp1 <= 'z'; ++tmp1) + { + sprintf(buf, "%c:\\", tmp1); + drivetype = GetDriveTypeA(buf); + ok(wrapAllowPermLayer(buf) == (drivetype != DRIVE_REMOTE), "Expected AllowPermLayer to be %d for %c:\\\n", (drivetype != DRIVE_REMOTE), tmp1); + } +} + +static BOOL wrapSdbSetPermLayerKeys(PCWSTR wszPath, PCSTR szLayers, BOOL bMachine) +{ + WCHAR wszLayers[MAX_LAYER_LENGTH]; + MultiByteToWideChar(CP_ACP, 0, szLayers, -1, wszLayers, MAX_LAYER_LENGTH); + return pSdbSetPermLayerKeys(wszPath, wszLayers, bMachine); +} + +static void test_SdbSetPermLayerKeysLevel(BOOL bMachine, const char* file) +{ + WCHAR fileW[MAX_PATH+20]; + WCHAR emptyString[1] = { 0 }; + + MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, MAX_PATH+20); + + /* Test some parameter validation. */ + ok(pSdbSetPermLayerKeys(NULL, NULL, bMachine) == FALSE, "Expected SdbSetPermLayerKeys to fail\n"); + ok(pSdbSetPermLayerKeys(NULL, emptyString, bMachine) == FALSE, "Expected SdbSetPermLayerKeys to fail\n"); + ok(pSdbSetPermLayerKeys(emptyString, emptyString, bMachine) == FALSE, "Expected SdbSetPermLayerKeys to fail\n"); + ok(pSdbSetPermLayerKeys(fileW, NULL, bMachine) == TRUE, "Expected SdbSetPermLayerKeys to succeed\n"); + ok(pSdbSetPermLayerKeys(fileW, emptyString, bMachine) == TRUE, "Expected SdbSetPermLayerKeys to fail\n"); + + /* Basic tests */ + ok(wrapSdbSetPermLayerKeys(fileW, "TEST1", bMachine), "Expected SdbSetPermLayerKeys to succeed\n"); + expect_LayerValue(bMachine, file, "TEST1"); + + ok(wrapSdbSetPermLayerKeys(fileW, "TEST1 TEST2", bMachine), "Expected SdbSetPermLayerKeys to succeed\n"); + expect_LayerValue(bMachine, file, "TEST1 TEST2"); + + /* SdbSetPermLayerKeys does not do any validation of the value passed in. */ + ok(wrapSdbSetPermLayerKeys(fileW, "!#$% TEST1 TEST2", bMachine), "Expected SdbSetPermLayerKeys to succeed\n"); + expect_LayerValue(bMachine, file, "!#$% TEST1 TEST2"); + + ok(wrapSdbSetPermLayerKeys(fileW, "!#$% TEST1 TEST2", bMachine), "Expected SdbSetPermLayerKeys to succeed\n"); + expect_LayerValue(bMachine, file, "!#$% TEST1 TEST2"); + + ok(pSdbSetPermLayerKeys(fileW, NULL, bMachine) == TRUE, "Expected SdbSetPermLayerKeys to succeed\n"); + expect_LayerValue(bMachine, file, NULL); + + ok(wrapSdbSetPermLayerKeys(fileW, " ", bMachine), "Expected SdbSetPermLayerKeys to succeed\n"); + expect_LayerValue(bMachine, file, " "); + + ok(pSdbSetPermLayerKeys(fileW, NULL, bMachine) == TRUE, "Expected SdbSetPermLayerKeys to fail\n"); + expect_LayerValue(bMachine, file, NULL); +} + +static void test_SdbGetPermLayerKeys(void) +{ + WCHAR pathW[MAX_PATH], buffer[MAX_LAYER_LENGTH] = { 0 }; + char file[MAX_PATH + 20], tmp[MAX_PATH + 20]; + BOOL bUser, bMachine; + HANDLE hfile; + DWORD dwBufSize = sizeof(buffer); + + GetTempPathA(MAX_PATH, tmp); + GetLongPathNameA(tmp, file, sizeof(FILE)); + strcpy(tmp, file); + strcat(file, "test_file.exe"); + strcat(tmp, "notexist.exe"); + + /* Check that we can access the keys */ + bUser = setLayerValue(FALSE, file, "RUNASADMIN WINXPSP3"); + expect_LayerValue(FALSE, file, "RUNASADMIN WINXPSP3"); + ok(bUser, "Expected to be able to set atleast the flags for the user\n"); + if (!bUser) + { + skip("Cannot do any tests if i cannot set some values\n"); + return; + } + bMachine = setLayerValue(TRUE, file, "WINXPSP3 WINXPSP2"); + if (bMachine) + { + expect_LayerValue(TRUE, file, "WINXPSP3 WINXPSP2"); + } + + + hfile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(hfile != INVALID_HANDLE_VALUE, "CreateFile failed..\n"); + if (hfile == INVALID_HANDLE_VALUE) + { + skip("Running these tests is useless without a file present\n"); + return; + } + CloseHandle(hfile); + + MultiByteToWideChar(CP_ACP, 0, file, -1, pathW, MAX_PATH); + + /* Parameter validation */ + ok(pSdbGetPermLayerKeys(NULL, NULL, NULL, 0) == FALSE, "Expected pSdbGetPermLayerKeys to fail\n"); + ok(pSdbGetPermLayerKeys(pathW, NULL, NULL, 0) == FALSE, "Expected pSdbGetPermLayerKeys to fail\n"); + ok(pSdbGetPermLayerKeys(pathW, buffer, NULL, 0) == FALSE, "Expected pSdbGetPermLayerKeys to fail\n"); + ok(pSdbGetPermLayerKeys(pathW, buffer, &dwBufSize, 0) == FALSE, "Expected pSdbGetPermLayerKeys to fail\n"); + ok(dwBufSize == 0, "Expected dwBufSize to be %u, was %u\n", 0, dwBufSize); + + /* It fails on a nonexisting file */ + expect_Sdb(tmp, GPLK_USER | GPLK_MACHINE, FALSE, 0xffffffff, ""); + expect_Sdb(file, GPLK_USER, TRUE, 40, "RUNASADMIN WINXPSP3"); + GetShortPathNameA(file, tmp, sizeof(tmp)); + expect_Sdb(tmp, GPLK_USER, TRUE, 40, "RUNASADMIN WINXPSP3"); + + if (bMachine) + { + /* Query from HKLM */ + expect_Sdb(file, GPLK_MACHINE, TRUE, 36, "WINXPSP3 WINXPSP2"); + /* Query from both, showing that duplicates are not removed */ + expect_Sdb(file, GPLK_USER | GPLK_MACHINE, TRUE, 76, "WINXPSP3 WINXPSP2 RUNASADMIN WINXPSP3"); + + /* Showing that no validation is done on the value read. */ + ok(setLayerValue(TRUE, file, "!#!# WINXPSP3 WINXPSP3 !# WINXPSP2 "), "Expected setLayerValue not to fail\n"); + expect_Sdb(file, GPLK_MACHINE, TRUE, 82, "!#!# WINXPSP3 WINXPSP3 !# WINXPSP2 "); + /* Showing that a space is inserted, even if the last char was already a space. */ + expect_Sdb(file, GPLK_USER | GPLK_MACHINE, TRUE, 122, "!#!# WINXPSP3 WINXPSP3 !# WINXPSP2 RUNASADMIN WINXPSP3"); + /* Now clear the user key */ + setLayerValue(FALSE, file, NULL); + /* Request both, to show that the last space (from the key) is not cut off. */ + expect_Sdb(file, GPLK_USER | GPLK_MACHINE, TRUE, 82, "!#!# WINXPSP3 WINXPSP3 !# WINXPSP2 "); + setLayerValue(FALSE, file, "RUNASADMIN WINXPSP3"); + } + else + { + skip("Skipping tests for HKLM, cannot alter the registry\n"); + } + /* Fail from these paths */ + sprintf(tmp, "\\?\\%s", file); + expect_Sdb(tmp, GPLK_USER, FALSE, 0xffffffff, ""); + sprintf(tmp, "\\??\\%s", file); + expect_Sdb(tmp, GPLK_USER, FALSE, 0xffffffff, ""); + + ok(setLayerValue(FALSE, file, "!#!# RUNASADMIN RUNASADMIN !# WINXPSP3 "), "Expected setLayerValue not to fail\n"); + /* There is no validation on information read back. */ + expect_Sdb(file, GPLK_USER, TRUE, 90, "!#!# RUNASADMIN RUNASADMIN !# WINXPSP3 "); + + + /* Cleanup */ + ok(DeleteFileA(file), "DeleteFile failed....\n"); + setLayerValue(FALSE, file, NULL); + setLayerValue(TRUE, file, NULL); +} + + +static BOOL wrapSetPermLayerState(PCWSTR wszPath, PCSTR szLayer, DWORD dwFlags, BOOL bMachine, BOOL bEnable) +{ + WCHAR wszLayer[MAX_LAYER_LENGTH]; + MultiByteToWideChar(CP_ACP, 0, szLayer, -1, wszLayer, MAX_LAYER_LENGTH); + return pSetPermLayerState(wszPath, wszLayer, dwFlags, bMachine, bEnable); +} + +static void test_SetPermLayerStateLevel(BOOL bMachine, const char* file) +{ + WCHAR fileW[MAX_PATH+20]; + WCHAR emptyString[1] = { 0 }; + DWORD dwFlag; + + MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, MAX_PATH+20); + + /* Test some parameter validation. */ + ok(pSetPermLayerState(fileW, NULL, 0, bMachine, 0) == FALSE, "Expected SetPermLayerState to fail\n"); + expect_LayerValue(bMachine, file, NULL); + + ok(pSetPermLayerState(fileW, NULL, 0, bMachine, 1) == FALSE, "Expected SetPermLayerState to fail\n"); + expect_LayerValue(bMachine, file, NULL); + + ok(wrapSetPermLayerState(fileW, "", 0, bMachine, 0) == TRUE, "Expected SetPermLayerState to succeed\n"); + expect_LayerValue(bMachine, file, NULL); + + ok(wrapSetPermLayerState(fileW, "", 0, bMachine, 1) == TRUE, "Expected SetPermLayerState to succeed\n"); + expect_LayerValue(bMachine, file, NULL); + + ok(wrapSetPermLayerState(NULL, NULL, 0, bMachine, 0) == FALSE, "Expected SetPermLayerState to fail\n"); + expect_LayerValue(bMachine, NULL, NULL); + + ok(wrapSetPermLayerState(NULL, NULL, 0, bMachine, 1) == FALSE, "Expected SetPermLayerState to fail\n"); + expect_LayerValue(bMachine, NULL, NULL); + + ok(wrapSetPermLayerState(emptyString, "", 0, bMachine, 0) == FALSE, "Expected SetPermLayerState to fail\n"); + expect_LayerValue(bMachine, NULL, NULL); + + ok(wrapSetPermLayerState(emptyString, "", 0, bMachine, 1) == FALSE, "Expected SetPermLayerState to fail\n"); + expect_LayerValue(bMachine, NULL, NULL); + + ok(wrapSetPermLayerState(emptyString, "TEST", 0, bMachine, 0) == FALSE, "Expected SetPermLayerState to fail\n"); + expect_LayerValue(bMachine, NULL, NULL); + + ok(wrapSetPermLayerState(emptyString, "TEST", 0, bMachine, 1) == FALSE, "Expected SetPermLayerState to fail\n"); + expect_LayerValue(bMachine, NULL, NULL); + + + /* Now, on to the actual tests. */ + expect_LayerValue(bMachine, file, NULL); + ok(wrapSetPermLayerState(fileW, "TEST", 0, bMachine, 0) == TRUE, "Expected SetPermLayerState to succeed\n"); + expect_LayerValue(bMachine, file, NULL); + + ok(wrapSetPermLayerState(fileW, "TEST", 0, bMachine, 1) == TRUE, "Expected SetPermLayerState to succeed\n"); + expect_LayerValue(bMachine, file, "TEST"); + + ok(wrapSetPermLayerState(fileW, "", 0, bMachine, 1) == TRUE, "Expected SetPermLayerState to succeed\n"); + expect_LayerValue(bMachine, file, "TEST"); + + ok(wrapSetPermLayerState(fileW, "test", 0, bMachine, 1) == TRUE, "Expected SetPermLayerState to succeed\n"); + expect_LayerValue(bMachine, file, "test"); + + ok(wrapSetPermLayerState(fileW, "TEST", 0, bMachine, 0) == TRUE, "Expected SetPermLayerState to succeed\n"); + expect_LayerValue(bMachine, file, NULL); + + ok(wrapSetPermLayerState(fileW, "TEST", 0, bMachine, 1) == TRUE, "Expected SetPermLayerState to succeed\n"); + expect_LayerValue(bMachine, file, "TEST"); + + ok(wrapSetPermLayerState(fileW, "TEST1", 0, bMachine, 1) == TRUE, "Expected SetPermLayerState to succeed\n"); + expect_LayerValue(bMachine, file, "TEST TEST1"); + + ok(wrapSetPermLayerState(fileW, "TEST2", 0, bMachine, 1) == TRUE, "Expected SetPermLayerState to succeed\n"); + expect_LayerValue(bMachine, file, "TEST TEST1 TEST2"); + + ok(wrapSetPermLayerState(fileW, "TEST1", 0, bMachine, 0) == TRUE, "Expected SetPermLayerState to succeed\n"); + expect_LayerValue(bMachine, file, "TEST TEST2"); + + ok(wrapSetPermLayerState(fileW, "TEST", 0, bMachine, 0) == TRUE, "Expected SetPermLayerState to succeed\n"); + expect_LayerValue(bMachine, file, "TEST2"); + + ok(wrapSetPermLayerState(fileW, "TEST2", 0, bMachine, 0) == TRUE, "Expected SetPermLayerState to succeed\n"); + expect_LayerValue(bMachine, file, NULL); + + /* Key is empty, now play around with the flags. */ + for (dwFlag = 2; dwFlag < 32; ++dwFlag) + { + ok(wrapSetPermLayerState(fileW, "TEST", (1<Name && ImportDescriptor->OriginalFirstThunk) + { + PCHAR Name = (PCHAR)(DllBase + ImportDescriptor->Name); + if (!lstrcmpiA(Name, DllName)) + { + return ImportDescriptor; + } + ImportDescriptor++; + } + return NULL; +} + +static BOOL RedirectIat(PCSTR TargetDllName, PCSTR DllName, PCSTR FunctionName, ULONG_PTR NewFunction, ULONG_PTR* OriginalFunction) +{ + PBYTE DllBase = (PBYTE)GetModuleHandleA(TargetDllName); + if (DllBase) + { + PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor = FindImportDescriptor(DllBase, DllName); + if (ImportDescriptor) + { + // On loaded images, OriginalFirstThunk points to the name / ordinal of the function + PIMAGE_THUNK_DATA OriginalThunk = (PIMAGE_THUNK_DATA)(DllBase + ImportDescriptor->OriginalFirstThunk); + // FirstThunk points to the resolved address. + PIMAGE_THUNK_DATA FirstThunk = (PIMAGE_THUNK_DATA)(DllBase + ImportDescriptor->FirstThunk); + while (OriginalThunk->u1.AddressOfData && FirstThunk->u1.Function) + { + if (!IMAGE_SNAP_BY_ORDINAL32(OriginalThunk->u1.AddressOfData)) + { + PIMAGE_IMPORT_BY_NAME ImportName = (PIMAGE_IMPORT_BY_NAME)(DllBase + OriginalThunk->u1.AddressOfData); + if (!lstrcmpiA((PCSTR)ImportName->Name, FunctionName)) + { + DWORD dwOld; + VirtualProtect(&FirstThunk->u1.Function, sizeof(ULONG_PTR), PAGE_EXECUTE_READWRITE, &dwOld); + *OriginalFunction = FirstThunk->u1.Function; + FirstThunk->u1.Function = NewFunction; + VirtualProtect(&FirstThunk->u1.Function, sizeof(ULONG_PTR), dwOld, &dwOld); + return TRUE; + } + } + OriginalThunk++; + FirstThunk++; + } + } + } + return FALSE; +} + +static BOOL RestoreIat(PCSTR target, PCSTR DllName, PCSTR FunctionName, ULONG_PTR OriginalFunction) +{ + ULONG_PTR old = 0; + return RedirectIat(target, DllName, FunctionName, OriginalFunction, &old); +} + +static BOOL wrapSdbSetPermLayerKeys2(LPCSTR dir, LPCSTR name, PCSTR szLayers, BOOL bMachine) +{ + char szPath[MAX_PATH]; + WCHAR wszPath[MAX_PATH], wszLayers[MAX_LAYER_LENGTH]; + sprintf(szPath, "%s\\%s", dir, name); + MultiByteToWideChar(CP_ACP, 0, szLayers, -1, wszLayers, MAX_LAYER_LENGTH); + MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, MAX_PATH); + return pSdbSetPermLayerKeys(wszPath, wszLayers, bMachine); +} + + + +static void test_Sign_Media(void) +{ + char workdir[MAX_PATH], subdir[MAX_PATH], drive[5] = "Z:"; + BOOL ret; + + DWORD logical_drives = GetLogicalDrives(); + g_FakeDrive = 0; + for (drive[0] = 'D'; drive[0] <= 'Z'; drive[0]++) + { + DWORD idx = 1 << (drive[0] - 'D' + 3); + if (!(logical_drives & idx)) + { + g_FakeDrive = drive[0]; + break; + } + } + if (!g_FakeDrive) + { + skip("Unable to find a free drive\n"); + return; + } + + ret = GetTempPathA(MAX_PATH, workdir); + ok(ret, "GetTempPathA error: %d\n", GetLastError()); + lstrcatA(workdir, "apphelp_test"); + + ret = CreateDirectoryA(workdir, NULL); + ok(ret, "CreateDirectoryA error: %d\n", GetLastError()); + + sprintf(subdir, "%s\\sub", workdir); + ret = CreateDirectoryA(subdir, NULL); + ok(ret, "CreateDirectoryA error: %d\n", GetLastError()); + + ret = DefineDosDeviceA(DDD_NO_BROADCAST_SYSTEM, drive, workdir); + ok(ret, "DefineDosDeviceA error: %d\n", GetLastError()); + if(ret) + { + ret = RedirectIat("apphelp.dll", "kernel32.dll", "GetDriveTypeW", (ULONG_PTR)mGetDriveTypeW, (ULONG_PTR*)&pGetDriveTypeW); + ok(ret, "Expected redirect_iat to succeed\n"); + + ok(create_file(workdir, "test.exe", 'a', 4), "create_file error: %d\n", GetLastError()); + + ok(wrapSdbSetPermLayerKeys2(drive, "test.exe", "TEST", 0), "Expected wrapSdbSetPermLayerKeys2 to succeed\n"); + /* 4 */ + /* test.exe */ + expect_LayerValue(0, "SIGN.MEDIA=4 test.exe", "TEST"); + ok(wrapSdbSetPermLayerKeys2(drive, "test.exe", "", 0), "Expected wrapSdbSetPermLayerKeys2 to succeed\n"); + + ok(create_file(workdir, "test.txt", 'a', 1), "create_file error: %d\n", GetLastError()); + + ok(wrapSdbSetPermLayerKeys2(drive, "test.exe", "TEST", 0), "Expected wrapSdbSetPermLayerKeys2 to succeed\n"); + /* (4 << 1) ^ 1 */ + /* test.exe test.txt */ + expect_LayerValue(0, "SIGN.MEDIA=9 test.exe", "TEST"); + ok(wrapSdbSetPermLayerKeys2(drive, "test.exe", "", 0), "Expected wrapSdbSetPermLayerKeys2 to succeed\n"); + + ok(create_file(workdir, "test.zz", 'a', 0x1000), "create_file error: %d\n", GetLastError()); + + ok(wrapSdbSetPermLayerKeys2(drive, "test.exe", "TEST", 0), "Expected wrapSdbSetPermLayerKeys2 to succeed\n"); + /* (((4 << 1) ^ 1) << 1) ^ 0x1000 */ + /* test.exe test.txt test.zz */ + expect_LayerValue(0, "SIGN.MEDIA=1012 test.exe", "TEST"); + ok(wrapSdbSetPermLayerKeys2(drive, "test.exe", "", 0), "Expected wrapSdbSetPermLayerKeys2 to succeed\n"); + + ok(create_file(subdir, "test.exe", 'a', 0x10203), "create_file error: %d\n", GetLastError()); + + ok(wrapSdbSetPermLayerKeys2(drive, "sub\\test.exe", "TEST", 0), "Expected wrapSdbSetPermLayerKeys2 to succeed\n"); + /* 0x10203 */ + /* test.exe */ + expect_LayerValue(0, "SIGN.MEDIA=10203 sub\\test.exe", "TEST"); + ok(wrapSdbSetPermLayerKeys2(drive, "sub\\test.exe", "", 0), "Expected wrapSdbSetPermLayerKeys2 to succeed\n"); + + ok(create_file(subdir, "test.bbb", 'a', 0), "create_file error: %d\n", GetLastError()); + + ok(wrapSdbSetPermLayerKeys2(drive, "sub\\test.exe", "TEST", 0), "Expected wrapSdbSetPermLayerKeys2 to succeed\n"); + /* 0x10203 */ + /* test.exe */ + expect_LayerValue(0, "SIGN.MEDIA=10203 sub\\test.exe", "TEST"); + ok(wrapSdbSetPermLayerKeys2(drive, "sub\\test.exe", "", 0), "Expected wrapSdbSetPermLayerKeys2 to succeed\n"); + + ok(create_file(subdir, "TEST.txt", 'a', 0x30201), "create_file error: %d\n", GetLastError()); + + ok(wrapSdbSetPermLayerKeys2(drive, "sub\\test.exe", "TEST", 0), "Expected wrapSdbSetPermLayerKeys2 to succeed\n"); + /* (0x10203 << 1) ^ 0x30201 */ + /* test.exe TEST.txt */ + expect_LayerValue(0, "SIGN.MEDIA=10607 sub\\test.exe", "TEST"); + ok(wrapSdbSetPermLayerKeys2(drive, "sub\\test.exe", "", 0), "Expected wrapSdbSetPermLayerKeys2 to succeed\n"); + + ok(create_file(subdir, "TEST.aaa", 'a', 0x3a2a1), "create_file error: %d\n", GetLastError()); + + ok(wrapSdbSetPermLayerKeys2(drive, "sub\\test.exe", "TEST", 0), "Expected wrapSdbSetPermLayerKeys2 to succeed\n"); + /* (((0x3a2a1 << 1) ^ 0x10203) << 1) ^ 0x30201 */ + /* TEST.aaa test.exe TEST.txt */ + todo_ros expect_LayerValue(0, "SIGN.MEDIA=F8C83 sub\\test.exe", "TEST"); + ok(wrapSdbSetPermLayerKeys2(drive, "sub\\test.exe", "", 0), "Expected wrapSdbSetPermLayerKeys2 to succeed\n"); + + ret = RestoreIat("apphelp.dll", "kernel32.dll", "GetDriveTypeW", (ULONG_PTR)pGetDriveTypeW); + ok(ret, "Expected restore_iat to succeed\n"); + + ok(delete_file(subdir, "test.bbb"), "delete_file error: %d\n", GetLastError()); + ok(delete_file(subdir, "TEST.aaa"), "delete_file error: %d\n", GetLastError()); + ok(delete_file(subdir, "TEST.txt"), "delete_file error: %d\n", GetLastError()); + ok(delete_file(subdir, "test.exe"), "delete_file error: %d\n", GetLastError()); + ok(delete_file(workdir, "test.zz"), "delete_file error: %d\n", GetLastError()); + ok(delete_file(workdir, "test.txt"), "delete_file error: %d\n", GetLastError()); + ok(delete_file(workdir, "test.exe"), "delete_file error: %d\n", GetLastError()); + ret = DefineDosDeviceA(DDD_REMOVE_DEFINITION | DDD_NO_BROADCAST_SYSTEM, drive, NULL); + ok(ret, "DefineDosDeviceA error: %d\n", GetLastError()); + } + ret = RemoveDirectoryA(subdir); + ok(ret, "RemoveDirectoryA error: %d\n", GetLastError()); + ret = RemoveDirectoryA(workdir); + ok(ret, "RemoveDirectoryA error: %d\n", GetLastError()); +} + + +START_TEST(layerapi) +{ + //SetEnvironmentVariable("SHIM_DEBUG_LEVEL", "4"); + hdll = LoadLibraryA("apphelp.dll"); + pAllowPermLayer = (void *) GetProcAddress(hdll, "AllowPermLayer"); + pSdbSetPermLayerKeys = (void *) GetProcAddress(hdll, "SdbSetPermLayerKeys"); + pSdbGetPermLayerKeys = (void *) GetProcAddress(hdll, "SdbGetPermLayerKeys"); + pSetPermLayerState = (void *) GetProcAddress(hdll, "SetPermLayerState"); + + if (!pAllowPermLayer || !pSdbSetPermLayerKeys || !pSdbGetPermLayerKeys || !pSetPermLayerState) + { + skip("Skipping layerapi tests, not everything is implemented!\n"); + return; + } + test_AllowPermLayer(); + test_SdbGetPermLayerKeys(); + test_SetPermLayer(); + test_Sign_Media(); +} Index: winetests/apphelp/testlist.c =================================================================== --- winetests/apphelp/testlist.c (revision 0) +++ winetests/apphelp/testlist.c (working copy) @@ -0,0 +1,13 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define STANDALONE +#define WINETEST_MSVC_IDE_FORMATTING +#include + +extern void func_layerapi(void); + +const struct test winetest_testlist[] = +{ + { "layerapi", func_layerapi }, + { 0, 0 } +}; Index: winetests/CMakeLists.txt =================================================================== --- winetests/CMakeLists.txt (revision 69817) +++ winetests/CMakeLists.txt (working copy) @@ -3,6 +3,7 @@ add_subdirectory(advapi32) add_subdirectory(advpack) +add_subdirectory(apphelp) add_subdirectory(amstream) add_subdirectory(atl) add_subdirectory(atl100)